From 5d7545652a6529c9076f67acd75f7a977c8a44a6 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Wed, 10 Oct 2012 16:47:11 -0400
Subject: [PATCH] Try regex permission matching if exact permission is not found (issue 36)

---
 docs/01_setup.mkd                            |   13 ++++++
 docs/04_releases.mkd                         |    2 +
 src/com/gitblit/models/TeamModel.java        |   11 +++++
 tests/com/gitblit/tests/PermissionsTest.java |   24 ++++++++++++
 src/com/gitblit/models/UserModel.java        |   11 +++++
 5 files changed, 60 insertions(+), 1 deletions(-)

diff --git a/docs/01_setup.mkd b/docs/01_setup.mkd
index 1cebb3b..3123aa1 100644
--- a/docs/01_setup.mkd
+++ b/docs/01_setup.mkd
@@ -234,7 +234,7 @@
 	    federationSets = 
 
 #### Repository Names
-Repository names must be unique and are CASE-SENSITIVE ON CASE-SENSITIVE FILESYSTEMS.  The name must be composed of letters, digits, or `/ _ - .`<br/>
+Repository names must be unique and are CASE-SENSITIVE ON CASE-SENSITIVE FILESYSTEMS.  The name must be composed of letters, digits, or `/ _ - . ~`<br/>
 Whitespace is illegal.
 
 Repositories can be grouped within subfolders.  e.g. *libraries/mycoollib.git* and *libraries/myotherlib.git*
@@ -257,6 +257,16 @@
 - **RWC** (clone and push with ref creation)
 - **RWD** (clone and push with ref creation, deletion)
 - **RW+** (clone and push with ref creation, deletion, rewind)
+
+These permission codes are combined with the repository path to create a user permission:
+
+    RW:mygroup/myrepo.git
+
+#### Discrete Permissions with Regex Matching (Gitblit v1.2.0+)
+
+Gitblit also supports regex matching for repository permissions.  The following permission grants push privileges to all repositories in the *mygroup* folder.
+
+    RW:mygroup/[A-Za-z0-9-~_\\./]+
 
 #### No-So-Discrete Permissions (Gitblit <= v1.1.0)
 
@@ -282,6 +292,7 @@
 	[user "hannibal"]
 		password = bossman
 		repository = RWD:topsecret.git
+		repository = RW+:ateam/[A-Za-z0-9-~_\\./]+
 
 	[user "faceman"]
 		password = vanity
diff --git a/docs/04_releases.mkd b/docs/04_releases.mkd
index 9795601..416aebe 100644
--- a/docs/04_releases.mkd
+++ b/docs/04_releases.mkd
@@ -28,6 +28,8 @@
     - RWD (clone and push with ref creation, deletion)
     - RW+ (clone and push with ref creation, deletion, rewind)  
 While not as sophisticated as Gitolite, this does give finer access controls.  These permissions fit in cleanly with the existing users.conf and users.properties files.  In Gitblit <= 1.1.0, all your existing user accounts have RW+ access.   If you are upgrading to 1.2.0, the RW+ access is *preserved* and you will have to lower/adjust accordingly.
+- Implemented regex repository permission matching (issue 36)  
+This allows you to specify a permission like `RW:mygroup/[A-Za-z0-9-~_\\./]+` to grant push privileges to all repositories within the *mygroup* project/folder.
 - Added DELETE, CREATE, and NON-FAST-FORWARD ref change logging
 - Added support for personal repositories.  
 Personal repositories can be created by accounts with the *create* permission and are stored in *git.repositoriesFolder/~username*.  Each user with personal repositories will have a user page, something like the GitHub profile page.  Personal repositories have all the same features as common repositories, except personal repositories can be renamed by their owner.
diff --git a/src/com/gitblit/models/TeamModel.java b/src/com/gitblit/models/TeamModel.java
index d185b9d..0b9c506 100644
--- a/src/com/gitblit/models/TeamModel.java
+++ b/src/com/gitblit/models/TeamModel.java
@@ -132,10 +132,21 @@
 	public AccessPermission getRepositoryPermission(RepositoryModel repository) {
 		AccessPermission permission = AccessPermission.NONE;
 		if (permissions.containsKey(repository.name.toLowerCase())) {
+			// exact repository permission specified
 			AccessPermission p = permissions.get(repository.name.toLowerCase());
 			if (p != null) {
 				permission = p;
 			}
+		} else {
+			// search for regex permission match
+			for (String key : permissions.keySet()) {
+				if (repository.name.matches(key)) {
+					AccessPermission p = permissions.get(key);
+					if (p != null) {
+						permission = p;
+					}
+				}
+			}
 		}
 		return permission;
 	}
diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java
index ee73025..a4a4024 100644
--- a/src/com/gitblit/models/UserModel.java
+++ b/src/com/gitblit/models/UserModel.java
@@ -175,10 +175,21 @@
 		// and the permissions of teams of which the user belongs
 		AccessPermission permission = AccessPermission.NONE;
 		if (permissions.containsKey(repository.name.toLowerCase())) {
+			// exact repository permission specified
 			AccessPermission p = permissions.get(repository.name.toLowerCase());
 			if (p != null) {
 				permission = p;
 			}
+		} else {
+			// search for regex permission match
+			for (String key : permissions.keySet()) {
+				if (repository.name.matches(key)) {
+					AccessPermission p = permissions.get(key);
+					if (p != null) {
+						permission = p;
+					}
+				}
+			}
 		}
 		
 		for (TeamModel team : teams) {
diff --git a/tests/com/gitblit/tests/PermissionsTest.java b/tests/com/gitblit/tests/PermissionsTest.java
index cb9925e..83ab11e 100644
--- a/tests/com/gitblit/tests/PermissionsTest.java
+++ b/tests/com/gitblit/tests/PermissionsTest.java
@@ -2388,4 +2388,28 @@
 		assertFalse("user CAN delete!", user.canDelete(repository));
 		assertFalse("user CAN edit!", user.canEdit(repository));
 	}
+	
+	@Test
+	public void testWildcardMatching() throws Exception {
+		RepositoryModel repository = new RepositoryModel("ubercool/_my-r/e~po.git", null, null, new Date());
+		repository.authorizationControl = AuthorizationControl.NAMED;
+		repository.accessRestriction = AccessRestrictionType.VIEW;
+
+		UserModel user = new UserModel("test");
+		user.setRepositoryPermission("ubercool/[A-Za-z0-9-~_\\./]+", AccessPermission.CLONE);
+
+		assertTrue("user CAN NOT view!", user.canView(repository));
+		assertTrue("user CAN NOT clone!", user.canClone(repository));
+		assertFalse("user CAN push!", user.canPush(repository));
+		
+		assertFalse("user CAN create ref!", user.canCreateRef(repository));
+		assertFalse("user CAN delete ref!", user.canDeleteRef(repository));
+		assertFalse("user CAN rewind ref!", user.canRewindRef(repository));
+
+		assertFalse("user CAN fork!", user.canFork(repository));
+		
+		assertFalse("user CAN delete!", user.canDelete(repository));
+		assertFalse("user CAN edit!", user.canEdit(repository));
+
+	}
 }

--
Gitblit v1.9.1