src/com/gitblit/AccessRestrictionFilter.java
@@ -42,8 +42,18 @@ import com.gitblit.utils.StringUtils; /** * The AccessRestrictionFilter is a servlet filter that preprocesses requests * that match its url pattern definition in the web.xml file. * * The filter extracts the name of the repository from the url and determines if * the requested action for the repository requires a Basic authentication * prompt. If authentication is required and no credentials are stored in the * "Authorization" header, then a basic authentication challenge is issued. * * http://en.wikipedia.org/wiki/Basic_access_authentication * * @author James Moger * */ public abstract class AccessRestrictionFilter implements Filter { @@ -59,15 +69,47 @@ logger = LoggerFactory.getLogger(getClass()); } /** * Extract the repository name from the url. * * @param url * @return repository name */ protected abstract String extractRepositoryName(String url); protected abstract String getUrlRequestType(String url); /** * Analyze the url and returns the action of the request. * * @param url * @return action of the request */ protected abstract String getUrlRequestAction(String url); /** * Determine if the repository requires authentication. * * @param repository * @return true if authentication required */ protected abstract boolean requiresAuthentication(RepositoryModel repository); protected abstract boolean canAccess(RepositoryModel repository, UserModel user, String restrictedUrl); /** * Determine if the user can access the repository and perform the specified * action. * * @param repository * @param user * @param action * @return true if user may execute the action on the repository */ protected abstract boolean canAccess(RepositoryModel repository, UserModel user, String action); /** * doFilter does the actual work of preprocessing the request to ensure that * the user may proceed. * * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) */ @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { @@ -98,7 +140,7 @@ // Determine if the request URL is restricted String fullSuffix = fullUrl.substring(repository.length()); String urlRequestType = getUrlRequestType(fullSuffix); String urlRequestType = getUrlRequestAction(fullSuffix); // Load the repository model RepositoryModel model = GitBlit.self().getRepositoryModel(repository); @@ -197,10 +239,16 @@ } } /** * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ @Override public void init(final FilterConfig config) throws ServletException { } /** * @see javax.servlet.Filter#destroy() */ @Override public void destroy() { } src/com/gitblit/Constants.java
@@ -15,6 +15,12 @@ */ package com.gitblit; /** * Constant values used by Gitblit. * * @author James Moger * */ public class Constants { public static final String NAME = "Gitblit"; src/com/gitblit/DownloadZipServlet.java
@@ -30,6 +30,19 @@ import com.gitblit.utils.JGitUtils; import com.gitblit.utils.StringUtils; /** * Streams out a zip file from the specified repository for any tree path at any * revision. * * Unlike the GitServlet and the SyndicationServlet, this servlet is not * protected by an AccessRestrictionFilter. It performs its own authorization * check, but it does not perform any authentication. The assumption is that * requests to this servlet are made via the web ui and not by direct url * access. Unauthorized requests fail with a standard 403 (FORBIDDEN) code. * * @author James Moger * */ public class DownloadZipServlet extends HttpServlet { private static final long serialVersionUID = 1L; @@ -40,6 +53,15 @@ super(); } /** * Returns an url to this servlet for the specified parameters. * * @param baseURL * @param repository * @param objectId * @param path * @return an url */ public static String asLink(String baseURL, String repository, String objectId, String path) { if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') { baseURL = baseURL.substring(0, baseURL.length() - 1); @@ -49,6 +71,14 @@ + (objectId == null ? "" : ("&h=" + objectId)); } /** * Performs the authorization and zip streaming of the specified elements. * * @param request * @param response * @throws javax.servlet.ServletException * @throws java.io.IOException */ private void processRequest(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException { @@ -92,7 +122,6 @@ Date date = JGitUtils.getCommitDate(commit); String contentType = "application/octet-stream"; response.setContentType(contentType + "; charset=" + response.getCharacterEncoding()); // response.setContentLength(attachment.getFileSize()); response.setHeader("Content-Disposition", "attachment; filename=\"" + name + ".zip" + "\""); response.setDateHeader("Last-Modified", date.getTime()); src/com/gitblit/FileSettings.java
@@ -21,7 +21,10 @@ import java.util.Properties; /** * Reads GitBlit settings file. * Dynamically loads and reloads a properties file by keeping track of the last * modification date. * * @author James Moger * */ public class FileSettings extends IStoredSettings { @@ -30,16 +33,20 @@ private final Properties properties = new Properties(); private volatile long lastread; private volatile long lastModified; public FileSettings(String file) { super(FileSettings.class); this.propertiesFile = new File(file); } /** * Returns a properties object which contains the most recent contents of * the properties file. */ @Override protected synchronized Properties read() { if (propertiesFile.exists() && (propertiesFile.lastModified() > lastread)) { if (propertiesFile.exists() && (propertiesFile.lastModified() > lastModified)) { FileInputStream is = null; try { Properties props = new Properties(); @@ -49,7 +56,7 @@ // load properties after we have successfully read file properties.clear(); properties.putAll(props); lastread = propertiesFile.lastModified(); lastModified = propertiesFile.lastModified(); } catch (FileNotFoundException f) { // IGNORE - won't happen because file.exists() check above } catch (Throwable t) { @@ -67,8 +74,11 @@ return properties; } protected long lastRead() { return lastread; /** * @return the last modification date of the properties file */ protected long lastModified() { return lastModified; } @Override src/com/gitblit/FileUserService.java
@@ -33,6 +33,15 @@ import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; /** * FileUserService is Gitblit's default user service implementation. * * Users and their repository memberships are stored in a simple properties file * which is cached and dynamically reloaded when modified. * * @author James Moger * */ public class FileUserService extends FileSettings implements IUserService { private final Logger logger = LoggerFactory.getLogger(FileUserService.class); @@ -43,11 +52,22 @@ super(realmFile.getAbsolutePath()); } /** * Does the user service support cookie authentication? * * @return true or false */ @Override public boolean supportsCookies() { return true; } /** * Returns the cookie value for the specified user. * * @param model * @return cookie value */ @Override public char[] getCookie(UserModel model) { Properties allUsers = super.read(); @@ -58,6 +78,12 @@ return cookie.toCharArray(); } /** * Authenticate a user based on their cookie. * * @param cookie * @return a user object or null */ @Override public UserModel authenticate(char[] cookie) { String hash = new String(cookie); @@ -73,6 +99,13 @@ return model; } /** * Authenticate a user based on a username and password. * * @param username * @param password * @return a user object or null */ @Override public UserModel authenticate(String username, char[] password) { Properties allUsers = read(); @@ -93,6 +126,12 @@ return returnedUser; } /** * Retrieve the user object for the specified username. * * @param username * @return a user object or null */ @Override public UserModel getUserModel(String username) { Properties allUsers = read(); @@ -119,11 +158,27 @@ return model; } /** * Updates/writes a complete user object. * * @param model * @return true if update is successful */ @Override public boolean updateUserModel(UserModel model) { return updateUserModel(model.username, model); } /** * Updates/writes and replaces a complete user object keyed by username. * This method allows for renaming a user. * * @param username * the old username * @param model * the user object to use for username * @return true if update is successful */ @Override public boolean updateUserModel(String username, UserModel model) { try { @@ -156,11 +211,23 @@ return false; } /** * Deletes the user object from the user service. * * @param model * @return true if successful */ @Override public boolean deleteUserModel(UserModel model) { return deleteUser(model.username); } /** * Delete the user object with the specified username * * @param username * @return true if successful */ @Override public boolean deleteUser(String username) { try { @@ -175,6 +242,11 @@ return false; } /** * Returns the list of all users available to the login service. * * @return list of all usernames */ @Override public List<String> getAllUsernames() { Properties allUsers = read(); @@ -182,8 +254,16 @@ return list; } /** * Returns the list of all users who are allowed to bypass the access * restriction placed on the specified repository. * * @param role * the repository name * @return list of all usernames that can bypass the access restriction */ @Override public List<String> getUsernamesForRepository(String role) { public List<String> getUsernamesForRepositoryRole(String role) { List<String> list = new ArrayList<String>(); try { Properties allUsers = read(); @@ -205,8 +285,17 @@ return list; } /** * Sets the list of all uses who are allowed to bypass the access * restriction placed on the specified repository. * * @param role * the repository name * @param usernames * @return true if successful */ @Override public boolean setUsernamesForRepository(String role, List<String> usernames) { public boolean setUsernamesForRepositoryRole(String role, List<String> usernames) { try { Set<String> specifiedUsers = new HashSet<String>(usernames); Set<String> needsAddRole = new HashSet<String>(specifiedUsers); @@ -272,6 +361,13 @@ return false; } /** * Renames a repository role. * * @param oldRole * @param newRole * @return true if successful */ @Override public boolean renameRepositoryRole(String oldRole, String newRole) { try { @@ -327,6 +423,12 @@ return false; } /** * Removes a repository role from all users. * * @param role * @return true if successful */ @Override public boolean deleteRepositoryRole(String role) { try { @@ -380,14 +482,22 @@ return false; } /** * Writes the properties file. * * @param properties * @throws IOException */ private void write(Properties properties) throws IOException { // Update realm file // Write a temporary copy of the users file File realmFileCopy = new File(propertiesFile.getAbsolutePath() + ".tmp"); FileWriter writer = new FileWriter(realmFileCopy); properties .store(writer, "# Gitblit realm file format: username=password,\\#permission,repository1,repository2..."); writer.close(); // If the write is successful, delete the current file and rename // the temporary copy to the original filename. if (realmFileCopy.exists() && realmFileCopy.length() > 0) { if (propertiesFile.delete()) { if (!realmFileCopy.renameTo(propertiesFile)) { @@ -404,11 +514,14 @@ } } /** * Reads the properties file and rebuilds the in-memory cookie lookup table. */ @Override protected synchronized Properties read() { long lastRead = lastRead(); long lastRead = lastModified(); Properties allUsers = super.read(); if (lastRead != lastRead()) { if (lastRead != lastModified()) { // reload hash cache cookies.clear(); for (String username : allUsers.stringPropertyNames()) { src/com/gitblit/GitBlit.java
@@ -34,6 +34,8 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.transport.resolver.FileResolver; import org.eclipse.jgit.transport.resolver.RepositoryResolver; import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.eclipse.jgit.util.FileUtils; import org.slf4j.Logger; @@ -45,13 +47,29 @@ import com.gitblit.utils.JGitUtils; import com.gitblit.utils.StringUtils; /** * GitBlit is the servlet context listener singleton that acts as the core for * the web ui and the servlets. This class is either directly instantiated by * the GitBlitServer class (Gitblit GO) or is reflectively instantiated from the * definition in the web.xml file (Gitblit WAR). * * This class is the central logic processor for Gitblit. All settings, user * object, and repository object operations pass through this class. * * Repository Resolution. There are two pathways for finding repositories. One * pathway, for web ui display and repository authentication & authorization, is * within this class. The other pathway is through the standard GitServlet. * * @author James Moger * */ public class GitBlit implements ServletContextListener { private static GitBlit gitblit; private final Logger logger = LoggerFactory.getLogger(GitBlit.class); private FileResolver<Void> repositoryResolver; private RepositoryResolver<Void> repositoryResolver; private File repositoriesFolder; @@ -59,59 +77,136 @@ private IUserService userService; private IStoredSettings storedSettings; private IStoredSettings settings; public GitBlit() { if (gitblit == null) { // Singleton reference when running in standard servlet container // set the static singleton reference gitblit = this; } } /** * Returns the Gitblit singleton. * * @return gitblit singleton */ public static GitBlit self() { if (gitblit == null) { gitblit = new GitBlit(); new GitBlit(); } return gitblit; } /** * Returns the boolean value for the specified key. If the key does not * exist or the value for the key can not be interpreted as a boolean, the * defaultValue is returned. * * @see IStoredSettings.getBoolean(String, boolean) * @param key * @param defaultValue * @return key value or defaultValue */ public static boolean getBoolean(String key, boolean defaultValue) { return self().storedSettings.getBoolean(key, defaultValue); return self().settings.getBoolean(key, defaultValue); } /** * Returns the integer value for the specified key. If the key does not * exist or the value for the key can not be interpreted as an integer, the * defaultValue is returned. * * @see IStoredSettings.getInteger(String key, int defaultValue) * @param key * @param defaultValue * @return key value or defaultValue */ public static int getInteger(String key, int defaultValue) { return self().storedSettings.getInteger(key, defaultValue); return self().settings.getInteger(key, defaultValue); } /** * Returns the string value for the specified key. If the key does not exist * or the value for the key can not be interpreted as a string, the * defaultValue is returned. * * @see IStoredSettings.getString(String key, String defaultValue) * @param key * @param defaultValue * @return key value or defaultValue */ public static String getString(String key, String defaultValue) { return self().storedSettings.getString(key, defaultValue); return self().settings.getString(key, defaultValue); } /** * Returns a list of space-separated strings from the specified key. * * @see IStoredSettings.getStrings(String key) * @param name * @return list of strings */ public static List<String> getStrings(String key) { return self().storedSettings.getStrings(key); return self().settings.getStrings(key); } /** * Returns the list of keys whose name starts with the specified prefix. If * the prefix is null or empty, all key names are returned. * * @see IStoredSettings.getAllKeys(String key) * @param startingWith * @return list of keys */ public static List<String> getAllKeys(String startingWith) { return self().storedSettings.getAllKeys(startingWith); return self().settings.getAllKeys(startingWith); } /** * Is Gitblit running in debug mode? * * @return true if Gitblit is running in debug mode */ public static boolean isDebugMode() { return self().storedSettings.getBoolean(Keys.web.debugMode, false); return self().settings.getBoolean(Keys.web.debugMode, false); } /** * Returns the list of non-Gitblit clone urls. This allows Gitblit to * advertise alternative urls for Git client repository access. * * @param repositoryName * @return list of non-gitblit clone urls */ public List<String> getOtherCloneUrls(String repositoryName) { List<String> cloneUrls = new ArrayList<String>(); for (String url : storedSettings.getStrings(Keys.web.otherUrls)) { for (String url : settings.getStrings(Keys.web.otherUrls)) { cloneUrls.add(MessageFormat.format(url, repositoryName)); } return cloneUrls; } /** * Set the user service. The user service authenticates all users and is * responsible for managing user permissions. * * @param userService */ public void setUserService(IUserService userService) { logger.info("Setting up user service " + userService.toString()); this.userService = userService; } /** * Authenticate a user based on a username and password. * * @see IUserService.authenticate(String, char[]) * @param username * @param password * @return a user object or null */ public UserModel authenticate(String username, char[] password) { if (userService == null) { return null; @@ -119,6 +214,12 @@ return userService.authenticate(username, password); } /** * Authenticate a user based on their cookie. * * @param cookies * @return a user object or null */ public UserModel authenticate(Cookie[] cookies) { if (userService == null) { return null; @@ -136,6 +237,12 @@ return null; } /** * Sets a cookie for the specified user. * * @param response * @param user */ public void setCookie(WebResponse response, UserModel user) { if (userService == null) { return; @@ -156,41 +263,100 @@ } } /** * Returns the list of all users available to the login service. * * @see IUserService.getAllUsernames() * @return list of all usernames */ public List<String> getAllUsernames() { List<String> names = new ArrayList<String>(userService.getAllUsernames()); Collections.sort(names); return names; } /** * Delete the user object with the specified username * * @see IUserService.deleteUser(String) * @param username * @return true if successful */ public boolean deleteUser(String username) { return userService.deleteUser(username); } /** * Retrieve the user object for the specified username. * * @see IUserService.getUserModel(String) * @param username * @return a user object or null */ public UserModel getUserModel(String username) { UserModel user = userService.getUserModel(username); return user; } /** * Returns the list of all users who are allowed to bypass the access * restriction placed on the specified repository. * * @see IUserService.getUsernamesForRepositoryRole(String) * @param repository * @return list of all usernames that can bypass the access restriction */ public List<String> getRepositoryUsers(RepositoryModel repository) { return userService.getUsernamesForRepository(repository.name); return userService.getUsernamesForRepositoryRole(repository.name); } /** * Sets the list of all uses who are allowed to bypass the access * restriction placed on the specified repository. * * @see IUserService.setUsernamesForRepositoryRole(String, List<String>) * @param repository * @param usernames * @return true if successful */ public boolean setRepositoryUsers(RepositoryModel repository, List<String> repositoryUsers) { return userService.setUsernamesForRepository(repository.name, repositoryUsers); return userService.setUsernamesForRepositoryRole(repository.name, repositoryUsers); } public void editUserModel(String username, UserModel user, boolean isCreate) /** * 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 */ public void updateUserModel(String username, UserModel user, boolean isCreate) throws GitBlitException { if (!userService.updateUserModel(username, user)) { throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!"); } } /** * Returns the list of all repositories available to Gitblit. This method * does not consider user access permissions. * * @return list of all repositories */ public List<String> getRepositoryList() { return JGitUtils.getRepositoryList(repositoriesFolder, exportAll, storedSettings.getBoolean(Keys.git.searchRepositoriesSubfolders, true)); settings.getBoolean(Keys.git.searchRepositoriesSubfolders, true)); } /** * Returns the JGit repository for the specified name. * * @param repositoryName * @return repository or null */ public Repository getRepository(String repositoryName) { Repository r = null; try { @@ -199,13 +365,24 @@ r = null; logger.error("GitBlit.getRepository(String) failed to find " + new File(repositoriesFolder, repositoryName).getAbsolutePath()); } catch (ServiceNotAuthorizedException e) { r = null; logger.error("GitBlit.getRepository(String) failed to find " + new File(repositoriesFolder, repositoryName).getAbsolutePath(), e); } catch (ServiceNotEnabledException e) { r = null; e.printStackTrace(); logger.error("GitBlit.getRepository(String) failed to find " + new File(repositoriesFolder, repositoryName).getAbsolutePath(), e); } return r; } /** * Returns the list of repository models that are accessible to the user. * * @param user * @return list of repository models accessible to user */ public List<RepositoryModel> getRepositoryModels(UserModel user) { List<String> list = getRepositoryList(); List<RepositoryModel> repositories = new ArrayList<RepositoryModel>(); @@ -218,6 +395,14 @@ return repositories; } /** * Returns a repository model if the repository exists and the user may * access the repository. * * @param user * @param repositoryName * @return repository model or null */ public RepositoryModel getRepositoryModel(UserModel user, String repositoryName) { RepositoryModel model = getRepositoryModel(repositoryName); if (model == null) { @@ -233,6 +418,13 @@ } } /** * Returns the repository model for the specified repository. This method * does not consider user access permissions. * * @param repositoryName * @return repository model or null */ public RepositoryModel getRepositoryModel(String repositoryName) { Repository r = getRepository(repositoryName); if (r == null) { @@ -258,6 +450,15 @@ return model; } /** * Returns the gitblit string vlaue for the specified key. If key is not * set, returns defaultValue. * * @param config * @param field * @param defaultValue * @return field value or defaultValue */ private String getConfig(StoredConfig config, String field, String defaultValue) { String value = config.getString("gitblit", null, field); if (StringUtils.isEmpty(value)) { @@ -266,11 +467,34 @@ return value; } /** * Returns the gitblit boolean vlaue for the specified key. If key is not * set, returns defaultValue. * * @param config * @param field * @param defaultValue * @return field value or defaultValue */ private boolean getConfig(StoredConfig config, String field, boolean defaultValue) { return config.getBoolean("gitblit", field, defaultValue); } public void editRepositoryModel(String repositoryName, RepositoryModel repository, /** * Creates/updates the repository model keyed by reopsitoryName. Saves all * repository settings in .git/config. This method allows for renaming * repositories and will update user access permissions accordingly. * * All repositories created by this method are bare and automatically have * .git appended to their names, which is the standard convention for bare * repositories. * * @param repositoryName * @param repository * @param isCreate * @throws GitBlitException */ public void updateRepositoryModel(String repositoryName, RepositoryModel repository, boolean isCreate) throws GitBlitException { Repository r = null; if (isCreate) { @@ -316,6 +540,8 @@ r = repositoryResolver.open(null, repository.name); } catch (RepositoryNotFoundException e) { logger.error("Repository not found", e); } catch (ServiceNotAuthorizedException e) { logger.error("Service not authorized", e); } catch (ServiceNotEnabledException e) { logger.error("Service not enabled", e); } @@ -342,15 +568,29 @@ } } /** * Deletes the repository from the file system and removes the repository * permission from all repository users. * * @param model * @return true if successful */ public boolean deleteRepositoryModel(RepositoryModel model) { return deleteRepository(model.name); } /** * Deletes the repository from the file system and removes the repository * permission from all repository users. * * @param repositoryName * @return true if successful */ public boolean deleteRepository(String repositoryName) { try { File folder = new File(repositoriesFolder, repositoryName); if (folder.exists() && folder.isDirectory()) { FileUtils.delete(folder, FileUtils.RECURSIVE); FileUtils.delete(folder, FileUtils.RECURSIVE | FileUtils.RETRY); if (userService.deleteRepositoryRole(repositoryName)) { return true; } @@ -361,25 +601,33 @@ return false; } /** * Returns an html version of the commit message with any global or * repository-specific regular expression substitution applied. * * @param repositoryName * @param text * @return html version of the commit message */ public String processCommitMessage(String repositoryName, String text) { String html = StringUtils.breakLinesForHtml(text); Map<String, String> map = new HashMap<String, String>(); // global regex keys if (storedSettings.getBoolean(Keys.regex.global, false)) { for (String key : storedSettings.getAllKeys(Keys.regex.global)) { if (settings.getBoolean(Keys.regex.global, false)) { for (String key : settings.getAllKeys(Keys.regex.global)) { if (!key.equals(Keys.regex.global)) { String subKey = key.substring(key.lastIndexOf('.') + 1); map.put(subKey, storedSettings.getString(key, "")); map.put(subKey, settings.getString(key, "")); } } } // repository-specific regex keys List<String> keys = storedSettings.getAllKeys(Keys.regex._ROOT + "." List<String> keys = settings.getAllKeys(Keys.regex._ROOT + "." + repositoryName.toLowerCase()); for (String key : keys) { String subKey = key.substring(key.lastIndexOf('.') + 1); map.put(subKey, storedSettings.getString(key, "")); map.put(subKey, settings.getString(key, "")); } for (Entry<String, String> entry : map.entrySet()) { @@ -396,23 +644,30 @@ return html; } /** * Configure the Gitblit singleton with the specified settings source. This * source may be file settings (Gitblit GO) or may be web.xml settings * (Gitblit WAR). * * @param settings */ public void configureContext(IStoredSettings settings) { logger.info("Reading configuration from " + settings.toString()); this.storedSettings = settings; this.settings = settings; repositoriesFolder = new File(settings.getString(Keys.git.repositoriesFolder, "git")); logger.info("Git repositories folder " + repositoriesFolder.getAbsolutePath()); repositoryResolver = new FileResolver<Void>(repositoriesFolder, exportAll); String realm = settings.getString(Keys.realm.userService, "users.properties"); IUserService loginService = null; try { // Check to see if this "file" is a login service class // check to see if this "file" is a login service class Class<?> realmClass = Class.forName(realm); if (IUserService.class.isAssignableFrom(realmClass)) { loginService = (IUserService) realmClass.newInstance(); } } catch (Throwable t) { // Not a login service class OR other issue // Use default file login service // not a login service class or class could not be instantiated. // try to use default file login service File realmFile = new File(realm); if (!realmFile.exists()) { try { @@ -427,16 +682,25 @@ setUserService(loginService); } /** * Configure Gitblit from the web.xml, if no configuration has already been * specified. * * @see ServletContextListener.contextInitialize(ServletContextEvent) */ @Override public void contextInitialized(ServletContextEvent contextEvent) { if (storedSettings == null) { // for running gitblit as a traditional webapp in a servlet // container if (settings == null) { // Gitblit WAR is running in a servlet container WebXmlSettings webxmlSettings = new WebXmlSettings(contextEvent.getServletContext()); configureContext(webxmlSettings); } } /** * Gitblit is being shutdown either because the servlet container is * shutting down or because the servlet container is re-deploying Gitblit. */ @Override public void contextDestroyed(ServletContextEvent contextEvent) { logger.info("Gitblit context destroyed by servlet container."); src/com/gitblit/GitBlitException.java
@@ -15,6 +15,12 @@ */ package com.gitblit; /** * GitBlitException is a marginally useful class. :) * * @author James Moger * */ public class GitBlitException extends Exception { private static final long serialVersionUID = 1L; src/com/gitblit/GitBlitServer.java
@@ -40,6 +40,7 @@ import org.eclipse.jetty.server.ssl.SslSocketConnector; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jgit.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,6 +50,17 @@ import com.beust.jcommander.Parameters; import com.gitblit.utils.StringUtils; /** * GitBlitServer is the embedded Jetty server for Gitblit GO. This class starts * and stops an instance of Jetty that is configured from a combination of the * gitblit.properties file and command line parameters. JCommander is used to * simplify command line parameter processing. This class also automatically * generates a self-signed certificate for localhost, if the keystore does not * already exist. * * @author James Moger * */ public class GitBlitServer { private static Logger logger; @@ -72,6 +84,12 @@ } } /** * Display the command line usage of Gitblit GO. * * @param jc * @param t */ private static void usage(JCommander jc, ParameterException t) { System.out.println(Constants.BORDER); System.out.println(Constants.getGitBlitVersion()); @@ -84,13 +102,13 @@ if (jc != null) { jc.usage(); System.out .println("\nExample:\n java -server -Xmx1024M -jar gitblit.jar --repos c:\\git --port 80 --securePort 443"); .println("\nExample:\n java -server -Xmx1024M -jar gitblit.jar --repositoriesFolder c:\\git --httpPort 80 --httpsPort 443"); } System.exit(0); } /** * Stop Server. * Stop Gitblt GO. */ public static void stop(Params params) { try { @@ -108,7 +126,7 @@ } /** * Start Server. * Start Gitblit GO. */ private static void start(Params params) { FileSettings settings = Params.FILESETTINGS; @@ -122,8 +140,9 @@ String osversion = System.getProperty("os.version"); logger.info("Running on " + osname + " (" + osversion + ")"); // Determine port connectors List<Connector> connectors = new ArrayList<Connector>(); // conditionally configure the http connector if (params.port > 0) { Connector httpConnector = createConnector(params.useNIO, params.port); String bindInterface = settings.getString(Keys.server.httpBindInterface, null); @@ -135,10 +154,11 @@ connectors.add(httpConnector); } // conditionally configure the https connector if (params.securePort > 0) { File keystore = new File("keystore"); if (!keystore.exists()) { logger.info("Generating self-signed SSL certificate"); logger.info("Generating self-signed SSL certificate for localhost"); MakeCertificate.generateSelfSignedCertificate("localhost", keystore, params.storePassword); } @@ -158,13 +178,14 @@ } } // tempDir = Directory where... // * WebApp is expanded // // tempDir is where the embedded Gitblit web application is expanded and // where Jetty creates any necessary temporary files File tempDir = new File(params.temp); if (tempDir.exists()) { if (!deleteRecursively(tempDir)) { logger.warn("Failed to delete temp dir " + tempDir.getAbsolutePath()); try { FileUtils.delete(tempDir, FileUtils.RECURSIVE | FileUtils.RETRY); } catch (IOException x) { logger.warn("Failed to delete temp dir " + tempDir.getAbsolutePath(), x); } } if (!tempDir.mkdirs()) { @@ -201,7 +222,7 @@ return; } // Override settings // Override settings from the command-line settings.overrideSetting(Keys.realm.userService, params.userService); settings.overrideSetting(Keys.git.repositoriesFolder, params.repositoriesFolder); @@ -213,12 +234,14 @@ gitblit.configureContext(settings); rootContext.addEventListener(gitblit); // Start the Server try { // start the shutdown monitor if (params.shutdownPort > 0) { Thread shutdownMonitor = new ShutdownMonitorThread(server, params); shutdownMonitor.start(); } // start Jetty server.start(); server.join(); } catch (Exception e) { @@ -227,6 +250,13 @@ } } /** * Creates an http connector. * * @param useNIO * @param port * @return an http cnonector */ private static Connector createConnector(boolean useNIO, int port) { Connector connector; if (useNIO) { @@ -246,6 +276,15 @@ return connector; } /** * Creates an https connector. * * @param keystore * @param password * @param useNIO * @param port * @return an https connector */ private static Connector createSSLConnector(File keystore, String password, boolean useNIO, int port) { SslConnector connector; @@ -269,22 +308,13 @@ } /** * Recursively delete a folder and its contents. * The ShutdownMonitorThread opens a socket on a specified port and waits * for an incoming connection. When that connection is accepted a shutdown * message is issued to the running Jetty server. * * @param folder * @author James Moger * */ private static boolean deleteRecursively(File folder) { boolean deleted = true; for (File file : folder.listFiles()) { if (file.isDirectory()) { deleted &= deleteRecursively(file); } else { deleted &= file.delete(); } } return deleted && folder.delete(); } private static class ShutdownMonitorThread extends Thread { private final ServerSocket socket; @@ -356,7 +386,8 @@ * Authentication Parameters */ @Parameter(names = { "--userService" }, description = "Authentication and Authorization Service (filename or fully qualified classname)") public String userService = FILESETTINGS.getString(Keys.realm.userService, "users.properties"); public String userService = FILESETTINGS.getString(Keys.realm.userService, "users.properties"); /* * JETTY Parameters src/com/gitblit/GitFilter.java
@@ -22,6 +22,14 @@ import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; /** * The GitFilter is an AccessRestrictionFilter which ensures that Git client * requests for push, clone, or view restricted repositories are authenticated * and authorized. * * @author James Moger * */ public class GitFilter extends AccessRestrictionFilter { protected final String gitReceivePack = "/git-receive-pack"; @@ -31,9 +39,16 @@ protected final String[] suffixes = { gitReceivePack, gitUploadPack, "/info/refs", "/HEAD", "/objects" }; /** * Extract the repository name from the url. * * @param url * @return repository name */ @Override protected String extractRepositoryName(String url) { String repository = url; // get the repository name from the url by finding a known url suffix for (String urlSuffix : suffixes) { if (repository.indexOf(urlSuffix) > -1) { repository = repository.substring(0, repository.indexOf(urlSuffix)); @@ -42,8 +57,15 @@ return repository; } /** * Analyze the url and returns the action of the request. Return values are * either "/git-receive-pack" or "/git-upload-pack". * * @param url * @return action of the request */ @Override protected String getUrlRequestType(String suffix) { protected String getUrlRequestAction(String suffix) { if (!StringUtils.isEmpty(suffix)) { if (suffix.startsWith(gitReceivePack)) { return gitReceivePack; @@ -58,20 +80,35 @@ return null; } /** * Determine if the repository requires authentication. * * @param repository * @return true if authentication required */ @Override protected boolean requiresAuthentication(RepositoryModel repository) { return repository.accessRestriction.atLeast(AccessRestrictionType.PUSH); } /** * Determine if the user can access the repository and perform the specified * action. * * @param repository * @param user * @param action * @return true if user may execute the action on the repository */ @Override protected boolean canAccess(RepositoryModel repository, UserModel user, String urlRequestType) { protected boolean canAccess(RepositoryModel repository, UserModel user, String action) { if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true)) { // Git Servlet disabled return false; } if (repository.isFrozen || repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) { boolean authorizedUser = user.canAccessRepository(repository.name); if (urlRequestType.equals(gitReceivePack)) { if (action.equals(gitReceivePack)) { // Push request if (!repository.isFrozen && authorizedUser) { // clone-restricted or push-authorized @@ -82,7 +119,7 @@ user.username, repository)); return false; } } else if (urlRequestType.equals(gitUploadPack)) { } else if (action.equals(gitUploadPack)) { // Clone request boolean cloneRestricted = repository.accessRestriction .atLeast(AccessRestrictionType.CLONE); src/com/gitblit/GitServlet.java
@@ -1,9 +1,37 @@ /* * Copyright 2011 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit; /** * The GitServlet exists to force configuration of the JGit GitServlet based on * the Gitblit settings from either gitblit.properties or from context * parameters in the web.xml file. * * Access to this servlet is protected by the GitFilter. * * @author James Moger * */ public class GitServlet extends org.eclipse.jgit.http.server.GitServlet { private static final long serialVersionUID = 1L; /** * Configure the servlet from Gitblit's configuration. */ @Override public String getInitParameter(String name) { if (name.equals("base-path")) { src/com/gitblit/IStoredSettings.java
@@ -24,6 +24,12 @@ import com.gitblit.utils.StringUtils; /** * Base class for stored settings implementations. * * @author James Moger * */ public abstract class IStoredSettings { protected final Logger logger; @@ -42,6 +48,13 @@ return props; } /** * Returns the list of keys whose name starts with the specified prefix. If * the prefix is null or empty, all key names are returned. * * @param startingWith * @return list of keys */ public List<String> getAllKeys(String startingWith) { List<String> keys = new ArrayList<String>(); Properties props = getSettings(); @@ -59,6 +72,15 @@ return keys; } /** * Returns the boolean value for the specified key. If the key does not * exist or the value for the key can not be interpreted as a boolean, the * defaultValue is returned. * * @param key * @param defaultValue * @return key value or defaultValue */ public boolean getBoolean(String name, boolean defaultValue) { Properties props = getSettings(); if (props.containsKey(name)) { @@ -70,6 +92,15 @@ return defaultValue; } /** * Returns the integer value for the specified key. If the key does not * exist or the value for the key can not be interpreted as an integer, the * defaultValue is returned. * * @param key * @param defaultValue * @return key value or defaultValue */ public int getInteger(String name, int defaultValue) { Properties props = getSettings(); if (props.containsKey(name)) { @@ -86,6 +117,15 @@ return defaultValue; } /** * Returns the string value for the specified key. If the key does not exist * or the value for the key can not be interpreted as a string, the * defaultValue is returned. * * @param key * @param defaultValue * @return key value or defaultValue */ public String getString(String name, String defaultValue) { Properties props = getSettings(); if (props.containsKey(name)) { @@ -97,10 +137,24 @@ return defaultValue; } /** * Returns a list of space-separated strings from the specified key. * * @param name * @return list of strings */ public List<String> getStrings(String name) { return getStrings(name, " "); } /** * Returns a list of strings from the specified key using the specified * string separator. * * @param name * @param separator * @return list of strings */ public List<String> getStrings(String name, String separator) { List<String> strings = new ArrayList<String>(); Properties props = getSettings(); @@ -111,6 +165,12 @@ return strings; } /** * Override the specified key with the specified value. * * @param key * @param value */ public void overrideSetting(String key, String value) { overrides.put(key, value); } src/com/gitblit/IUserService.java
@@ -19,35 +19,139 @@ import com.gitblit.models.UserModel; /** * Implementations of IUserService control all aspects of UserModel objects and * user authentication. * * @author James Moger * */ public interface IUserService { /** * Does the user service support cookie authentication? * * @return true or false */ boolean supportsCookies(); /** * Returns the cookie value for the specified user. * * @param model * @return cookie value */ char[] getCookie(UserModel model); /** * Authenticate a user based on their cookie. * * @param cookie * @return a user object or null */ UserModel authenticate(char[] cookie); /** * Authenticate a user based on a username and password. * * @param username * @param password * @return a user object or null */ UserModel authenticate(String username, char[] password); /** * Retrieve the user object for the specified username. * * @param username * @return a user object or null */ UserModel getUserModel(String username); /** * Updates/writes a complete user object. * * @param model * @return true if update is successful */ boolean updateUserModel(UserModel model); /** * Adds/updates a user object keyed by username. This method allows for * renaming a user. * * @param username * the old username * @param model * the user object to use for username * @return true if update is successful */ boolean updateUserModel(String username, UserModel model); /** * Deletes the user object from the user service. * * @param model * @return true if successful */ boolean deleteUserModel(UserModel model); /** * Delete the user object with the specified username * * @param username * @return true if successful */ boolean deleteUser(String username); /** * Returns the list of all users available to the login service. * * @return list of all usernames */ List<String> getAllUsernames(); List<String> getUsernamesForRepository(String role); /** * Returns the list of all users who are allowed to bypass the access * restriction placed on the specified repository. * * @param role * the repository name * @return list of all usernames that can bypass the access restriction */ List<String> getUsernamesForRepositoryRole(String role); boolean setUsernamesForRepository(String role, List<String> usernames); /** * Sets the list of all uses who are allowed to bypass the access * restriction placed on the specified repository. * * @param role * the repository name * @param usernames * @return true if successful */ boolean setUsernamesForRepositoryRole(String role, List<String> usernames); /** * Renames a repository role. * * @param oldRole * @param newRole * @return true if successful */ boolean renameRepositoryRole(String oldRole, String newRole); /** * Removes a repository role from all users. * * @param role * @return true if successful */ boolean deleteRepositoryRole(String role); /** * @See java.lang.Object.toString(); * @return string representation of the login service */ String toString(); } src/com/gitblit/Launcher.java
@@ -30,9 +30,14 @@ import com.gitblit.build.Build; /** * Launch helper class that adds all jars found in the local "lib" folder and * then calls the application main. Using this technique we do not have to * specify a classpath and we can dynamically add jars to the distribution. * Launch helper class that adds all jars found in the local "lib" & "ext" * folders and then calls the application main. Using this technique we do not * have to specify a classpath and we can dynamically add jars to the * distribution. * * This class also downloads all runtime dependencies, if they are not found. * * @author James Moger * */ public class Launcher { @@ -52,6 +57,7 @@ + protectionDomain.getCodeSource().getLocation().toExternalForm()); } // download all runtime dependencies Build.runtime(); // Load the JARs in the lib and ext folder src/com/gitblit/MakeCertificate.java
@@ -43,6 +43,12 @@ import com.beust.jcommander.Parameters; import com.gitblit.utils.TimeUtils; /** * Utility class to generate self-signed certificates. * * @author James Moger * */ public class MakeCertificate { private static final String BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME; src/com/gitblit/ServletRequestWrapper.java
@@ -29,6 +29,22 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * ServletRequestWrapper is a pass-through/delegate wrapper class for a servlet * request. This class is used in conjunction with ServletFilters, such as the * AccessRestrictionFilter. * * The original request is wrapped by instances of this class and this class is * set as the servlet request in the filter. This allows for specialized * implementations of request methods, like getUserPrincipal() with delegation * to the original request for any method not overridden. * * This class, by itself, is not altogether interesting. Subclasses of this * class, however, are of interest. * * @author James Moger * */ public abstract class ServletRequestWrapper implements HttpServletRequest { protected final HttpServletRequest req; src/com/gitblit/SyndicationFilter.java
@@ -19,25 +19,60 @@ import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; /** * The SyndicationFilter is an AccessRestrictionFilter which ensures that feed * requests for view-restricted repositories have proper authentication * credentials and are authorized for the requested feed. * * @author James Moger * */ public class SyndicationFilter extends AccessRestrictionFilter { /** * Extract the repository name from the url. * * @param url * @return repository name */ @Override protected String extractRepositoryName(String url) { return url; } /** * Analyze the url and returns the action of the request. * * @param url * @return action of the request */ @Override protected String getUrlRequestType(String url) { return "RESTRICTED"; protected String getUrlRequestAction(String url) { return "VIEW"; } /** * Determine if the repository requires authentication. * * @param repository * @return true if authentication required */ @Override protected boolean requiresAuthentication(RepositoryModel repository) { return repository.accessRestriction.atLeast(AccessRestrictionType.VIEW); } /** * Determine if the user can access the repository and perform the specified * action. * * @param repository * @param user * @param action * @return true if user may execute the action on the repository */ @Override protected boolean canAccess(RepositoryModel repository, UserModel user, String restrictedURL) { protected boolean canAccess(RepositoryModel repository, UserModel user, String action) { return user.canAccessRepository(repository.name); } src/com/gitblit/SyndicationServlet.java
@@ -31,12 +31,32 @@ import com.gitblit.utils.SyndicationUtils; import com.gitblit.wicket.WicketUtils; /** * SyndicationServlet generates RSS 2.0 feeds and feed links. * * Access to this servlet is protected by the SyndicationFilter. * * @author James Moger * */ public class SyndicationServlet extends HttpServlet { private static final long serialVersionUID = 1L; private transient Logger logger = LoggerFactory.getLogger(SyndicationServlet.class); /** * Create a feed link for the specified repository and branch/tag/commit id. * * @param baseURL * @param repository * the repository name * @param objectId * the branch, tag, or first commit for the feed * @param length * the number of commits to include in the feed * @return an RSS feed url */ public static String asLink(String baseURL, String repository, String objectId, int length) { if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') { baseURL = baseURL.substring(0, baseURL.length() - 1); @@ -63,6 +83,13 @@ return url.toString(); } /** * Determines the appropriate title for a feed. * * @param repository * @param objectId * @return title of the feed */ public static String getTitle(String repository, String objectId) { String id = objectId; if (!StringUtils.isEmpty(id)) { @@ -77,6 +104,14 @@ return MessageFormat.format("{0} ({1})", repository, id); } /** * Generates the feed content. * * @param request * @param response * @throws javax.servlet.ServletException * @throws java.io.IOException */ private void processRequest(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException { src/com/gitblit/WebXmlSettings.java
@@ -22,6 +22,12 @@ import com.gitblit.utils.StringUtils; /** * Loads Gitblit settings from the context-parameter values of a web.xml file. * * @author James Moger * */ public class WebXmlSettings extends IStoredSettings { private final Properties properties = new Properties(); @@ -36,9 +42,9 @@ logger.debug(key + "=" + properties.getProperty(key)); } } private String decodeValue(String value) { // Decode escaped backslashes and HTML entities // decode escaped backslashes and HTML entities return StringUtils.decodeFromHtml(value).replace("\\\\", "\\"); } src/com/gitblit/build/Build.java
@@ -35,6 +35,18 @@ import com.gitblit.Constants; import com.gitblit.utils.StringUtils; /** * The Build class downloads runtime and compile-time jar files from the Apache * or Eclipse Maven repositories. * * It also generates the Keys class from the gitblit.properties file. * * Its important that this class have minimal compile dependencies since its * called very early in the build script. * * @author James Moger * */ public class Build { public static enum BuildType { @@ -95,6 +107,10 @@ downloadFromApache(MavenObject.COMMONSNET, BuildType.RUNTIME); } /** * Builds the Keys class based on the gitblit.properties file and inserts * the class source into the project source folder. */ public static void buildSettingKeys() { // Load all keys Properties properties = new Properties(); src/com/gitblit/build/BuildSite.java
@@ -15,7 +15,6 @@ */ package com.gitblit.build; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -37,9 +36,21 @@ import com.beust.jcommander.ParameterException; import com.beust.jcommander.Parameters; import com.gitblit.Constants; import com.gitblit.utils.FileUtils; import com.gitblit.utils.MarkdownUtils; import com.gitblit.utils.StringUtils; /** * Builds the web site or deployment documentation from Markdown source files. * * All Markdown source files must have the .mkd extension. * * Natural string sort order of the Markdown source filenames is the order of * page links. "##_" prefixes are used to control the sort order. * * @author James Moger * */ public class BuildSite { public static void main(String... args) { @@ -87,8 +98,8 @@ sb.setLength(sb.length() - 3); sb.trimToSize(); String htmlHeader = readContent(new File(params.pageHeader), "\n"); String htmlFooter = readContent(new File(params.pageFooter), "\n"); String htmlHeader = FileUtils.readContent(new File(params.pageHeader), "\n"); String htmlFooter = FileUtils.readContent(new File(params.pageFooter), "\n"); final String links = sb.toString(); final String header = MessageFormat.format(htmlHeader, Constants.FULL_NAME, links); final String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); @@ -109,7 +120,7 @@ } for (String alias : params.loads) { String[] kv = alias.split("="); String loadedContent = readContent(new File(kv[1]), "\n"); String loadedContent = FileUtils.readContent(new File(kv[1]), "\n"); loadedContent = StringUtils.escapeForHtml(loadedContent, false); loadedContent = StringUtils.breakLinesForHtml(loadedContent); content = content.replace(kv[0], loadedContent); @@ -129,32 +140,15 @@ } } private static String readContent(File file, String lineEnding) { StringBuilder sb = new StringBuilder(); try { InputStreamReader is = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")); BufferedReader reader = new BufferedReader(is); String line = null; while ((line = reader.readLine()) != null) { sb.append(line); if (lineEnding != null) { sb.append(lineEnding); } } reader.close(); } catch (Throwable t) { System.err.println("Failed to read content of " + file.getAbsolutePath()); t.printStackTrace(); } return sb.toString(); } private static String getDocumentName(File file) { String displayName = file.getName().substring(0, file.getName().lastIndexOf('.')) .toLowerCase(); // trim leading ##_ which is to control display order return displayName.substring(3); int underscore = displayName.indexOf('_') + 1; if (underscore > -1) { // trim leading ##_ which is to control display order return displayName.substring(underscore); } return displayName; } private static void usage(JCommander jc, ParameterException t) { src/com/gitblit/build/BuildThumbnails.java
@@ -22,6 +22,7 @@ import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.text.MessageFormat; import java.util.Iterator; import javax.imageio.ImageIO; @@ -33,6 +34,12 @@ import com.beust.jcommander.ParameterException; import com.beust.jcommander.Parameters; /** * Generates PNG thumbnails of the PNG images from the specified source folder. * * @author James Moger * */ public class BuildThumbnails { public static void main(String[] args) { @@ -47,6 +54,15 @@ createImageThumbnail(params.sourceFolder, params.destinationFolder, params.maximumDimension); } /** * Generates thumbnails from all PNG images in the source folder and saves * them to the destination folder. * * @param sourceFolder * @param destinationFolder * @param maxDimension * the maximum height or width of the image. */ public static void createImageThumbnail(String sourceFolder, String destinationFolder, int maxDimension) { if (maxDimension <= 0) @@ -71,18 +87,18 @@ // Scale to Width w = maxDimension; float f = maxDimension; h = (int) ((f / sz.width) * sz.height); // normalize height // normalize height h = (int) ((f / sz.width) * sz.height); } else if (sz.height > maxDimension) { // Scale to Height h = maxDimension; float f = maxDimension; w = (int) ((f / sz.height) * sz.width); // normalize width } else { // No thumbnail return; // normalize width w = (int) ((f / sz.height) * sz.width); } System.out.println("Generating thumbnail for " + sourceFile.getName() + " as (" + w + "," + h + ")"); System.out.println(MessageFormat.format( "Generating thumbnail for {0} as ({1,number,#}, {2,number,#})", sourceFile.getName(), w, h)); BufferedImage image = ImageIO.read(sourceFile); Image scaledImage = image.getScaledInstance(w, h, BufferedImage.SCALE_SMOOTH); BufferedImage destImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); @@ -98,6 +114,13 @@ } } /** * Return the dimensions of the specified image file. * * @param file * @return dimensions of the image * @throws IOException */ public static Dimension getImageDimensions(File file) throws IOException { ImageInputStream in = ImageIO.createImageInputStream(file); try { src/com/gitblit/build/BuildWebXml.java
@@ -29,9 +29,15 @@ import com.beust.jcommander.ParameterException; import com.beust.jcommander.Parameters; import com.gitblit.Keys; import com.gitblit.Keys.server; import com.gitblit.utils.StringUtils; /** * Builds the Gitblit WAR web.xml file by merging the Gitblit GO web.xml file * with the gitblit.properties comments, settings, and values. * * @author James Moger * */ public class BuildWebXml { private static final String PARAMS = "<!-- PARAMS -->"; @@ -88,7 +94,8 @@ for (String comment : setting.comments) { parameters.append(MessageFormat.format(COMMENT_PATTERN, comment)); } parameters.append(MessageFormat.format(PARAM_PATTERN, setting.name, StringUtils.escapeForHtml(setting.value, false))); parameters.append(MessageFormat.format(PARAM_PATTERN, setting.name, StringUtils.escapeForHtml(setting.value, false))); } // Read the prototype web.xml file src/com/gitblit/utils/FileUtils.java
New file @@ -0,0 +1,59 @@ /* * Copyright 2011 gitblit.com. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gitblit.utils; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; /** * Common file utilities. * * @author James Moger * */ public class FileUtils { /** * Returns the string content of the specified file. * * @param file * @param lineEnding * @return */ public static String readContent(File file, String lineEnding) { StringBuilder sb = new StringBuilder(); try { InputStreamReader is = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")); BufferedReader reader = new BufferedReader(is); String line = null; while ((line = reader.readLine()) != null) { sb.append(line); if (lineEnding != null) { sb.append(lineEnding); } } reader.close(); } catch (Throwable t) { System.err.println("Failed to read content of " + file.getAbsolutePath()); t.printStackTrace(); } return sb.toString(); } } src/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -143,7 +143,7 @@ } // save the repository GitBlit.self().editRepositoryModel(oldName, repositoryModel, isCreate); GitBlit.self().updateRepositoryModel(oldName, repositoryModel, isCreate); // save the repository access list if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) { src/com/gitblit/wicket/pages/EditUserPage.java
@@ -143,7 +143,7 @@ userModel.repositories.clear(); userModel.repositories.addAll(repos); try { GitBlit.self().editUserModel(oldName, userModel, isCreate); GitBlit.self().updateUserModel(oldName, userModel, isCreate); } catch (GitBlitException e) { error(e.getMessage()); return; tests/com/gitblit/tests/GitBlitSuite.java
@@ -101,7 +101,7 @@ try { RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName); model.useTickets = true; GitBlit.self().editRepositoryModel(model.name, model, false); GitBlit.self().updateRepositoryModel(model.name, model, false); } catch (GitBlitException g) { g.printStackTrace(); } @@ -111,7 +111,7 @@ try { RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName); model.useDocs = true; GitBlit.self().editRepositoryModel(model.name, model, false); GitBlit.self().updateRepositoryModel(model.name, model, false); } catch (GitBlitException g) { g.printStackTrace(); } @@ -121,7 +121,7 @@ try { RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName); model.showRemoteBranches = true; GitBlit.self().editRepositoryModel(model.name, model, false); GitBlit.self().updateRepositoryModel(model.name, model, false); } catch (GitBlitException g) { g.printStackTrace(); }