Initial empty skeleton to display list of plugins Define the initial project skeleton with: - Buck build - AngularJS HTML and JS - X-GerritAuth expansion for REST API calls As demo of the skeleton working well, the index.html display the list of currently installed plugin invoking the Gerrit REST API /plugins/?all Change-Id: I122c37b8486609363bc92222d60153266c92e6d0
diff --git a/BUCK b/BUCK new file mode 100644 index 0000000..de8caf8 --- /dev/null +++ b/BUCK
@@ -0,0 +1,12 @@ +gerrit_plugin( + name = 'plugin-manager', + srcs = glob(['src/main/java/**/*.java']), + resources = glob(['src/main/**/*']), + manifest_entries = [ + 'Gerrit-PluginName: plugin-manager', + 'Gerrit-ApiType: plugin', + 'Gerrit-HttpModule: com.googlesource.gerrit.plugins.manager.WebModule', + 'Implementation-Title: Plugin manager', + 'Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/plugin-manager', + ], +)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/TokenReplaceOutputStream.java b/src/main/java/com/googlesource/gerrit/plugins/manager/TokenReplaceOutputStream.java new file mode 100644 index 0000000..9810318 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/manager/TokenReplaceOutputStream.java
@@ -0,0 +1,107 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// 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.googlesource.gerrit.plugins.manager; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServletResponse; + +public class TokenReplaceOutputStream extends ServletOutputStream { + + private final byte[] token; + + private final byte[] replace; + + private final ByteArrayOutputStream outBuff; + + private HttpServletResponse resp; + + private int outLen; + + public TokenReplaceOutputStream(HttpServletResponse resp, int contentLength, + byte[] token, byte[] replace) { + this.resp = resp; + this.outLen = contentLength; + this.token = token; + this.replace = replace; + this.outBuff = new ByteArrayOutputStream(contentLength); + } + + @Override + public void write(int b) throws IOException { + outBuff.write(b); + } + + @Override + public void flush() throws IOException { + if (outBuff.size() < outLen) { + return; + } + + byte[] outData = outBuff.toByteArray(); + byte[] cmp = new byte[token.length]; + ByteArrayOutputStream convertedData = + new ByteArrayOutputStream(outData.length); + + for (int i = 0; i < outData.length; i++) { + byte b = outData[i]; + if (b != token[0] || (outData.length - i) < token.length) { + convertedData.write(outData, i, 1); + continue; + } + + System.arraycopy(outData, i, cmp, 0, token.length); + if (Arrays.equals(cmp, token)) { + convertedData.write(replace); + i += token.length - 1; + } + } + + resp.setHeader("Content-Length", "" + convertedData.size()); + + ServletOutputStream out = resp.getOutputStream(); + out.write(convertedData.toByteArray()); + out.flush(); + + } + + @Override + public void close() throws IOException { + flush(); + } + + @Override + public void write(byte[] b) throws IOException { + outBuff.write(b); + flush(); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + outBuff.write(b, off, len); + flush(); + } + + public void setWriteListener(@SuppressWarnings("unused") WriteListener writeListener) { + } + + public boolean isReady() { + return true; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/WebModule.java b/src/main/java/com/googlesource/gerrit/plugins/manager/WebModule.java new file mode 100644 index 0000000..9a32518 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/manager/WebModule.java
@@ -0,0 +1,30 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// 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.googlesource.gerrit.plugins.manager; + +import com.google.gerrit.extensions.restapi.RestApiModule; +import com.google.inject.servlet.ServletModule; + +public class WebModule extends ServletModule { + + @Override + protected void configureServlets() { + install(new RestApiModule() { + @Override + protected void configure() { + filterRegex(".*\\.js").through(XAuthFilter.class); + } + }); + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/XAuthFilter.java b/src/main/java/com/googlesource/gerrit/plugins/manager/XAuthFilter.java new file mode 100644 index 0000000..68874be --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/manager/XAuthFilter.java
@@ -0,0 +1,97 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// 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.googlesource.gerrit.plugins.manager; + +import com.google.gerrit.extensions.registration.DynamicItem; +import com.google.gerrit.httpd.WebSession; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +@Singleton +public class XAuthFilter implements Filter { + private static final Logger log = LoggerFactory.getLogger(XAuthFilter.class); + + private DynamicItem<WebSession> webSession; + + @Inject + public XAuthFilter(DynamicItem<WebSession> webSession) { + this.webSession = webSession; + } + + @Override + public void destroy() { + } + + @Override + public void doFilter(ServletRequest req, ServletResponse resp, + FilterChain chain) throws IOException, ServletException { + HttpServletRequest httpReq = (HttpServletRequest) req; + HttpServletResponse httpResp = (HttpServletResponse) resp; + + final String gerritAuth = webSession.get().getXGerritAuth(); + if (gerritAuth != null) { + log.info("Injecting X-Gerrit-Auth for {}", httpReq.getRequestURI()); + httpResp = new HttpServletResponseWrapper(httpResp) { + + private int origContentLength; + + @Override + public void setHeader(String name, String value) { + log.info("{}: {}", name, value); + if (name.equalsIgnoreCase("Content-Length")) { + origContentLength = Integer.parseInt(value); + } else { + super.setHeader(name, value); + } + } + + @Override + public PrintWriter getWriter() throws IOException { + return super.getWriter(); + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + return new TokenReplaceOutputStream( + (HttpServletResponse) getResponse(), origContentLength, + "@X-Gerrit-Auth".getBytes(), gerritAuth.getBytes()); + } + }; + } + + chain.doFilter(req, httpResp); + } + + @Override + public void init(FilterConfig conf) throws ServletException { + } +}
diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html new file mode 100644 index 0000000..9d16466 --- /dev/null +++ b/src/main/resources/static/index.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html ng-app="PluginManager"> +<head> +<meta charset="UTF-8"> +<title>Gerrit Plugin Manager</title> +<script src= "https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script> +<script src="js/plugin-manager.js"></script> +</head> +<body> +<div ng-controller="LoadInstalledPlugins as plugins"> + <h1>Installed plugins</h1> + <ul> + <li ng-repeat="(key, prop) in plugins.list"> + {{key}} + </li> + </ul> +</div> +</body> +</html>
diff --git a/src/main/resources/static/js/plugin-manager.js b/src/main/resources/static/js/plugin-manager.js new file mode 100644 index 0000000..ad01b06 --- /dev/null +++ b/src/main/resources/static/js/plugin-manager.js
@@ -0,0 +1,35 @@ +// Copyright (C) 2015 The Android Open Source Project +// +// 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. + +var app = angular.module('PluginManager', []).controller( + 'LoadInstalledPlugins', + function($http) { + var plugins = this; + + plugins.list = {}; + + $http.get('/plugins/?all', plugins.httpConfig).then( + function successCallback(response) { + plugins.list = response.data; + }, function errorCallback(response) { + // called asynchronously if an error occurs + // or server returns response with an error status. + }); + }); + +app.config(function($httpProvider) { + $httpProvider.defaults.headers.common = { + 'X-Gerrit-Auth' : '@X-Gerrit-Auth' + }; +}); \ No newline at end of file