From 4e84166db5c5538e3984d9d2d6bb1f9902e65ee0 Mon Sep 17 00:00:00 2001 From: James Moger <james.moger@gitblit.com> Date: Tue, 04 Nov 2014 17:38:17 -0500 Subject: [PATCH] Merged #217 "Exclude SSLv3 from Gitblit GO https protocols" --- src/main/java/com/gitblit/manager/GitblitManager.java | 1428 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 1,150 insertions(+), 278 deletions(-) diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java index 9947382..9692e65 100644 --- a/src/main/java/com/gitblit/manager/GitblitManager.java +++ b/src/main/java/com/gitblit/manager/GitblitManager.java @@ -27,59 +27,135 @@ import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.eclipse.jgit.api.CloneCommand; +import org.eclipse.jgit.api.FetchCommand; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.RefSpec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ro.fortsoft.pf4j.PluginState; +import ro.fortsoft.pf4j.PluginWrapper; +import ro.fortsoft.pf4j.Version; + import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; -import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.FederationRequest; +import com.gitblit.Constants.FederationToken; +import com.gitblit.Constants.Role; import com.gitblit.GitBlitException; import com.gitblit.IStoredSettings; -import com.gitblit.Keys; +import com.gitblit.models.FederationModel; +import com.gitblit.models.FederationProposal; +import com.gitblit.models.FederationSet; +import com.gitblit.models.ForkModel; import com.gitblit.models.GitClientApplication; +import com.gitblit.models.Mailing; +import com.gitblit.models.Metric; +import com.gitblit.models.PluginRegistry.InstallState; +import com.gitblit.models.PluginRegistry.PluginRegistration; +import com.gitblit.models.PluginRegistry.PluginRelease; +import com.gitblit.models.ProjectModel; +import com.gitblit.models.RegistrantAccessPermission; import com.gitblit.models.RepositoryModel; -import com.gitblit.models.RepositoryUrl; +import com.gitblit.models.SearchResult; import com.gitblit.models.ServerSettings; +import com.gitblit.models.ServerStatus; import com.gitblit.models.SettingModel; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; +import com.gitblit.tickets.ITicketService; +import com.gitblit.transport.ssh.IPublicKeyManager; +import com.gitblit.transport.ssh.SshKey; import com.gitblit.utils.ArrayUtils; -import com.gitblit.utils.HttpUtils; -import com.gitblit.utils.JGitUtils; import com.gitblit.utils.JsonUtils; import com.gitblit.utils.ObjectCache; import com.gitblit.utils.StringUtils; +import com.gitblit.utils.XssFilter; import com.google.gson.Gson; import com.google.gson.JsonIOException; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Provider; +import com.google.inject.Singleton; -public class GitblitManager implements IGitblitManager { +/** + * GitblitManager is an aggregate interface delegate. It implements all the manager + * interfaces and delegates most methods calls to the proper manager implementation. + * It's primary purpose is to provide complete management control to the git + * upload and receive pack functions. + * + * GitblitManager also implements several integration methods when it is required + * to manipulate several manages for one operation. + * + * @author James Moger + * + */ +@Singleton +public class GitblitManager implements IGitblit { - private final Logger logger = LoggerFactory.getLogger(getClass()); + protected final Logger logger = LoggerFactory.getLogger(getClass()); - private final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>(); + protected final ObjectCache<Collection<GitClientApplication>> clientApplications = new ObjectCache<Collection<GitClientApplication>>(); - private final IStoredSettings settings; + protected final Provider<IPublicKeyManager> publicKeyManagerProvider; - private final IRuntimeManager runtimeManager; + protected final Provider<ITicketService> ticketServiceProvider; - private final IUserManager userManager; + protected final IStoredSettings settings; - private final IRepositoryManager repositoryManager; + protected final IRuntimeManager runtimeManager; + protected final IPluginManager pluginManager; + + protected final INotificationManager notificationManager; + + protected final IUserManager userManager; + + protected final IAuthenticationManager authenticationManager; + + protected final IRepositoryManager repositoryManager; + + protected final IProjectManager projectManager; + + protected final IFederationManager federationManager; + + @Inject public GitblitManager( + Provider<IPublicKeyManager> publicKeyManagerProvider, + Provider<ITicketService> ticketServiceProvider, IRuntimeManager runtimeManager, + IPluginManager pluginManager, + INotificationManager notificationManager, IUserManager userManager, - IRepositoryManager repositoryManager) { + IAuthenticationManager authenticationManager, + IRepositoryManager repositoryManager, + IProjectManager projectManager, + IFederationManager federationManager) { + + this.publicKeyManagerProvider = publicKeyManagerProvider; + this.ticketServiceProvider = ticketServiceProvider; this.settings = runtimeManager.getSettings(); this.runtimeManager = runtimeManager; + this.pluginManager = pluginManager; + this.notificationManager = notificationManager; this.userManager = userManager; + this.authenticationManager = authenticationManager; this.repositoryManager = repositoryManager; + this.projectManager = projectManager; + this.federationManager = federationManager; } @Override @@ -91,6 +167,265 @@ @Override public GitblitManager stop() { return this; + } + + /* + * IGITBLIT + */ + + /** + * Creates a personal fork of the specified repository. The clone is view + * restricted by default and the owner of the source repository is given + * access to the clone. + * + * @param repository + * @param user + * @return the repository model of the fork, if successful + * @throws GitBlitException + */ + @Override + public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException { + String cloneName = MessageFormat.format("{0}/{1}.git", user.getPersonalPath(), StringUtils.stripDotGit(StringUtils.getLastPathElement(repository.name))); + String fromUrl = MessageFormat.format("file://{0}/{1}", repositoryManager.getRepositoriesFolder().getAbsolutePath(), repository.name); + + // clone the repository + try { + Repository canonical = getRepository(repository.name); + File folder = new File(repositoryManager.getRepositoriesFolder(), cloneName); + CloneCommand clone = new CloneCommand(); + clone.setBare(true); + + // fetch branches with exclusions + Collection<Ref> branches = canonical.getRefDatabase().getRefs(Constants.R_HEADS).values(); + List<String> branchesToClone = new ArrayList<String>(); + for (Ref branch : branches) { + String name = branch.getName(); + if (name.startsWith(Constants.R_TICKET)) { + // exclude ticket branches + continue; + } + branchesToClone.add(name); + } + clone.setBranchesToClone(branchesToClone); + clone.setURI(fromUrl); + clone.setDirectory(folder); + Git git = clone.call(); + + // fetch tags + FetchCommand fetch = git.fetch(); + fetch.setRefSpecs(new RefSpec("+refs/tags/*:refs/tags/*")); + fetch.call(); + + git.getRepository().close(); + } catch (Exception e) { + throw new GitBlitException(e); + } + + // create a Gitblit repository model for the clone + RepositoryModel cloneModel = repository.cloneAs(cloneName); + // owner has REWIND/RW+ permissions + cloneModel.addOwner(user.username); + + // ensure initial access restriction of the fork + // is not lower than the source repository (issue-495/ticket-167) + if (repository.accessRestriction.exceeds(cloneModel.accessRestriction)) { + cloneModel.accessRestriction = repository.accessRestriction; + } + + repositoryManager.updateRepositoryModel(cloneName, cloneModel, false); + + // add the owner of the source repository to the clone's access list + if (!ArrayUtils.isEmpty(repository.owners)) { + for (String owner : repository.owners) { + UserModel originOwner = userManager.getUserModel(owner); + if (originOwner != null && !originOwner.canClone(cloneModel)) { + // origin owner can't yet clone fork, grant explicit clone access + originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); + reviseUser(originOwner.username, originOwner); + } + } + } + + // grant origin's user list clone permission to fork + List<String> users = repositoryManager.getRepositoryUsers(repository); + List<UserModel> cloneUsers = new ArrayList<UserModel>(); + for (String name : users) { + if (!name.equalsIgnoreCase(user.username)) { + UserModel cloneUser = userManager.getUserModel(name); + if (cloneUser.canClone(repository) && !cloneUser.canClone(cloneModel)) { + // origin user can't yet clone fork, grant explicit clone access + cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE); + } + cloneUsers.add(cloneUser); + } + } + userManager.updateUserModels(cloneUsers); + + // grant origin's team list clone permission to fork + List<String> teams = repositoryManager.getRepositoryTeams(repository); + List<TeamModel> cloneTeams = new ArrayList<TeamModel>(); + for (String name : teams) { + TeamModel cloneTeam = userManager.getTeamModel(name); + if (cloneTeam.canClone(repository) && !cloneTeam.canClone(cloneModel)) { + // origin team can't yet clone fork, grant explicit clone access + cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE); + } + cloneTeams.add(cloneTeam); + } + userManager.updateTeamModels(cloneTeams); + + // add this clone to the cached model + repositoryManager.addToCachedRepositoryList(cloneModel); + return cloneModel; + } + + /** + * Adds a TeamModel object. + * + * @param team + */ + @Override + public void addTeam(TeamModel team) throws GitBlitException { + if (!userManager.updateTeamModel(team)) { + throw new GitBlitException("Failed to add team!"); + } + } + + /** + * Updates the TeamModel object for the specified name. + * + * @param teamname + * @param team + */ + @Override + public void reviseTeam(String teamname, TeamModel team) throws GitBlitException { + if (!teamname.equalsIgnoreCase(team.name)) { + if (userManager.getTeamModel(team.name) != null) { + throw new GitBlitException(MessageFormat.format( + "Failed to rename ''{0}'' because ''{1}'' already exists.", teamname, + team.name)); + } + } + if (!userManager.updateTeamModel(teamname, team)) { + throw new GitBlitException("Failed to update team!"); + } + } + + /** + * Adds a user object. + * + * @param user + * @throws GitBlitException + */ + @Override + public void addUser(UserModel user) throws GitBlitException { + if (!userManager.updateUserModel(user)) { + throw new GitBlitException("Failed to add user!"); + } + } + + /** + * Updates a user object keyed by username. This method allows + * for renaming a user. + * + * @param username + * @param user + * @throws GitBlitException + */ + @Override + public void reviseUser(String username, UserModel user) throws GitBlitException { + if (!username.equalsIgnoreCase(user.username)) { + if (userManager.getUserModel(user.username) != null) { + throw new GitBlitException(MessageFormat.format( + "Failed to rename ''{0}'' because ''{1}'' already exists.", username, + user.username)); + } + + // rename repositories and owner fields for all repositories + for (RepositoryModel model : repositoryManager.getRepositoryModels(user)) { + if (model.isUsersPersonalRepository(username)) { + // personal repository + model.addOwner(user.username); + String oldRepositoryName = model.name; + model.name = user.getPersonalPath() + model.name.substring(model.projectPath.length()); + model.projectPath = user.getPersonalPath(); + repositoryManager.updateRepositoryModel(oldRepositoryName, model, false); + } else if (model.isOwner(username)) { + // common/shared repo + model.addOwner(user.username); + repositoryManager.updateRepositoryModel(model.name, model, false); + } + } + + // rename the user's ssh public keystore + getPublicKeyManager().renameUser(username, user.username); + } + if (!userManager.updateUserModel(username, user)) { + throw new GitBlitException("Failed to update user!"); + } + } + + /** + * Returns the list of custom client applications to be used for the + * repository url panel; + * + * @return a collection of client applications + */ + @Override + public Collection<GitClientApplication> getClientApplications() { + // prefer user definitions, if they exist + File userDefs = new File(runtimeManager.getBaseFolder(), "clientapps.json"); + if (userDefs.exists()) { + Date lastModified = new Date(userDefs.lastModified()); + if (clientApplications.hasCurrent("user", lastModified)) { + return clientApplications.getObject("user"); + } else { + // (re)load user definitions + try { + InputStream is = new FileInputStream(userDefs); + Collection<GitClientApplication> clients = readClientApplications(is); + is.close(); + if (clients != null) { + clientApplications.updateObject("user", lastModified, clients); + return clients; + } + } catch (IOException e) { + logger.error("Failed to deserialize " + userDefs.getAbsolutePath(), e); + } + } + } + + // no user definitions, use system definitions + if (!clientApplications.hasCurrent("system", new Date(0))) { + try { + InputStream is = GitblitManager.class.getResourceAsStream("/clientapps.json"); + Collection<GitClientApplication> clients = readClientApplications(is); + is.close(); + if (clients != null) { + clientApplications.updateObject("system", new Date(0), clients); + } + } catch (IOException e) { + logger.error("Failed to deserialize clientapps.json resource!", e); + } + } + + return clientApplications.getObject("system"); + } + + private Collection<GitClientApplication> readClientApplications(InputStream is) { + try { + Type type = new TypeToken<Collection<GitClientApplication>>() { + }.getType(); + InputStreamReader reader = new InputStreamReader(is); + Gson gson = JsonUtils.gson(); + Collection<GitClientApplication> links = gson.fromJson(reader, type); + return links; + } catch (JsonIOException e) { + logger.error("Error deserializing client applications!", e); + } catch (JsonSyntaxException e) { + logger.error("Error deserializing client applications!", e); + } + return null; } /** @@ -105,7 +440,7 @@ // Read bundled Gitblit properties to extract setting descriptions. // This copy is pristine and only used for populating the setting // models map. - InputStream is = getClass().getResourceAsStream("/reference.properties"); + InputStream is = GitblitManager.class.getResourceAsStream("/defaults.properties"); BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is)); StringBuilder description = new StringBuilder(); SettingModel setting = new SettingModel(); @@ -150,307 +485,844 @@ } propertiesReader.close(); } catch (NullPointerException e) { - logger.error("Failed to find resource copy of gitblit.properties"); + logger.error("Failed to find classpath resource 'defaults.properties'"); } catch (IOException e) { - logger.error("Failed to load resource copy of gitblit.properties"); + logger.error("Failed to load classpath resource 'defaults.properties'"); } } - /** - * Returns a list of repository URLs and the user access permission. - * - * @param request - * @param user - * @param repository - * @return a list of repository urls - */ @Override - public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { + public ITicketService getTicketService() { + return ticketServiceProvider.get(); + } + + @Override + public IPublicKeyManager getPublicKeyManager() { + return publicKeyManagerProvider.get(); + } + + /* + * ISTOREDSETTINGS + * + * these methods are necessary for (nearly) seamless Groovy hook operation + * after the massive refactor. + */ + + public boolean getBoolean(String key, boolean defaultValue) { + return runtimeManager.getSettings().getBoolean(key, defaultValue); + } + + public String getString(String key, String defaultValue) { + return runtimeManager.getSettings().getString(key, defaultValue); + } + + public int getInteger(String key, int defaultValue) { + return runtimeManager.getSettings().getInteger(key, defaultValue); + } + + public List<String> getStrings(String key) { + return runtimeManager.getSettings().getStrings(key); + } + + /* + * RUNTIME MANAGER + */ + + @Override + public File getBaseFolder() { + return runtimeManager.getBaseFolder(); + } + + @Override + public void setBaseFolder(File folder) { + runtimeManager.setBaseFolder(folder); + } + + @Override + public Date getBootDate() { + return runtimeManager.getBootDate(); + } + + @Override + public ServerSettings getSettingsModel() { + return runtimeManager.getSettingsModel(); + } + + @Override + public TimeZone getTimezone() { + return runtimeManager.getTimezone(); + } + + @Override + public Locale getLocale() { + return runtimeManager.getLocale(); + } + + @Override + public boolean isDebugMode() { + return runtimeManager.isDebugMode(); + } + + @Override + public File getFileOrFolder(String key, String defaultFileOrFolder) { + return runtimeManager.getFileOrFolder(key, defaultFileOrFolder); + } + + @Override + public File getFileOrFolder(String fileOrFolder) { + return runtimeManager.getFileOrFolder(fileOrFolder); + } + + @Override + public IStoredSettings getSettings() { + return runtimeManager.getSettings(); + } + + @Override + public boolean updateSettings(Map<String, String> updatedSettings) { + return runtimeManager.updateSettings(updatedSettings); + } + + @Override + public ServerStatus getStatus() { + return runtimeManager.getStatus(); + } + + @Override + public Injector getInjector() { + return runtimeManager.getInjector(); + } + + @Override + public XssFilter getXssFilter() { + return runtimeManager.getXssFilter(); + } + + /* + * NOTIFICATION MANAGER + */ + + @Override + public boolean isSendingMail() { + return notificationManager.isSendingMail(); + } + + @Override + public void sendMailToAdministrators(String subject, String message) { + notificationManager.sendMailToAdministrators(subject, message); + } + + @Override + public void sendMail(String subject, String message, Collection<String> toAddresses) { + notificationManager.sendMail(subject, message, toAddresses); + } + + @Override + public void sendHtmlMail(String subject, String message, Collection<String> toAddresses) { + notificationManager.sendHtmlMail(subject, message, toAddresses); + } + + @Override + public void send(Mailing mail) { + notificationManager.send(mail); + } + + /* + * SESSION MANAGER + */ + + @Override + public UserModel authenticate(String username, char[] password) { + return authenticationManager.authenticate(username, password); + } + + @Override + public UserModel authenticate(HttpServletRequest httpRequest) { + UserModel user = authenticationManager.authenticate(httpRequest, false); if (user == null) { - user = UserModel.ANONYMOUS; + user = federationManager.authenticate(httpRequest); } - String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); - - List<RepositoryUrl> list = new ArrayList<RepositoryUrl>(); - // http/https url - if (settings.getBoolean(Keys.git.enableGitServlet, true)) { - AccessPermission permission = user.getRepositoryPermission(repository).permission; - if (permission.exceeds(AccessPermission.NONE)) { - list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission)); - } - } - - // git daemon url - String gitDaemonUrl = getGitDaemonUrl(request, user, repository); - if (!StringUtils.isEmpty(gitDaemonUrl)) { - AccessPermission permission = getGitDaemonAccessPermission(user, repository); - if (permission.exceeds(AccessPermission.NONE)) { - list.add(new RepositoryUrl(gitDaemonUrl, permission)); - } - } - - // add all other urls - // {0} = repository - // {1} = username - for (String url : settings.getStrings(Keys.web.otherUrls)) { - if (url.contains("{1}")) { - // external url requires username, only add url IF we have one - if (!StringUtils.isEmpty(username)) { - list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null)); - } - } else { - // external url does not require username - list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null)); - } - } - return list; + return user; } - protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) { - StringBuilder sb = new StringBuilder(); - sb.append(HttpUtils.getGitblitURL(request)); - sb.append(Constants.GIT_PATH); - sb.append(repository.name); + @Override + public UserModel authenticate(String username, SshKey key) { + return authenticationManager.authenticate(username, key); + } - // inject username into repository url if authentication is required - if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) - && !StringUtils.isEmpty(username)) { - sb.insert(sb.indexOf("://") + 3, username + "@"); + @Override + public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) { + UserModel user = authenticationManager.authenticate(httpRequest, requiresCertificate); + if (user == null) { + user = federationManager.authenticate(httpRequest); } - return sb.toString(); + return user; } - protected String getGitDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) { -// if (gitDaemon != null) { -// String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost"); -// if (bindInterface.equals("localhost") -// && (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) { -// // git daemon is bound to localhost and the request is from elsewhere -// return null; -// } -// if (user.canClone(repository)) { -// String servername = request.getServerName(); -// String url = gitDaemon.formatUrl(servername, repository.name); -// return url; -// } -// } - return null; + @Override + public String getCookie(HttpServletRequest request) { + return authenticationManager.getCookie(request); } - protected AccessPermission getGitDaemonAccessPermission(UserModel user, RepositoryModel repository) { -// if (gitDaemon != null && user.canClone(repository)) { -// AccessPermission gitDaemonPermission = user.getRepositoryPermission(repository).permission; -// if (gitDaemonPermission.atLeast(AccessPermission.CLONE)) { -// if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) { -// // can not authenticate clone via anonymous git protocol -// gitDaemonPermission = AccessPermission.NONE; -// } else if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) { -// // can not authenticate push via anonymous git protocol -// gitDaemonPermission = AccessPermission.CLONE; -// } else { -// // normal user permission -// } -// } -// return gitDaemonPermission; -// } - return AccessPermission.NONE; + @Override + @Deprecated + public void setCookie(HttpServletResponse response, UserModel user) { + authenticationManager.setCookie(response, user); + } + + @Override + public void setCookie(HttpServletRequest request, HttpServletResponse response, UserModel user) { + authenticationManager.setCookie(request, response, user); + } + + @Override + @Deprecated + public void logout(HttpServletResponse response, UserModel user) { + authenticationManager.logout(response, user); + } + + @Override + public void logout(HttpServletRequest request, HttpServletResponse response, UserModel user) { + authenticationManager.logout(request, response, user); + } + + @Override + public boolean supportsCredentialChanges(UserModel user) { + return authenticationManager.supportsCredentialChanges(user); + } + + @Override + public boolean supportsDisplayNameChanges(UserModel user) { + return authenticationManager.supportsDisplayNameChanges(user); + } + + @Override + public boolean supportsEmailAddressChanges(UserModel user) { + return authenticationManager.supportsEmailAddressChanges(user); + } + + @Override + public boolean supportsTeamMembershipChanges(UserModel user) { + return authenticationManager.supportsTeamMembershipChanges(user); + } + + @Override + public boolean supportsTeamMembershipChanges(TeamModel team) { + return authenticationManager.supportsTeamMembershipChanges(team); + } + + @Override + public boolean supportsRoleChanges(UserModel user, Role role) { + return authenticationManager.supportsRoleChanges(user, role); + } + + @Override + public boolean supportsRoleChanges(TeamModel team, Role role) { + return authenticationManager.supportsRoleChanges(team, role); + } + + /* + * USER MANAGER + */ + + @Override + public void setup(IRuntimeManager runtimeManager) { + } + + @Override + public boolean isInternalAccount(String username) { + return userManager.isInternalAccount(username); + } + + @Override + public List<String> getAllUsernames() { + return userManager.getAllUsernames(); + } + + @Override + public List<UserModel> getAllUsers() { + return userManager.getAllUsers(); + } + + @Override + public UserModel getUserModel(String username) { + return userManager.getUserModel(username); + } + + @Override + public List<TeamModel> getAllTeams() { + return userManager.getAllTeams(); + } + + @Override + public TeamModel getTeamModel(String teamname) { + return userManager.getTeamModel(teamname); + } + + @Override + public String getCookie(UserModel model) { + return userManager.getCookie(model); + } + + @Override + public UserModel getUserModel(char[] cookie) { + return userManager.getUserModel(cookie); + } + + @Override + public boolean updateUserModel(UserModel model) { + return userManager.updateUserModel(model); + } + + @Override + public boolean updateUserModels(Collection<UserModel> models) { + return userManager.updateUserModels(models); + } + + @Override + public boolean updateUserModel(String username, UserModel model) { + return userManager.updateUserModel(username, model); + } + + @Override + public boolean deleteUser(String username) { + // delegate to deleteUserModel() to delete public ssh keys + UserModel user = userManager.getUserModel(username); + return deleteUserModel(user); } /** - * Returns the list of custom client applications to be used for the - * repository url panel; - * - * @return a collection of client applications + * Delete the user and all associated public ssh keys. */ @Override - public Collection<GitClientApplication> getClientApplications() { - // prefer user definitions, if they exist - File userDefs = new File(runtimeManager.getBaseFolder(), "clientapps.json"); - if (userDefs.exists()) { - Date lastModified = new Date(userDefs.lastModified()); - if (clientApplications.hasCurrent("user", lastModified)) { - return clientApplications.getObject("user"); - } else { - // (re)load user definitions - try { - InputStream is = new FileInputStream(userDefs); - Collection<GitClientApplication> clients = readClientApplications(is); - is.close(); - if (clients != null) { - clientApplications.updateObject("user", lastModified, clients); - return clients; - } - } catch (IOException e) { - logger.error("Failed to deserialize " + userDefs.getAbsolutePath(), e); - } - } + public boolean deleteUserModel(UserModel model) { + boolean success = userManager.deleteUserModel(model); + if (success) { + getPublicKeyManager().removeAllKeys(model.username); } - - // no user definitions, use system definitions - if (!clientApplications.hasCurrent("system", new Date(0))) { - try { - InputStream is = getClass().getResourceAsStream("/clientapps.json"); - Collection<GitClientApplication> clients = readClientApplications(is); - is.close(); - if (clients != null) { - clientApplications.updateObject("system", new Date(0), clients); - } - } catch (IOException e) { - logger.error("Failed to deserialize clientapps.json resource!", e); - } - } - - return clientApplications.getObject("system"); + return success; } - private Collection<GitClientApplication> readClientApplications(InputStream is) { - try { - Type type = new TypeToken<Collection<GitClientApplication>>() { - }.getType(); - InputStreamReader reader = new InputStreamReader(is); - Gson gson = JsonUtils.gson(); - Collection<GitClientApplication> links = gson.fromJson(reader, type); - return links; - } catch (JsonIOException e) { - logger.error("Error deserializing client applications!", e); - } catch (JsonSyntaxException e) { - logger.error("Error deserializing client applications!", e); - } - return null; + @Override + public List<String> getAllTeamNames() { + return userManager.getAllTeamNames(); + } + + @Override + public List<String> getTeamNamesForRepositoryRole(String role) { + return userManager.getTeamNamesForRepositoryRole(role); + } + + @Override + public boolean updateTeamModel(TeamModel model) { + return userManager.updateTeamModel(model); + } + + @Override + public boolean updateTeamModels(Collection<TeamModel> models) { + return userManager.updateTeamModels(models); + } + + @Override + public boolean updateTeamModel(String teamname, TeamModel model) { + return userManager.updateTeamModel(teamname, model); + } + + @Override + public boolean deleteTeamModel(TeamModel model) { + return userManager.deleteTeamModel(model); + } + + @Override + public List<String> getUsernamesForRepositoryRole(String role) { + return userManager.getUsernamesForRepositoryRole(role); + } + + @Override + public boolean renameRepositoryRole(String oldRole, String newRole) { + return userManager.renameRepositoryRole(oldRole, newRole); + } + + @Override + public boolean deleteRepositoryRole(String role) { + return userManager.deleteRepositoryRole(role); + } + + @Override + public boolean deleteTeam(String teamname) { + return userManager.deleteTeam(teamname); + } + + /* + * REPOSITORY MANAGER + */ + + @Override + public Date getLastActivityDate() { + return repositoryManager.getLastActivityDate(); + } + + @Override + public File getRepositoriesFolder() { + return repositoryManager.getRepositoriesFolder(); + } + + @Override + public File getHooksFolder() { + return repositoryManager.getHooksFolder(); + } + + @Override + public File getGrapesFolder() { + return repositoryManager.getGrapesFolder(); + } + + @Override + public List<RegistrantAccessPermission> getUserAccessPermissions(UserModel user) { + return repositoryManager.getUserAccessPermissions(user); + } + + @Override + public List<RegistrantAccessPermission> getUserAccessPermissions(RepositoryModel repository) { + return repositoryManager.getUserAccessPermissions(repository); + } + + @Override + public boolean setUserAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) { + return repositoryManager.setUserAccessPermissions(repository, permissions); + } + + @Override + public List<String> getRepositoryUsers(RepositoryModel repository) { + return repositoryManager.getRepositoryUsers(repository); + } + + @Override + public List<RegistrantAccessPermission> getTeamAccessPermissions(RepositoryModel repository) { + return repositoryManager.getTeamAccessPermissions(repository); + } + + @Override + public boolean setTeamAccessPermissions(RepositoryModel repository, Collection<RegistrantAccessPermission> permissions) { + return repositoryManager.setTeamAccessPermissions(repository, permissions); + } + + @Override + public List<String> getRepositoryTeams(RepositoryModel repository) { + return repositoryManager.getRepositoryTeams(repository); + } + @Override + public void addToCachedRepositoryList(RepositoryModel model) { + repositoryManager.addToCachedRepositoryList(model); + } + + @Override + public void resetRepositoryListCache() { + repositoryManager.resetRepositoryListCache(); + } + + @Override + public void resetRepositoryCache(String repositoryName) { + repositoryManager.resetRepositoryCache(repositoryName); + } + + @Override + public List<String> getRepositoryList() { + return repositoryManager.getRepositoryList(); + } + + @Override + public Repository getRepository(String repositoryName) { + return repositoryManager.getRepository(repositoryName); + } + + @Override + public Repository getRepository(String repositoryName, boolean logError) { + return repositoryManager.getRepository(repositoryName, logError); + } + + @Override + public List<RepositoryModel> getRepositoryModels() { + return repositoryManager.getRepositoryModels(); + } + + @Override + public List<RepositoryModel> getRepositoryModels(UserModel user) { + return repositoryManager.getRepositoryModels(user); + } + + @Override + public RepositoryModel getRepositoryModel(UserModel user, String repositoryName) { + return repositoryManager.getRepositoryModel(repositoryName); + } + + @Override + public RepositoryModel getRepositoryModel(String repositoryName) { + return repositoryManager.getRepositoryModel(repositoryName); + } + + @Override + public long getStarCount(RepositoryModel repository) { + return repositoryManager.getStarCount(repository); + } + + @Override + public boolean hasRepository(String repositoryName) { + return repositoryManager.hasRepository(repositoryName); + } + + @Override + public boolean hasRepository(String repositoryName, boolean caseSensitiveCheck) { + return repositoryManager.hasRepository(repositoryName, caseSensitiveCheck); + } + + @Override + public boolean hasFork(String username, String origin) { + return repositoryManager.hasFork(username, origin); + } + + @Override + public String getFork(String username, String origin) { + return repositoryManager.getFork(username, origin); + } + + @Override + public ForkModel getForkNetwork(String repository) { + return repositoryManager.getForkNetwork(repository); + } + + @Override + public long updateLastChangeFields(Repository r, RepositoryModel model) { + return repositoryManager.updateLastChangeFields(r, model); + } + + @Override + public List<Metric> getRepositoryDefaultMetrics(RepositoryModel model, Repository repository) { + return repositoryManager.getRepositoryDefaultMetrics(model, repository); } /** - * Creates a personal fork of the specified repository. The clone is view - * restricted by default and the owner of the source repository is given - * access to the clone. - * - * @param repository - * @param user - * @return the repository model of the fork, if successful - * @throws GitBlitException + * Detect renames and reindex as appropriate. */ @Override - public RepositoryModel fork(RepositoryModel repository, UserModel user) throws GitBlitException { - String cloneName = MessageFormat.format("{0}/{1}.git", user.getPersonalPath(), StringUtils.stripDotGit(StringUtils.getLastPathElement(repository.name))); - String fromUrl = MessageFormat.format("file://{0}/{1}", repositoryManager.getRepositoriesFolder().getAbsolutePath(), repository.name); - - // clone the repository - try { - JGitUtils.cloneRepository(repositoryManager.getRepositoriesFolder(), cloneName, fromUrl, true, null); - } catch (Exception e) { - throw new GitBlitException(e); + public void updateRepositoryModel(String repositoryName, RepositoryModel repository, + boolean isCreate) throws GitBlitException { + RepositoryModel oldModel = null; + boolean isRename = !isCreate && !repositoryName.equalsIgnoreCase(repository.name); + if (isRename) { + oldModel = repositoryManager.getRepositoryModel(repositoryName); } - // create a Gitblit repository model for the clone - RepositoryModel cloneModel = repository.cloneAs(cloneName); - // owner has REWIND/RW+ permissions - cloneModel.addOwner(user.username); - repositoryManager.updateRepositoryModel(cloneName, cloneModel, false); + repositoryManager.updateRepositoryModel(repositoryName, repository, isCreate); - // add the owner of the source repository to the clone's access list - if (!ArrayUtils.isEmpty(repository.owners)) { - for (String owner : repository.owners) { - UserModel originOwner = userManager.getUserModel(owner); - if (originOwner != null) { - originOwner.setRepositoryPermission(cloneName, AccessPermission.CLONE); - updateUserModel(originOwner.username, originOwner, false); - } - } - } - - // grant origin's user list clone permission to fork - List<String> users = repositoryManager.getRepositoryUsers(repository); - List<UserModel> cloneUsers = new ArrayList<UserModel>(); - for (String name : users) { - if (!name.equalsIgnoreCase(user.username)) { - UserModel cloneUser = userManager.getUserModel(name); - if (cloneUser.canClone(repository)) { - // origin user can clone origin, grant clone access to fork - cloneUser.setRepositoryPermission(cloneName, AccessPermission.CLONE); - } - cloneUsers.add(cloneUser); - } - } - userManager.updateUserModels(cloneUsers); - - // grant origin's team list clone permission to fork - List<String> teams = repositoryManager.getRepositoryTeams(repository); - List<TeamModel> cloneTeams = new ArrayList<TeamModel>(); - for (String name : teams) { - TeamModel cloneTeam = userManager.getTeamModel(name); - if (cloneTeam.canClone(repository)) { - // origin team can clone origin, grant clone access to fork - cloneTeam.setRepositoryPermission(cloneName, AccessPermission.CLONE); - } - cloneTeams.add(cloneTeam); - } - userManager.updateTeamModels(cloneTeams); - - // add this clone to the cached model - repositoryManager.addToCachedRepositoryList(cloneModel); - return cloneModel; - } - - /** - * Adds/updates a complete user object keyed by username. This method allows - * for renaming a user. - * - * @see IUserService.updateUserModel(String, UserModel) - * @param username - * @param user - * @param isCreate - * @throws GitBlitException - */ - @Override - public void updateUserModel(String username, UserModel user, boolean isCreate) - throws GitBlitException { - if (!username.equalsIgnoreCase(user.username)) { - if (userManager.getUserModel(user.username) != null) { - throw new GitBlitException(MessageFormat.format( - "Failed to rename ''{0}'' because ''{1}'' already exists.", username, - user.username)); - } - - // rename repositories and owner fields for all repositories - for (RepositoryModel model : repositoryManager.getRepositoryModels(user)) { - if (model.isUsersPersonalRepository(username)) { - // personal repository - model.addOwner(user.username); - String oldRepositoryName = model.name; - model.name = user.getPersonalPath() + model.name.substring(model.projectPath.length()); - model.projectPath = user.getPersonalPath(); - repositoryManager.updateRepositoryModel(oldRepositoryName, model, false); - } else if (model.isOwner(username)) { - // common/shared repo - model.addOwner(user.username); - repositoryManager.updateRepositoryModel(model.name, model, false); - } - } - } - if (!userManager.updateUserModel(username, user)) { - throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!"); + if (isRename && ticketServiceProvider.get() != null) { + ticketServiceProvider.get().rename(oldModel, repository); } } + @Override + public void updateConfiguration(Repository r, RepositoryModel repository) { + repositoryManager.updateConfiguration(r, repository); + } + + @Override + public boolean canDelete(RepositoryModel model) { + return repositoryManager.canDelete(model); + } + /** - * Updates the TeamModel object for the specified name. - * - * @param teamname - * @param team - * @param isCreate + * Delete the repository and all associated tickets. */ @Override - public void updateTeamModel(String teamname, TeamModel team, boolean isCreate) - throws GitBlitException { - if (!teamname.equalsIgnoreCase(team.name)) { - if (userManager.getTeamModel(team.name) != null) { - throw new GitBlitException(MessageFormat.format( - "Failed to rename ''{0}'' because ''{1}'' already exists.", teamname, - team.name)); - } + public boolean deleteRepositoryModel(RepositoryModel model) { + boolean success = repositoryManager.deleteRepositoryModel(model); + if (success && ticketServiceProvider.get() != null) { + ticketServiceProvider.get().deleteAll(model); } - if (!userManager.updateTeamModel(teamname, team)) { - throw new GitBlitException(isCreate ? "Failed to add team!" : "Failed to update team!"); - } + return success; + } + + @Override + public boolean deleteRepository(String repositoryName) { + // delegate to deleteRepositoryModel() to destroy indexed tickets + RepositoryModel repository = repositoryManager.getRepositoryModel(repositoryName); + return deleteRepositoryModel(repository); + } + + @Override + public List<String> getAllScripts() { + return repositoryManager.getAllScripts(); + } + + @Override + public List<String> getPreReceiveScriptsInherited(RepositoryModel repository) { + return repositoryManager.getPreReceiveScriptsInherited(repository); + } + + @Override + public List<String> getPreReceiveScriptsUnused(RepositoryModel repository) { + return repositoryManager.getPreReceiveScriptsUnused(repository); + } + + @Override + public List<String> getPostReceiveScriptsInherited(RepositoryModel repository) { + return repositoryManager.getPostReceiveScriptsInherited(repository); + } + + @Override + public List<String> getPostReceiveScriptsUnused(RepositoryModel repository) { + return repositoryManager.getPostReceiveScriptsUnused(repository); + } + + @Override + public List<SearchResult> search(String query, int page, int pageSize, List<String> repositories) { + return repositoryManager.search(query, page, pageSize, repositories); + } + + @Override + public boolean isCollectingGarbage() { + return repositoryManager.isCollectingGarbage(); + } + + @Override + public boolean isCollectingGarbage(String repositoryName) { + return repositoryManager.isCollectingGarbage(repositoryName); + } + + /* + * PROJECT MANAGER + */ + + @Override + public List<ProjectModel> getProjectModels(UserModel user, boolean includeUsers) { + return projectManager.getProjectModels(user, includeUsers); + } + + @Override + public ProjectModel getProjectModel(String name, UserModel user) { + return projectManager.getProjectModel(name, user); + } + + @Override + public ProjectModel getProjectModel(String name) { + return projectManager.getProjectModel(name); + } + + @Override + public List<ProjectModel> getProjectModels(List<RepositoryModel> repositoryModels, boolean includeUsers) { + return projectManager.getProjectModels(repositoryModels, includeUsers); + } + + /* + * FEDERATION MANAGER + */ + + @Override + public File getProposalsFolder() { + return federationManager.getProposalsFolder(); + } + + @Override + public boolean canFederate() { + return federationManager.canFederate(); + } + + @Override + public UserModel getFederationUser() { + return federationManager.getFederationUser(); + } + + @Override + public List<FederationModel> getFederationRegistrations() { + return federationManager.getFederationRegistrations(); + } + + @Override + public FederationModel getFederationRegistration(String url, String name) { + return federationManager.getFederationRegistration(url, name); + } + + @Override + public List<FederationSet> getFederationSets(String gitblitUrl) { + return federationManager.getFederationSets(gitblitUrl); + } + + @Override + public List<String> getFederationTokens() { + return federationManager.getFederationTokens(); + } + + @Override + public String getFederationToken(FederationToken type) { + return federationManager.getFederationToken(type); + } + + @Override + public String getFederationToken(String value) { + return federationManager.getFederationToken(value); + } + + @Override + public boolean validateFederationRequest(FederationRequest req, String token) { + return federationManager.validateFederationRequest(req, token); + } + + @Override + public boolean acknowledgeFederationStatus(String identification, FederationModel registration) { + return federationManager.acknowledgeFederationStatus(identification, registration); + } + + @Override + public List<FederationModel> getFederationResultRegistrations() { + return federationManager.getFederationResultRegistrations(); + } + + @Override + public boolean submitFederationProposal(FederationProposal proposal, String gitblitUrl) { + return federationManager.submitFederationProposal(proposal, gitblitUrl); + } + + @Override + public List<FederationProposal> getPendingFederationProposals() { + return federationManager.getPendingFederationProposals(); + } + + @Override + public Map<String, RepositoryModel> getRepositories(String gitblitUrl, String token) { + return federationManager.getRepositories(gitblitUrl, token); + } + + @Override + public FederationProposal createFederationProposal(String gitblitUrl, String token) { + return federationManager.createFederationProposal(gitblitUrl, token); + } + + @Override + public FederationProposal getPendingFederationProposal(String token) { + return federationManager.getPendingFederationProposal(token); + } + + @Override + public boolean deletePendingFederationProposal(FederationProposal proposal) { + return federationManager.deletePendingFederationProposal(proposal); + } + + @Override + public void closeAll() { + repositoryManager.closeAll(); + } + + @Override + public void close(String repository) { + repositoryManager.close(repository); + } + + @Override + public boolean isIdle(Repository repository) { + return repositoryManager.isIdle(repository); + } + + /* + * PLUGIN MANAGER + */ + + @Override + public Version getSystemVersion() { + return pluginManager.getSystemVersion(); + } + + @Override + public void startPlugins() { + pluginManager.startPlugins(); + } + + @Override + public void stopPlugins() { + pluginManager.stopPlugins(); + } + + @Override + public List<PluginWrapper> getPlugins() { + return pluginManager.getPlugins(); + } + + @Override + public PluginWrapper getPlugin(String pluginId) { + return pluginManager.getPlugin(pluginId); + } + + @Override + public List<Class<?>> getExtensionClasses(String pluginId) { + return pluginManager.getExtensionClasses(pluginId); + } + + @Override + public <T> List<T> getExtensions(Class<T> clazz) { + return pluginManager.getExtensions(clazz); + } + + @Override + public PluginWrapper whichPlugin(Class<?> clazz) { + return pluginManager.whichPlugin(clazz); + } + + @Override + public PluginState startPlugin(String pluginId) { + return pluginManager.startPlugin(pluginId); + } + + @Override + public PluginState stopPlugin(String pluginId) { + return pluginManager.stopPlugin(pluginId); + } + + @Override + public boolean disablePlugin(String pluginId) { + return pluginManager.disablePlugin(pluginId); + } + + @Override + public boolean enablePlugin(String pluginId) { + return pluginManager.enablePlugin(pluginId); + } + + @Override + public boolean uninstallPlugin(String pluginId) { + return pluginManager.uninstallPlugin(pluginId); + } + + @Override + public boolean refreshRegistry(boolean verifyChecksum) { + return pluginManager.refreshRegistry(verifyChecksum); + } + + @Override + public boolean installPlugin(String url, boolean verifyChecksum) throws IOException { + return pluginManager.installPlugin(url, verifyChecksum); + } + + @Override + public boolean upgradePlugin(String pluginId, String url, boolean verifyChecksum) throws IOException { + return pluginManager.upgradePlugin(pluginId, url, verifyChecksum); + } + + @Override + public List<PluginRegistration> getRegisteredPlugins() { + return pluginManager.getRegisteredPlugins(); + } + + @Override + public List<PluginRegistration> getRegisteredPlugins(InstallState state) { + return pluginManager.getRegisteredPlugins(state); + } + + @Override + public PluginRegistration lookupPlugin(String pluginId) { + return pluginManager.lookupPlugin(pluginId); + } + + @Override + public PluginRelease lookupRelease(String pluginId, String version) { + return pluginManager.lookupRelease(pluginId, version); } } -- Gitblit v1.9.1