source: apps/i2ptunnel/jsp/ssl.jsp @ d8516862

Last change on this file since d8516862 was d8516862, checked in by zzz <zzz@…>, 3 years ago

SSL Wizard: Add links

  • Property mode set to 100644
File size: 39.8 KB
Line 
1<%
2    // NOTE: Do the header carefully so there is no whitespace before the <?xml... line
3
4    response.setHeader("X-Frame-Options", "SAMEORIGIN");
5    response.setHeader("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'");
6    response.setHeader("X-XSS-Protection", "1; mode=block");
7    response.setHeader("X-Content-Type-Options", "nosniff");
8    response.setHeader("Referrer-Policy", "no-referrer");
9    response.setHeader("Accept-Ranges", "none");
10
11%><%@page pageEncoding="UTF-8"
12%><%@page contentType="text/html" import="java.io.File,java.io.IOException,net.i2p.crypto.KeyStoreUtil,net.i2p.data.DataHelper,net.i2p.jetty.JettyXmlConfigurationParser"
13%><%@page
14%><?xml version="1.0" encoding="UTF-8"?>
15<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
16<%
17  /* right now using EditBean instead of IndexBean for getSpoofedHost() */
18  /* but might want to POST to it anyway ??? */
19%>
20<jsp:useBean class="net.i2p.i2ptunnel.web.EditBean" id="editBean" scope="request" />
21<jsp:useBean class="net.i2p.i2ptunnel.ui.Messages" id="intl" scope="request" />
22<%
23   String tun = request.getParameter("tunnel");
24   int curTunnel = -1;
25   if (tun != null) {
26     try {
27       curTunnel = Integer.parseInt(tun);
28     } catch (NumberFormatException nfe) {
29       curTunnel = -1;
30     }
31   }
32%>
33<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
34<head>
35    <title><%=intl._t("Hidden Services Manager")%> - <%=intl._t("SSL Helper")%></title>
36    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
37    <link href="/themes/console/images/favicon.ico" type="image/x-icon" rel="shortcut icon" />
38    <% if (editBean.allowCSS()) {
39  %><link rel="icon" href="<%=editBean.getTheme()%>images/favicon.ico" />
40    <link href="<%=editBean.getTheme()%>i2ptunnel.css?<%=net.i2p.CoreVersion.VERSION%>" rel="stylesheet" type="text/css" /> 
41    <% }
42  %>
43<style type='text/css'>
44input.default { width: 1px; height: 1px; visibility: hidden; }
45</style>
46</head>
47<body id="tunnelSSL">
48<%
49
50  net.i2p.I2PAppContext ctx = net.i2p.I2PAppContext.getGlobalContext();
51  if (!ctx.isRouterContext()) {
52      %>Unsupported in app context<%
53  } else if (curTunnel < 0) {
54      %>Tunnel not found<% 
55  } else if (editBean.isClient(curTunnel)) {
56      %>Not supported for client tunnels<%
57  } else if (editBean.isInitialized()) {
58
59%>
60<div class="panel" id="ssl">
61<%
62    String tunnelTypeName;
63    String tunnelType;
64    boolean valid = false;
65    tunnelTypeName = editBean.getTunnelType(curTunnel);
66    tunnelType = editBean.getInternalType(curTunnel);
67%><h2><%=intl._t("SSL Wizard")%> (<%=editBean.getTunnelName(curTunnel)%>)</h2><% 
68
69    // set a bunch of variables for the current configuration
70    String b64 = editBean.getDestinationBase64(curTunnel);
71    String b32 = editBean.getDestHashBase32(curTunnel);
72    // todo
73    String altb32 = editBean.getAltDestHashBase32(curTunnel);
74    String name = editBean.getSpoofedHost(curTunnel);
75    // non-null, default 127.0.0.1
76    String targetHost = editBean.getTargetHost(curTunnel);
77    if (targetHost.indexOf(':') >= 0)
78        targetHost = '[' + targetHost + ']';
79    // non-null, default ""
80    String targetPort = editBean.getTargetPort(curTunnel);
81    int intPort = 0;
82    try {
83        intPort = Integer.parseInt(targetPort);
84    } catch (NumberFormatException nfe) {}
85    String clientTgt = targetHost + ':' + targetPort;
86    boolean sslToTarget = editBean.isSSLEnabled(curTunnel);
87    String targetLink = clientTgt;
88    boolean shouldLinkify = true;
89    if (shouldLinkify) {
90        String url = "://" + clientTgt + "\">" + clientTgt + "</a>";
91        if (sslToTarget)
92            targetLink = "<a href=\"https" + url;
93        else
94            targetLink = "<a href=\"http" + url;
95    }
96    net.i2p.util.PortMapper pm = ctx.portMapper();
97    int jettyPort = pm.getPort(net.i2p.util.PortMapper.SVC_EEPSITE);
98    int jettySSLPort = pm.getPort(net.i2p.util.PortMapper.SVC_HTTPS_EEPSITE);
99
100    if (name == null || name.equals(""))
101        name = editBean.getTunnelName(curTunnel);
102    if (!"new".equals(tunnelType)) {
103        // build tables for vhost and targets
104        java.util.TreeSet<Integer> ports = new java.util.TreeSet<Integer>();
105        java.util.Map<Integer, String> tgts = new java.util.HashMap<Integer, String>(4);
106        java.util.Map<Integer, String> spoofs = new java.util.HashMap<Integer, String>(4);
107        String custom = editBean.getCustomOptions(curTunnel);
108        String[] opts = DataHelper.split(custom, "[, ]");
109        for (int i = 0; i < opts.length; i++) {
110            String opt = opts[i];
111            boolean isTgt = false;
112            if (opt.startsWith("targetForPort.")) {
113                opt = opt.substring("targetForPort.".length());
114                isTgt = true;
115            } else if (opt.startsWith("spoofedHost.")) {
116                opt = opt.substring("spoofedHost.".length());
117            } else {
118                 continue;
119            }
120            int eq = opt.indexOf('=');
121            if (eq <= 0)
122                 continue;
123            int port;
124            try {
125                port = Integer.parseInt(opt.substring(0, eq));
126            } catch (NumberFormatException nfe) {
127                 continue;
128            }
129            String tgt = opt.substring(eq + 1);
130            Integer iport = Integer.valueOf(port);
131            ports.add(iport);
132            if (isTgt)
133                tgts.put(iport, tgt);
134            else
135                spoofs.put(iport, tgt);
136        }
137
138        // POST handling
139        String action = request.getParameter("action");
140        if (action != null) {
141            StringBuilder msgs = new StringBuilder();
142            String nonce = request.getParameter("nonce");
143            String newpw = request.getParameter("nofilter_keyPassword");
144            String kspw = request.getParameter("nofilter_obfKeyStorePassword");
145            String appNum = request.getParameter("clientAppNumber");
146            String ksPath = request.getParameter("nofilter_ksPath");
147            String jettySSLConfigPath = request.getParameter("nofilter_jettySSLFile");
148            String host = request.getParameter("jettySSLHost");
149            String port = request.getParameter("jettySSLPort");
150            if (newpw != null) {
151                newpw = newpw.trim();
152                if (newpw.length() <= 0)
153                    newpw = null;
154            }
155            if (kspw != null) {
156                kspw = JettyXmlConfigurationParser.deobfuscate(kspw);
157            } else {
158                kspw = net.i2p.crypto.KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD;
159            }
160            if (!net.i2p.i2ptunnel.web.IndexBean.haveNonce(nonce)) {
161                msgs.append(intl._t("Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit."))
162                    .append('\n')
163                    .append(intl._t("If the problem persists, verify that you have cookies enabled in your browser."))
164                    .append('\n');
165            } else if (!action.equals("Generate") && !action.equals("Enable") && !action.equals("Disable")) {
166                msgs.append("Unknown form action\n");
167            } else if (action.equals("Generate") && newpw == null) {
168                msgs.append("Password required\n");
169            } else if (appNum == null || ksPath == null || jettySSLConfigPath == null || host == null || port == null) {
170                msgs.append("Missing parameters\n");
171            } else if (b32.length() <= 0) {
172                msgs.append("No destination set - start tunnel first\n");
173            } else if (name == null || !name.endsWith(".i2p")) {
174                msgs.append("No hostname set - go back and configure\n");
175            } else if (intPort <= 0) {
176                msgs.append("No target port set - go back and configure\n");
177            } else {
178                boolean ok = true;
179
180                if (action.equals("Generate")) {
181                    // generate selfsigned cert
182                    java.util.Set<String> altNames = new java.util.HashSet<String>(4);
183                    altNames.add(b32);
184                    altNames.add(name);
185                    if (!name.startsWith("www."))
186                        altNames.add("www." + name);
187                    if (altb32 != null && altb32.length() > 0)
188                        altNames.add(altb32);
189                    altNames.addAll(spoofs.values());
190                    File ks = new File(ksPath);
191                    if (ks.exists()) {
192                        // old ks if any must be moved or deleted, as any keys
193                        // under different alias for a different chain will confuse jetty
194                        File ksb = new File(ksPath + ".bkup");
195                        if (ksb.exists())
196                            ksb = new File(ksPath + '-' + System.currentTimeMillis() + ".bkup");
197                        boolean rok = net.i2p.util.FileUtil.rename(ks, ksb);
198                        if (!rok)
199                            ks.delete();
200                    }
201                    try {
202                        Object[] rv = net.i2p.crypto.KeyStoreUtil.createKeysAndCRL(ks, kspw, "eepsite", name, altNames, b32,
203                                                                                   3652, "EC", 256, newpw);
204                        msgs.append("Created selfsigned cert\n");
205                        // save cert
206                        java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) rv[2];
207                        File f = new net.i2p.util.SecureFile(ctx.getConfigDir(), "certificates");
208                        if (!f.exists())
209                            f.mkdir();
210                        f = new net.i2p.util.SecureFile(f, "eepsite");
211                        if (!f.exists())
212                            f.mkdir();
213                        f = new net.i2p.util.SecureFile(f, b32 + ".crt");
214                        if (f.exists()) {
215                            File fb = new File(f.getParentFile(), b32 + ".crt-" + System.currentTimeMillis() + ".bkup");
216                            net.i2p.util.FileUtil.copy(f, fb, false, true);
217                        }
218                        ok = net.i2p.crypto.CertUtil.saveCert(cert, f);
219                        if (ok)
220                            msgs.append("selfsigned cert stored\n");
221                        else
222                            msgs.append("selfsigned cert store failed\n");
223                    } catch (IOException ioe) {
224                        ioe.printStackTrace();
225                        msgs.append("selfsigned cert store failed ").append(DataHelper.escapeHTML(ioe.toString())).append('\n');
226                        ok = false;
227                    } catch (java.security.GeneralSecurityException gse) {
228                        gse.printStackTrace();
229                        msgs.append("selfsigned cert store failed ").append(DataHelper.escapeHTML(gse.toString())).append('\n');
230                        ok = false;
231                    }
232
233                    // rewrite jetty-ssl.xml
234                    if (ok) {
235                        String obf = JettyXmlConfigurationParser.obfuscate(newpw);
236                        String obfkspw = JettyXmlConfigurationParser.obfuscate(kspw);
237                        File f = new File(jettySSLConfigPath);
238                        try {
239                            org.eclipse.jetty.xml.XmlParser.Node root;
240                            root = JettyXmlConfigurationParser.parse(f);
241                            JettyXmlConfigurationParser.setValue(root, "KeyStorePath", ksPath);
242                            JettyXmlConfigurationParser.setValue(root, "TrustStorePath", ksPath);
243                            JettyXmlConfigurationParser.setValue(root, "KeyStorePassword", obfkspw);
244                            JettyXmlConfigurationParser.setValue(root, "TrustStorePassword", obfkspw);
245                            JettyXmlConfigurationParser.setValue(root, "KeyManagerPassword", obf);
246                            File fb = new File(jettySSLConfigPath + ".bkup");
247                            if (fb.exists())
248                                fb = new File(jettySSLConfigPath + '-' + System.currentTimeMillis() + ".bkup");
249                            ok = net.i2p.util.FileUtil.copy(f, fb, false, true);
250                            if (ok) {
251                                java.io.Writer w = null;
252                                try {
253                                    w = new java.io.OutputStreamWriter(new net.i2p.util.SecureFileOutputStream(f), "UTF-8");
254                                    w.write("<?xml version=\"1.0\"?>\n" +
255                                            "<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"http://www.eclipse.org/jetty/configure.dtd\">\n\n" +
256                                            "<!-- Modified by SSL Wizard -->\n\n");
257                                    JettyXmlConfigurationParser.write(root, w);
258                                    msgs.append("Jetty configuration updated\n");
259                                } catch (IOException ioe) {
260                                    ioe.printStackTrace();
261                                    ok = false;
262                                } finally {
263                                    if (w != null) try { w.close(); } catch (IOException ioe2) {}
264                                }
265                            } else {
266                                msgs.append("Jetty configuration backup failed");
267                            }
268                        } catch (org.xml.sax.SAXException saxe) {
269                            saxe.printStackTrace();
270                            msgs.append("Jetty config parse failed ").append(DataHelper.escapeHTML(saxe.toString())).append('\n');
271                            ok = false;
272                        }
273                    }
274                }  // action == Generate
275
276                // rewrite clients.config
277                boolean isSSLEnabled = Boolean.parseBoolean(request.getParameter("isSSLEnabled"));
278                boolean addssl = ok && !isSSLEnabled && !action.equals("Disable");
279                boolean delssl = ok && isSSLEnabled && action.equals("Disable");
280                if (addssl || delssl) {
281                    File f = new File(ctx.getConfigDir(), "clients.config");
282                    java.util.Properties p = new net.i2p.util.OrderedProperties();
283                    try {
284                        DataHelper.loadProps(p, f);
285                        String k = "clientApp." + appNum + ".args";
286                        String v = p.getProperty(k);
287                        if (v == null) {
288                            ok = false;
289                        } else if (addssl) {
290                            // TODO use net.i2p.i2ptunnel.web.SSLHelper.parseArgs(v) instead?
291                            if (!v.contains(jettySSLConfigPath)) {
292                                v += " \"" + jettySSLConfigPath + '"';
293                                p.setProperty(k, v);
294                                DataHelper.storeProps(p, f);
295                                msgs.append("Jetty SSL enabled\n");
296                            }
297                        } else {
298                            // action = disable
299                            boolean save = false;
300                            java.util.List<String> argList = net.i2p.i2ptunnel.web.SSLHelper.parseArgs(v);
301                            if (argList.remove(jettySSLConfigPath)) {
302                                StringBuilder buf = new StringBuilder(v.length());
303                                for (String arg : argList) {
304                                     buf.append(arg).append(' ');
305                                }
306                                v = buf.toString().trim();
307                                p.setProperty(k, v);
308                                DataHelper.storeProps(p, f);
309                                msgs.append("Jetty SSL disabled\n");
310                            }
311                        }
312                    } catch (IOException ioe) {
313                        ioe.printStackTrace();
314                        ok = false;
315                    }
316                }
317
318                // stop and restart jetty
319                // this only works if running already, else it isn't registered
320                net.i2p.app.ClientAppManager cmgr = ctx.clientAppManager();
321                net.i2p.app.ClientApp jstart = cmgr.getRegisteredApp("Jetty");
322                if (ok && jstart != null) {
323                    String fullname = jstart.getDisplayName();
324                    if (fullname.contains(jettySSLConfigPath) ||
325                        fullname.contains(jettySSLConfigPath.replace("jetty-ssl.xml", "jetty.xml"))) {
326                        // ok, this is probably the right ClientApp
327                        net.i2p.app.ClientAppState state = jstart.getState();
328                        if (state == net.i2p.app.ClientAppState.RUNNING) {
329                            try {
330                                // app becomes untracked,
331                                // see workaround in RouterAppManager
332                                jstart.shutdown(null);
333                                for (int i = 0; i < 20; i++) {
334                                    state = jstart.getState();
335                                    if (state == net.i2p.app.ClientAppState.STOPPED) {
336                                        if (i < 4) {
337                                            try { Thread.sleep(1000); } catch (InterruptedException ie) { break; }
338                                        }
339                                        msgs.append("Jetty server stopped\n");
340                                        break;
341                                    }
342                                    try { Thread.sleep(250); } catch (InterruptedException ie) { break; }
343                                }
344                                if (state != net.i2p.app.ClientAppState.STOPPED)
345                                    msgs.append("Jetty server stop failed\n");
346                            } catch (Throwable t) {
347                                msgs.append("Jetty server stop failed: " + t + '\n');
348                            }
349                        }
350                        if (state == net.i2p.app.ClientAppState.STOPPED) {
351                            try {
352                                jstart.startup();
353                                for (int i = 0; i < 20; i++) {
354                                    state = jstart.getState();
355                                    if (state == net.i2p.app.ClientAppState.RUNNING) {
356                                        msgs.append("Jetty server restarted\n");
357                                        break;
358                                    }
359                                    try { Thread.sleep(250); } catch (InterruptedException ie) { break; }
360                                }
361                                if (state != net.i2p.app.ClientAppState.RUNNING)
362                                    msgs.append("Jetty server start failed\n");
363                            } catch (Throwable t) {
364                                msgs.append("Jetty server start failed: " + t + '\n');
365                                ok = false;
366                            }
367                        }
368                    } else {
369                        //msgs.append("Unable to restart Jetty server\n");
370                        msgs.append("You must start the Jetty server on <a href=\"/configclients\">the configure clients page</a>.\n");
371                    }
372                } else if (ok) {
373                    //msgs.append("Unable to restart Jetty server\n");
374                    msgs.append("You must start the Jetty server on <a href=\"/configclients\">the configure clients page</a>.\n");
375                }
376
377                // rewrite i2ptunnel.config
378                Integer i443 = Integer.valueOf(443);
379                boolean addtgt = ok && !tgts.containsKey(i443) && !action.equals("Disable");
380                boolean deltgt = ok && tgts.containsKey(i443) && action.equals("Disable");
381                if (addtgt || deltgt) {
382                    if (addtgt) {
383                        // update table for display
384                        tgts.put(i443, host + ':' + port);
385                        ports.add(i443);
386                        // add ssl config
387                        custom += " targetForPort.443=" + host + ':' + port;
388                    } else {
389                        // update table for display
390                        tgts.remove(i443);
391                        ports.remove(i443);
392                        // remove ssl config
393                        StringBuilder newCust = new StringBuilder(custom.length());
394                        for (int i = 0; i < opts.length; i++) {
395                             String opt = opts[i];
396                             if (opt.startsWith("targetForPort.443="))
397                                 continue;
398                             newCust.append(opt).append(' ');
399                        }
400                        custom = newCust.toString().trim();
401                    }
402                    editBean.setNofilter_customOptions(custom);
403                    // copy over existing settings
404                    // we only set the applicable server settings
405                    editBean.setTunnel(tun);
406                    editBean.setType(tunnelType);
407                    editBean.setName(editBean.getTunnelName(curTunnel));
408                    editBean.setTargetHost(editBean.getTargetHost(curTunnel));
409                    editBean.setTargetPort(editBean.getTargetPort(curTunnel));
410                    editBean.setSpoofedHost(editBean.getSpoofedHost(curTunnel));
411                    editBean.setPrivKeyFile(editBean.getPrivateKeyFile(curTunnel));
412                    editBean.setAltPrivKeyFile(editBean.getAltPrivateKeyFile(curTunnel));
413                    editBean.setNofilter_description(editBean.getTunnelDescription(curTunnel));
414                    editBean.setTunnelDepth(Integer.toString(editBean.getTunnelDepth(curTunnel, 3)));
415                    editBean.setTunnelQuantity(Integer.toString(editBean.getTunnelQuantity(curTunnel, 2)));
416                    editBean.setTunnelBackupQuantity(Integer.toString(editBean.getTunnelBackupQuantity(curTunnel, 0)));
417                    editBean.setTunnelVariance(Integer.toString(editBean.getTunnelVariance(curTunnel, 0)));
418                    editBean.setTunnelDepthOut(Integer.toString(editBean.getTunnelDepthOut(curTunnel, 3)));
419                    editBean.setTunnelQuantityOut(Integer.toString(editBean.getTunnelQuantityOut(curTunnel, 2)));
420                    editBean.setTunnelBackupQuantityOut(Integer.toString(editBean.getTunnelBackupQuantityOut(curTunnel, 0)));
421                    editBean.setTunnelVarianceOut(Integer.toString(editBean.getTunnelVarianceOut(curTunnel, 0)));
422                    editBean.setReduceCount(Integer.toString(editBean.getReduceCount(curTunnel)));
423                    editBean.setReduceTime(Integer.toString(editBean.getReduceTime(curTunnel)));
424                    editBean.setCert(Integer.toString(editBean.getCert(curTunnel)));
425                    editBean.setLimitMinute(Integer.toString(editBean.getLimitMinute(curTunnel)));
426                    editBean.setLimitHour(Integer.toString(editBean.getLimitHour(curTunnel)));
427                    editBean.setLimitDay(Integer.toString(editBean.getLimitDay(curTunnel)));
428                    editBean.setTotalMinute(Integer.toString(editBean.getTotalMinute(curTunnel)));
429                    editBean.setTotalHour(Integer.toString(editBean.getTotalHour(curTunnel)));
430                    editBean.setTotalDay(Integer.toString(editBean.getTotalDay(curTunnel)));
431                    editBean.setMaxStreams(Integer.toString(editBean.getMaxStreams(curTunnel)));
432                    editBean.setPostMax(Integer.toString(editBean.getPostMax(curTunnel)));
433                    editBean.setPostTotalMax(Integer.toString(editBean.getPostTotalMax(curTunnel)));
434                    editBean.setPostCheckTime(Integer.toString(editBean.getPostCheckTime(curTunnel)));
435                    editBean.setPostBanTime(Integer.toString(editBean.getPostBanTime(curTunnel)));
436                    editBean.setPostTotalBanTime(Integer.toString(editBean.getPostTotalBanTime(curTunnel)));
437                    editBean.setUserAgents(editBean.getUserAgents(curTunnel));
438                    editBean.setEncryptKey(editBean.getEncryptKey(curTunnel));
439                    editBean.setAccessMode(editBean.getAccessMode(curTunnel));
440                    editBean.setAccessList(editBean.getAccessList(curTunnel));
441                    editBean.setKey1(editBean.getKey1(curTunnel));
442                    editBean.setKey2(editBean.getKey2(curTunnel));
443                    editBean.setKey3(editBean.getKey3(curTunnel));
444                    editBean.setKey4(editBean.getKey4(curTunnel));
445                    if (editBean.getMultihome(curTunnel))
446                        editBean.setMultihome("");
447                    if (editBean.getReduce(curTunnel))
448                        editBean.setReduce("");
449                    if (editBean.getEncrypt(curTunnel))
450                        editBean.setEncrypt("");
451                    if (editBean.getUniqueLocal(curTunnel))
452                        editBean.setUniqueLocal("");
453                    if (editBean.isRejectInproxy(curTunnel))
454                        editBean.setRejectInproxy("");
455                    if (editBean.isRejectReferer(curTunnel))
456                        editBean.setRejectReferer("");
457                    if (editBean.isRejectUserAgents(curTunnel))
458                        editBean.setRejectUserAgents("");
459                    editBean.setNonce(nonce);
460                    editBean.setAction("Save changes");
461                    String msg = editBean.getMessages();
462                    msgs.append(msg);
463                }
464            }
465%>
466<div class="panel" id="messages">
467    <h2><%=intl._t("Status Messages")%></h2>
468    <table id="statusMessagesTable">
469        <tr>
470            <td id="tunnelMessages">
471        <textarea id="statusMessages" rows="4" cols="60" readonly="readonly"><%=msgs%></textarea>
472            </td>
473        </tr>
474    </table>
475</div>
476<%
477        } // action != null
478
479%>
480
481<form method="post" action="ssl" accept-charset="UTF-8">
482<input type="hidden" name="tunnel" value="<%=curTunnel%>" />
483<input type="hidden" name="nonce" value="<%=net.i2p.i2ptunnel.web.IndexBean.getNextNonce()%>" />
484<input type="hidden" name="type" value="<%=tunnelType%>" />
485<input type="submit" class="default" name="action" value="Save changes" />
486<table>
487<tr><td colspan="4" class="infohelp"><%=intl._t("Experts only!")%> Beta!</td></tr>
488<tr><td colspan="4"><b><%=intl._t("Tunnel name")%>:</b> <%=editBean.getTunnelName(curTunnel)%></td></tr>
489<%
490      if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) {
491%>
492<tr><td colspan="4"><b><%=intl._t("Website name")%>:</b> <%=editBean.getSpoofedHost(curTunnel)%></td></tr>
493<%
494       }
495       if (b64 == null || b64.length() < 516) {
496           %><tr><td class="infohelp"><%=intl._t("Local destination is not available. Start the tunnel.")%></td></tr><%
497       } else if (name == null || name.equals("") || name.contains(" ") || !name.endsWith(".i2p")) {
498           if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) {
499               %><tr><td class="infohelp"><%=intl._t("To enable registration verification, edit tunnel and set name (or website name) to a valid host name ending in '.i2p'")%></td></tr><%
500           } else {
501               %><tr><td class="infohelp"><%=intl._t("To enable registration verification, edit tunnel and set name to a valid host name ending in '.i2p'")%></td></tr><%
502           }
503       } else {
504           valid = true;
505%>
506<tr><td colspan="4"><b><%=intl._t("Base 32")%>:</b> <%=b32%></td></tr>
507<%
508    if (altb32 != null && altb32.length() > 0) {
509%>
510        <tr><td><%=intl._t("Alt Base 32")%>: <%=altb32%></td></tr>
511<%
512    }  // altb32
513%>
514<tr><th colspan="4"><%=intl._t("Incoming I2P Port Routing")%></th></tr>
515<tr><th><%=intl._t("Route From I2P Port")%></th><th><%=intl._t("With Virtual Host")%></th><th><%=intl._t("Via SSL?")%></th><th><%=intl._t("To Server Host:Port")%></th></tr>
516<tr><td><a href="http://<%=b32%>/"><%=intl._t("Default")%></a></td><td><%=name%></td><td><%=sslToTarget%></td><td><%=targetLink%></td></tr>
517<%
518    // output vhost and targets
519    for (Integer port : ports) {
520        boolean ssl = sslToTarget;
521        boolean sslPort = false;
522        String spoof = spoofs.get(port);
523        if (spoof == null)
524            spoof = name;
525        // can't spoof for HTTPS
526        if (port.intValue() == 443) {
527            spoof = b32;
528            if (altb32 != null && altb32.length() > 0)
529                spoof += "<br />" + altb32;
530            ssl = true;
531            sslPort = true;
532        }
533        String tgt = tgts.get(port);
534        if (tgt != null) {
535            if (shouldLinkify) {
536                String url = "://" + tgt + "\">" + tgt + "</a>";
537                if (ssl)
538                    tgt = "<a href=\"https" + url;
539                else
540                    tgt = "<a href=\"http" + url;
541            }
542        } else {
543            tgt = targetLink;
544        }
545        String portTgt = sslPort ? "https" : "http";
546%>
547<tr><td><a href="<%=portTgt%>://<%=b32%>:<%=port%>/"><%=port%></a></td><td><%=spoof%></td><td><%=ssl%></td><td><%=tgt%></td></tr>
548<%
549    }
550%>
551<%--
552<tr><th colspan="4"><%=intl._t("Add Port Routing")%></th></tr>
553<tr><td>
554    <input type="text" size="6" maxlength="5" id="i2pPort" name="i2pPort" title="<%=intl._t("Specify the port the server is running on")%>" value="" class="freetext port" placeholder="required" />
555</td><td>
556    <input type="text" size="20" id="websiteName" name="spoofedHost" title="<%=intl._t("Website Hostname e.g. mysite.i2p")%>" value="<%=name%>" class="freetext" />
557</td><td>
558    <input value="1" type="checkbox" name="useSSL" class="tickbox" />
559</td><td>
560    <input type="text" size="20" name="targetHost" title="<%=intl._t("Hostname or IP address of the target server")%>" value="<%=targetHost%>" class="freetext host" /> :
561    <input type="text" size="6" maxlength="5" id="targetPort" name="targetPort" title="<%=intl._t("Specify the port the server is running on")%>" value="" class="freetext port" placeholder="required" />
562</td></tr>
563--%>
564<tr><th colspan="4"><%=intl._t("Jetty Server")%></th></tr>
565<tr><th><%=intl._t("Server")%></th><th><%=intl._t("Configuration Files")%></th><th><%=intl._t("Enabled?")%></th><th><%=intl._t("SSL Enabled?")%></th></tr>
566<%
567    // Now try to find the Jetty server in clients.config
568    File configDir = ctx.getConfigDir();
569    File clientsConfig = new File(configDir, "clients.config");
570    java.util.Properties clientProps = new java.util.Properties();
571    try {
572        boolean foundClientConfig = false;
573        DataHelper.loadProps(clientProps, clientsConfig);
574        for (int i = 0; i < 100; i++) {
575            String prop = "clientApp." + i + ".main";
576            String cls = clientProps.getProperty(prop);
577            if (cls == null)
578                break;
579            if (!cls.equals("net.i2p.jetty.JettyStart"))
580                continue;
581            prop = "clientApp." + i + ".args";
582            String clArgs = clientProps.getProperty(prop);
583            if (clArgs == null)
584                continue;
585            prop = "clientApp." + i + ".name";
586            String clName = clientProps.getProperty(prop);
587            if (clName == null)
588                clName = intl._t("I2P webserver (eepsite)");
589            prop = "clientApp." + i + ".startOnLoad";
590            String clStart = clientProps.getProperty(prop);
591            boolean start = true;
592            if (clStart != null)
593                start = Boolean.parseBoolean(clStart);
594            // sample args
595            // clientApp.3.args="/home/xxx/.i2p/eepsite/jetty.xml" "/home/xxx/.i2p/eepsite/jetty-ssl.xml" "/home/xxx/.i2p/eepsite/jetty-rewrite.xml"
596            boolean ssl = clArgs.contains("jetty-ssl.xml");
597
598            boolean jettySSLFileInArgs = false;
599            boolean jettySSLFileExists = false;
600            boolean jettySSLFilePWSet = false;
601            File jettyFile = null, jettySSLFile = null;
602            String ksPW = null, kmPW = null, tsPW = null;
603            String ksPath = null, tsPath = null;
604            String host = null, port = null;
605            String sslHost = null, sslPort = null;
606            String error = "";
607            java.util.List<String> argList = net.i2p.i2ptunnel.web.SSLHelper.parseArgs(clArgs);
608            for (String arg : argList) {
609                if (arg.endsWith("jetty.xml")) {
610                    jettyFile = new File(arg);
611                    if (!jettyFile.isAbsolute())
612                        jettyFile = new File(ctx.getConfigDir(), arg);
613                } else if (arg.endsWith("jetty-ssl.xml")) {
614                    jettySSLFile = new File(arg);
615                    if (!jettySSLFile.isAbsolute())
616                        jettySSLFile = new File(ctx.getConfigDir(), arg);
617                    jettySSLFileInArgs = true;
618                }
619            }  // for arg in argList
620            if (jettyFile == null || !jettyFile.exists())
621                continue;
622            try {
623                org.eclipse.jetty.xml.XmlParser.Node root;
624                root = JettyXmlConfigurationParser.parse(jettyFile);
625                host = JettyXmlConfigurationParser.getValue(root, "host");
626                port = JettyXmlConfigurationParser.getValue(root, "port");
627                // now check if host/port match the tunnel
628                if (!targetPort.equals(port))
629                    continue;
630                if (!targetHost.equals(host) && !"0.0.0.0".equals(host) && !"::".equals(host) &&
631                    !((targetHost.equals("127.0.0.1") && "localhost".equals(host)) ||
632                      (targetHost.equals("localhost") && "127.0.0.1".equals(host))))
633                    continue;
634            } catch (org.xml.sax.SAXException saxe) {
635                saxe.printStackTrace();
636                error = DataHelper.escapeHTML(saxe.getMessage());
637                continue;
638            }
639            if (jettySSLFile == null && !argList.isEmpty()) {
640                String arg = argList.get(0);
641                File f = new File(arg);
642                if (!f.isAbsolute())
643                    f = new File(ctx.getConfigDir(), arg);
644                File p = f.getParentFile();
645                if (p != null)
646                    jettySSLFile = new File(p, "jetty-ssl.xml");
647            }
648            boolean ksDflt = false;
649            boolean kmDflt = false;
650            boolean tsDflt = false;
651            boolean ksExists = false;
652            if (jettySSLFile.exists()) {
653                try {
654                    org.eclipse.jetty.xml.XmlParser.Node root;
655                    root = JettyXmlConfigurationParser.parse(jettySSLFile);
656                    ksPW = JettyXmlConfigurationParser.getValue(root, "KeyStorePassword");
657                    kmPW = JettyXmlConfigurationParser.getValue(root, "KeyManagerPassword");
658                    tsPW = JettyXmlConfigurationParser.getValue(root, "TrustStorePassword");
659                    ksPath = JettyXmlConfigurationParser.getValue(root, "KeyStorePath");
660                    tsPath = JettyXmlConfigurationParser.getValue(root, "TrustStorePath");
661                    sslHost = JettyXmlConfigurationParser.getValue(root, "host");
662                    sslPort = JettyXmlConfigurationParser.getValue(root, "port");
663                    // we can't proceed unless they are there
664                    // tsPW may be null
665                    File ksFile = null;
666                    boolean tsIsKs = true;
667                    boolean ksArgs = ksPW != null && kmPW != null && ksPath != null && sslHost != null && sslPort != null;
668                    /** 2015+ installs */
669                    final String DEFAULT_KSPW_1 = KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD;
670                    final String DEFAULT_KMPW_1 = "myKeyPassword";
671                    /** earlier */
672                    final String DEFAULT_KSPW_2 = "OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4";
673                    final String DEFAULT_KMPW_2 = "OBF:1u2u1wml1z7s1z7a1wnl1u2g";
674                    if (ksArgs) {
675                        jettySSLFileExists = true;
676                        ksDflt = ksPW.equals(DEFAULT_KSPW_1) || ksPW.equals(DEFAULT_KSPW_2);
677                        kmDflt = kmPW.equals(DEFAULT_KMPW_1) || kmPW.equals(DEFAULT_KMPW_2);
678                        ksFile = new File(ksPath);
679                        if (!ksFile.isAbsolute())
680                            ksFile = new File(ctx.getConfigDir(), ksPath);
681                        ksExists = ksFile.exists();
682                        tsIsKs = tsPath == null || ksPath.equals(tsPath);
683                    }
684                    if (tsPW != null) {
685                        tsDflt = tsPW.equals(DEFAULT_KSPW_1) || tsPW.equals(DEFAULT_KSPW_2);
686                    }
687                } catch (org.xml.sax.SAXException saxe) {
688                    saxe.printStackTrace();
689                    error = DataHelper.escapeHTML(saxe.getMessage());
690                }
691            }
692            boolean canConfigure = jettySSLFileExists;
693            boolean isEnabled = canConfigure && jettySSLFileInArgs && ksExists && ports.contains(Integer.valueOf(443));
694            boolean isPWDefault = kmDflt || !ksExists;
695            foundClientConfig = true;
696            // now start the output for this client
697
698%>
699<tr><td><%=DataHelper.escapeHTML(clName)%></td><td>
700<%
701            for (String arg : argList) {
702                %><%=DataHelper.escapeHTML(arg)%><br /><%
703            }
704%>
705    </td><td><%=start%></td><td><%=ssl%></td></tr>
706<%
707            if (!canConfigure) {
708%>
709<tr><td colspan="4">Cannot configure, no Jetty SSL configuration template exists</td></tr>
710<%
711            } else {
712%>
713<tr><td colspan="4">
714<input type="hidden" name="clientAppNumber" value="<%=i%>" />
715<input type="hidden" name="isSSLEnabled" value="<%=isEnabled%>" />
716<input type="hidden" name="nofilter_ksPath" value="<%=ksPath%>" />
717<input type="hidden" name="nofilter_jettySSLFile" value="<%=jettySSLFile%>" />
718<input type="hidden" name="jettySSLHost" value="<%=sslHost%>" />
719<input type="hidden" name="jettySSLPort" value="<%=sslPort%>" />
720<%
721                if (ksPW != null) {
722                    if (!ksPW.startsWith("OBF:"))
723                        ksPW = JettyXmlConfigurationParser.obfuscate(ksPW);
724%>
725<input type="hidden" name="nofilter_obfKeyStorePassword" value="<%=ksPW%>" />
726<%
727                }
728%>
729</td></tr>
730<tr><td class="buttons" colspan="4">
731<%
732                if (isEnabled && !isPWDefault) {
733%>
734<b><%=intl._t("SSL is enabled")%></b>
735<button id="controlSave" class="control" type="submit" name="action" value="Disable"><%=intl._t("Disable SSL")%></button>
736<%
737                } else if (!isPWDefault) {
738%>
739<b><%=intl._t("SSL is disabled")%></b>
740<button id="controlSave" class="control" type="submit" name="action" value="Enable"><%=intl._t("Enable SSL")%></button>
741<%
742                } else {
743%>
744<b><%=intl._t("Password")%>:</b>
745<input type="password" name="nofilter_keyPassword" title="<%=intl._t("Set password required to access this service")%>" value="" class="freetext password" />
746<%
747                    if (isEnabled) {
748%>
749<button id="controlSave" class="control" type="submit" name="action" value="Generate"><%=intl._t("Generate new SSL certificate")%></button>
750<%
751                    } else {
752%>
753<button id="controlSave" class="control" type="submit" name="action" value="Generate"><%=intl._t("Generate SSL certificate and enable")%></button>
754<%
755                    }
756                }
757%>
758</td></tr>
759<%
760                break;
761            }  // canConfigure
762        }  // for client
763        if (!foundClientConfig) {
764%>
765<tr><td colspan="4">Cannot configure, no Jetty server found in clients.config that matches this tunnel</td></tr>
766<tr><td colspan="4">Support for non-Jetty servers TBD</td></tr>
767<%
768        }
769    } catch (IOException ioe) { ioe.printStackTrace(); }
770%>
771</table>
772</form>
773<%
774       }  // valid b64 and name
775    }  // !"new".equals(tunnelType)
776    if (!valid && curTunnel >= 0) {
777%>
778<table>
779  <tr><td><a href="edit?tunnel=<%=curTunnel%>"><%=intl._t("Go back and edit the tunnel")%></a></td></tr>
780</table>
781<%
782    }  // !valid
783%>
784</div>
785<%
786  } else {
787%>
788<div id="notReady"><%=intl._t("Tunnels are not initialized yet, please reload in two minutes.")%></div>
789<%
790  }  // isInitialized()
791%>
792</body>
793</html>
Note: See TracBrowser for help on using the repository browser.