From 1590fd791c7fc4d6849479cad88956f37360bbbf Mon Sep 17 00:00:00 2001
From: Joel Johnson <mrjoel@lixil.net>
Date: Wed, 01 Jul 2015 15:05:50 -0400
Subject: [PATCH] allow advertising gitblit privileges for external URLs

---
 src/main/java/com/gitblit/manager/ServicesManager.java          |   37 ++++++++++++++----
 src/main/java/com/gitblit/models/RepositoryUrl.java             |    4 +-
 src/main/distrib/data/defaults.properties                       |   14 +++++++
 src/main/java/com/gitblit/wicket/pages/TicketPage.java          |    2 
 src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java |   36 +++++++++---------
 5 files changed, 63 insertions(+), 30 deletions(-)

diff --git a/src/main/distrib/data/defaults.properties b/src/main/distrib/data/defaults.properties
index 60c914b..d4ebcc3 100644
--- a/src/main/distrib/data/defaults.properties
+++ b/src/main/distrib/data/defaults.properties
@@ -1203,6 +1203,20 @@
 # SINCE 1.7.0
 web.showSshDaemonUrls = true
 
+# Should effective permissions be advertised for access paths defined in web.otherUrls?
+# If false, gitblit will indicate unknown permissions for the external link. If true,
+# gitblit will indicate permissions as defined within gitblit (including limiting to clone
+# permission is the transport type is not a valid push mechaism in git.acceptedPushTransports).
+#
+# Configure with caution: Note that gitblit has no way of knowing if further restrictions
+# are imposed by an external forwarding agent, so this may cause user confusion due to
+# more rights being advertised than are available through the URL. It will NOT grant
+# additional rights, but may incorrectly offer actions that are unavailable externally.
+# default: false
+#
+# SINCE 1.7.0
+web.advertiseAccessPermissionForOtherUrls = false
+
 # Should app-specific clone links be displayed for SourceTree, SparkleShare, etc?
 #
 # SINCE 1.3.0
diff --git a/src/main/java/com/gitblit/manager/ServicesManager.java b/src/main/java/com/gitblit/manager/ServicesManager.java
index c911f31..b993eb6 100644
--- a/src/main/java/com/gitblit/manager/ServicesManager.java
+++ b/src/main/java/com/gitblit/manager/ServicesManager.java
@@ -211,16 +211,35 @@
 		// add all other urls
 		// {0} = repository
 		// {1} = username
+		boolean advertisePermsForOther = settings.getBoolean(Keys.web.advertiseAccessPermissionForOtherUrls, false);
 		for (String url : settings.getStrings(Keys.web.otherUrls)) {
+			String externalUrl = null;
+
 			if (url.contains("{1}")) {
 				// external url requires username, only add url IF we have one
-				if (!StringUtils.isEmpty(username)) {
-					list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null));
+				if (StringUtils.isEmpty(username)) {
+					continue;
+				} else {
+					externalUrl = MessageFormat.format(url, repository.name, username);
 				}
 			} else {
-				// external url does not require username
-				list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null));
+				// external url does not require username, just do repo name formatting
+				externalUrl = MessageFormat.format(url, repository.name);
 			}
+
+			AccessPermission permission = null;
+			if (advertisePermsForOther) {
+				permission = user.getRepositoryPermission(repository).permission;
+				if (permission.exceeds(AccessPermission.NONE)) {
+					Transport transport = Transport.fromUrl(externalUrl);
+					if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(transport)) {
+						// downgrade the repo permission for this transport
+						// because it is not an acceptable PUSH transport
+						permission = AccessPermission.CLONE;
+					}
+				}
+			}
+			list.add(new RepositoryUrl(externalUrl, permission));
 		}
 
 		// sort transports by highest permission and then by transport security
@@ -228,13 +247,13 @@
 
 			@Override
 			public int compare(RepositoryUrl o1, RepositoryUrl o2) {
-				if (!o1.isExternal() && o2.isExternal()) {
-					// prefer Gitblit over external
+				if (o1.hasPermission() && !o2.hasPermission()) {
+					// prefer known permission items over unknown
 					return -1;
-				} else if (o1.isExternal() && !o2.isExternal()) {
-					// prefer Gitblit over external
+				} else if (!o1.hasPermission() && o2.hasPermission()) {
+					// prefer known permission items over unknown
 					return 1;
-				} else if (o1.isExternal() && o2.isExternal()) {
+				} else if (!o1.hasPermission() && !o2.hasPermission()) {
 					// sort by Transport ordinal
 					return o1.transport.compareTo(o2.transport);
 				} else if (o1.permission.exceeds(o2.permission)) {
diff --git a/src/main/java/com/gitblit/models/RepositoryUrl.java b/src/main/java/com/gitblit/models/RepositoryUrl.java
index d155dbd..13f6917 100644
--- a/src/main/java/com/gitblit/models/RepositoryUrl.java
+++ b/src/main/java/com/gitblit/models/RepositoryUrl.java
@@ -41,8 +41,8 @@
 		this.permission = permission;
 	}
 
-	public boolean isExternal() {
-		return permission == null;
+	public boolean hasPermission() {
+		return permission != null;
 	}
 
 	@Override
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.java b/src/main/java/com/gitblit/wicket/pages/TicketPage.java
index 1aa8954..2dbc8e9 100644
--- a/src/main/java/com/gitblit/wicket/pages/TicketPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.java
@@ -752,7 +752,7 @@
 		if (currentPatchset == null) {
 			// no patchset available
 			RepositoryUrl repoUrl = getRepositoryUrl(user, repository);
-			boolean canPropose = repoUrl != null && repoUrl.permission.atLeast(AccessPermission.CLONE) && !UserModel.ANONYMOUS.equals(user);
+			boolean canPropose = repoUrl != null && repoUrl.hasPermission() && repoUrl.permission.atLeast(AccessPermission.CLONE) && !UserModel.ANONYMOUS.equals(user);
 			if (ticket.isOpen() && app().tickets().isAcceptingNewPatchsets(repository) && canPropose) {
 				// ticket & repo will accept a proposal patchset
 				// show the instructions for proposing a patchset
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
index 0666fcd..207f125 100644
--- a/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/RepositoryUrlPanel.java
@@ -84,7 +84,7 @@
 		// grab primary url from the top of the list
 		primaryUrl = repositoryUrls.size() == 0 ? null : repositoryUrls.get(0);
 
-		boolean canClone = primaryUrl != null && ((primaryUrl.permission == null) || primaryUrl.permission.atLeast(AccessPermission.CLONE));
+		boolean canClone = primaryUrl != null && (!primaryUrl.hasPermission() || primaryUrl.permission.atLeast(AccessPermission.CLONE));
 
 		if (repositoryUrls.size() == 0 || !canClone) {
 			// no urls, nothing to show.
@@ -145,7 +145,7 @@
 					fragment.add(content);
 					item.add(fragment);
 
-					Label permissionLabel = new Label("permission", repoUrl.isExternal() ? externalPermission : repoUrl.permission.toString());
+					Label permissionLabel = new Label("permission", repoUrl.hasPermission() ? repoUrl.permission.toString() : externalPermission);
 					WicketUtils.setPermissionClass(permissionLabel, repoUrl.permission);
 					String tooltip = getProtocolPermissionDescription(repository, repoUrl);
 					WicketUtils.setHtmlTooltip(permissionLabel, tooltip);
@@ -201,7 +201,7 @@
 
 		urlPanel.add(new Label("primaryUrl", primaryUrl.url).setRenderBodyOnly(true));
 
-		Label permissionLabel = new Label("primaryUrlPermission", primaryUrl.isExternal() ? externalPermission : primaryUrl.permission.toString());
+		Label permissionLabel = new Label("primaryUrlPermission", primaryUrl.hasPermission() ? primaryUrl.permission.toString() : externalPermission);
 		String tooltip = getProtocolPermissionDescription(repository, primaryUrl);
 		WicketUtils.setHtmlTooltip(permissionLabel, tooltip);
 		urlPanel.add(permissionLabel);
@@ -234,8 +234,8 @@
 				// filter the urls for the client app
 				List<RepositoryUrl> urls = new ArrayList<RepositoryUrl>();
 				for (RepositoryUrl repoUrl : repositoryUrls) {
-					if (clientApp.minimumPermission == null || repoUrl.permission == null) {
-						// no minimum permission or external permissions, assume it is satisfactory
+					if (clientApp.minimumPermission == null || !repoUrl.hasPermission()) {
+						// no minimum permission or untracked permissions, assume it is satisfactory
 						if (clientApp.supportsTransport(repoUrl.url)) {
 							urls.add(repoUrl);
 						}
@@ -339,7 +339,7 @@
 	}
 
 	protected Label createPermissionBadge(String wicketId, RepositoryUrl repoUrl) {
-		Label permissionLabel = new Label(wicketId, repoUrl.isExternal() ? externalPermission : repoUrl.permission.toString());
+		Label permissionLabel = new Label(wicketId, repoUrl.hasPermission() ? repoUrl.permission.toString() : externalPermission);
 		WicketUtils.setPermissionClass(permissionLabel, repoUrl.permission);
 		String tooltip = getProtocolPermissionDescription(repository, repoUrl);
 		WicketUtils.setHtmlTooltip(permissionLabel, tooltip);
@@ -369,18 +369,7 @@
 			RepositoryUrl repoUrl) {
 		if (!urlPermissionsMap.containsKey(repoUrl.url)) {
 			String note;
-			if (repoUrl.isExternal()) {
-				String protocol;
-				int protocolIndex = repoUrl.url.indexOf("://");
-				if (protocolIndex > -1) {
-					// explicit protocol specified
-					protocol = repoUrl.url.substring(0, protocolIndex);
-				} else {
-					// implicit SSH url
-					protocol = "ssh";
-				}
-				note = MessageFormat.format(getString("gb.externalPermissions"), protocol);
-			} else {
+			if (repoUrl.hasPermission()) {
 				note = null;
 				String key;
 				switch (repoUrl.permission) {
@@ -411,6 +400,17 @@
 					String description = MessageFormat.format(pattern, repoUrl.permission.toString());
 					note = description;
 				}
+			} else {
+				String protocol;
+				int protocolIndex = repoUrl.url.indexOf("://");
+				if (protocolIndex > -1) {
+					// explicit protocol specified
+					protocol = repoUrl.url.substring(0, protocolIndex);
+				} else {
+					// implicit SSH url
+					protocol = "ssh";
+				}
+				note = MessageFormat.format(getString("gb.externalPermissions"), protocol);
 			}
 			urlPermissionsMap.put(repoUrl.url, note);
 		}

--
Gitblit v1.9.1