diff --git a/pom.xml b/pom.xml
index 4a2684a..31e5bb9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.danielflower.apprunner
restabuild
- 1.1-SNAPSHOT
+ 1.2-SNAPSHOT
Restabuild
Builds Git-hosted projects via a REST API
@@ -58,7 +58,7 @@
ch.qos.logback
logback-classic
- 1.5.2
+ 1.5.6
runtime
@@ -86,7 +86,7 @@
io.muserver
mu-server
- 2.0.0
+ 2.0.1
@@ -203,7 +203,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.5.3
+ 3.6.0
package
@@ -236,7 +236,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.6.3
+ 3.7.0
attach-javadocs
diff --git a/sample-config.properties b/sample-config.properties
index 65529ec..89049a3 100644
--- a/sample-config.properties
+++ b/sample-config.properties
@@ -14,5 +14,14 @@ restabuild.context=/restabuild
# The timeout threshold per run (unit in minute)
restabuild.timeout=30
-# Controls whether or not to delete the instance directories of each build upon completion. Valid values: ALWAYS, NEVER, ON_SUCCESS
-restabuild.delete.policy=ON_SUCCESS
\ No newline at end of file
+# Controls whether to delete the instance directories of each build upon completion. Valid values: ALWAYS, NEVER, ON_SUCCESS
+restabuild.delete.policy=ON_SUCCESS
+
+# An optional regular expression pattern that git URLs must match. Empty to allow any URLs.
+restabuild.git.url.pattern=https://github\.com/.*\.git
+
+# The message to return to users if the git URL specified does not match the allowed regular expression
+restabuild.git.url.validation.message=Only HTTPS github.com URLs are allowed
+
+# The example URL to show in the UI
+restabuild.example.url=https://github.com/3redronin/mu-server-sample.git
\ No newline at end of file
diff --git a/src/main/java/com/danielflower/restabuild/App.java b/src/main/java/com/danielflower/restabuild/App.java
index 025a284..30e571a 100644
--- a/src/main/java/com/danielflower/restabuild/App.java
+++ b/src/main/java/com/danielflower/restabuild/App.java
@@ -48,9 +48,9 @@ public void start() throws IOException {
buildQueue = new BuildQueue(numberOfConcurrentBuilds, buildTimeoutMinutes, config.deletePolicy());
- BuildResource buildResource = new BuildResource(fileSandbox, database, buildQueue, executorService);
+ BuildResource buildResource = new BuildResource(fileSandbox, database, buildQueue, executorService, config.allowedRepoUrlPattern(), config.allowedRepoUrlValidationMessage());
String context = Mutils.trim(config.get(Config.CONTEXT, "restabuild"), "/");
- webServer = WebServer.start(appRunnerPort, context, buildResource, buildTimeoutMinutes);
+ webServer = WebServer.start(appRunnerPort, context, buildResource, buildTimeoutMinutes, config);
}
private void deleteOldTempFiles(File tempDir) {
diff --git a/src/main/java/com/danielflower/restabuild/Config.java b/src/main/java/com/danielflower/restabuild/Config.java
index 9d3ee71..b5eed23 100644
--- a/src/main/java/com/danielflower/restabuild/Config.java
+++ b/src/main/java/com/danielflower/restabuild/Config.java
@@ -1,8 +1,8 @@
package com.danielflower.restabuild;
import com.danielflower.restabuild.build.DeletePolicy;
-import com.danielflower.restabuild.build.RestaBuildException;
import com.danielflower.restabuild.build.InvalidConfigException;
+import com.danielflower.restabuild.build.RestaBuildException;
import org.apache.commons.io.FileUtils;
import java.io.File;
@@ -11,6 +11,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -90,6 +91,19 @@ public int getInt(String name, int defaultValue) {
}
}
+ public Pattern allowedRepoUrlPattern() {
+ String exp = get("restabuild.git.url.pattern", ".*");
+ return Pattern.compile(exp);
+ }
+
+ public String allowedRepoUrlValidationMessage() {
+ return get("restabuild.git.url.validation.message", "Sorry, that URL is not allowed.");
+ }
+
+ public String exampleURl() {
+ return get("restabuild.example.url", "");
+ }
+
public File getOrCreateDir(String name) {
File f = new File(get(name));
@@ -105,5 +119,11 @@ public static boolean isWindows() {
return File.separatorChar == '\\';
}
+ public Config clone(String keyToChange, String valueForKey) {
+ Map copy = new HashMap<>(raw);
+ copy.put(keyToChange, valueForKey);
+ return new Config(copy);
+ }
+
}
diff --git a/src/main/java/com/danielflower/restabuild/web/BuildResource.java b/src/main/java/com/danielflower/restabuild/web/BuildResource.java
index fbbec89..a4e9e5a 100644
--- a/src/main/java/com/danielflower/restabuild/web/BuildResource.java
+++ b/src/main/java/com/danielflower/restabuild/web/BuildResource.java
@@ -26,6 +26,7 @@
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Path("api/v1/builds")
@@ -42,12 +43,16 @@ public class BuildResource {
private final BuildDatabase database;
private final BuildQueue buildQueue;
private final ExecutorService executorService;
+ private final Pattern allowedUrlPattern;
+ private final String urlPatternValidationErrorMessage;
- public BuildResource(FileSandbox fileSandbox, BuildDatabase database, BuildQueue buildQueue, ExecutorService executorService) {
+ public BuildResource(FileSandbox fileSandbox, BuildDatabase database, BuildQueue buildQueue, ExecutorService executorService, Pattern allowedUrlPattern, String urlPatternValidationErrorMessage) {
this.fileSandbox = fileSandbox;
this.buildQueue = buildQueue;
this.database = database;
this.executorService = executorService;
+ this.allowedUrlPattern = allowedUrlPattern;
+ this.urlPatternValidationErrorMessage = urlPatternValidationErrorMessage;
}
@POST
@@ -104,6 +109,10 @@ private URIish validateGitUrl(String gitUrl) {
} catch (URISyntaxException e) {
throw new BadRequestException("An invalid Git URL was specified: " + e.getMessage());
}
+ if (!allowedUrlPattern.matcher(gitUrl).matches()) {
+ System.out.println("gitUrl = " + gitUrl);
+ throw new BadRequestException(urlPatternValidationErrorMessage);
+ }
return gitURIish;
}
diff --git a/src/main/java/com/danielflower/restabuild/web/IndexHtmlHandler.java b/src/main/java/com/danielflower/restabuild/web/IndexHtmlHandler.java
index ead9495..2dbcbd4 100644
--- a/src/main/java/com/danielflower/restabuild/web/IndexHtmlHandler.java
+++ b/src/main/java/com/danielflower/restabuild/web/IndexHtmlHandler.java
@@ -1,10 +1,12 @@
package com.danielflower.restabuild.web;
+import com.danielflower.restabuild.Config;
import com.danielflower.restabuild.build.BuildResult;
-import com.danielflower.restabuild.build.RemoteGitRepo;
import io.muserver.*;
import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.Map;
import static io.muserver.Mutils.coalesce;
@@ -13,17 +15,30 @@ public class IndexHtmlHandler implements RouteHandler {
private final String template;
- public IndexHtmlHandler() throws IOException {
+ public IndexHtmlHandler(Config config) throws IOException {
String version = coalesce(getClass().getPackage().getImplementationVersion(), "dev");
- template = new String(Mutils.toByteArray(IndexHtmlHandler.class.getResourceAsStream("/web/index.html"), 8192), "UTF-8")
+ StringBuilder inputBoxAttributes = new StringBuilder();
+ String urlPattern = config.allowedRepoUrlPattern().pattern();
+ if (!urlPattern.equals(".*")) {
+ inputBoxAttributes.append(" pattern=\"").append(Mutils.htmlEncode(urlPattern)).append("\" title=\"").append(Mutils.htmlEncode(config.allowedRepoUrlValidationMessage())).append("\"");
+ }
+ if (!Mutils.nullOrEmpty(config.exampleURl())) {
+ inputBoxAttributes.append(" placeholder=\"").append(Mutils.htmlEncode(config.exampleURl())).append("\"");
+ }
+
+ InputStream template = IndexHtmlHandler.class.getResourceAsStream("/web/index.html");
+ this.template = new String(Mutils.toByteArray(template, 8192), StandardCharsets.UTF_8)
.replace("{{buildfilename}}", BuildResult.buildFile)
- .replace("{{restabuildversion}}", version);
+ .replace("{{restabuildversion}}", version)
+ .replace("{{gitUrlTextBoxAttributes}}", inputBoxAttributes.toString())
+
+ ;
}
@Override
- public void handle(MuRequest request, MuResponse response, Map pathParams) throws Exception {
+ public void handle(MuRequest request, MuResponse response, Map pathParams) {
response.contentType(ContentTypes.TEXT_HTML_UTF8);
response.write(template);
}
diff --git a/src/main/java/com/danielflower/restabuild/web/WebServer.java b/src/main/java/com/danielflower/restabuild/web/WebServer.java
index ff0c7dc..c7f6043 100644
--- a/src/main/java/com/danielflower/restabuild/web/WebServer.java
+++ b/src/main/java/com/danielflower/restabuild/web/WebServer.java
@@ -1,5 +1,6 @@
package com.danielflower.restabuild.web;
+import com.danielflower.restabuild.Config;
import io.muserver.Method;
import io.muserver.MuServer;
import io.muserver.Mutils;
@@ -25,7 +26,7 @@ private WebServer(MuServer server) {
this.server = server;
}
- public static WebServer start(int port, String context, BuildResource buildResource, int buildTimeoutMinutes) throws IOException {
+ public static WebServer start(int port, String context, BuildResource buildResource, int buildTimeoutMinutes, Config config) throws IOException {
boolean hasContext = !Mutils.nullOrEmpty(context);
MuServer server = muServer()
.withHttpPort(port)
@@ -55,7 +56,7 @@ public static WebServer start(int port, String context, BuildResource buildResou
.build())
)
)
- .addHandler(Method.GET, "/", new IndexHtmlHandler())
+ .addHandler(Method.GET, "/", new IndexHtmlHandler(config))
.addHandler(fileOrClasspath("src/main/resources/web", "/web")))
.start();
diff --git a/src/main/resources/web/index.html b/src/main/resources/web/index.html
index 8da9e9c..06c169c 100644
--- a/src/main/resources/web/index.html
+++ b/src/main/resources/web/index.html
@@ -49,8 +49,7 @@ Submit a build