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