package com.rekoe.service; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.nutz.dao.Cnd; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.log.Log; import org.nutz.log.Logs; import org.nutz.repo.Base64; import com.rekoe.domain.Pj; import com.rekoe.domain.PjAuth; import com.rekoe.domain.PjGrUsr; import com.rekoe.domain.Usr; import com.rekoe.utils.Constants; import com.rekoe.utils.EncryptUtil; import cn.hutool.crypto.digest.DigestAlgorithm; import cn.hutool.crypto.digest.DigestUtil; /** * 导出svn配置信息服务层 * */ @IocBean public class SvnService { /** * 分隔符 */ private static final String SEP = System.getProperty("line.separator"); /** * 日志 */ private final Log LOG = Logs.get(); @Inject private ProjectService projectService; @Inject private ProjectUserService projectUserService; @Inject private ProjectAuthService projectAuthService; @Inject private ProjectGroupService projectGroupService; @Inject private ProjectGroupUsrService projectGroupUsrService; @Inject private ProjectConfigService projectConfigService; /** * 导出到配置文件 * * @param pj 项目id */ public synchronized void exportConfig(String pj) { this.exportConfig(projectService.fetch(Cnd.where("pj", "=", pj))); } /** * 导出到配置文件 * * @param pj 项目 */ public synchronized void exportConfig(Pj pj) { if (pj == null) { return; } String path = projectConfigService.getRepoPath(pj); File parent = new File(path); if (!parent.exists() || !parent.isDirectory()) { throw new RuntimeException(String.format("找不到仓库 路径 %s", path)); } if (Constants.HTTP.equalsIgnoreCase(pj.getType())) {// HTTP(单库) SVNPath this.exportHTTP(pj); } else if (Constants.HTTP_MUTIL.equalsIgnoreCase(pj.getType())) {// HTTP(多库) File root = new File(path).getParentFile(); this.exportHTTPMutil(root); } else if (Constants.SVN.equalsIgnoreCase(pj.getType())) {// SVN this.exportSVN(pj); } } @Inject private UsrService usrService; /** * 导出svn协议的配置信息 * * @param pj 项目 */ private void exportSVN(Pj pj) { // 项目的用户 List usrList = this.usrService.getList(pj.getPj()); // 项目的用户组 Map> pjGrUsrMap = this.getPjGrUsrs(pj.getPj()); // 项目的权限 Map> pjAuthMap = this.getPjAuths(pj.getPj()); this.exportSvnConf(pj); this.exportPasswdSVN(pj, usrList); this.exportAuthz(pj, pjGrUsrMap, pjAuthMap); } /** * 导出http(单库)的配置信息 * * @param pj 项目 */ private void exportHTTP(Pj pj) { // 项目的用户 List usrList = usrService.getList(pj.getPj()); // 项目的用户组 Map> pjGrUsrMap = this.getPjGrUsrs(pj.getPj()); // 项目的权限 Map> pjAuthMap = this.getPjAuths(pj.getPj()); this.exportSVNPathConf(pj); this.exportPasswdHTTP(pj, usrList); this.exportAuthz(pj, pjGrUsrMap, pjAuthMap); } /** * 导出http(多库)的配置信息 * * @param root svn root */ private void exportHTTPMutil(File root) { String svnRoot = StringUtils.replace(root.getAbsolutePath(), "\\", "/"); if (!svnRoot.endsWith("/")) { svnRoot += "/"; } // 和这个项目在同一个父目录的所有项目的用户 List usrList = this.usrService.getListByRootPath(svnRoot); // 和这个项目在同一个父目录的所有项目的用户组 Map> pjGrUsrMap = this.getPjGrUsrsByRootPath(svnRoot); // 和这个项目在同一个父目录的所有项目的权限 Map> pjAuthMap = this.getPjAuthsByRootPath(svnRoot); this.exportSVNParentPathConf(root); this.exportPasswdHTTPMutil(root, usrList); this.exportAuthzHTTPMutil(root, pjGrUsrMap, pjAuthMap); } /** * 获取有相同svn root的项目的权限列表 * * @param rootPath svn root * @return 有相同svn root的项目的权限列表 */ private Map> getPjAuthsByRootPath(String rootPath) { Map> results = new LinkedHashMap>();// > List pjAuthList = this.projectAuthService.getListByRootPath(rootPath); // 格式化返回数据 for (PjAuth pjAuth : pjAuthList) { List authList = results.get(pjAuth.getRes()); if (authList == null) { authList = new ArrayList(); results.put(pjAuth.getRes(), authList); } authList.add(pjAuth); } return results; } /** * 获取项目的权限列表 * * @param pj 项目 * @return 项目的权限列表 */ private Map> getPjAuths(String pj) { Map> results = new LinkedHashMap>();// > List pjAuthList = this.projectAuthService.getList(pj); // 格式化返回数据 for (PjAuth pjAuth : pjAuthList) { List authList = results.get(pjAuth.getRes()); if (authList == null) { authList = new ArrayList(); results.put(pjAuth.getRes(), authList); } authList.add(pjAuth); } return results; } /** * 获取项目的组列表 * * @param pj 项目 * @return 项目的组列表 */ private Map> getPjGrUsrs(String pj) { Map> results = new LinkedHashMap>();// > List pjGrUsrs = this.projectGroupUsrService.getList(pj); // 格式化返回数据 for (PjGrUsr pjGrUsr : pjGrUsrs) { List grUsrList = results.get(pjGrUsr.getGr()); if (grUsrList == null) { grUsrList = new ArrayList(); results.put(pjGrUsr.getGr(), grUsrList); } grUsrList.add(pjGrUsr); } return results; } /** * 获取有相同svn root的项目的权限列表 * * @param rootPath svn root * @return 有相同svn root的项目的权限列表 */ private Map> getPjGrUsrsByRootPath(String rootPath) { Map> results = new LinkedHashMap>();// > List pjGrUsrs = this.projectGroupUsrService.getListByRootPath(rootPath); // 格式化返回数据 for (PjGrUsr pjGrUsr : pjGrUsrs) { String key = pjGrUsr.getPj() + "_" + pjGrUsr.getGr(); List grUsrList = results.get(key);// 项目ID_组ID see: Issue 4 if (grUsrList == null) { grUsrList = new ArrayList(); results.put(key, grUsrList); } grUsrList.add(pjGrUsr); } return results; } /** * 输出http多库方式的密码文件 * * @param root svn root * @param usrList 所有用户列表 */ private void exportPasswdHTTPMutil(File root, List usrList) { File outFile = new File(root, "passwd.http"); StringBuffer contents = new StringBuffer(); for (Usr usr : usrList) { // 采用SHA加密 // http://httpd.apache.org/docs/2.2/misc/password_encryptions.html String shaPsw = "{SHA}" + EncryptUtil.encriptSHA1(EncryptUtil.decrypt(usr.getPsw())); contents.append(usr.getUsr()).append(":").append(shaPsw).append(SEP); } this.write(outFile, contents.toString()); } /** * 输出http单库方式的密码文件 * * @param pj 项目 * @param usrList 项目用户列表 */ private void exportPasswdHTTP(Pj pj, List usrList) { String path = projectConfigService.getRepoPath(pj); File outFile = new File(path, "/conf/passwd.http"); StringBuffer contents = new StringBuffer(); for (Usr usr : usrList) { // 采用SHA加密 // http://httpd.apache.org/docs/2.2/misc/password_encryptions.html String shaPsw = "{SHA}" + EncryptUtil.encriptSHA1(EncryptUtil.decrypt(usr.getPsw())); contents.append(usr.getUsr()).append(":").append(shaPsw).append(SEP); } this.write(outFile, contents.toString()); } /** * 输出svn方式的密码文件 * * @param pj 项目 * @param usrList 项目用户列表 */ private void exportPasswdSVN(Pj pj, List usrList) { String path = projectConfigService.getRepoPath(pj); File outFile = new File(path, "/conf/passwd"); StringBuffer contents = new StringBuffer(); contents.append("[users]").append(SEP); for (Usr usr : usrList) { contents.append(usr.getUsr()).append("=").append(EncryptUtil.decrypt(usr.getPsw())).append(SEP);// 解密 } this.write(outFile, contents.toString()); } /** * 输出http多库方式的权限文件 * * @param root svn root * @param pjGrUsrMap 所有的项目组用户列表 * @param resMap 所有的权限列表 */ private void exportAuthzHTTPMutil(File root, Map> pjGrUsrMap, Map> resMap) { if (root == null) { return; } File outFile = new File(root, "authz"); StringBuffer contents = new StringBuffer(); contents.append("[aliases]").append(SEP); contents.append("[groups]").append(SEP); for (Iterator grIterator = pjGrUsrMap.keySet().iterator(); grIterator.hasNext();) { String gr = grIterator.next();// 项目ID_组ID see: Issue 4 contents.append(gr).append("="); List pjGrUsrList = pjGrUsrMap.get(gr); for (int i = 0; i < pjGrUsrList.size(); i++) { PjGrUsr pjGrUsr = pjGrUsrList.get(i); if (pjGrUsr.getUsr() == null) { continue; } if (i != 0) { contents.append(","); } contents.append(pjGrUsr.getUsr()); } contents.append(SEP); } contents.append(SEP); for (Iterator resIterator = resMap.keySet().iterator(); resIterator.hasNext();) { String res = resIterator.next(); contents.append(res).append(SEP); for (PjAuth pjAuth : resMap.get(res)) { if (StringUtils.isNotBlank(pjAuth.getGr())) { // 项目ID_组ID see: Issue 4 contents.append("@").append(pjAuth.getPj() + "_" + pjAuth.getGr()).append("=").append(pjAuth.getRw()).append(SEP); } else if (StringUtils.isNotBlank(pjAuth.getUsr())) { contents.append(pjAuth.getUsr()).append("=").append(pjAuth.getRw()).append(SEP); } } contents.append(SEP); } this.write(outFile, contents.toString()); } /** * 输出权限配置文件 * * @param pj 项目 * @param pjGrUsrMap 项目的组列表 * @param resMap 项目的权限列表 */ private void exportAuthz(Pj pj, Map> pjGrUsrMap, Map> resMap) { if (pj == null || StringUtils.isBlank(pj.getPj())) { return; } /* * if(pjGrList == null || pjGrList.size() == 0){ return; } if(pjAuthMap == null * || pjAuthMap.size() == 0){ return; } */ String path = projectConfigService.getRepoPath(pj); File outFile = new File(path, "/conf/authz"); StringBuffer contents = new StringBuffer(); contents.append("[aliases]").append(SEP); contents.append("[groups]").append(SEP); for (Iterator grIterator = pjGrUsrMap.keySet().iterator(); grIterator.hasNext();) { String gr = grIterator.next(); contents.append(gr).append("="); List pjGrUsrList = pjGrUsrMap.get(gr); for (int i = 0; i < pjGrUsrList.size(); i++) { PjGrUsr pjGrUsr = pjGrUsrList.get(i); if (pjGrUsr.getUsr() == null) { continue; } if (i != 0) { contents.append(","); } contents.append(pjGrUsr.getUsr()); } contents.append(SEP); } contents.append(SEP); for (Iterator resIterator = resMap.keySet().iterator(); resIterator.hasNext();) { String res = resIterator.next(); contents.append(res).append(SEP); for (PjAuth pjAuth : resMap.get(res)) { if (StringUtils.isNotBlank(pjAuth.getGr())) { contents.append("@").append(pjAuth.getGr()).append("=").append(pjAuth.getRw()).append(SEP); } else if (StringUtils.isNotBlank(pjAuth.getUsr())) { contents.append(pjAuth.getUsr()).append("=").append(pjAuth.getRw()).append(SEP); } } contents.append(SEP); } this.write(outFile, contents.toString()); } /** * 输出svn方式的svnserve.conf * * @param pj 项目 */ private void exportSvnConf(Pj pj) { if (pj == null || StringUtils.isBlank(pj.getPj())) { return; } String path = projectConfigService.getRepoPath(pj); File outFile = new File(path, "/conf/svnserve.conf"); StringBuffer contents = new StringBuffer(); contents.append("[general]").append(SEP); contents.append("anon-access = none").append(SEP); contents.append("auth-access = write").append(SEP); contents.append("password-db = passwd").append(SEP); contents.append("authz-db = authz").append(SEP); contents.append("[sasl]").append(SEP); this.write(outFile, contents.toString()); } /** * 输出http单库方式的httpd.conf文件 * * @param pj 项目 */ private void exportSVNPathConf(Pj pj) { if (pj == null || StringUtils.isBlank(pj.getPj())) { return; } String path = projectConfigService.getRepoPath(pj); File outFile = new File(path, "/conf/httpd.conf"); StringBuffer contents = new StringBuffer(); contents.append("#Include ").append(path).append("/conf/httpd.conf").append(SEP); String location = pj.getPj(); // 例如 http://192.168.1.100/svn/projar/trunk String svnUrl = RepositoryService.parseURL(projectConfigService.getProjectUrl(pj)); location = StringUtils.substringAfter(svnUrl, "//");// 192.168.1.100/svn/projar/trunk location = StringUtils.substringAfter(location, "/");// svn/projar/trunk location = StringUtils.substringBeforeLast(location, "/trunk");// svn/projar contents.append("").append(SEP); contents.append("DAV svn").append(SEP); contents.append("SVNPath ").append(path).append(SEP); contents.append("AuthType Basic").append(SEP); contents.append("AuthName ").append("\"").append(path).append("\"").append(SEP); contents.append("AuthUserFile ").append(path).append("/conf/passwd.http").append(SEP); contents.append("AuthzSVNAccessFile ").append(path).append("/conf/authz").append(SEP); contents.append("Require valid-user").append(SEP); contents.append("").append(SEP); this.write(outFile, contents.toString()); } /** * 输出http多库方式的httpd.conf文件 * * @param root svn root */ private void exportSVNParentPathConf(File root) { String svnRoot = StringUtils.replace(root.getAbsolutePath(), "\\", "/"); File outFile = new File(root, "httpd.conf"); StringBuffer contents = new StringBuffer(); contents.append("#Include ").append(svnRoot).append("/httpd.conf").append(SEP); String location = root.getName(); contents.append("").append(SEP); contents.append("DAV svn").append(SEP); contents.append("SVNListParentPath on").append(SEP); contents.append("SVNParentPath ").append(svnRoot).append(SEP); contents.append("AuthType Basic").append(SEP); contents.append("AuthName ").append("\"").append("Subversion repositories").append("\"").append(SEP); contents.append("AuthUserFile ").append(svnRoot).append("/passwd.http").append(SEP); contents.append("AuthzSVNAccessFile ").append(svnRoot).append("/authz").append(SEP); contents.append("Require valid-user").append(SEP); contents.append("").append(SEP); contents.append("RedirectMatch ^(/").append(location).append(")$ $1/").append(SEP); this.write(outFile, contents.toString()); } /** * 写文件流 * * @param outFile 输出文件 * @param contents 内容 */ private void write(File outFile, String contents) { BufferedWriter writer = null; try { if (contents == null) { contents = ""; } if (!outFile.getParentFile().exists()) { outFile.getParentFile().mkdirs(); } writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "UTF-8"));// UTF-8 writer.write(contents); LOG.debug(outFile); } catch (Exception e) { LOG.error(e); throw new RuntimeException(e.getMessage()); } finally { if (writer != null) { try { writer.flush(); } catch (IOException e) { LOG.error(e); } try { writer.close(); } catch (IOException e) { LOG.error(e); } } } } public static void main(String[] args) { String key = "admin" + ":{SHA}" + Base64.encodeToString(DigestUtil.digester(DigestAlgorithm.SHA1).digest("123456"), false); System.out.println(key); String key2 = "admin" + ":{SHA}" + EncryptUtil.encriptSHA1("123456"); System.out.println(key2); String decode = EncryptUtil.decrypt("fEqNCco3Yq9h5ZUglD3CZJT4lBs="); System.out.println(decode); } }