summaryrefslogtreecommitdiffstats
path: root/src/com/gitblit
diff options
context:
space:
mode:
authorRafael Cavazin <rafaelcavazin@gmail.com>2012-12-06 14:25:01 -0200
committerRafael Cavazin <rafaelcavazin@gmail.com>2012-12-06 14:25:01 -0200
commitd4b95298902c8cea1411fc696ed80028b6091aa7 (patch)
tree1ee58f481203ef60c030a3d0119784c37a8b7b3f /src/com/gitblit
parent6aea2fa8aee24114bc59b09bc3c5b68fcd948790 (diff)
parentdc9735acfc9dcea6b970d18a315cbf8a6997c4f9 (diff)
downloadgitblit-d4b95298902c8cea1411fc696ed80028b6091aa7.tar.gz
gitblit-d4b95298902c8cea1411fc696ed80028b6091aa7.zip
Update from upstream/master
Merge remote-tracking branch 'upstream/master' into translation_to_pt-br
Diffstat (limited to 'src/com/gitblit')
-rw-r--r--src/com/gitblit/AuthenticationFilter.java43
-rw-r--r--src/com/gitblit/Constants.java2
-rw-r--r--src/com/gitblit/GitBlit.java117
-rw-r--r--src/com/gitblit/GitBlitServer.java44
-rw-r--r--src/com/gitblit/GitblitSslContextFactory.java94
-rw-r--r--src/com/gitblit/GitblitTrustManager.java125
-rw-r--r--src/com/gitblit/authority/GitblitAuthority.java55
-rw-r--r--src/com/gitblit/authority/NewSSLCertificateDialog.java12
-rw-r--r--src/com/gitblit/build/Build.java20
-rw-r--r--src/com/gitblit/client/EditRepositoryDialog.java9
-rw-r--r--src/com/gitblit/client/EditUserDialog.java39
-rw-r--r--src/com/gitblit/models/PathModel.java4
-rw-r--r--src/com/gitblit/models/RepositoryModel.java1
-rw-r--r--src/com/gitblit/models/UserModel.java2
-rw-r--r--src/com/gitblit/utils/ActivityUtils.java6
-rw-r--r--src/com/gitblit/utils/CompressionUtils.java100
-rw-r--r--src/com/gitblit/utils/HttpUtils.java23
-rw-r--r--src/com/gitblit/utils/X509Utils.java12
-rw-r--r--src/com/gitblit/wicket/GitBlitWebApp.properties11
-rw-r--r--src/com/gitblit/wicket/pages/CommitPage.java10
-rw-r--r--src/com/gitblit/wicket/pages/EditRepositoryPage.html15
-rw-r--r--src/com/gitblit/wicket/pages/EditRepositoryPage.java27
-rw-r--r--src/com/gitblit/wicket/pages/EditTeamPage.java3
-rw-r--r--src/com/gitblit/wicket/pages/EditUserPage.html14
-rw-r--r--src/com/gitblit/wicket/pages/EditUserPage.java7
-rw-r--r--src/com/gitblit/wicket/pages/RepositoryPage.java8
-rw-r--r--src/com/gitblit/wicket/pages/TreePage.java18
27 files changed, 627 insertions, 194 deletions
diff --git a/src/com/gitblit/AuthenticationFilter.java b/src/com/gitblit/AuthenticationFilter.java
index 64aa4411..eb6e95b7 100644
--- a/src/com/gitblit/AuthenticationFilter.java
+++ b/src/com/gitblit/AuthenticationFilter.java
@@ -16,9 +16,7 @@
package com.gitblit;
import java.io.IOException;
-import java.nio.charset.Charset;
import java.security.Principal;
-import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@@ -37,7 +35,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.models.UserModel;
-import com.gitblit.utils.Base64;
import com.gitblit.utils.StringUtils;
/**
@@ -51,9 +48,7 @@ import com.gitblit.utils.StringUtils;
*/
public abstract class AuthenticationFilter implements Filter {
- protected static final String BASIC = "Basic";
-
- protected static final String CHALLENGE = BASIC + " realm=\"" + Constants.NAME + "\"";
+ protected static final String CHALLENGE = "Basic realm=\"" + Constants.NAME + "\"";
protected static final String SESSION_SECURED = "com.gitblit.secured";
@@ -103,40 +98,8 @@ public abstract class AuthenticationFilter implements Filter {
* @return user
*/
protected UserModel getUser(HttpServletRequest httpRequest) {
- UserModel user = null;
- // try request authentication
- user = GitBlit.self().authenticate(httpRequest);
- if (user != null) {
- return user;
- } else if (requiresClientCertificate()) {
- // http request does not have a valid certificate
- // and the filter requires one
- return null;
- }
-
- // look for client authorization credentials in header
- final String authorization = httpRequest.getHeader("Authorization");
- if (authorization != null && authorization.startsWith(BASIC)) {
- // Authorization: Basic base64credentials
- String base64Credentials = authorization.substring(BASIC.length()).trim();
- String credentials = new String(Base64.decode(base64Credentials),
- Charset.forName("UTF-8"));
- // credentials = username:password
- final String[] values = credentials.split(":",2);
-
- if (values.length == 2) {
- String username = values[0];
- char[] password = values[1].toCharArray();
- user = GitBlit.self().authenticate(username, password);
- if (user != null) {
- return user;
- }
- }
- if (GitBlit.isDebugMode()) {
- logger.info(MessageFormat.format("AUTH: invalid credentials ({0})", credentials));
- }
- }
- return null;
+ UserModel user = GitBlit.self().authenticate(httpRequest, requiresClientCertificate());
+ return user;
}
/**
diff --git a/src/com/gitblit/Constants.java b/src/com/gitblit/Constants.java
index 4669c4c9..d152651b 100644
--- a/src/com/gitblit/Constants.java
+++ b/src/com/gitblit/Constants.java
@@ -399,7 +399,7 @@ public class Constants {
}
public static enum AuthenticationType {
- CREDENTIALS, COOKIE, CERTIFICATE;
+ CREDENTIALS, COOKIE, CERTIFICATE, CONTAINER;
public boolean isStandard() {
return ordinal() <= COOKIE.ordinal();
diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java
index 69135c49..c2d4a85a 100644
--- a/src/com/gitblit/GitBlit.java
+++ b/src/com/gitblit/GitBlit.java
@@ -24,6 +24,8 @@ import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.security.Principal;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -98,6 +100,7 @@ import com.gitblit.models.SettingModel;
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ArrayUtils;
+import com.gitblit.utils.Base64;
import com.gitblit.utils.ByteFormat;
import com.gitblit.utils.ContainerUtils;
import com.gitblit.utils.DeepCopier;
@@ -567,6 +570,20 @@ public class GitBlit implements ServletContextListener {
* @return a user object or null
*/
public UserModel authenticate(HttpServletRequest httpRequest) {
+ return authenticate(httpRequest, false);
+ }
+
+ /**
+ * Authenticate a user based on HTTP request parameters.
+ *
+ * Authentication by X509Certificate, servlet container principal, cookie,
+ * and BASIC header.
+ *
+ * @param httpRequest
+ * @param requiresCertificate
+ * @return a user object or null
+ */
+ public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
// try to authenticate by certificate
boolean checkValidity = settings.getBoolean(Keys.git.enforceCertificateValidity, true);
String [] oids = getStrings(Keys.git.certificateUsernameOIDs).toArray(new String[0]);
@@ -574,39 +591,85 @@ public class GitBlit implements ServletContextListener {
if (model != null) {
// grab real user model and preserve certificate serial number
UserModel user = getUserModel(model.username);
+ X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest);
if (user != null) {
- RequestCycle requestCycle = RequestCycle.get();
- if (requestCycle != null) {
- // flag the Wicket session, if this is a Wicket request
- GitBlitWebSession session = GitBlitWebSession.get();
- session.authenticationType = AuthenticationType.CERTIFICATE;
- }
- X509Metadata metadata = HttpUtils.getCertificateMetadata(httpRequest);
+ flagWicketSession(AuthenticationType.CERTIFICATE);
logger.info(MessageFormat.format("{0} authenticated by client certificate {1} from {2}",
user.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
return user;
+ } else {
+ logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted client certificate ({1}) authentication from {2}",
+ model.username, metadata.serialNumber, httpRequest.getRemoteAddr()));
+ }
+ }
+
+ if (requiresCertificate) {
+ // caller requires client certificate authentication (e.g. git servlet)
+ return null;
+ }
+
+ // try to authenticate by servlet container principal
+ Principal principal = httpRequest.getUserPrincipal();
+ if (principal != null) {
+ UserModel user = getUserModel(principal.getName());
+ if (user != null) {
+ flagWicketSession(AuthenticationType.CONTAINER);
+ logger.info(MessageFormat.format("{0} authenticated by servlet container principal from {1}",
+ user.username, httpRequest.getRemoteAddr()));
+ return user;
+ } else {
+ logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted servlet container authentication from {1}",
+ principal.getName(), httpRequest.getRemoteAddr()));
}
}
// try to authenticate by cookie
- Cookie[] cookies = httpRequest.getCookies();
- if (allowCookieAuthentication() && cookies != null && cookies.length > 0) {
- // Grab cookie from Browser Session
- UserModel user = authenticate(cookies);
+ if (allowCookieAuthentication()) {
+ UserModel user = authenticate(httpRequest.getCookies());
if (user != null) {
- RequestCycle requestCycle = RequestCycle.get();
- if (requestCycle != null) {
- // flag the Wicket session, if this is a Wicket request
- GitBlitWebSession session = GitBlitWebSession.get();
- session.authenticationType = AuthenticationType.COOKIE;
- }
+ flagWicketSession(AuthenticationType.COOKIE);
logger.info(MessageFormat.format("{0} authenticated by cookie from {1}",
user.username, httpRequest.getRemoteAddr()));
return user;
}
}
+
+ // try to authenticate by BASIC
+ final String authorization = httpRequest.getHeader("Authorization");
+ if (authorization != null && authorization.startsWith("Basic")) {
+ // Authorization: Basic base64credentials
+ String base64Credentials = authorization.substring("Basic".length()).trim();
+ String credentials = new String(Base64.decode(base64Credentials),
+ Charset.forName("UTF-8"));
+ // credentials = username:password
+ final String[] values = credentials.split(":",2);
+
+ if (values.length == 2) {
+ String username = values[0];
+ char[] password = values[1].toCharArray();
+ UserModel user = authenticate(username, password);
+ if (user != null) {
+ flagWicketSession(AuthenticationType.CREDENTIALS);
+ logger.info(MessageFormat.format("{0} authenticated by BASIC request header from {1}",
+ user.username, httpRequest.getRemoteAddr()));
+ return user;
+ } else {
+ logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials ({1}) from {2}",
+ username, credentials, httpRequest.getRemoteAddr()));
+ }
+ }
+ }
return null;
}
+
+ protected void flagWicketSession(AuthenticationType authenticationType) {
+ RequestCycle requestCycle = RequestCycle.get();
+ if (requestCycle != null) {
+ // flag the Wicket session, if this is a Wicket request
+ GitBlitWebSession session = GitBlitWebSession.get();
+ session.authenticationType = authenticationType;
+ }
+ }
/**
* Open a file resource using the Servlet container.
@@ -693,6 +756,9 @@ public class GitBlit implements ServletContextListener {
* @return true if successful
*/
public boolean deleteUser(String username) {
+ if (StringUtils.isEmpty(username)) {
+ return false;
+ }
return userService.deleteUser(username);
}
@@ -704,6 +770,9 @@ public class GitBlit implements ServletContextListener {
* @return a user object or null
*/
public UserModel getUserModel(String username) {
+ if (StringUtils.isEmpty(username)) {
+ return null;
+ }
UserModel user = userService.getUserModel(username);
return user;
}
@@ -1533,6 +1602,7 @@ public class GitBlit implements ServletContextListener {
} catch (Exception e) {
model.lastGC = new Date(0);
}
+ model.maxActivityCommits = getConfig(config, "maxActivityCommits", settings.getInteger(Keys.web.maxActivityCommits, 0));
model.origin = config.getString("remote", "origin", "url");
if (model.origin != null) {
model.origin = model.origin.replace('\\', '/');
@@ -1999,10 +2069,21 @@ public class GitBlit implements ServletContextListener {
repository.federationStrategy.name());
config.setBoolean(Constants.CONFIG_GITBLIT, null, "isFederated", repository.isFederated);
config.setString(Constants.CONFIG_GITBLIT, null, "gcThreshold", repository.gcThreshold);
- config.setInt(Constants.CONFIG_GITBLIT, null, "gcPeriod", repository.gcPeriod);
+ if (repository.gcPeriod == settings.getInteger(Keys.git.defaultGarbageCollectionPeriod, 7)) {
+ // use default from config
+ config.unset(Constants.CONFIG_GITBLIT, null, "gcPeriod");
+ } else {
+ config.setInt(Constants.CONFIG_GITBLIT, null, "gcPeriod", repository.gcPeriod);
+ }
if (repository.lastGC != null) {
config.setString(Constants.CONFIG_GITBLIT, null, "lastGC", new SimpleDateFormat(Constants.ISO8601).format(repository.lastGC));
}
+ if (repository.maxActivityCommits == settings.getInteger(Keys.web.maxActivityCommits, 0)) {
+ // use default from config
+ config.unset(Constants.CONFIG_GITBLIT, null, "maxActivityCommits");
+ } else {
+ config.setInt(Constants.CONFIG_GITBLIT, null, "maxActivityCommits", repository.maxActivityCommits);
+ }
updateList(config, "federationSets", repository.federationSets);
updateList(config, "preReceiveScript", repository.preReceiveScripts);
diff --git a/src/com/gitblit/GitBlitServer.java b/src/com/gitblit/GitBlitServer.java
index d98f8916..4c0e89f6 100644
--- a/src/com/gitblit/GitBlitServer.java
+++ b/src/com/gitblit/GitBlitServer.java
@@ -44,7 +44,6 @@ import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.ssl.SslConnector;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.server.ssl.SslSocketConnector;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jgit.storage.file.FileBasedConfig;
@@ -242,7 +241,7 @@ public class GitBlitServer {
});
if (serverKeyStore.exists()) {
- Connector secureConnector = createSSLConnector(serverKeyStore, serverTrustStore, params.storePassword,
+ Connector secureConnector = createSSLConnector(params.alias, serverKeyStore, serverTrustStore, params.storePassword,
caRevocationList, params.useNIO, params.securePort, params.requireClientCertificates);
String bindInterface = settings.getString(Keys.server.httpsBindInterface, null);
if (!StringUtils.isEmpty(bindInterface)) {
@@ -413,6 +412,7 @@ public class GitBlitServer {
* SSL renegotiation will be enabled if the JVM is 1.6.0_22 or later.
* oracle.com/technetwork/java/javase/documentation/tlsreadme2-176330.html
*
+ * @param certAlias
* @param keyStore
* @param clientTrustStore
* @param storePassword
@@ -422,52 +422,31 @@ public class GitBlitServer {
* @param requireClientCertificates
* @return an https connector
*/
- private static Connector createSSLConnector(File keyStore, File clientTrustStore,
+ private static Connector createSSLConnector(String certAlias, File keyStore, File clientTrustStore,
String storePassword, File caRevocationList, boolean useNIO, int port,
boolean requireClientCertificates) {
- SslContextFactory sslContext = new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH);
+ GitblitSslContextFactory factory = new GitblitSslContextFactory(certAlias,
+ keyStore, clientTrustStore, storePassword, caRevocationList);
SslConnector connector;
if (useNIO) {
logger.info("Setting up NIO SslSelectChannelConnector on port " + port);
- SslSelectChannelConnector ssl = new SslSelectChannelConnector(sslContext);
+ SslSelectChannelConnector ssl = new SslSelectChannelConnector(factory);
ssl.setSoLingerTime(-1);
if (requireClientCertificates) {
- sslContext.setNeedClientAuth(true);
+ factory.setNeedClientAuth(true);
} else {
- sslContext.setWantClientAuth(true);
+ factory.setWantClientAuth(true);
}
ssl.setThreadPool(new QueuedThreadPool(20));
connector = ssl;
} else {
logger.info("Setting up NIO SslSocketConnector on port " + port);
- SslSocketConnector ssl = new SslSocketConnector(sslContext);
+ SslSocketConnector ssl = new SslSocketConnector(factory);
connector = ssl;
}
- // disable renegotiation unless this is a patched JVM
- boolean allowRenegotiation = false;
- String v = System.getProperty("java.version");
- if (v.startsWith("1.7")) {
- allowRenegotiation = true;
- } else if (v.startsWith("1.6")) {
- // 1.6.0_22 was first release with RFC-5746 implemented fix.
- if (v.indexOf('_') > -1) {
- String b = v.substring(v.indexOf('_') + 1);
- if (Integer.parseInt(b) >= 22) {
- allowRenegotiation = true;
- }
- }
- }
- if (allowRenegotiation) {
- logger.info(" allowing SSL renegotiation on Java " + v);
- sslContext.setAllowRenegotiate(allowRenegotiation);
- }
- sslContext.setKeyStorePath(keyStore.getAbsolutePath());
- sslContext.setKeyStorePassword(storePassword);
- sslContext.setTrustStore(clientTrustStore.getAbsolutePath());
- sslContext.setTrustStorePassword(storePassword);
- sslContext.setCrlPath(caRevocationList.getAbsolutePath());
connector.setPort(port);
connector.setMaxIdleTime(30000);
+
return connector;
}
@@ -596,6 +575,9 @@ public class GitBlitServer {
@Parameter(names = "--ajpPort", description = "AJP port to serve. (port <= 0 will disable this connector)")
public Integer ajpPort = FILESETTINGS.getInteger(Keys.server.ajpPort, 0);
+ @Parameter(names = "--alias", description = "Alias of SSL certificate in keystore for serving https.")
+ public String alias = FILESETTINGS.getString(Keys.server.certificateAlias, "");
+
@Parameter(names = "--storePassword", description = "Password for SSL (https) keystore.")
public String storePassword = FILESETTINGS.getString(Keys.server.storePassword, "");
diff --git a/src/com/gitblit/GitblitSslContextFactory.java b/src/com/gitblit/GitblitSslContextFactory.java
new file mode 100644
index 00000000..f025c452
--- /dev/null
+++ b/src/com/gitblit/GitblitSslContextFactory.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 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;
+
+import java.io.File;
+import java.security.KeyStore;
+import java.security.cert.CRL;
+import java.util.Collection;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.gitblit.utils.StringUtils;
+
+/**
+ * Special SSL context factory that configures Gitblit GO and replaces the
+ * primary trustmanager with a GitblitTrustManager.
+ *
+ * @author James Moger
+ */
+public class GitblitSslContextFactory extends SslContextFactory {
+
+ private static final Logger logger = LoggerFactory.getLogger(GitblitSslContextFactory.class);
+
+ private final File caRevocationList;
+
+ public GitblitSslContextFactory(String certAlias, File keyStore, File clientTrustStore,
+ String storePassword, File caRevocationList) {
+ super(keyStore.getAbsolutePath());
+
+ this.caRevocationList = caRevocationList;
+
+ // disable renegotiation unless this is a patched JVM
+ boolean allowRenegotiation = false;
+ String v = System.getProperty("java.version");
+ if (v.startsWith("1.7")) {
+ allowRenegotiation = true;
+ } else if (v.startsWith("1.6")) {
+ // 1.6.0_22 was first release with RFC-5746 implemented fix.
+ if (v.indexOf('_') > -1) {
+ String b = v.substring(v.indexOf('_') + 1);
+ if (Integer.parseInt(b) >= 22) {
+ allowRenegotiation = true;
+ }
+ }
+ }
+ if (allowRenegotiation) {
+ logger.info(" allowing SSL renegotiation on Java " + v);
+ setAllowRenegotiate(allowRenegotiation);
+ }
+
+
+ if (!StringUtils.isEmpty(certAlias)) {
+ logger.info(" certificate alias = " + certAlias);
+ setCertAlias(certAlias);
+ }
+ setKeyStorePassword(storePassword);
+ setTrustStore(clientTrustStore.getAbsolutePath());
+ setTrustStorePassword(storePassword);
+
+ logger.info(" keyStorePath = " + keyStore.getAbsolutePath());
+ logger.info(" trustStorePath = " + clientTrustStore.getAbsolutePath());
+ logger.info(" crlPath = " + caRevocationList.getAbsolutePath());
+ }
+
+ @Override
+ protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls)
+ throws Exception {
+ TrustManager[] managers = super.getTrustManagers(trustStore, crls);
+ X509TrustManager delegate = (X509TrustManager) managers[0];
+ GitblitTrustManager root = new GitblitTrustManager(delegate, caRevocationList);
+
+ // replace first manager with the GitblitTrustManager
+ managers[0] = root;
+ return managers;
+ }
+}
diff --git a/src/com/gitblit/GitblitTrustManager.java b/src/com/gitblit/GitblitTrustManager.java
new file mode 100644
index 00000000..4127caf4
--- /dev/null
+++ b/src/com/gitblit/GitblitTrustManager.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.text.MessageFormat;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.net.ssl.X509TrustManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * GitblitTrustManager is a wrapper trust manager that hot-reloads a local file
+ * CRL and enforces client certificate revocations. The GitblitTrustManager
+ * also implements fuzzy revocation enforcement in case of issuer mismatch BUT
+ * serial number match. These rejecions are specially noted in the log.
+ *
+ * @author James Moger
+ */
+public class GitblitTrustManager implements X509TrustManager {
+
+ private static final Logger logger = LoggerFactory.getLogger(GitblitTrustManager.class);
+
+ private final X509TrustManager delegate;
+ private final File caRevocationList;
+
+ private final AtomicLong lastModified = new AtomicLong(0);
+ private volatile X509CRL crl;
+
+ public GitblitTrustManager(X509TrustManager delegate, File crlFile) {
+ this.delegate = delegate;
+ this.caRevocationList = crlFile;
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ X509Certificate cert = chain[0];
+ if (isRevoked(cert)) {
+ String message = MessageFormat.format("Rejecting revoked certificate {0,number,0} for {1}",
+ cert.getSerialNumber(), cert.getSubjectDN().getName());
+ logger.warn(message);
+ throw new CertificateException(message);
+ }
+ delegate.checkClientTrusted(chain, authType);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ delegate.checkServerTrusted(chain, authType);
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return delegate.getAcceptedIssuers();
+ }
+
+ protected boolean isRevoked(X509Certificate cert) {
+ if (!caRevocationList.exists()) {
+ return false;
+ }
+ read();
+
+ if (crl.isRevoked(cert)) {
+ // exact cert is revoked
+ return true;
+ }
+
+ X509CRLEntry entry = crl.getRevokedCertificate(cert.getSerialNumber());
+ if (entry != null) {
+ logger.warn("Certificate issuer does not match CRL issuer, but serial number has been revoked!");
+ logger.warn(" cert issuer = " + cert.getIssuerX500Principal());
+ logger.warn(" crl issuer = " + crl.getIssuerX500Principal());
+ return true;
+ }
+
+ return false;
+ }
+
+ protected synchronized void read() {
+ if (lastModified.get() == caRevocationList.lastModified()) {
+ return;
+ }
+ logger.info("Reloading CRL from " + caRevocationList.getAbsolutePath());
+ InputStream inStream = null;
+ try {
+ inStream = new FileInputStream(caRevocationList);
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ X509CRL list = (X509CRL)cf.generateCRL(inStream);
+ crl = list;
+ lastModified.set(caRevocationList.lastModified());
+ } catch (Exception e) {
+ } finally {
+ if (inStream != null) {
+ try {
+ inStream.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/gitblit/authority/GitblitAuthority.java b/src/com/gitblit/authority/GitblitAuthority.java
index d97a8e39..909831fe 100644
--- a/src/com/gitblit/authority/GitblitAuthority.java
+++ b/src/com/gitblit/authority/GitblitAuthority.java
@@ -21,6 +21,7 @@ import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
+import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
@@ -69,6 +70,7 @@ import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
+import javax.swing.JToolBar;
import javax.swing.RowFilter;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
@@ -565,15 +567,26 @@ public class GitblitAuthority extends JFrame implements X509Log {
}
};
- JTextField durationTF = new JTextField(4);
- durationTF.setInputVerifier(verifier);
- durationTF.setVerifyInputWhenFocusTarget(true);
- durationTF.setText("" + certificateConfig.duration);
- JPanel durationPanel = Utils.newFieldPanel(Translation.get("gb.duration"), durationTF, Translation.get("gb.duration.days").replace("{0}", "").trim());
+ JTextField siteNameTF = new JTextField(20);
+ siteNameTF.setText(gitblitSettings.getString(Keys.web.siteName, "Gitblit"));
+ JPanel siteNamePanel = Utils.newFieldPanel(Translation.get("gb.siteName"),
+ siteNameTF, Translation.get("gb.siteNameDescription"));
+
+ JTextField validityTF = new JTextField(4);
+ validityTF.setInputVerifier(verifier);
+ validityTF.setVerifyInputWhenFocusTarget(true);
+ validityTF.setText("" + certificateConfig.duration);
+ JPanel validityPanel = Utils.newFieldPanel(Translation.get("gb.validity"),
+ validityTF, Translation.get("gb.duration.days").replace("{0}", "").trim());
+
+ JPanel p1 = new JPanel(new GridLayout(0, 1, 5, 2));
+ p1.add(siteNamePanel);
+ p1.add(validityPanel);
+
DefaultOidsPanel oids = new DefaultOidsPanel(metadata);
JPanel panel = new JPanel(new BorderLayout());
- panel.add(durationPanel, BorderLayout.NORTH);
+ panel.add(p1, BorderLayout.NORTH);
panel.add(oids, BorderLayout.CENTER);
int result = JOptionPane.showConfirmDialog(GitblitAuthority.this,
@@ -582,9 +595,13 @@ public class GitblitAuthority extends JFrame implements X509Log {
if (result == JOptionPane.OK_OPTION) {
try {
oids.update(metadata);
- certificateConfig.duration = Integer.parseInt(durationTF.getText());
+ certificateConfig.duration = Integer.parseInt(validityTF.getText());
certificateConfig.store(config, metadata);
config.save();
+
+ Map<String, String> updates = new HashMap<String, String>();
+ updates.put(Keys.web.siteName, siteNameTF.getText());
+ gitblitSettings.saveSettings(updates);
} catch (Exception e1) {
Utils.showException(GitblitAuthority.this, e1);
}
@@ -607,7 +624,8 @@ public class GitblitAuthority extends JFrame implements X509Log {
}
final Date expires = dialog.getExpiration();
final String hostname = dialog.getHostname();
-
+ final boolean serveCertificate = dialog.isServeCertificate();
+
AuthorityWorker worker = new AuthorityWorker(GitblitAuthority.this) {
@Override
@@ -623,17 +641,31 @@ public class GitblitAuthority extends JFrame implements X509Log {
// generate new SSL certificate
X509Metadata metadata = new X509Metadata(hostname, caKeystorePassword);
+ setMetadataDefaults(metadata);
metadata.notAfter = expires;
File serverKeystoreFile = new File(folder, X509Utils.SERVER_KEY_STORE);
X509Certificate cert = X509Utils.newSSLCertificate(metadata, caPrivateKey, caCert, serverKeystoreFile, GitblitAuthority.this);
- return cert != null;
+ boolean hasCert = cert != null;
+ if (hasCert && serveCertificate) {
+ // update Gitblit https connector alias
+ Map<String, String> updates = new HashMap<String, String>();
+ updates.put(Keys.server.certificateAlias, metadata.commonName);
+ gitblitSettings.saveSettings(updates);
+ }
+ return hasCert;
}
@Override
protected void onSuccess() {
- JOptionPane.showMessageDialog(GitblitAuthority.this,
+ if (serveCertificate) {
+ JOptionPane.showMessageDialog(GitblitAuthority.this,
+ MessageFormat.format(Translation.get("gb.sslCertificateGeneratedRestart"), hostname),
+ Translation.get("gb.newSSLCertificate"), JOptionPane.INFORMATION_MESSAGE);
+ } else {
+ JOptionPane.showMessageDialog(GitblitAuthority.this,
MessageFormat.format(Translation.get("gb.sslCertificateGenerated"), hostname),
Translation.get("gb.newSSLCertificate"), JOptionPane.INFORMATION_MESSAGE);
+ }
}
};
@@ -713,7 +745,8 @@ public class GitblitAuthority extends JFrame implements X509Log {
}
});
- JPanel buttonControls = new JPanel(new FlowLayout(FlowLayout.LEFT, Utils.MARGIN, Utils.MARGIN));
+ JToolBar buttonControls = new JToolBar(JToolBar.HORIZONTAL);
+ buttonControls.setFloatable(false);
buttonControls.add(certificateDefaultsButton);
buttonControls.add(newSSLCertificate);
buttonControls.add(emailBundle);
diff --git a/src/com/gitblit/authority/NewSSLCertificateDialog.java b/src/com/gitblit/authority/NewSSLCertificateDialog.java
index 1ff542a2..821e9e9f 100644
--- a/src/com/gitblit/authority/NewSSLCertificateDialog.java
+++ b/src/com/gitblit/authority/NewSSLCertificateDialog.java
@@ -24,6 +24,7 @@ import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.JButton;
+import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
@@ -41,6 +42,7 @@ public class NewSSLCertificateDialog extends JDialog {
JDateChooser expirationDate;
JTextField hostname;
+ JCheckBox serveCertificate;
boolean isCanceled = true;
public NewSSLCertificateDialog(Frame owner, Date defaultExpiration) {
@@ -60,6 +62,7 @@ public class NewSSLCertificateDialog extends JDialog {
expirationDate = new JDateChooser(defaultExpiration);
hostname = new JTextField(20);
+ serveCertificate = new JCheckBox(Translation.get("gb.serveCertificate"), true);
JPanel panel = new JPanel(new GridLayout(0, 2, Utils.MARGIN, Utils.MARGIN));
@@ -69,6 +72,9 @@ public class NewSSLCertificateDialog extends JDialog {
panel.add(new JLabel(Translation.get("gb.expires")));
panel.add(expirationDate);
+ panel.add(new JLabel(""));
+ panel.add(serveCertificate);
+
JButton ok = new JButton(Translation.get("gb.ok"));
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
@@ -123,7 +129,11 @@ public class NewSSLCertificateDialog extends JDialog {
public Date getExpiration() {
return expirationDate.getDate();
}
-
+
+ public boolean isServeCertificate() {
+ return serveCertificate.isSelected();
+ }
+
public boolean isCanceled() {
return isCanceled;
}
diff --git a/src/com/gitblit/build/Build.java b/src/com/gitblit/build/Build.java
index e8e6b45d..19d80e78 100644
--- a/src/com/gitblit/build/Build.java
+++ b/src/com/gitblit/build/Build.java
@@ -565,17 +565,17 @@ public class Build {
"c7adc475ca40c288c93054e0f4fe58f3a98c0cb5");
public static final MavenObject JETTY = new MavenObject(
- "Jetty", "org/eclipse/jetty/aggregate", "jetty-webapp", "7.6.7.v20120910",
+ "Jetty", "org/eclipse/jetty/aggregate", "jetty-webapp", "7.6.8.v20121106",
1000000, 680000, 2720000,
- "d621fa6419aaa37edbcab8e16a5e6b05c9527e62",
- "b505f7b493c5aa262d371d90754bded8b392ffb0",
+ "6333969b4d509c4b681e05302ca7ebccb9c3efb5",
+ "354f2752ed6544296bc0fc92e533d68a5b03045b",
"");
public static final MavenObject JETTY_AJP = new MavenObject(
- "Jetty-AJP", "org/eclipse/jetty", "jetty-ajp", "7.6.7.v20120910",
+ "Jetty-AJP", "org/eclipse/jetty", "jetty-ajp", "7.6.8.v20121106",
32000, 22000, 97000,
- "578d502bc78ed7aa1c0b6afef4cd59477041ec37",
- "6cfed9a1354f720fcde12ec15d5e1ae9cf97000c",
+ "95bd1c89bb2afd4eeaabc6f4b0183a9f26a522d7",
+ "e1fc2539202ebb240a87a080bc44a24c93d7318b",
"");
public static final MavenObject SERVLET = new MavenObject(
@@ -647,10 +647,10 @@ public class Build {
"");
public static final MavenObject MARKDOWNPAPERS = new MavenObject(
- "MarkdownPapers", "org/tautua/markdownpapers", "markdownpapers-core", "1.2.7",
- 87000, 58000, 268000,
- "84ac5636ac7ddfad9d2ee8456a0f4f69709b6ee0",
- "453cf00a289c46a0e4f6f019a28d2a2605f652c8",
+ "MarkdownPapers", "org/tautua/markdownpapers", "markdownpapers-core", "1.3.2",
+ 92000, 60000, 268000,
+ "da22db6660e90b9a677bbdfc2c511c619ea5c249",
+ "6a7228280a229144afe6c01351a8f44675d8524d",
"");
public static final MavenObject BOUNCYCASTLE = new MavenObject(
diff --git a/src/com/gitblit/client/EditRepositoryDialog.java b/src/com/gitblit/client/EditRepositoryDialog.java
index a9274964..aa6ad58d 100644
--- a/src/com/gitblit/client/EditRepositoryDialog.java
+++ b/src/com/gitblit/client/EditRepositoryDialog.java
@@ -124,6 +124,8 @@ public class EditRepositoryDialog extends JDialog {
private JComboBox gcPeriod;
private JTextField gcThreshold;
+
+ private JComboBox maxActivityCommits;
private RegistrantPermissionsPanel usersPalette;
@@ -225,6 +227,10 @@ public class EditRepositoryDialog extends JDialog {
isFrozen = new JCheckBox(Translation.get("gb.isFrozenDescription"),
anRepository.isFrozen);
+ maxActivityCommits = new JComboBox(new Integer [] { 0, 25, 50, 75, 100, 150, 250, 500 });
+ maxActivityCommits.setSelectedItem(anRepository.maxActivityCommits);
+
+
mailingListsField = new JTextField(
ArrayUtils.isEmpty(anRepository.mailingLists) ? ""
: StringUtils.flattenStrings(anRepository.mailingLists,
@@ -314,6 +320,8 @@ public class EditRepositoryDialog extends JDialog {
skipSizeCalculation));
fieldsPanel.add(newFieldPanel(Translation.get("gb.skipSummaryMetrics"),
skipSummaryMetrics));
+ fieldsPanel.add(newFieldPanel(Translation.get("gb.maxActivityCommits"),
+ maxActivityCommits));
fieldsPanel.add(newFieldPanel(Translation.get("gb.mailingLists"),
mailingListsField));
@@ -561,6 +569,7 @@ public class EditRepositoryDialog extends JDialog {
repository.showReadme = showReadme.isSelected();
repository.skipSizeCalculation = skipSizeCalculation.isSelected();
repository.skipSummaryMetrics = skipSummaryMetrics.isSelected();
+ repository.maxActivityCommits = (Integer) maxActivityCommits.getSelectedItem();
repository.isFrozen = isFrozen.isSelected();
repository.allowForks = allowForks.isSelected();
diff --git a/src/com/gitblit/client/EditUserDialog.java b/src/com/gitblit/client/EditUserDialog.java
index e954fed6..0400f5c9 100644
--- a/src/com/gitblit/client/EditUserDialog.java
+++ b/src/com/gitblit/client/EditUserDialog.java
@@ -90,7 +90,17 @@ public class EditUserDialog extends JDialog {
private JCheckBox canCreateCheckbox;
private JCheckBox notFederatedCheckbox;
+
+ private JTextField organizationalUnitField;
+
+ private JTextField organizationField;
+ private JTextField localityField;
+
+ private JTextField stateProvinceField;
+
+ private JTextField countryCodeField;
+
private RegistrantPermissionsPanel repositoryPalette;
private JPalette<TeamModel> teamsPalette;
@@ -142,6 +152,12 @@ public class EditUserDialog extends JDialog {
Translation.get("gb.excludeFromFederationDescription"),
anUser.excludeFromFederation);
+ organizationalUnitField = new JTextField(anUser.organizationalUnit == null ? "" : anUser.organizationalUnit, 25);
+ organizationField = new JTextField(anUser.organization == null ? "" : anUser.organization, 25);
+ localityField = new JTextField(anUser.locality == null ? "" : anUser.locality, 25);
+ stateProvinceField = new JTextField(anUser.stateProvince == null ? "" : anUser.stateProvince, 25);
+ countryCodeField = new JTextField(anUser.countryCode == null ? "" : anUser.countryCode, 15);
+
// credentials are optionally controlled by 3rd-party authentication
usernameField.setEnabled(settings.supportsCredentialChanges);
passwordField.setEnabled(settings.supportsCredentialChanges);
@@ -149,6 +165,12 @@ public class EditUserDialog extends JDialog {
displayNameField.setEnabled(settings.supportsDisplayNameChanges);
emailAddressField.setEnabled(settings.supportsEmailAddressChanges);
+
+ organizationalUnitField.setEnabled(settings.supportsDisplayNameChanges);
+ organizationField.setEnabled(settings.supportsDisplayNameChanges);
+ localityField.setEnabled(settings.supportsDisplayNameChanges);
+ stateProvinceField.setEnabled(settings.supportsDisplayNameChanges);
+ countryCodeField.setEnabled(settings.supportsDisplayNameChanges);
JPanel fieldsPanel = new JPanel(new GridLayout(0, 1));
fieldsPanel.add(newFieldPanel(Translation.get("gb.username"), usernameField));
@@ -162,6 +184,13 @@ public class EditUserDialog extends JDialog {
fieldsPanel.add(newFieldPanel(Translation.get("gb.excludeFromFederation"),
notFederatedCheckbox));
+ JPanel attributesPanel = new JPanel(new GridLayout(0, 1, 5, 2));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.organizationalUnit") + " (OU)", organizationalUnitField));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.organization") + " (O)", organizationField));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.locality") + " (L)", localityField));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.stateProvince") + " (ST)", stateProvinceField));
+ attributesPanel.add(newFieldPanel(Translation.get("gb.countryCode") + " (C)", countryCodeField));
+
final Insets _insets = new Insets(5, 5, 5, 5);
repositoryPalette = new RegistrantPermissionsPanel(RegistrantType.REPOSITORY);
teamsPalette = new JPalette<TeamModel>();
@@ -170,6 +199,9 @@ public class EditUserDialog extends JDialog {
JPanel fieldsPanelTop = new JPanel(new BorderLayout());
fieldsPanelTop.add(fieldsPanel, BorderLayout.NORTH);
+ JPanel attributesPanelTop = new JPanel(new BorderLayout());
+ attributesPanelTop.add(attributesPanel, BorderLayout.NORTH);
+
JPanel repositoriesPanel = new JPanel(new BorderLayout()) {
private static final long serialVersionUID = 1L;
@@ -192,6 +224,7 @@ public class EditUserDialog extends JDialog {
JTabbedPane panel = new JTabbedPane(JTabbedPane.TOP);
panel.addTab(Translation.get("gb.general"), fieldsPanelTop);
+ panel.addTab(Translation.get("gb.attributes"), attributesPanelTop);
if (protocolVersion > 1) {
panel.addTab(Translation.get("gb.teamMemberships"), teamsPanel);
}
@@ -324,6 +357,12 @@ public class EditUserDialog extends JDialog {
user.canCreate = canCreateCheckbox.isSelected();
user.excludeFromFederation = notFederatedCheckbox.isSelected();
+ user.organizationalUnit = organizationalUnitField.getText().trim();
+ user.organization = organizationField.getText().trim();
+ user.locality = localityField.getText().trim();
+ user.stateProvince = stateProvinceField.getText().trim();
+ user.countryCode = countryCodeField.getText().trim();
+
for (RegistrantAccessPermission rp : repositoryPalette.getPermissions()) {
user.setRepositoryPermission(rp.registrant, rp.permission);
}
diff --git a/src/com/gitblit/models/PathModel.java b/src/com/gitblit/models/PathModel.java
index 8692359c..84571cbb 100644
--- a/src/com/gitblit/models/PathModel.java
+++ b/src/com/gitblit/models/PathModel.java
@@ -48,6 +48,10 @@ public class PathModel implements Serializable, Comparable<PathModel> {
this.commitId = commitId;
}
+ public boolean isSymlink() {
+ return FileMode.SYMLINK.equals(mode);
+ }
+
public boolean isSubmodule() {
return FileMode.GITLINK.equals(mode);
}
diff --git a/src/com/gitblit/models/RepositoryModel.java b/src/com/gitblit/models/RepositoryModel.java
index ed9e7188..5be33a2d 100644
--- a/src/com/gitblit/models/RepositoryModel.java
+++ b/src/com/gitblit/models/RepositoryModel.java
@@ -78,6 +78,7 @@ public class RepositoryModel implements Serializable, Comparable<RepositoryModel
public boolean verifyCommitter;
public String gcThreshold;
public int gcPeriod;
+ public int maxActivityCommits;
public transient boolean isCollectingGarbage;
public Date lastGC;
diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java
index bd40985f..f1bc5efc 100644
--- a/src/com/gitblit/models/UserModel.java
+++ b/src/com/gitblit/models/UserModel.java
@@ -589,7 +589,7 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel>
public boolean hasBranchPermission(String repositoryName, String branch) {
// Default UserModel doesn't implement branch-level security. Other Realms (i.e. Gerrit) may override this method.
- return hasRepositoryPermission(repositoryName);
+ return hasRepositoryPermission(repositoryName) || hasTeamRepositoryPermission(repositoryName);
}
public boolean isMyPersonalRepository(String repository) {
diff --git a/src/com/gitblit/utils/ActivityUtils.java b/src/com/gitblit/utils/ActivityUtils.java
index e389e642..80aaebbb 100644
--- a/src/com/gitblit/utils/ActivityUtils.java
+++ b/src/com/gitblit/utils/ActivityUtils.java
@@ -106,7 +106,11 @@ public class ActivityUtils {
}
List<RevCommit> commits = JGitUtils.getRevLog(repository,
branch, thresholdDate);
- for (RevCommit commit : commits) {
+ if (model.maxActivityCommits > 0 && commits.size() > model.maxActivityCommits) {
+ // trim commits to maximum count
+ commits = commits.subList(0, model.maxActivityCommits);
+ }
+ for (RevCommit commit : commits) {
Date date = JGitUtils.getCommitDate(commit);
String dateStr = df.format(date);
if (!activity.containsKey(dateStr)) {
diff --git a/src/com/gitblit/utils/CompressionUtils.java b/src/com/gitblit/utils/CompressionUtils.java
index 7b0d0471..a8dcdd8f 100644
--- a/src/com/gitblit/utils/CompressionUtils.java
+++ b/src/com/gitblit/utils/CompressionUtils.java
@@ -15,27 +15,25 @@
*/
package com.gitblit.utils;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
-import org.apache.commons.compress.utils.IOUtils;
+import org.apache.wicket.util.io.ByteArrayOutputStream;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
-import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
@@ -99,37 +97,35 @@ public class CompressionUtils {
RevWalk rw = new RevWalk(repository);
TreeWalk tw = new TreeWalk(repository);
try {
+ tw.reset();
tw.addTree(commit.getTree());
- ZipOutputStream zos = new ZipOutputStream(os);
+ ZipArchiveOutputStream zos = new ZipArchiveOutputStream(os);
zos.setComment("Generated by Gitblit");
if (!StringUtils.isEmpty(basePath)) {
PathFilter f = PathFilter.create(basePath);
tw.setFilter(f);
}
tw.setRecursive(true);
+ MutableObjectId id = new MutableObjectId();
+ ObjectReader reader = tw.getObjectReader();
+ long modified = commit.getAuthorIdent().getWhen().getTime();
while (tw.next()) {
- if (tw.getFileMode(0) == FileMode.GITLINK) {
+ FileMode mode = tw.getFileMode(0);
+ if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
continue;
}
- ZipEntry entry = new ZipEntry(tw.getPathString());
- entry.setSize(tw.getObjectReader().getObjectSize(tw.getObjectId(0),
- Constants.OBJ_BLOB));
- entry.setComment(commit.getName());
- zos.putNextEntry(entry);
+ tw.getObjectId(id, 0);
- ObjectId entid = tw.getObjectId(0);
- FileMode entmode = tw.getFileMode(0);
- RevBlob blob = (RevBlob) rw.lookupAny(entid, entmode.getObjectType());
- rw.parseBody(blob);
+ ZipArchiveEntry entry = new ZipArchiveEntry(tw.getPathString());
+ entry.setSize(reader.getObjectSize(id, Constants.OBJ_BLOB));
+ entry.setComment(commit.getName());
+ entry.setUnixMode(mode.getBits());
+ entry.setTime(modified);
+ zos.putArchiveEntry(entry);
- ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);
- byte[] tmp = new byte[4096];
- InputStream in = ldr.openStream();
- int n;
- while ((n = in.read(tmp)) > 0) {
- zos.write(tmp, 0, n);
- }
- in.close();
+ ObjectLoader ldr = repository.open(id);
+ ldr.copyTo(zos);
+ zos.closeArchiveEntry();
}
zos.finish();
success = true;
@@ -250,6 +246,7 @@ public class CompressionUtils {
RevWalk rw = new RevWalk(repository);
TreeWalk tw = new TreeWalk(repository);
try {
+ tw.reset();
tw.addTree(commit.getTree());
TarArchiveOutputStream tos = new TarArchiveOutputStream(cos);
tos.setAddPaxHeadersForNonAsciiNames(true);
@@ -259,46 +256,33 @@ public class CompressionUtils {
tw.setFilter(f);
}
tw.setRecursive(true);
+ MutableObjectId id = new MutableObjectId();
+ long modified = commit.getAuthorIdent().getWhen().getTime();
while (tw.next()) {
FileMode mode = tw.getFileMode(0);
- if (mode == FileMode.GITLINK) {
+ if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
continue;
}
- ObjectId id = tw.getObjectId(0);
-
- // new entry
- TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString());
- entry.setSize(tw.getObjectReader().getObjectSize(id, Constants.OBJ_BLOB));
+ tw.getObjectId(id, 0);
- if (FileMode.SYMLINK.equals(mode)) {
- // symlink
- entry.setMode(mode.getBits());
-
- // read the symlink target
- ByteArrayOutputStream bs = new ByteArrayOutputStream();
- RevBlob blob = (RevBlob) rw.lookupAny(id, mode.getObjectType());
- rw.parseBody(blob);
- ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);
- IOUtils.copy(ldr.openStream(), bs);
- entry.setLinkName(bs.toString("UTF-8"));
+ ObjectLoader loader = repository.open(id);
+ if (FileMode.SYMLINK == mode) {
+ TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString(),TarArchiveEntry.LF_SYMLINK);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ loader.copyTo(bos);
+ entry.setLinkName(bos.toString());
+ entry.setModTime(modified);
+ tos.putArchiveEntry(entry);
+ tos.closeArchiveEntry();
} else {
- // regular file or executable file
+ TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString());
entry.setMode(mode.getBits());
- }
- entry.setModTime(commit.getAuthorIdent().getWhen());
-
- tos.putArchiveEntry(entry);
-
- if (!FileMode.SYMLINK.equals(mode)) {
- // write the blob
- RevBlob blob = (RevBlob) rw.lookupAny(id, mode.getObjectType());
- rw.parseBody(blob);
- ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);
- IOUtils.copy(ldr.openStream(), tos);
+ entry.setModTime(modified);
+ entry.setSize(loader.getSize());
+ tos.putArchiveEntry(entry);
+ loader.copyTo(tos);
+ tos.closeArchiveEntry();
}
-
- // close entry
- tos.closeArchiveEntry();
}
tos.finish();
tos.close();
diff --git a/src/com/gitblit/utils/HttpUtils.java b/src/com/gitblit/utils/HttpUtils.java
index b40088c8..86f53cfe 100644
--- a/src/com/gitblit/utils/HttpUtils.java
+++ b/src/com/gitblit/utils/HttpUtils.java
@@ -178,4 +178,27 @@ public class HttpUtils {
}
return null;
}
+
+ public static boolean isIpAddress(String address) {
+ if (StringUtils.isEmpty(address)) {
+ return false;
+ }
+ String [] fields = address.split("\\.");
+ if (fields.length == 4) {
+ // IPV4
+ for (String field : fields) {
+ try {
+ int value = Integer.parseInt(field);
+ if (value < 0 || value > 255) {
+ return false;
+ }
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ return true;
+ }
+ // TODO IPV6?
+ return false;
+ }
}
diff --git a/src/com/gitblit/utils/X509Utils.java b/src/com/gitblit/utils/X509Utils.java
index cfad9ec0..237c8dad 100644
--- a/src/com/gitblit/utils/X509Utils.java
+++ b/src/com/gitblit/utils/X509Utils.java
@@ -46,11 +46,13 @@ import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
@@ -556,6 +558,16 @@ public class X509Utils {
certBuilder.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(false));
certBuilder.addExtension(X509Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCert.getPublicKey()));
+ // support alternateSubjectNames for SSL certificates
+ List<GeneralName> altNames = new ArrayList<GeneralName>();
+ if (HttpUtils.isIpAddress(sslMetadata.commonName)) {
+ altNames.add(new GeneralName(GeneralName.iPAddress, sslMetadata.commonName));
+ }
+ if (altNames.size() > 0) {
+ GeneralNames subjectAltName = new GeneralNames(altNames.toArray(new GeneralName [altNames.size()]));
+ certBuilder.addExtension(X509Extension.subjectAlternativeName, false, subjectAltName);
+ }
+
ContentSigner caSigner = new JcaContentSignerBuilder(SIGNING_ALGORITHM)
.setProvider(BC).build(caPrivateKey);
X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC)
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties
index 6ee12990..5b42a2c0 100644
--- a/src/com/gitblit/wicket/GitBlitWebApp.properties
+++ b/src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -430,4 +430,13 @@ gb.pleaseGenerateClientCertificate = Please generate a client certificate for {0
gb.clientCertificateBundleSent = Client certificate bundle for {0} sent
gb.enterKeystorePassword = Please enter the Gitblit keystore password
gb.warning = warning
-gb.jceWarning = Your Java Runtime Environment does not have the \"JCE Unlimited Strength Jurisdiction Policy\" files.\nThis will limit the length of passwords you may use to encrypt your keystores to 7 characters.\nThese policy files are an optional download from Oracle.\n\nWould you like to continue and generate the certificate infrastructure anyway?\n\nAnswering No will direct your browser to Oracle's download page so that you may download the policy files. \ No newline at end of file
+gb.jceWarning = Your Java Runtime Environment does not have the \"JCE Unlimited Strength Jurisdiction Policy\" files.\nThis will limit the length of passwords you may use to encrypt your keystores to 7 characters.\nThese policy files are an optional download from Oracle.\n\nWould you like to continue and generate the certificate infrastructure anyway?\n\nAnswering No will direct your browser to Oracle's download page so that you may download the policy files.
+gb.maxActivityCommits = max activity commits
+gb.maxActivityCommitsDescription = maximum number of commits to contribute to the Activity page
+gb.noMaximum = no maximum
+gb.attributes = attributes
+gb.serveCertificate = serve https with this certificate
+gb.sslCertificateGeneratedRestart = Successfully generated new server SSL certificate for {0}.\nYou must restart Gitblit to use the new certificate.\n\nIf you are launching with the '--alias' parameter you will have to set that to ''--alias {0}''.
+gb.validity = validity
+gb.siteName = site name
+gb.siteNameDescription = short, descriptive name of your server \ No newline at end of file
diff --git a/src/com/gitblit/wicket/pages/CommitPage.java b/src/com/gitblit/wicket/pages/CommitPage.java
index b2a8112b..17621ad0 100644
--- a/src/com/gitblit/wicket/pages/CommitPage.java
+++ b/src/com/gitblit/wicket/pages/CommitPage.java
@@ -169,9 +169,15 @@ public class CommitPage extends RepositoryPage {
WicketUtils.newPathParameter(submodulePath, submoduleId, "")).setEnabled(hasSubmodule));
} else {
// blob
- item.add(new LinkPanel("pathName", "list", entry.path, BlobPage.class,
+ String displayPath = entry.path;
+ String path = entry.path;
+ if (entry.isSymlink()) {
+ path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path);
+ displayPath = entry.path + " -> " + path;
+ }
+ item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
WicketUtils
- .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ .newPathParameter(repositoryName, entry.commitId, path)));
}
// quick links
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/com/gitblit/wicket/pages/EditRepositoryPage.html
index cd3c4662..60893f44 100644
--- a/src/com/gitblit/wicket/pages/EditRepositoryPage.html
+++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.html
@@ -39,8 +39,9 @@
<tr><th><wicket:message key="gb.showReadme"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="showReadme" tabindex="10" /> &nbsp;<span class="help-inline"><wicket:message key="gb.showReadmeDescription"></wicket:message></span></label></td></tr>
<tr><th><wicket:message key="gb.skipSizeCalculation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSizeCalculation" tabindex="11" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSizeCalculationDescription"></wicket:message></span></label></td></tr>
<tr><th><wicket:message key="gb.skipSummaryMetrics"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="skipSummaryMetrics" tabindex="12" /> &nbsp;<span class="help-inline"><wicket:message key="gb.skipSummaryMetricsDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.maxActivityCommits"></wicket:message></th><td class="edit"><select class="span2" wicket:id="maxActivityCommits" tabindex="13" /> &nbsp;<span class="help-inline"><wicket:message key="gb.maxActivityCommitsDescription"></wicket:message></span></td></tr>
<tr><th colspan="2"><hr/></th></tr>
- <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="13" /></td></tr>
+ <tr><th><wicket:message key="gb.mailingLists"></wicket:message></th><td class="edit"><input class="span8" type="text" wicket:id="mailingLists" size="40" tabindex="14" /></td></tr>
</tbody>
</table>
</div>
@@ -49,15 +50,15 @@
<div class="tab-pane" id="permissions">
<table class="plain">
<tbody class="settings">
- <tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><select class="span2" wicket:id="owner" tabindex="14" /> &nbsp;<span class="help-inline"><wicket:message key="gb.ownerDescription"></wicket:message></span></td></tr>
+ <tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><select class="span2" wicket:id="owner" tabindex="15" /> &nbsp;<span class="help-inline"><wicket:message key="gb.ownerDescription"></wicket:message></span></td></tr>
<tr><th colspan="2"><hr/></th></tr>
- <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="15" /></td></tr>
+ <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select class="span4" wicket:id="accessRestriction" tabindex="16" /></td></tr>
<tr><th colspan="2"><hr/></th></tr>
<tr><th><wicket:message key="gb.authorizationControl"></wicket:message></th><td style="padding:2px;"><span class="authorizationControl" wicket:id="authorizationControl"></span></td></tr>
<tr><th colspan="2"><hr/></th></tr>
- <tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="isFrozen" tabindex="18" /> &nbsp;<span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></label></td></tr>
- <tr><th><wicket:message key="gb.allowForks"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="allowForks" tabindex="19" /> &nbsp;<span class="help-inline"><wicket:message key="gb.allowForksDescription"></wicket:message></span></label></td></tr>
- <tr><th><wicket:message key="gb.verifyCommitter"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="verifyCommitter" tabindex="20" /> &nbsp;<span class="help-inline"><wicket:message key="gb.verifyCommitterDescription"></wicket:message></span><br/><span class="help-inline" style="padding-left:10px;"><wicket:message key="gb.verifyCommitterNote"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.isFrozen"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="isFrozen" tabindex="17" /> &nbsp;<span class="help-inline"><wicket:message key="gb.isFrozenDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.allowForks"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="allowForks" tabindex="18" /> &nbsp;<span class="help-inline"><wicket:message key="gb.allowForksDescription"></wicket:message></span></label></td></tr>
+ <tr><th><wicket:message key="gb.verifyCommitter"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="verifyCommitter" tabindex="19" /> &nbsp;<span class="help-inline"><wicket:message key="gb.verifyCommitterDescription"></wicket:message></span><br/><span class="help-inline" style="padding-left:10px;"><wicket:message key="gb.verifyCommitterNote"></wicket:message></span></label></td></tr>
<tr><th colspan="2"><hr/></th></tr>
<tr><th><wicket:message key="gb.userPermissions"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>
<tr><th colspan="2"><hr/></th></tr>
@@ -70,7 +71,7 @@
<div class="tab-pane" id="federation">
<table class="plain">
<tbody class="settings">
- <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="21" /></td></tr>
+ <tr><th><wicket:message key="gb.federationStrategy"></wicket:message></th><td class="edit"><select class="span4" wicket:id="federationStrategy" tabindex="20" /></td></tr>
<tr><th><wicket:message key="gb.federationSets"></wicket:message></th><td style="padding:2px;"><span wicket:id="federationSets"></span></td></tr>
</tbody>
</table>
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java
index dead34a9..7f66f688 100644
--- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java
+++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java
@@ -379,7 +379,7 @@ public class EditRepositoryPage extends RootSubPage {
form.add(new TextField<String>("description"));
form.add(new DropDownChoice<String>("owner", GitBlit.self().getAllUsernames())
.setEnabled(GitBlitWebSession.get().canAdmin() && !repositoryModel.isPersonalRepository()));
- form.add(new CheckBox("allowForks"));
+ form.add(new CheckBox("allowForks").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
DropDownChoice<AccessRestrictionType> accessRestriction = new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays
.asList(AccessRestrictionType.values()), new AccessRestrictionRenderer());
form.add(accessRestriction);
@@ -414,6 +414,9 @@ public class EditRepositoryPage extends RootSubPage {
form.add(new CheckBox("showReadme"));
form.add(new CheckBox("skipSizeCalculation"));
form.add(new CheckBox("skipSummaryMetrics"));
+ List<Integer> maxActivityCommits = Arrays.asList(0, 25, 50, 75, 100, 150, 200, 250, 500 );
+ form.add(new DropDownChoice<Integer>("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer()));
+
mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
: StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
form.add(new TextField<String>("mailingLists", mailingLists));
@@ -654,4 +657,26 @@ public class EditRepositoryPage extends RootSubPage {
}
}
+ private class MaxActivityCommitsRenderer implements IChoiceRenderer<Integer> {
+
+ private static final long serialVersionUID = 1L;
+
+ public MaxActivityCommitsRenderer() {
+ }
+
+ @Override
+ public String getDisplayValue(Integer value) {
+ if (value == 0) {
+ return getString("gb.noMaximum");
+ } else {
+ return value + " " + getString("gb.commits");
+ }
+ }
+
+ @Override
+ public String getIdValue(Integer value, int index) {
+ return Integer.toString(index);
+ }
+ }
+
}
diff --git a/src/com/gitblit/wicket/pages/EditTeamPage.java b/src/com/gitblit/wicket/pages/EditTeamPage.java
index a22361f1..1991c02a 100644
--- a/src/com/gitblit/wicket/pages/EditTeamPage.java
+++ b/src/com/gitblit/wicket/pages/EditTeamPage.java
@@ -38,6 +38,7 @@ import org.apache.wicket.model.util.ListModel;
import com.gitblit.GitBlit;
import com.gitblit.GitBlitException;
+import com.gitblit.Keys;
import com.gitblit.Constants.RegistrantType;
import com.gitblit.models.RegistrantAccessPermission;
import com.gitblit.models.TeamModel;
@@ -216,7 +217,7 @@ public class EditTeamPage extends RootSubPage {
// field names reflective match TeamModel fields
form.add(new TextField<String>("name"));
form.add(new CheckBox("canAdmin"));
- form.add(new CheckBox("canFork"));
+ form.add(new CheckBox("canFork").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
form.add(new CheckBox("canCreate"));
form.add(users.setEnabled(editMemberships));
mailingLists = new Model<String>(teamModel.mailingLists == null ? ""
diff --git a/src/com/gitblit/wicket/pages/EditUserPage.html b/src/com/gitblit/wicket/pages/EditUserPage.html
index e697a354..e79011c8 100644
--- a/src/com/gitblit/wicket/pages/EditUserPage.html
+++ b/src/com/gitblit/wicket/pages/EditUserPage.html
@@ -13,6 +13,7 @@
<!-- tab titles -->
<ul class="nav nav-tabs">
<li class="active"><a href="#general" data-toggle="tab"><wicket:message key="gb.general"></wicket:message></a></li>
+ <li><a href="#attributes" data-toggle="tab"><wicket:message key="gb.attributes"></wicket:message></a></li>
<li><a href="#permissions" data-toggle="tab"><wicket:message key="gb.accessPermissions"></wicket:message></a></li>
</ul>
@@ -36,6 +37,19 @@
</table>
</div>
+ <!-- attributes tab -->
+ <div class="tab-pane" id="attributes">
+ <table class="plain">
+ <tbody class="settings">
+ <tr><th><wicket:message key="gb.organizationalUnit"></wicket:message> (OU)</th><td class="edit"><input type="text" wicket:id="organizationalUnit" size="30" tabindex="1" /></td></tr>
+ <tr><th><wicket:message key="gb.organization"></wicket:message> (O)</th><td class="edit"><input type="text" wicket:id="organization" size="30" tabindex="2" /></td></tr>
+ <tr><th><wicket:message key="gb.locality"></wicket:message> (L)</th><td class="edit"><input type="text" wicket:id="locality" size="30" tabindex="3" /></td></tr>
+ <tr><th><wicket:message key="gb.stateProvince"></wicket:message> (ST)</th><td class="edit"><input type="text" wicket:id="stateProvince" size="30" tabindex="4" /></td></tr>
+ <tr><th><wicket:message key="gb.countryCode"></wicket:message> (C)</th><td class="edit"><input type="text" wicket:id="countryCode" size="15 " tabindex="5" /></td></tr>
+ </tbody>
+ </table>
+ </div>
+
<!-- access permissions tab -->
<div class="tab-pane" id="permissions">
<table class="plain">
diff --git a/src/com/gitblit/wicket/pages/EditUserPage.java b/src/com/gitblit/wicket/pages/EditUserPage.java
index 80f09dba..7a01fb68 100644
--- a/src/com/gitblit/wicket/pages/EditUserPage.java
+++ b/src/com/gitblit/wicket/pages/EditUserPage.java
@@ -233,12 +233,17 @@ public class EditUserPage extends RootSubPage {
form.add(new TextField<String>("displayName").setEnabled(editDisplayName));
form.add(new TextField<String>("emailAddress").setEnabled(editEmailAddress));
form.add(new CheckBox("canAdmin"));
- form.add(new CheckBox("canFork"));
+ form.add(new CheckBox("canFork").setEnabled(GitBlit.getBoolean(Keys.web.allowForking, true)));
form.add(new CheckBox("canCreate"));
form.add(new CheckBox("excludeFromFederation"));
form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY, repos, permissions, getAccessPermissions()));
form.add(teams.setEnabled(editTeams));
+ form.add(new TextField<String>("organizationalUnit").setEnabled(editDisplayName));
+ form.add(new TextField<String>("organization").setEnabled(editDisplayName));
+ form.add(new TextField<String>("locality").setEnabled(editDisplayName));
+ form.add(new TextField<String>("stateProvince").setEnabled(editDisplayName));
+ form.add(new TextField<String>("countryCode").setEnabled(editDisplayName));
form.add(new Button("save"));
Button cancel = new Button("cancel") {
private static final long serialVersionUID = 1L;
diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.java b/src/com/gitblit/wicket/pages/RepositoryPage.java
index 346edc3e..3acf73af 100644
--- a/src/com/gitblit/wicket/pages/RepositoryPage.java
+++ b/src/com/gitblit/wicket/pages/RepositoryPage.java
@@ -154,7 +154,9 @@ public abstract class RepositoryPage extends BasePage {
pages.put("branches", new PageRegistration("gb.branches", BranchesPage.class, params));
pages.put("tags", new PageRegistration("gb.tags", TagsPage.class, params));
pages.put("tree", new PageRegistration("gb.tree", TreePage.class, params));
- pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));
+ if (GitBlit.getBoolean(Keys.web.allowForking, true)) {
+ pages.put("forks", new PageRegistration("gb.forks", ForksPage.class, params));
+ }
// conditional links
Repository r = getRepository();
@@ -191,7 +193,7 @@ public abstract class RepositoryPage extends BasePage {
}
protected boolean allowForkControls() {
- return true;
+ return GitBlit.getBoolean(Keys.web.allowForking, true);
}
@Override
@@ -597,4 +599,4 @@ public abstract class RepositoryPage extends BasePage {
getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
}
}
-}
+}
diff --git a/src/com/gitblit/wicket/pages/TreePage.java b/src/com/gitblit/wicket/pages/TreePage.java
index 345814f4..b8ce7b48 100644
--- a/src/com/gitblit/wicket/pages/TreePage.java
+++ b/src/com/gitblit/wicket/pages/TreePage.java
@@ -144,25 +144,31 @@ public class TreePage extends RepositoryPage {
item.add(links);
} else {
// blob link
+ String displayPath = entry.name;
+ String path = entry.path;
+ if (entry.isSymlink()) {
+ path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path);
+ displayPath = entry.name + " -> " + path;
+ }
item.add(WicketUtils.getFileImage("pathIcon", entry.name));
item.add(new Label("pathSize", byteFormat.format(entry.size)));
- item.add(new LinkPanel("pathName", "list", entry.name, BlobPage.class,
+ item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
WicketUtils.newPathParameter(repositoryName, entry.commitId,
- entry.path)));
+ path)));
// links
Fragment links = new Fragment("pathLinks", "blobLinks", this);
links.add(new BookmarkablePageLink<Void>("view", BlobPage.class,
WicketUtils.newPathParameter(repositoryName, entry.commitId,
- entry.path)));
+ path)));
links.add(new BookmarkablePageLink<Void>("raw", RawPage.class, WicketUtils
- .newPathParameter(repositoryName, entry.commitId, entry.path)));
+ .newPathParameter(repositoryName, entry.commitId, path)));
links.add(new BookmarkablePageLink<Void>("blame", BlamePage.class,
WicketUtils.newPathParameter(repositoryName, entry.commitId,
- entry.path)));
+ path)));
links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class,
WicketUtils.newPathParameter(repositoryName, entry.commitId,
- entry.path)));
+ path)));
item.add(links);
}
}