mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-15 16:37:28 +00:00
[git-bridge] add CORS support (#23892)
GitOrigin-RevId: 9e3d85e479746affd047434ec9ce2588b60ca76c
This commit is contained in:
parent
18fb4effb1
commit
14d9874b68
9 changed files with 149 additions and 3 deletions
|
@ -3,6 +3,7 @@
|
|||
"bindIp": "${GIT_BRIDGE_BIND_IP:-0.0.0.0}",
|
||||
"idleTimeout": ${GIT_BRIDGE_IDLE_TIMEOUT:-30000},
|
||||
"rootGitDirectory": "${GIT_BRIDGE_ROOT_DIR:-/tmp/wlgb}",
|
||||
"allowedCorsOrigins": "${GIT_BRIDGE_ALLOWED_CORS_ORIGINS:-https://localhost}",
|
||||
"apiBaseUrl": "${GIT_BRIDGE_API_BASE_URL:-https://localhost/api/v0}",
|
||||
"postbackBaseUrl": "${GIT_BRIDGE_POSTBACK_BASE_URL:-https://localhost}",
|
||||
"serviceName": "${GIT_BRIDGE_SERVICE_NAME:-Overleaf}",
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"bindIp": "127.0.0.1",
|
||||
"idleTimeout": 30000,
|
||||
"rootGitDirectory": "/tmp/wlgb",
|
||||
"allowedCorsOrigins": "https://localhost",
|
||||
"apiBaseUrl": "https://localhost/api/v0",
|
||||
"postbackBaseUrl": "https://localhost",
|
||||
"serviceName": "Overleaf",
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"bindIp": "0.0.0.0",
|
||||
"idleTimeout": 30000,
|
||||
"rootGitDirectory": "/tmp/wlgb",
|
||||
"allowedCorsOrigins": "http://v2.overleaf.test",
|
||||
"apiBaseUrl": "http://v2.overleaf.test:3000/api/v0",
|
||||
"postbackBaseUrl": "http://git-bridge:8000",
|
||||
"serviceName": "Overleaf",
|
||||
|
|
|
@ -26,6 +26,7 @@ public class Config implements JSONSource {
|
|||
config.bindIp,
|
||||
config.idleTimeout,
|
||||
config.rootGitDirectory,
|
||||
config.allowedCorsOrigins,
|
||||
config.apiBaseURL,
|
||||
config.postbackURL,
|
||||
config.serviceName,
|
||||
|
@ -41,6 +42,7 @@ public class Config implements JSONSource {
|
|||
private String bindIp;
|
||||
private int idleTimeout;
|
||||
private String rootGitDirectory;
|
||||
private String[] allowedCorsOrigins;
|
||||
private String apiBaseURL;
|
||||
private String postbackURL;
|
||||
private String serviceName;
|
||||
|
@ -64,6 +66,7 @@ public class Config implements JSONSource {
|
|||
String bindIp,
|
||||
int idleTimeout,
|
||||
String rootGitDirectory,
|
||||
String[] allowedCorsOrigins,
|
||||
String apiBaseURL,
|
||||
String postbackURL,
|
||||
String serviceName,
|
||||
|
@ -77,6 +80,7 @@ public class Config implements JSONSource {
|
|||
this.bindIp = bindIp;
|
||||
this.idleTimeout = idleTimeout;
|
||||
this.rootGitDirectory = rootGitDirectory;
|
||||
this.allowedCorsOrigins = allowedCorsOrigins;
|
||||
this.apiBaseURL = apiBaseURL;
|
||||
this.postbackURL = postbackURL;
|
||||
this.serviceName = serviceName;
|
||||
|
@ -101,6 +105,13 @@ public class Config implements JSONSource {
|
|||
}
|
||||
this.apiBaseURL = apiBaseURL;
|
||||
serviceName = getElement(configObject, "serviceName").getAsString();
|
||||
final String rawAllowedCorsOrigins =
|
||||
getOptionalString(configObject, "allowedCorsOrigins").trim();
|
||||
if (rawAllowedCorsOrigins.isEmpty()) {
|
||||
allowedCorsOrigins = new String[] {};
|
||||
} else {
|
||||
allowedCorsOrigins = rawAllowedCorsOrigins.split(",");
|
||||
}
|
||||
postbackURL = getElement(configObject, "postbackBaseUrl").getAsString();
|
||||
if (!postbackURL.endsWith("/")) {
|
||||
postbackURL += "/";
|
||||
|
@ -139,6 +150,10 @@ public class Config implements JSONSource {
|
|||
return this.sqliteHeapLimitBytes;
|
||||
}
|
||||
|
||||
public String[] getAllowedCorsOrigins() {
|
||||
return allowedCorsOrigins;
|
||||
}
|
||||
|
||||
public String getAPIBaseURL() {
|
||||
return apiBaseURL;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package uk.ac.ic.wlgitbridge.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import uk.ac.ic.wlgitbridge.util.Log;
|
||||
|
||||
public class CORSHandler extends AbstractHandler {
|
||||
private final Set<String> allowedCorsOrigins;
|
||||
|
||||
public CORSHandler(String[] allowedCorsOrigins) {
|
||||
this.allowedCorsOrigins = Set.of(allowedCorsOrigins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(
|
||||
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
|
||||
String origin = request.getHeader("Origin");
|
||||
if (origin == null) {
|
||||
return; // Not a CORS request
|
||||
}
|
||||
|
||||
final boolean ok = allowedCorsOrigins.contains(origin);
|
||||
if (ok) {
|
||||
response.setHeader("Access-Control-Allow-Origin", origin);
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, PUT, POST, DELETE");
|
||||
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
|
||||
response.setHeader("Access-Control-Max-Age", "86400"); // cache for 24h
|
||||
}
|
||||
String method = baseRequest.getMethod();
|
||||
if ("OPTIONS".equals(method)) {
|
||||
Log.debug("OPTIONS <- {}", target);
|
||||
baseRequest.setHandled(true);
|
||||
if (ok) {
|
||||
response.setStatus(200);
|
||||
} else {
|
||||
response.setStatus(403);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -110,6 +110,7 @@ public class GitBridgeServer {
|
|||
this.jettyServer.addConnector(connector);
|
||||
|
||||
HandlerCollection handlers = new HandlerList();
|
||||
handlers.addHandler(new CORSHandler(config.getAllowedCorsOrigins()));
|
||||
handlers.addHandler(initApiHandler());
|
||||
handlers.addHandler(initBaseHandler());
|
||||
handlers.addHandler(initGitHandler(config, repoStore, snapshotApi));
|
||||
|
|
|
@ -465,8 +465,12 @@ public class WLGitBridgeIntegrationTest {
|
|||
|
||||
@After
|
||||
public void tearDown() {
|
||||
server.stop();
|
||||
wlgb.stop();
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
}
|
||||
if (wlgb != null) {
|
||||
wlgb.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void gitConfig(File dir) throws IOException, InterruptedException {
|
||||
|
@ -1391,6 +1395,80 @@ public class WLGitBridgeIntegrationTest {
|
|||
assertTrue(f.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCors() throws IOException, ExecutionException, InterruptedException {
|
||||
|
||||
int gitBridgePort = 33893;
|
||||
int mockServerPort = 3893;
|
||||
|
||||
server = new MockSnapshotServer(mockServerPort, getResource("/canServePushedFiles").toFile());
|
||||
server.start();
|
||||
server.setState(states.get("canServePushedFiles").get("state"));
|
||||
|
||||
wlgb = new GitBridgeApp(new String[] {makeConfigFile(gitBridgePort, mockServerPort)});
|
||||
wlgb.run();
|
||||
|
||||
String url = "http://127.0.0.1:" + gitBridgePort + "/status";
|
||||
Response response = asyncHttpClient().prepareGet(url).execute().get();
|
||||
assertEquals(200, response.getStatusCode());
|
||||
assertEquals("ok\n", response.getResponseBody());
|
||||
assertNull(response.getHeader("Access-Control-Allow-Origin"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cors() throws IOException, ExecutionException, InterruptedException {
|
||||
|
||||
int gitBridgePort = 33894;
|
||||
int mockServerPort = 3894;
|
||||
|
||||
server = new MockSnapshotServer(mockServerPort, getResource("/canServePushedFiles").toFile());
|
||||
server.start();
|
||||
server.setState(states.get("canServePushedFiles").get("state"));
|
||||
|
||||
wlgb = new GitBridgeApp(new String[] {makeConfigFile(gitBridgePort, mockServerPort)});
|
||||
wlgb.run();
|
||||
|
||||
String url = "http://127.0.0.1:" + gitBridgePort + "/status";
|
||||
|
||||
// Success
|
||||
Response response =
|
||||
asyncHttpClient()
|
||||
.prepareOptions(url)
|
||||
.setHeader("Origin", "https://localhost")
|
||||
.execute()
|
||||
.get();
|
||||
assertEquals(200, response.getStatusCode());
|
||||
assertEquals("", response.getResponseBody());
|
||||
assertEquals("https://localhost", response.getHeader("Access-Control-Allow-Origin"));
|
||||
|
||||
response =
|
||||
asyncHttpClient().prepareGet(url).setHeader("Origin", "https://localhost").execute().get();
|
||||
assertEquals(200, response.getStatusCode());
|
||||
assertEquals("ok\n", response.getResponseBody());
|
||||
assertEquals("https://localhost", response.getHeader("Access-Control-Allow-Origin"));
|
||||
|
||||
// Deny
|
||||
response =
|
||||
asyncHttpClient()
|
||||
.prepareOptions(url)
|
||||
.setHeader("Origin", "https://not-localhost")
|
||||
.execute()
|
||||
.get();
|
||||
assertEquals(403, response.getStatusCode());
|
||||
assertEquals("", response.getResponseBody());
|
||||
assertNull(response.getHeader("Access-Control-Allow-Origin"));
|
||||
|
||||
response =
|
||||
asyncHttpClient()
|
||||
.prepareGet(url)
|
||||
.setHeader("Origin", "https://not-localhost")
|
||||
.execute()
|
||||
.get();
|
||||
assertEquals(200, response.getStatusCode());
|
||||
assertEquals("ok\n", response.getResponseBody());
|
||||
assertNull(response.getHeader("Access-Control-Allow-Origin"));
|
||||
}
|
||||
|
||||
private String makeConfigFile(int port, int apiPort) throws IOException {
|
||||
return makeConfigFile(port, apiPort, null);
|
||||
}
|
||||
|
@ -1409,6 +1487,7 @@ public class WLGitBridgeIntegrationTest {
|
|||
+ " \"rootGitDirectory\": \""
|
||||
+ wlgb.getAbsolutePath()
|
||||
+ "\",\n"
|
||||
+ " \"allowedCorsOrigins\": \"https://localhost\",\n"
|
||||
+ " \"apiBaseUrl\": \"http://127.0.0.1:"
|
||||
+ apiPort
|
||||
+ "/api/v0\",\n"
|
||||
|
|
|
@ -90,6 +90,7 @@ public class ConfigTest {
|
|||
+ " \"bindIp\": \"127.0.0.1\",\n"
|
||||
+ " \"idleTimeout\": 30000,\n"
|
||||
+ " \"rootGitDirectory\": \"/var/wlgb/git\",\n"
|
||||
+ " \"allowedCorsOrigins\": [],\n"
|
||||
+ " \"apiBaseURL\": \"http://127.0.0.1:60000/api/v0/\",\n"
|
||||
+ " \"postbackURL\": \"http://127.0.0.1/\",\n"
|
||||
+ " \"serviceName\": \"Overleaf\",\n"
|
||||
|
|
|
@ -50,7 +50,7 @@ public class BridgeTest {
|
|||
gcJob = mock(GcJob.class);
|
||||
bridge =
|
||||
new Bridge(
|
||||
new Config(0, "", 0, "", "", "", "", null, false, null, null, null, 0),
|
||||
new Config(0, "", 0, "", null, "", "", "", null, false, null, null, null, 0),
|
||||
lock,
|
||||
repoStore,
|
||||
dbStore,
|
||||
|
|
Loading…
Add table
Reference in a new issue