/build
/keystore
/gitblit.zip
+/gitblit-0.1.0-SNAPSHOT.zip
\r
<!-- Project Properties -->\r
<property name="project.jar" value="gitblit.jar" />\r
- <property name="project.mainclass" value="com.gitblit.Launcher" />\r
- <property name="distribution.zipfile" value="gitblit.zip" />\r
+ <property name="project.mainclass" value="com.gitblit.Launcher" /> \r
<property name="project.build.dir" value="${basedir}/build" />\r
\r
<target name="main">\r
-\r
+ \r
+ <!-- extract version number from source code -->\r
+ <loadfile property="gb.version" srcfile="${basedir}/src/com/gitblit/Constants.java">\r
+ <filterchain>\r
+ <linecontains>\r
+ <contains value="public final static String VERSION = "/>\r
+ </linecontains>\r
+ <striplinebreaks/>\r
+ <tokenfilter> \r
+ <replacestring from="public final static String VERSION = "" to=""/>\r
+ <replacestring from="";" to=""/>\r
+ <trim />\r
+ </tokenfilter>\r
+ </filterchain>\r
+ </loadfile>\r
+ <echo>Building Git:Blit ${gb.version}</echo>\r
+ \r
+ <!-- copy required distribution files to project folder -->\r
+ <copy todir="${basedir}" overwrite="false">\r
+ <fileset dir="${basedir}/distrib">\r
+ <include name="gitblit.properties" />\r
+ <include name="users.properties" />\r
+ </fileset>\r
+ </copy>\r
+ \r
<!-- Compile the build tool and execute it.\r
This downloads missing compile-time dependencies from Maven. -->\r
\r
<mkdir dir="${basedir}/deploy" />\r
<copy todir="${basedir}/deploy" file="${project.jar}" />\r
<copy todir="${basedir}/deploy">\r
- <fileset dir="${basedir}/service">\r
+ <fileset dir="${basedir}/distrib">\r
<include name="**/*" />\r
</fileset>\r
- <fileset dir="${basedir}">\r
- <include name="*.cmd" />\r
- <include name="*.properties" />\r
- </fileset>\r
</copy>\r
\r
<!-- Create Zip deployment -->\r
+ <property name="distribution.zipfile" value="gitblit-${gb.version}.zip" />\r
<zip destfile="${distribution.zipfile}">\r
<fileset dir="${basedir}/deploy">\r
<include name="**/*" />\r
--- /dev/null
+javaservice -uninstall gitblit
\ No newline at end of file
--- /dev/null
+javaservice64 -uninstall gitblit
\ No newline at end of file
--- /dev/null
+@java -jar gitblit.jar --stop\r
--- /dev/null
+@java -jar gitblit.jar\r
--- /dev/null
+#\r
+# Git Servlet Settings\r
+#\r
+\r
+# Allow push/pull over http/https with JGit servlet\r
+git.enableGitServlet = true\r
+\r
+# Base folder for repositories\r
+# Use forward slashes even on Windows!!\r
+git.repositoriesFolder = c:/git\r
+\r
+# Export all repositories\r
+# if false, each exported repository must have a .git/git-daemon-export-ok file\r
+git.exportAll = true\r
+\r
+# Search repositories folder for nested repositories\r
+# e.g. /libraries/mylibrary.git\r
+git.nestedRepositories = true\r
+\r
+# The root clone url\r
+git.cloneUrl = https://localhost/git/\r
+\r
+#\r
+# Authentication Settings\r
+#\r
+\r
+# Require authentication to see everything but the admin pages\r
+web.authenticateViewPages = false\r
+\r
+# Require admin authentication for the admin functions and pages\r
+web.authenticateAdminPages = true\r
+\r
+# Simple user realm file to authenticate users\r
+realm.realmFile = users.properties\r
+\r
+# How to store passwords.\r
+# Valid values are plain, md5 or crypt (unix style). Default is md5. \r
+realm.passwordStorage = md5\r
+\r
+#\r
+# Git:Blit Web Settings\r
+#\r
+# If blank Git:Blit is displayed.\r
+web.siteName =\r
+\r
+# If web.authenticate=true, users with "admin" role can create repositories,\r
+# create users, and edit repository metadata (owner, description, etc)\r
+#\r
+# If web.authenticate=false, any user can execute the aforementioned functions. \r
+web.allowAdministration = true\r
+\r
+# This is the message display above the repositories table.\r
+# This can point to a file with Markdown content.\r
+# Specifying "gitblit" uses the internal welcome message.\r
+web.repositoriesMessage = gitblit\r
+\r
+# Use the client timezone when formatting dates.\r
+# This uses AJAX to determine the browser's timezone.\r
+web.useClientTimezone = false\r
+\r
+# Date and Time formats\r
+web.datestampShortFormat = yyyy-MM-dd\r
+web.datetimestampLongFormat = EEEE, MMMM d, yyyy h:mm a z\r
+\r
+# Choose the diff presentation style: gitblt, gitweb, or plain\r
+web.diffStyle = gitblit\r
+\r
+# Control if email addresses are shown in web ui\r
+web.showEmailAddresses = true\r
+\r
+# Shows a combobox in the page links header with commit, committer, and author\r
+# search selection. Default search is commit.\r
+web.showSearchTypeSelection = false\r
+\r
+# Generates a line graph of repository activity over time on the Summary page.\r
+# This is a real-time graph so generation may be expensive. \r
+web.generateActivityGraph = true\r
+\r
+# The number of commits to display on the summary page\r
+# Value must exceed 0 else default of 20 is used\r
+web.summaryCommitCount = 16\r
+\r
+# The number of tags/heads to display on the summary page\r
+# Value must exceed 0 else default of 5 is used\r
+web.summaryRefsCount = 5\r
+\r
+# The number of items to show on a page before showing the first, prev, next\r
+# pagination links. A default if 50 is used for any invalid value.\r
+web.itemsPerPage = 50\r
+\r
+# Registered extensions for google-code-prettify\r
+web.prettyPrintExtensions = c cpp cs css htm html java js php pl prefs properties py rb sh sql xml vb\r
+\r
+# Registered extensions for markdown transformation\r
+web.markdownExtensions = md mkd markdown\r
+\r
+# Image extensions\r
+web.imageExtensions = bmp jpg gif png \r
+\r
+# Registered extensions for binary blobs\r
+web.binaryExtensions = jar pdf tar.gz zip\r
+\r
+# Aggressive heap management will run the garbage collector on every generated\r
+# page. This slows down page generation but improves heap consumption. \r
+web.aggressiveHeapManagement = true\r
+\r
+# Run the webapp in debug mode\r
+web.debugMode = false\r
+\r
+# Enable/disable global regex substitutions (i.e. shared across repositories)\r
+regex.global = true\r
+\r
+# Example global regex substitutions\r
+# Use !!! to separate the search pattern and the replace pattern\r
+# searchpattern!!!replacepattern\r
+#regex.global.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!<a href="http://somehost/bug/$3">Bug-Id: $3</a>\r
+#regex.global.changeid = \\b(Change-Id:\\s*)([A-Za-z0-9]*)\\b!!!<a href="http://somehost/changeid/$2">Change-Id: $2</a>\r
+\r
+# Example per-repository regex substitutions overrides global\r
+#regex.myrepository.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!<a href="http://elsewhere/bug/$3">Bug-Id: $3</a>\r
+\r
+#\r
+# Server Settings\r
+#\r
+server.tempFolder = temp\r
+server.log4jPattern = %-5p %d{MM-dd HH:mm:ss.SSS} %-20.20c{1} %m%n\r
+server.log4jPattern.windows = %-5p %m%n\r
+server.log4jPattern.linux =\r
+\r
+\r
+#\r
+# Jetty Settings\r
+#\r
+\r
+# Use Jetty NIO connectors. If false, Jetty Socket connectors will be used.\r
+server.useNio = true\r
+\r
+# Standard http port to serve. <= 0 disables this connector.\r
+server.httpPort = 0\r
+\r
+# Secure/SSL https port to serve. <= 0 disables this connector.\r
+server.httpsPort = 443\r
+\r
+# Specify the interface for Jetty to bind the standard connector.\r
+# You may specify an ip or an empty value to bind to all interfaces. \r
+server.httpBindInterface = localhost\r
+\r
+# Specify the interface for Jetty to bind the secure connector.\r
+# You may specify an ip or an empty value to bind to all interfaces.\r
+server.httpsBindInterface = localhost\r
+\r
+# Password for SSL keystore.\r
+# Keystore password and certificate password must match.\r
+# This is provided for convenience, its probably more secure to set this value\r
+# using the --storePassword command line parameter.\r
+server.storePassword = dosomegit\r
+\r
+# Port for shutdown monitor to listen on.\r
+server.shutdownPort = 8081\r
--- /dev/null
+set JDK=C:\Program Files\Java\jdk1.6.0_21\r
+JavaService.exe -install gitblit "%JDK%\jre\bin\server\jvm.dll" -Xmx1024M -Djava.class.path=%CD%\gitblit.jar;"%JDK%\lib\tools.jar" -start com.gitblit.Launcher -params --storePassword dosomegit -stop com.gitblit.Launcher -params --stop -out %CD%\logs\stdout.log -err %CD%\logs\stderr.log -current %CD%
\ No newline at end of file
--- /dev/null
+set JDK=C:\Program Files\Java\jdk1.6.0_21\r
+JavaService64.exe -install gitblit "%JDK%\jre\bin\server\jvm.dll" -Djava.class.path=%CD%\gitblit.jar;"%JDK%\lib\tools.jar" -start com.gitblit.Launcher -params --storePassword dosomegit -stop com.gitblit.Launcher -params --stop -out %CD%\logs\stdout.log -err %CD%\logs\stderr.log -current %CD%
\ No newline at end of file
--- /dev/null
+@del keystore\r
+@keytool -keystore keystore -alias localhost -genkey -keyalg RSA -dname "CN=localhost, OU=Git:Blit, O=Git:Blit, L=Some Town, ST=Some State, C=US"
\ No newline at end of file
--- /dev/null
+# Git:Blit realm file format: username=password,\#permission,repository1,repository2...\r
+admin=admin,\#admin\r
web.authenticateAdminPages = true\r
\r
# Simple user realm file to authenticate users\r
-server.realmFile = users.properties\r
+realm.realmFile = users.properties\r
+\r
+# How to store passwords.\r
+# Valid values are plain, md5 or crypt (unix style). Default is md5. \r
+realm.passwordStorage = md5\r
\r
#\r
# Git:Blit Web Settings\r
+++ /dev/null
-javaservice -uninstall gitblit
\ No newline at end of file
+++ /dev/null
-javaservice64 -uninstall gitblit
\ No newline at end of file
+++ /dev/null
-set JDK=C:\Program Files\Java\jdk1.6.0_21\r
-JavaService.exe -install gitblit "%JDK%\jre\bin\server\jvm.dll" -Xmx1024M -Djava.class.path=%CD%\gitblit.jar;"%JDK%\lib\tools.jar" -start com.gitblit.Launcher -params --storePassword dosomegit -stop com.gitblit.Launcher -params --stop -out %CD%\logs\stdout.log -err %CD%\logs\stderr.log -current %CD%
\ No newline at end of file
+++ /dev/null
-set JDK=C:\Program Files\Java\jdk1.6.0_21\r
-JavaService64.exe -install gitblit "%JDK%\jre\bin\server\jvm.dll" -Djava.class.path=%CD%\gitblit.jar;"%JDK%\lib\tools.jar" -start com.gitblit.Launcher -params --storePassword dosomegit -stop com.gitblit.Launcher -params --stop -out %CD%\logs\stdout.log -err %CD%\logs\stderr.log -current %CD%
\ No newline at end of file
\r
public final static String NAME = "Git:Blit";\r
\r
+ // The build script extracts this exact line so be careful editing it\r
+ // and only use A-Z a-z 0-9 .-_ in the string. \r
public final static String VERSION = "0.1.0-SNAPSHOT";\r
\r
public final static String ADMIN_ROLE = "#admin";\r
}\r
return NONE;\r
}\r
- \r
+\r
+ public boolean exceeds(AccessRestrictionType type) {\r
+ return this.ordinal() > type.ordinal();\r
+ }\r
+\r
public boolean atLeast(AccessRestrictionType type) {\r
return this.ordinal() >= type.ordinal();\r
}\r
\r
public String toString() {\r
- switch (this) {\r
- case NONE:\r
- return "Anonymous View, Clone, & Push";\r
- case PUSH:\r
- return "Anonymous View & Clone, Authenticated Push";\r
- case CLONE:\r
- return "Anonymous View, Authenticated Clone & Push";\r
- case VIEW:\r
- return "Authenticated View, Clone, & Push";\r
- }\r
- return "none";\r
+ return name();\r
}\r
}\r
\r
userCookie.setPath("/");\r
response.addCookie(userCookie);\r
}\r
+ \r
+ public List<String> getAllUsernames() {\r
+ return loginService.getAllUsernames();\r
+ }\r
\r
- public UserModel getUser(String username) {\r
+ public UserModel getUserModel(String username) {\r
UserModel user = loginService.getUserModel(username);\r
return user;\r
}\r
+ \r
+ public List<String> getRepositoryUsers(RepositoryModel repository) {\r
+ return loginService.getUsernamesForRole(repository.name);\r
+ }\r
+ \r
+ public boolean setRepositoryUsers(RepositoryModel repository, List<String> repositoryUsers) {\r
+ return loginService.setUsernamesForRole(repository.name, repositoryUsers);\r
+ }\r
\r
public void editUserModel(UserModel user, boolean isCreate) throws GitBlitException {\r
if (!loginService.updateUserModel(user)) {\r
}\r
\r
public void configureContext(IStoredSettings settings) {\r
- logger.info("Configure GitBlit from " + settings.toString());\r
+ logger.info("Using configuration from " + settings.toString());\r
this.storedSettings = settings;\r
repositoriesFolder = new File(settings.getString(Keys.git.repositoriesFolder, "repos"));\r
exportAll = settings.getBoolean(Keys.git.exportAll, true);\r
* Authentication Parameters\r
*/\r
@Parameter(names = { "--realmFile" }, description = "Users Realm Hash File")\r
- public String realmFile = fileSettings.getString(Keys.server.realmFile, "users.properties");\r
+ public String realmFile = fileSettings.getString(Keys.realm.realmFile, "users.properties");\r
\r
/*\r
* JETTY Parameters\r
package com.gitblit;\r
\r
+import java.util.List;\r
+\r
import com.gitblit.wicket.models.UserModel;\r
\r
public interface ILoginService {\r
\r
boolean deleteUserModel(UserModel model);\r
\r
+ List<String> getAllUsernames();\r
+ \r
+ List<String> getUsernamesForRole(String role);\r
+ \r
+ boolean setUsernamesForRole(String role, List<String> usernames);\r
+ \r
+ boolean renameRole(String oldRole, String newRole);\r
+ \r
+ boolean deleteRole(String role);\r
+ \r
}\r
import java.io.FileWriter;\r
import java.io.IOException;\r
import java.security.Principal;\r
+import java.text.MessageFormat;\r
import java.util.ArrayList;\r
+import java.util.HashSet;\r
+import java.util.List;\r
import java.util.Map;\r
import java.util.Properties;\r
+import java.util.Set;\r
\r
import javax.security.auth.Subject;\r
\r
import org.eclipse.jetty.security.MappedLoginService;\r
import org.eclipse.jetty.server.UserIdentity;\r
import org.eclipse.jetty.util.log.Log;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
\r
import com.gitblit.utils.StringUtils;\r
import com.gitblit.wicket.models.UserModel;\r
\r
public class JettyLoginService extends MappedLoginService implements ILoginService {\r
\r
+ private final Logger logger = LoggerFactory.getLogger(JettyLoginService.class);\r
+\r
private final File realmFile;\r
\r
public JettyLoginService(File realmFile) {\r
for (Principal principal : identity.getSubject().getPrincipals()) {\r
if (principal instanceof RolePrincipal) {\r
RolePrincipal role = (RolePrincipal) principal;\r
- if (role.getName().charAt(0) != '#') {\r
- user.addRepository(role.getName().substring(1));\r
+ String roleName = role.getName();\r
+ if (roleName.charAt(0) != '#') {\r
+ user.addRepository(roleName);\r
}\r
}\r
}\r
}\r
break;\r
default:\r
- model.addRepository(name.substring(1));\r
+ model.addRepository(name);\r
}\r
}\r
}\r
+ // Retrieve the password from the realm file.\r
+ // Stupid, I know, but the password is buried within protected inner\r
+ // classes in private variables. Too much work to reflectively retrieve.\r
+ try {\r
+ Properties allUsers = readRealmFile();\r
+ String value = allUsers.getProperty(username);\r
+ String password = value.split(",")[0];\r
+ model.setPassword(password);\r
+ } catch (Throwable t) {\r
+ logger.error(MessageFormat.format("Failed to read password for user {0}!", username), t);\r
+ }\r
return model;\r
}\r
\r
@Override\r
public boolean updateUserModel(UserModel model) {\r
try {\r
- Properties properties = new Properties();\r
- FileReader reader = new FileReader(realmFile);\r
- properties.load(reader);\r
- reader.close();\r
-\r
- ArrayList<String> roles = new ArrayList<String>();\r
-\r
- // Repositories\r
- roles.addAll(model.getRepositories());\r
+ Properties allUsers = readRealmFile();\r
+ ArrayList<String> roles = new ArrayList<String>(model.getRepositories());\r
\r
// Permissions\r
if (model.canAdmin()) {\r
}\r
// trim trailing comma\r
sb.setLength(sb.length() - 1);\r
+ allUsers.put(model.getUsername(), sb.toString());\r
\r
- // Update realm file\r
- File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");\r
- FileWriter writer = new FileWriter(realmFileCopy);\r
- properties.put(model.getUsername(), sb.toString());\r
- properties.store(writer, null);\r
- writer.close();\r
- realmFile.delete();\r
- realmFileCopy.renameTo(realmFile);\r
+ writeRealmFile(allUsers);\r
\r
// Update login service\r
putUser(model.getUsername(), Credential.getCredential(model.getPassword()), roles.toArray(new String[0]));\r
return true;\r
} catch (Throwable t) {\r
- t.printStackTrace();\r
+ logger.error(MessageFormat.format("Failed to update user model {0}!", model.getUsername()), t);\r
}\r
return false;\r
}\r
public boolean deleteUserModel(UserModel model) {\r
try {\r
// Read realm file\r
- Properties properties = new Properties();\r
- FileReader reader = new FileReader(realmFile);\r
- properties.load(reader);\r
- reader.close();\r
- properties.remove(model.getUsername());\r
-\r
- // Update realm file\r
- File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");\r
- FileWriter writer = new FileWriter(realmFileCopy);\r
- properties.store(writer, null);\r
- writer.close();\r
- realmFile.delete();\r
- realmFileCopy.renameTo(realmFile);\r
+ Properties allUsers = readRealmFile();\r
+ allUsers.remove(model.getUsername());\r
+ writeRealmFile(allUsers);\r
\r
// Drop user from map\r
_users.remove(model.getUsername());\r
return true;\r
} catch (Throwable t) {\r
- t.printStackTrace();\r
+ logger.error(MessageFormat.format("Failed to delete user model {0}!", model.getUsername()), t);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public List<String> getAllUsernames() {\r
+ List<String> list = new ArrayList<String>();\r
+ list.addAll(_users.keySet());\r
+ return list;\r
+ }\r
+\r
+ @Override\r
+ public List<String> getUsernamesForRole(String role) {\r
+ List<String> list = new ArrayList<String>();\r
+ try {\r
+ Properties allUsers = readRealmFile();\r
+ for (String username : allUsers.stringPropertyNames()) {\r
+ String value = allUsers.getProperty(username);\r
+ String[] values = value.split(",");\r
+ // skip first value (password)\r
+ for (int i = 1; i < values.length; i++) {\r
+ String r = values[i];\r
+ if (r.equalsIgnoreCase(role)) {\r
+ list.add(username);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ } catch (Throwable t) {\r
+ logger.error(MessageFormat.format("Failed to get usernames for role {0}!", role), t);\r
+ }\r
+ return list;\r
+ }\r
+\r
+ @Override\r
+ public boolean setUsernamesForRole(String role, List<String> usernames) {\r
+ try {\r
+ Set<String> specifiedUsers = new HashSet<String>(usernames);\r
+ Set<String> needsAddRole = new HashSet<String>(specifiedUsers);\r
+ Set<String> needsRemoveRole = new HashSet<String>();\r
+\r
+ // identify users which require add and remove role\r
+ Properties allUsers = readRealmFile();\r
+ for (String username : allUsers.stringPropertyNames()) {\r
+ String value = allUsers.getProperty(username);\r
+ String[] values = value.split(",");\r
+ // skip first value (password)\r
+ for (int i = 1; i < values.length; i++) {\r
+ String r = values[i];\r
+ if (r.equalsIgnoreCase(role)) {\r
+ // user has role, check against revised user list\r
+ if (specifiedUsers.contains(username)) {\r
+ needsAddRole.remove(username);\r
+ } else {\r
+ // remove role from user\r
+ needsRemoveRole.add(username);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // add roles to users\r
+ for (String user : needsAddRole) {\r
+ String userValues = allUsers.getProperty(user);\r
+ userValues += ("," + role);\r
+ allUsers.put(user, userValues);\r
+ String[] values = userValues.split(",");\r
+ String password = values[0];\r
+ String[] roles = new String[values.length - 1];\r
+ System.arraycopy(values, 1, roles, 0, values.length - 1);\r
+ putUser(user, Credential.getCredential(password), roles);\r
+ }\r
+\r
+ // remove role from user\r
+ for (String user : needsRemoveRole) {\r
+ String[] values = allUsers.getProperty(user).split(",");\r
+ String password = values[0];\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append(password);\r
+ sb.append(',');\r
+ List<String> revisedRoles = new ArrayList<String>();\r
+ // skip first value (password)\r
+ for (int i = 1; i < values.length; i++) {\r
+ String value = values[i];\r
+ if (!value.equalsIgnoreCase(role)) {\r
+ revisedRoles.add(value);\r
+ sb.append(value);\r
+ sb.append(',');\r
+ }\r
+ }\r
+ sb.setLength(sb.length() - 1);\r
+\r
+ // update properties\r
+ allUsers.put(user, sb.toString());\r
+\r
+ // update memory\r
+ putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));\r
+ }\r
+\r
+ // persist changes\r
+ writeRealmFile(allUsers);\r
+ return true;\r
+ } catch (Throwable t) {\r
+ logger.error(MessageFormat.format("Failed to set usernames for role {0}!", role), t);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public boolean renameRole(String oldRole, String newRole) {\r
+ try {\r
+ Properties allUsers = readRealmFile();\r
+ Set<String> needsRenameRole = new HashSet<String>();\r
+\r
+ // identify users which require role rename\r
+ for (String username : allUsers.stringPropertyNames()) {\r
+ String value = allUsers.getProperty(username);\r
+ String[] roles = value.split(",");\r
+ // skip first value (password)\r
+ for (int i = 1; i < roles.length; i++) {\r
+ String r = roles[i];\r
+ if (r.equalsIgnoreCase(oldRole)) {\r
+ needsRenameRole.remove(username);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // rename role for identified users\r
+ for (String user : needsRenameRole) {\r
+ String userValues = allUsers.getProperty(user);\r
+ String[] values = userValues.split(",");\r
+ String password = values[0];\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append(password);\r
+ sb.append(',');\r
+ List<String> revisedRoles = new ArrayList<String>();\r
+ revisedRoles.add(newRole);\r
+ // skip first value (password)\r
+ for (int i = 1; i < values.length; i++) {\r
+ String value = values[i];\r
+ if (!value.equalsIgnoreCase(oldRole)) {\r
+ revisedRoles.add(value);\r
+ sb.append(value);\r
+ sb.append(',');\r
+ }\r
+ }\r
+ sb.setLength(sb.length() - 1);\r
+\r
+ // update properties\r
+ allUsers.put(user, sb.toString());\r
+\r
+ // update memory\r
+ putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));\r
+ }\r
+\r
+ // persist changes\r
+ writeRealmFile(allUsers);\r
+ return true;\r
+ } catch (Throwable t) {\r
+ logger.error(MessageFormat.format("Failed to rename role {0} to {1}!", oldRole, newRole), t);\r
}\r
return false;\r
}\r
\r
+ @Override\r
+ public boolean deleteRole(String role) {\r
+ try {\r
+ Properties allUsers = readRealmFile();\r
+ Set<String> needsDeleteRole = new HashSet<String>();\r
+\r
+ // identify users which require role rename\r
+ for (String username : allUsers.stringPropertyNames()) {\r
+ String value = allUsers.getProperty(username);\r
+ String[] roles = value.split(",");\r
+ // skip first value (password)\r
+ for (int i = 1; i < roles.length; i++) {\r
+ String r = roles[i];\r
+ if (r.equalsIgnoreCase(role)) {\r
+ needsDeleteRole.remove(username);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // delete role for identified users\r
+ for (String user : needsDeleteRole) {\r
+ String userValues = allUsers.getProperty(user);\r
+ String[] values = userValues.split(",");\r
+ String password = values[0];\r
+ StringBuilder sb = new StringBuilder();\r
+ sb.append(password);\r
+ sb.append(',');\r
+ List<String> revisedRoles = new ArrayList<String>();\r
+ // skip first value (password)\r
+ for (int i = 1; i < values.length; i++) {\r
+ String value = values[i];\r
+ if (!value.equalsIgnoreCase(role)) {\r
+ revisedRoles.add(value);\r
+ sb.append(value);\r
+ sb.append(',');\r
+ }\r
+ }\r
+ sb.setLength(sb.length() - 1);\r
+\r
+ // update properties\r
+ allUsers.put(user, sb.toString());\r
+\r
+ // update memory\r
+ putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));\r
+ }\r
+\r
+ // persist changes\r
+ writeRealmFile(allUsers);\r
+ } catch (Throwable t) {\r
+ logger.error(MessageFormat.format("Failed to delete role {0}!", role), t);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ private Properties readRealmFile() throws IOException {\r
+ Properties allUsers = new Properties();\r
+ FileReader reader = new FileReader(realmFile);\r
+ allUsers.load(reader);\r
+ reader.close();\r
+ return allUsers;\r
+ }\r
+\r
+ private void writeRealmFile(Properties properties) throws IOException {\r
+ // Update realm file\r
+ File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");\r
+ FileWriter writer = new FileWriter(realmFileCopy);\r
+ properties.store(writer, "# Git:Blit realm file format: username=password,\\#permission,repository1,repository2...");\r
+ writer.close();\r
+ if (realmFileCopy.exists() && realmFileCopy.length() > 0) {\r
+ realmFile.delete();\r
+ realmFileCopy.renameTo(realmFile);\r
+ } else {\r
+ throw new IOException("Failed to save realmfile!");\r
+ }\r
+ }\r
+\r
/* ------------------------------------------------------------ */\r
@Override\r
public void loadUsers() throws IOException {\r
\r
if (Log.isDebugEnabled())\r
Log.debug("Load " + this + " from " + realmFile);\r
- Properties properties = new Properties();\r
- FileReader reader = new FileReader(realmFile);\r
- properties.load(reader);\r
- reader.close();\r
+ Properties allUsers = readRealmFile();\r
\r
// Map Users\r
- for (Map.Entry<Object, Object> entry : properties.entrySet()) {\r
+ for (Map.Entry<Object, Object> entry : allUsers.entrySet()) {\r
String username = ((String) entry.getKey()).trim();\r
String credentials = ((String) entry.getValue()).trim();\r
String roles = null;\r
package com.gitblit.wicket;\r
\r
+import java.util.LinkedHashMap;\r
+import java.util.Map;\r
import java.util.TimeZone;\r
\r
import javax.servlet.http.HttpServletRequest;\r
import org.slf4j.LoggerFactory;\r
\r
import com.gitblit.Constants;\r
+import com.gitblit.Constants.AccessRestrictionType;\r
import com.gitblit.GitBlit;\r
import com.gitblit.Keys;\r
import com.gitblit.wicket.pages.SummaryPage;\r
}\r
}\r
\r
+ protected Map<AccessRestrictionType, String> getAccessRestrictions() {\r
+ Map<AccessRestrictionType, String> map = new LinkedHashMap<AccessRestrictionType, String>();\r
+ for (AccessRestrictionType type : AccessRestrictionType.values()) {\r
+ switch (type) {\r
+ case NONE:\r
+ map.put(type, getString("gb.notRestricted"));\r
+ break;\r
+ case PUSH:\r
+ map.put(type, getString("gb.pushRestricted"));\r
+ break;\r
+ case CLONE:\r
+ map.put(type, getString("gb.cloneRestricted"));\r
+ break;\r
+ case VIEW:\r
+ map.put(type, getString("gb.viewRestricted"));\r
+ break;\r
+ }\r
+ }\r
+ return map;\r
+ }\r
+\r
protected TimeZone getTimeZone() {\r
return GitBlit.self().settings().getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get().getTimezone() : TimeZone.getDefault();\r
}\r
gb.editUsers = edit users\r
gb.password = password\r
gb.confirmPassword = confirm password\r
-gb.repositories = repositories\r
+gb.restrictedRepositories = restricted repositories\r
gb.canAdmin can admin\r
-gb.notRestricted = open repository\r
-gb.cloneRestricted = clone-restricted repository\r
-gb.pushRestricted = push-restricted repository\r
-gb.viewRestricted = view-restricted repository
\ No newline at end of file
+gb.notRestricted = anonymous view, clone, & push\r
+gb.pushRestricted = authenticated push\r
+gb.cloneRestricted = authenticated clone & push\r
+gb.viewRestricted = authenticated view, clone, & push\r
+gb.useTicketsDescription = distributed Ticgit issues\r
+gb.useDocsDescription = enumerates Markdown documentation in repository\r
+gb.showRemoteBranchesDescription = show remote branches\r
+gb.canAdminDescription = can administer Git:Blit server\r
+gb.permittedUsers = permitted users
\ No newline at end of file
<tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input type="text" wicket:id="name" id="name" size="40" tabindex="1" /></td></tr>\r
<tr><th><wicket:message key="gb.description"></wicket:message></th><td class="edit"><input type="text" wicket:id="description" size="40" tabindex="2" /></td></tr>\r
<tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><input type="text" wicket:id="owner" size="40" tabindex="3" /></td></tr>\r
- <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select wicket:id="accessRestriction" tabindex="4" /></td></tr> \r
- <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="5" /> <i>distributed Ticgit issues</i></td></tr>\r
- <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="6" /> <i>enumerates Markdown documentation in repository</i></td></tr>\r
- <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="7" /> <i>show remote branches</i></td></tr>\r
+ <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="4" /> <i><wicket:message key="gb.useTicketsDescription"></wicket:message></i></td></tr>\r
+ <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="5" /> <i><wicket:message key="gb.useDocsDescription"></wicket:message></i></td></tr>\r
+ <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="6" /> <i><wicket:message key="gb.showRemoteBranchesDescription"></wicket:message></i></td></tr>\r
+ <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select wicket:id="accessRestriction" tabindex="7" /></td></tr> \r
+ <tr><th style="vertical-align: top;"><wicket:message key="gb.permittedUsers"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr> \r
<tr><th></th><td class="editButton"><input type="submit" value="Save" wicket:message="value:gb.save" tabindex="8" /></td></tr>\r
</tbody>\r
</table>\r
package com.gitblit.wicket.pages;\r
\r
+import java.text.MessageFormat;\r
+import java.util.ArrayList;\r
import java.util.Arrays;\r
import java.util.Date;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
\r
import org.apache.wicket.PageParameters;\r
+import org.apache.wicket.extensions.markup.html.form.palette.Palette;\r
import org.apache.wicket.markup.html.form.CheckBox;\r
+import org.apache.wicket.markup.html.form.ChoiceRenderer;\r
import org.apache.wicket.markup.html.form.DropDownChoice;\r
import org.apache.wicket.markup.html.form.Form;\r
+import org.apache.wicket.markup.html.form.IChoiceRenderer;\r
import org.apache.wicket.markup.html.form.TextField;\r
import org.apache.wicket.model.CompoundPropertyModel;\r
+import org.apache.wicket.model.util.CollectionModel;\r
+import org.apache.wicket.model.util.ListModel;\r
\r
import com.gitblit.Constants.AccessRestrictionType;\r
import com.gitblit.GitBlit;\r
import com.gitblit.GitBlitException;\r
+import com.gitblit.utils.StringUtils;\r
import com.gitblit.wicket.AdminPage;\r
import com.gitblit.wicket.BasePage;\r
import com.gitblit.wicket.WicketUtils;\r
}\r
\r
protected void setupPage(final RepositoryModel repositoryModel) {\r
+ List<String> repositoryUsers = new ArrayList<String>();\r
if (isCreate) {\r
super.setupPage("", getString("gb.newRepository"));\r
} else {\r
- super.setupPage("", getString("gb.edit") + " " + repositoryModel.name);\r
+ super.setupPage("", getString("gb.edit"));\r
+ if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {\r
+ repositoryUsers.addAll(GitBlit.self().getRepositoryUsers(repositoryModel));\r
+ }\r
}\r
+\r
+ final Palette<String> usersPalette = new Palette<String>("users", new ListModel<String>(repositoryUsers), new CollectionModel<String>(GitBlit.self().getAllUsernames()), new ChoiceRenderer<String>("", ""), 10, false);\r
CompoundPropertyModel<RepositoryModel> model = new CompoundPropertyModel<RepositoryModel>(repositoryModel);\r
Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", model) {\r
\r
@Override\r
protected void onSubmit() {\r
try {\r
+ // confirm a repository name was entered\r
+ if (StringUtils.isEmpty(repositoryModel.name)) {\r
+ error("Please set repository name!");\r
+ return;\r
+ }\r
+\r
+ // automatically convert backslashes to forward slashes\r
+ repositoryModel.name = repositoryModel.name.replace('\\', '/');\r
+\r
+ // confirm valid characters in repository name\r
+ char[] validChars = { '/', '.', '_', '-' };\r
+ for (char c : repositoryModel.name.toCharArray()) {\r
+ if (!Character.isLetterOrDigit(c)) {\r
+ boolean ok = false;\r
+ for (char vc : validChars) {\r
+ ok |= c == vc;\r
+ }\r
+ if (!ok) {\r
+ error(MessageFormat.format("Illegal character '{0}' in repository name!", c));\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ // confirm access restriction selection\r
+ if (repositoryModel.accessRestriction == null) {\r
+ error("Please select access restriction!");\r
+ return;\r
+ }\r
+ \r
+ // save the repository\r
GitBlit.self().editRepositoryModel(repositoryModel, isCreate);\r
+ \r
+ // save the repository access list\r
+ if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {\r
+ Iterator<String> users = usersPalette.getSelectedChoices();\r
+ List<String> repositoryUsers = new ArrayList<String>();\r
+ while (users.hasNext()) {\r
+ repositoryUsers.add(users.next());\r
+ }\r
+ GitBlit.self().setRepositoryUsers(repositoryModel, repositoryUsers);\r
+ }\r
} catch (GitBlitException e) {\r
error(e.getMessage());\r
return;\r
form.add(new TextField<String>("name").setEnabled(isCreate));\r
form.add(new TextField<String>("description"));\r
form.add(new TextField<String>("owner"));\r
- form.add(new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays.asList(AccessRestrictionType.values())));\r
+ form.add(new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays.asList(AccessRestrictionType.values()), new AccessRestrictionRenderer()));\r
form.add(new CheckBox("useTickets"));\r
form.add(new CheckBox("useDocs"));\r
form.add(new CheckBox("showRemoteBranches"));\r
+ form.add(usersPalette);\r
\r
add(form);\r
}\r
+\r
+ private class AccessRestrictionRenderer implements IChoiceRenderer<AccessRestrictionType> {\r
+\r
+ private static final long serialVersionUID = 1L;\r
+\r
+ private final Map<AccessRestrictionType, String> map;\r
+\r
+ public AccessRestrictionRenderer() {\r
+ map = getAccessRestrictions();\r
+ }\r
+\r
+ @Override\r
+ public String getDisplayValue(AccessRestrictionType type) {\r
+ return map.get(type);\r
+ }\r
+\r
+ @Override\r
+ public String getIdValue(AccessRestrictionType type, int index) {\r
+ return Integer.toString(index);\r
+ }\r
+ }\r
}\r
<tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input type="text" wicket:id="username" id="username" size="30" tabindex="1" /></td></tr>\r
<tr><th><wicket:message key="gb.password"></wicket:message></th><td class="edit"><input type="password" wicket:id="password" size="30" tabindex="2" /></td></tr>\r
<tr><th><wicket:message key="gb.confirmPassword"></wicket:message></th><td class="edit"><input type="password" wicket:id="confirmPassword" size="30" tabindex="3" /></td></tr>\r
- <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <i>can administer Git:Blit server</i></td></tr> \r
- <tr><th style="vertical-align: top;"><wicket:message key="gb.repositories"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr>\r
+ <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <i><wicket:message key="gb.canAdminDescription"></wicket:message></i></td></tr> \r
+ <tr><th style="vertical-align: top;"><wicket:message key="gb.restrictedRepositories"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr>\r
<tr><th></th><td class="editButton"><input type="submit" value="Save" wicket:message="value:gb.save" tabindex="7" /></td></tr>\r
</tbody>\r
</table>\r
import org.apache.wicket.model.Model;\r
import org.apache.wicket.model.util.CollectionModel;\r
import org.apache.wicket.model.util.ListModel;\r
+import org.eclipse.jetty.http.security.Credential.Crypt;\r
import org.eclipse.jetty.http.security.Credential.MD5;\r
\r
+import com.gitblit.Constants.AccessRestrictionType;\r
import com.gitblit.GitBlit;\r
import com.gitblit.GitBlitException;\r
+import com.gitblit.Keys;\r
+import com.gitblit.utils.StringUtils;\r
import com.gitblit.wicket.AdminPage;\r
import com.gitblit.wicket.BasePage;\r
import com.gitblit.wicket.WicketUtils;\r
+import com.gitblit.wicket.models.RepositoryModel;\r
import com.gitblit.wicket.models.UserModel;\r
\r
@AdminPage\r
super(params);\r
isCreate = false;\r
String name = WicketUtils.getUsername(params);\r
- UserModel model = GitBlit.self().getUser(name);\r
+ UserModel model = GitBlit.self().getUserModel(name);\r
setupPage(model);\r
}\r
\r
} else {\r
super.setupPage("", getString("gb.edit"));\r
}\r
- final Model<String> confirmPassword = new Model<String>();\r
+ final Model<String> confirmPassword = new Model<String>(StringUtils.isEmpty(userModel.getPassword()) ? "" : userModel.getPassword());\r
CompoundPropertyModel<UserModel> model = new CompoundPropertyModel<UserModel>(userModel);\r
\r
- List<String> repos = GitBlit.self().getRepositoryList();\r
- repos.add(0, "*"); // all repositories wildcard\r
- final Palette<String> repositories = new Palette<String>("repositories", new ListModel<String>(userModel.getRepositories()), new CollectionModel<String>(repos), new ChoiceRenderer<String>("", ""), 10, false); \r
+ List<String> repos = new ArrayList<String>();\r
+ for (String repo : GitBlit.self().getRepositoryList()) {\r
+ RepositoryModel repositoryModel = GitBlit.self().getRepositoryModel(repo);\r
+ if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {\r
+ repos.add(repo);\r
+ }\r
+ }\r
+ final Palette<String> repositories = new Palette<String>("repositories", new ListModel<String>(userModel.getRepositories()), new CollectionModel<String>(repos), new ChoiceRenderer<String>("", ""), 10, false);\r
Form<UserModel> form = new Form<UserModel>("editForm", model) {\r
\r
private static final long serialVersionUID = 1L;\r
error("Passwords do not match!");\r
return;\r
}\r
- userModel.setPassword(MD5.digest(userModel.getPassword()));\r
- \r
+ String password = userModel.getPassword();\r
+ if (!password.toUpperCase().startsWith(Crypt.__TYPE) && !password.toUpperCase().startsWith(MD5.__TYPE)) {\r
+ // This is a plain text password.\r
+ // Optionally encrypt/obfuscate the password.\r
+ String type = GitBlit.self().settings().getString(Keys.realm.passwordStorage, "md5");\r
+ if (type.equalsIgnoreCase("md5")) {\r
+ // store MD5 checksum of password\r
+ userModel.setPassword(MD5.digest(userModel.getPassword()));\r
+ } else if (type.equalsIgnoreCase("crypt")) {\r
+ // simple unix encryption\r
+ userModel.setPassword(Crypt.crypt(userModel.getUsername(), userModel.getPassword()));\r
+ }\r
+ }\r
+\r
Iterator<String> selectedRepositories = repositories.getSelectedChoices();\r
List<String> repos = new ArrayList<String>();\r
while (selectedRepositories.hasNext()) {\r
return;\r
}\r
setRedirect(true);\r
- setResponsePage(EditUserPage.class);\r
+ if (isCreate) {\r
+ // create another user\r
+ setResponsePage(EditUserPage.class);\r
+ } else {\r
+ // back to home\r
+ setResponsePage(RepositoriesPage.class);\r
+ }\r
}\r
};\r
\r
// field names reflective match UserModel fields\r
form.add(new TextField<String>("username").setEnabled(isCreate));\r
- form.add(new PasswordTextField("password"));\r
- form.add(new PasswordTextField("confirmPassword", confirmPassword));\r
+ PasswordTextField passwordField = new PasswordTextField("password");\r
+ passwordField.setResetPassword(false);\r
+ form.add(passwordField);\r
+ PasswordTextField confirmPasswordField = new PasswordTextField("confirmPassword", confirmPassword);\r
+ confirmPasswordField.setResetPassword(false);\r
+ form.add(confirmPasswordField);\r
form.add(new CheckBox("canAdmin"));\r
form.add(repositories);\r
add(form);\r
<td><div class="list" wicket:id="repositoryName">[repository name]</div></td>\r
<td><div class="list" wicket:id="repositoryDescription">[repository description]</div></td>\r
<td class="author"><span wicket:id="repositoryOwner">[repository owner]</span></td>\r
- <td class="icon"><img wicket:id="ticketsIcon" /><img wicket:id="docsIcon" /><img wicket:id="restrictedAccessIcon" /></td>\r
+ <td class="icon"><img wicket:id="ticketsIcon" /><img wicket:id="docsIcon" /><img wicket:id="accessRestrictionIcon" /></td>\r
<td><span wicket:id="repositoryLastChange">[last change]</span></td>\r
<td class="rightAlign"><span wicket:id="repositoryLinks"></span></td>\r
</tr>\r
import java.util.Comparator;\r
import java.util.Iterator;\r
import java.util.List;\r
+import java.util.Map;\r
\r
import org.apache.wicket.Component;\r
import org.apache.wicket.PageParameters;\r
import org.apache.wicket.model.Model;\r
import org.apache.wicket.resource.ContextRelativeResource;\r
\r
+import com.gitblit.Constants.AccessRestrictionType;\r
import com.gitblit.GitBlit;\r
import com.gitblit.Keys;\r
import com.gitblit.utils.MarkdownUtils;\r
}\r
add(repositoriesMessage);\r
\r
+ final Map<AccessRestrictionType, String> accessRestrictionTranslations = getAccessRestrictions();\r
UserModel user = GitBlitWebSession.get().getUser();\r
List<RepositoryModel> rows = GitBlit.self().getRepositoryModels(user);\r
DataProvider dp = new DataProvider(rows);\r
} else {\r
item.add(WicketUtils.newBlankImage("docsIcon"));\r
}\r
-\r
+ \r
switch (entry.accessRestriction) {\r
case NONE:\r
- item.add(WicketUtils.newBlankImage("restrictedAccessIcon"));\r
+ item.add(WicketUtils.newBlankImage("accessRestrictionIcon"));\r
break;\r
case PUSH:\r
- item.add(WicketUtils.newImage("restrictedAccessIcon", "lock_go_16x16.png", getString("gb.pushRestricted")));\r
+ item.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
break;\r
case CLONE:\r
- item.add(WicketUtils.newImage("restrictedAccessIcon", "lock_pull_16x16.png", getString("gb.cloneRestricted")));\r
+ item.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
break;\r
case VIEW:\r
- item.add(WicketUtils.newImage("restrictedAccessIcon", "shield_16x16.png", getString("gb.viewRestricted")));\r
+ item.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));\r
break;\r
default:\r
- item.add(WicketUtils.newBlankImage("restrictedAccessIcon"));\r
+ item.add(WicketUtils.newBlankImage("accessRestrictionIcon"));\r
}\r
\r
item.add(new Label("repositoryOwner", entry.owner));\r
<tr><th><wicket:message key="gb.owner">[owner]</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>\r
<tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>\r
<tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="repositoryStats">[repository stats]</span></td></tr>\r
- <tr><th><wicket:message key="gb.url">[URL]</wicket:message></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>\r
+ <tr><th><wicket:message key="gb.url">[URL]</wicket:message></th><td><img style="vertical-align: top; padding-right:5px;" wicket:id="accessRestrictionIcon" /><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>\r
</table>\r
</div>\r
</div>\r
import org.wicketstuff.googlecharts.MarkerType;\r
import org.wicketstuff.googlecharts.ShapeMarker;\r
\r
+import com.gitblit.Constants.AccessRestrictionType;\r
import com.gitblit.GitBlit;\r
import com.gitblit.Keys;\r
import com.gitblit.utils.JGitUtils;\r
} else {\r
add(new Label("repositoryStats", MessageFormat.format("{0} commits and {1} tags in {2}", metricsTotal.count, metricsTotal.tag, TimeUtils.duration(metricsTotal.duration))));\r
}\r
+ \r
+ AccessRestrictionType accessRestriction = getRepositoryModel().accessRestriction;\r
+ switch (accessRestriction) {\r
+ case NONE:\r
+ add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));\r
+ break;\r
+ case PUSH:\r
+ add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", getAccessRestrictions().get(accessRestriction)));\r
+ break;\r
+ case CLONE:\r
+ add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", getAccessRestrictions().get(accessRestriction)));\r
+ break;\r
+ case VIEW:\r
+ add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", getAccessRestrictions().get(accessRestriction)));\r
+ break;\r
+ default:\r
+ add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));\r
+ }\r
add(new Label("repositoryCloneUrl", GitBlit.self().getCloneUrl(repositoryName)));\r
\r
add(new LogPanel("commitsPanel", repositoryName, null, r, numberCommits, 0));\r
-#Wed May 11 21:30:28 EDT 2011\r
+# Git:Blit realm file format: username=password,\#permission,repository1,repository2...\r
admin=admin,\#admin\r
-test=test\r