]> WPIA git - gigi.git/blob - util-testing/org/cacert/gigi/DevelLauncher.java
736947d55ac566675d62c25b93d06fa2120058ff
[gigi.git] / util-testing / org / cacert / gigi / DevelLauncher.java
1 package org.cacert.gigi;
2
3 import static org.cacert.gigi.Gigi.*;
4
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.InputStream;
13 import java.io.InputStreamReader;
14 import java.io.OutputStream;
15 import java.lang.reflect.Field;
16 import java.net.URISyntaxException;
17 import java.net.URL;
18 import java.nio.file.Files;
19 import java.nio.file.Path;
20 import java.nio.file.Paths;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.Properties;
25
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28 import javax.servlet.http.HttpSession;
29
30 import org.cacert.gigi.dbObjects.ObjectCache;
31 import org.cacert.gigi.dbObjects.User;
32 import org.cacert.gigi.localisation.Language;
33 import org.cacert.gigi.output.template.Template;
34 import org.cacert.gigi.output.template.TranslateCommand;
35 import org.cacert.gigi.pages.LoginPage;
36 import org.cacert.gigi.pages.Page;
37 import org.cacert.gigi.pages.account.certs.CertificateRequest;
38 import org.cacert.gigi.pages.main.RegisterPage;
39 import org.cacert.gigi.util.AuthorizationContext;
40 import org.cacert.gigi.util.ServerConstants;
41 import org.kamranzafar.jtar.TarEntry;
42 import org.kamranzafar.jtar.TarHeader;
43 import org.kamranzafar.jtar.TarOutputStream;
44
45 public class DevelLauncher {
46
47     public static void main(String[] args) throws Exception {
48         Properties mainProps = new Properties();
49         try (FileInputStream inStream = new FileInputStream("config/gigi.properties")) {
50             mainProps.load(inStream);
51         }
52         for (int i = 0; i < args.length; i++) {
53             if (args[i].equals("--port")) {
54                 mainProps.setProperty("port", args[i + 1]);
55             }
56             i++;
57         }
58         killPreviousInstance(mainProps);
59
60         ByteArrayOutputStream chunkConfig = new ByteArrayOutputStream();
61         DataOutputStream dos = new DataOutputStream(chunkConfig);
62         byte[] cacerts = Files.readAllBytes(Paths.get("config/cacerts.jks"));
63         byte[] keystore = null;
64         Path p = Paths.get("config/keystore.pkcs12");
65         if (p.toFile().exists()) {
66             keystore = Files.readAllBytes(p);
67         } else {
68             mainProps.setProperty("proxy", "true");
69         }
70
71         DevelLauncher.writeGigiConfig(dos, "changeit".getBytes("UTF-8"), "changeit".getBytes("UTF-8"), mainProps, cacerts, keystore);
72         dos.flush();
73         InputStream oldin = System.in;
74         System.setIn(new ByteArrayInputStream(chunkConfig.toByteArray()));
75         new Launcher().boot();
76         addDevelPage(true);
77         new Thread("ticket awaiter") {
78
79             @Override
80             public void run() {
81                 try {
82                     Thread.sleep(8000);
83                 } catch (InterruptedException e) {
84                     e.printStackTrace();
85                 }
86                 try {
87                     if ( !ticketUsed) {
88                         Desktop.getDesktop().browse(new URL("http://" + ServerConstants.getWwwHostNamePort() + "/ticketWait").toURI());
89                     }
90                 } catch (IOException e) {
91                     e.printStackTrace();
92                 } catch (URISyntaxException e) {
93                     e.printStackTrace();
94                 }
95             }
96         }.start();
97         System.setIn(oldin);
98         BufferedReader br = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
99         System.out.println("Cacert-gigi system sucessfully started.");
100         System.out.println("Press enter to shutdown.");
101         br.readLine();
102         System.exit(0);
103     }
104
105     private static void killPreviousInstance(Properties mainProps) {
106         try {
107             String targetPort = mainProps.getProperty("http.port");
108             String targetHost = mainProps.getProperty("name.www");
109             URL u = new URL("http://" + targetHost + ":" + targetPort + "/kill");
110             u.openStream();
111         } catch (IOException e) {
112         }
113     }
114
115     public static void addDevelPage(boolean withToken) {
116         try {
117             Field instF = Gigi.class.getDeclaredField("instance");
118             Field pageF = Gigi.class.getDeclaredField("pages");
119             instF.setAccessible(true);
120             pageF.setAccessible(true);
121             Object gigi = instF.get(null);
122
123             // Check if we got a proper map (as much as we can tell)
124             Object pagesObj = pageF.get(gigi);
125             if ( !(pagesObj instanceof Map)) {
126                 throw new Error("Invalid state when initializing page structure");
127             }
128
129             @SuppressWarnings("unchecked")
130             HashMap<String, Page> pages = new HashMap<>((Map<String, Page>) pagesObj);
131
132             pages.put("/manage", new Page("Page-manager") {
133
134                 @Override
135                 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
136                     ObjectCache.clearAllCaches();
137                     RegisterPage.RATE_LIMIT.bypass();
138                     LoginPage.RATE_LIMIT.bypass();
139                     CertificateRequest.RATE_LIMIT.bypass();
140                     resp.getWriter().println("All caches cleared.");
141                     System.out.println("Caches cleared.");
142
143                 }
144
145                 @Override
146                 public boolean needsLogin() {
147                     return false;
148                 }
149
150             });
151
152             pages.put("/kill", new Page("Kill") {
153
154                 /**
155                  * The contained call to {@link System#exit(int)} is mainly
156                  * needed to kill this instance immediately if another
157                  * {@link DevelLauncher} is booting up to free all ports This is
158                  * required for fast development cycles.
159                  * 
160                  * @see #killPreviousInstance(Properties)
161                  */
162                 @Override
163                 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
164                     System.exit(0);
165                 }
166
167                 @Override
168                 public boolean needsLogin() {
169                     return false;
170                 }
171             });
172
173             if (withToken) {
174                 addTicketPage(pages);
175             }
176
177             pageF.set(gigi, Collections.unmodifiableMap(pages));
178         } catch (ReflectiveOperationException e) {
179             e.printStackTrace();
180         }
181     }
182
183     static boolean ticketUsed = false;
184
185     private static void addTicketPage(HashMap<String, Page> pages) {
186         pages.put("/ticketWait", new Page("ticket") {
187
188             private final Template t = new Template(DevelLauncher.class.getResource("DevelTicketWait.templ"));
189
190             @Override
191             public boolean needsLogin() {
192                 return false;
193             }
194
195             @Override
196             public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
197                 resp.setHeader("content-security-policy", "");
198                 t.output(resp.getWriter(), getLanguage(req), new HashMap<String, Object>());
199             }
200
201         });
202         pages.put("/ticket", new Page("ticket") {
203
204             @Override
205             public boolean beforeTemplate(HttpServletRequest req, HttpServletResponse resp) throws IOException {
206                 // TODO Auto-generated method stub
207                 if ( !ticketUsed) {
208                     HttpSession sess = req.getSession();
209                     User user = User.getById(1);
210                     if (user == null) {
211                         resp.getWriter().println("ticket consumed but no user available for that action");
212                         ticketUsed = true;
213                         return true;
214                     }
215                     sess.setAttribute(LOGGEDIN, true);
216                     sess.setAttribute(Language.SESSION_ATTRIB_NAME, user.getPreferredLocale());
217                     sess.setAttribute(AUTH_CONTEXT, new AuthorizationContext(user, user));
218                     req.getSession().setAttribute(LOGIN_METHOD, new TranslateCommand("Ticket"));
219                     resp.getWriter().println("ticket consumed");
220                     ticketUsed = true;
221                 }
222                 return true;
223             }
224
225             @Override
226             public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {}
227
228             @Override
229             public boolean needsLogin() {
230                 return false;
231             }
232         });
233     }
234
235     public static void writeGigiConfig(OutputStream target, byte[] keystorepw, byte[] truststorepw, Properties mainprop, byte[] cacerts, byte[] keystore) throws IOException {
236         TarOutputStream tos = new TarOutputStream(target);
237         ByteArrayOutputStream baos = new ByteArrayOutputStream();
238         mainprop.store(baos, "");
239
240         putTarEntry(baos.toByteArray(), tos, "gigi.properties");
241         putTarEntry(keystorepw, tos, "keystorepw");
242         putTarEntry(truststorepw, tos, "truststorepw");
243         putTarEntry(keystore, tos, "keystore.pkcs12");
244         putTarEntry(cacerts, tos, "cacerts.jks");
245         tos.close();
246
247     }
248
249     private static void putTarEntry(byte[] data, TarOutputStream tos, String name) throws IOException {
250         if (data == null) {
251             return;
252         }
253         TarHeader th = new TarHeader();
254         th.name = new StringBuffer(name);
255         th.size = data.length;
256         tos.putNextEntry(new TarEntry(th));
257         tos.write(data);
258     }
259
260 }