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