1 package club.wpia.gigi;
3 import static club.wpia.gigi.Gigi.*;
5 import java.awt.Desktop;
6 import java.io.BufferedReader;
7 import java.io.ByteArrayInputStream;
8 import java.io.ByteArrayOutputStream;
9 import java.io.DataOutputStream;
10 import java.io.FileInputStream;
11 import java.io.IOException;
12 import java.io.InputStreamReader;
13 import java.io.OutputStream;
14 import java.lang.reflect.Field;
15 import java.net.URISyntaxException;
17 import java.nio.file.Files;
18 import java.nio.file.Path;
19 import java.nio.file.Paths;
20 import java.util.Collections;
21 import java.util.HashMap;
23 import java.util.Properties;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27 import javax.servlet.http.HttpSession;
29 import org.kamranzafar.jtar.TarEntry;
30 import org.kamranzafar.jtar.TarHeader;
31 import org.kamranzafar.jtar.TarOutputStream;
33 import club.wpia.gigi.dbObjects.ObjectCache;
34 import club.wpia.gigi.dbObjects.User;
35 import club.wpia.gigi.localisation.Language;
36 import club.wpia.gigi.output.template.Template;
37 import club.wpia.gigi.output.template.TranslateCommand;
38 import club.wpia.gigi.pages.LoginPage;
39 import club.wpia.gigi.pages.Page;
40 import club.wpia.gigi.pages.account.certs.CertificateRequest;
41 import club.wpia.gigi.pages.main.RegisterPage;
42 import club.wpia.gigi.util.AuthorizationContext;
43 import club.wpia.gigi.util.ServerConstants;
44 import club.wpia.gigi.util.ServerConstants.Host;
46 public class DevelLauncher {
48 public static void main(String[] args) throws Exception {
49 Properties mainProps = new Properties();
50 try (FileInputStream inStream = new FileInputStream("config/gigi.properties")) {
51 mainProps.load(inStream);
53 for (int i = 0; i < args.length; i++) {
54 if (args[i].equals("--port")) {
55 mainProps.setProperty("port", args[i + 1]);
59 killPreviousInstance(mainProps);
61 ByteArrayOutputStream chunkConfig = new ByteArrayOutputStream();
62 DataOutputStream dos = new DataOutputStream(chunkConfig);
63 byte[] cacerts = Files.readAllBytes(Paths.get("config/cacerts.jks"));
64 byte[] keystore = null;
65 Path p = Paths.get("config/keystore.pkcs12");
66 if (p.toFile().exists()) {
67 keystore = Files.readAllBytes(p);
69 mainProps.setProperty("proxy", "true");
72 DevelLauncher.writeGigiConfig(dos, "changeit".getBytes("UTF-8"), "changeit".getBytes("UTF-8"), mainProps, cacerts, keystore);
74 new Launcher().boot(new ByteArrayInputStream(chunkConfig.toByteArray()));
76 new Thread("ticket awaiter") {
82 } catch (InterruptedException e) {
87 Desktop.getDesktop().browse(new URL("http://" + ServerConstants.getHostNamePort(Host.WWW) + "/ticketWait").toURI());
89 } catch (IOException e) {
91 } catch (URISyntaxException e) {
96 BufferedReader br = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
97 System.out.println("Gigi system sucessfully started.");
98 System.out.println("Press enter to shutdown.");
103 private static void killPreviousInstance(Properties mainProps) {
105 String targetPort = mainProps.getProperty("http.port");
106 String targetHost = mainProps.getProperty("name.www", "www." + mainProps.getProperty("name.suffix"));
107 URL u = new URL("http://" + targetHost + ":" + targetPort + "/kill");
109 } catch (IOException e) {
113 public static void addDevelPage(boolean withToken) {
115 Field instF = Gigi.class.getDeclaredField("instance");
116 Field pageF = Gigi.class.getDeclaredField("pages");
117 instF.setAccessible(true);
118 pageF.setAccessible(true);
119 Object gigi = instF.get(null);
121 // Check if we got a proper map (as much as we can tell)
122 Object pagesObj = pageF.get(gigi);
123 if ( !(pagesObj instanceof Map)) {
124 throw new Error("Invalid state when initializing page structure");
127 @SuppressWarnings("unchecked")
128 HashMap<String, Page> pages = new HashMap<>((Map<String, Page>) pagesObj);
130 pages.put("/manage", new Page("Page-manager") {
133 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
134 ObjectCache.clearAllCaches();
135 RegisterPage.RATE_LIMIT.bypass();
136 LoginPage.RATE_LIMIT.bypass();
137 CertificateRequest.RATE_LIMIT.bypass();
138 resp.getWriter().println("All caches cleared.");
139 System.out.println("Caches cleared.");
144 public boolean needsLogin() {
150 pages.put("/kill", new Page("Kill") {
153 * The contained call to {@link System#exit(int)} is mainly
154 * needed to kill this instance immediately if another
155 * {@link DevelLauncher} is booting up to free all ports This is
156 * required for fast development cycles.
158 * @see #killPreviousInstance(Properties)
161 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
166 public boolean needsLogin() {
172 addTicketPage(pages);
175 pageF.set(gigi, Collections.unmodifiableMap(pages));
176 } catch (ReflectiveOperationException e) {
181 static boolean ticketUsed = false;
183 private static void addTicketPage(HashMap<String, Page> pages) {
184 pages.put("/ticketWait", new Page("ticket") {
186 private final Template t = new Template(DevelLauncher.class.getResource("DevelTicketWait.templ"));
189 public boolean needsLogin() {
194 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
195 resp.setHeader("content-security-policy", "");
196 t.output(resp.getWriter(), getLanguage(req), new HashMap<String, Object>());
200 pages.put("/ticket", new Page("ticket") {
203 public boolean beforeTemplate(HttpServletRequest req, HttpServletResponse resp) throws IOException {
204 // TODO Auto-generated method stub
206 HttpSession sess = req.getSession();
207 User user = User.getById(1);
209 resp.getWriter().println("ticket consumed but no user available for that action");
213 sess.setAttribute(LOGGEDIN, true);
214 sess.setAttribute(Language.SESSION_ATTRIB_NAME, user.getPreferredLocale());
215 sess.setAttribute(AUTH_CONTEXT, new AuthorizationContext(user, user));
216 req.getSession().setAttribute(LOGIN_METHOD, new TranslateCommand("Ticket"));
217 resp.getWriter().println("ticket consumed");
224 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {}
227 public boolean needsLogin() {
233 public static void writeGigiConfig(OutputStream target, byte[] keystorepw, byte[] truststorepw, Properties mainprop, byte[] cacerts, byte[] keystore) throws IOException {
234 TarOutputStream tos = new TarOutputStream(target);
235 ByteArrayOutputStream baos = new ByteArrayOutputStream();
236 mainprop.store(baos, "");
238 putTarEntry(baos.toByteArray(), tos, "gigi.properties");
239 putTarEntry(keystorepw, tos, "keystorepw");
240 putTarEntry(truststorepw, tos, "truststorepw");
241 putTarEntry(keystore, tos, "keystore.pkcs12");
242 putTarEntry(cacerts, tos, "cacerts.jks");
247 private static void putTarEntry(byte[] data, TarOutputStream tos, String name) throws IOException {
251 TarHeader th = new TarHeader();
252 th.name = new StringBuffer(name);
253 th.size = data.length;
254 tos.putNextEntry(new TarEntry(th));