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