source: apps/i2ptunnel/jsp/register.jsp @ d6a53cc

Last change on this file since d6a53cc was d6a53cc, checked in by zzz <zzz@…>, 16 months ago

Data: Consolidate offline key check
i2ptunnel: Prevent registration auth if key offline

  • Property mode set to 100644
File size: 17.0 KB
RevLine 
[cae1fe1]1<%
2    // NOTE: Do the header carefully so there is no whitespace before the <?xml... line
3
4    response.setHeader("X-Frame-Options", "SAMEORIGIN");
[419d411b]5    response.setHeader("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'");
[cae1fe1]6    response.setHeader("X-XSS-Protection", "1; mode=block");
7    response.setHeader("X-Content-Type-Options", "nosniff");
8    response.setHeader("Referrer-Policy", "no-referrer");
[a845d4f]9    response.setHeader("Accept-Ranges", "none");
[cae1fe1]10
11%><%@page pageEncoding="UTF-8"
12%><%@page contentType="text/html" import="java.io.InputStream,net.i2p.i2ptunnel.web.EditBean,net.i2p.servlet.RequestWrapper,net.i2p.client.I2PSessionException,net.i2p.client.naming.HostTxtEntry,net.i2p.data.PrivateKeyFile,net.i2p.data.SigningPrivateKey,net.i2p.util.OrderedProperties"
[597231b]13%><%@page
[2a34d1c4]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" />
[8c0e82d]21<jsp:useBean class="net.i2p.i2ptunnel.ui.Messages" id="intl" scope="request" />
[0ac83bd]22<%
23   RequestWrapper wrequest = new RequestWrapper(request);
24   String tun = wrequest.getParameter("tunnel");
[2a34d1c4]25   int curTunnel = -1;
26   if (tun != null) {
27     try {
28       curTunnel = Integer.parseInt(tun);
29     } catch (NumberFormatException nfe) {
30       curTunnel = -1;
31     }
32   }
33%>
34<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
35<head>
36    <title><%=intl._t("Hidden Services Manager")%> - <%=intl._t("Registration Helper")%></title>
37    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
38    <link href="/themes/console/images/favicon.ico" type="image/x-icon" rel="shortcut icon" />
39
40    <% if (editBean.allowCSS()) {
41  %><link rel="icon" href="<%=editBean.getTheme()%>images/favicon.ico" />
[14bacc2]42    <link href="<%=editBean.getTheme()%>i2ptunnel.css?<%=net.i2p.CoreVersion.VERSION%>" rel="stylesheet" type="text/css" /> 
[2a34d1c4]43    <% }
44  %>
45<style type='text/css'>
46input.default { width: 1px; height: 1px; visibility: hidden; }
47</style>
48</head>
[c586970]49<body id="tunnelRegistration">
50
[2a34d1c4]51<%
52
53  if (editBean.isInitialized()) {
54
55%>
[0ac83bd]56    <form method="post" enctype="multipart/form-data" action="register" accept-charset="UTF-8">
[c586970]57        <div class="panel" id="registration">
[2a34d1c4]58<%
59    String tunnelTypeName;
60    String tunnelType;
61    boolean valid = false;
62    if (curTunnel >= 0) {
63        tunnelTypeName = editBean.getTunnelType(curTunnel);
64        tunnelType = editBean.getInternalType(curTunnel);
[c586970]65      %><h2><%=intl._t("Registration Helper")%> (<%=editBean.getTunnelName(curTunnel)%>)</h2><% 
[2a34d1c4]66    } else {
67        tunnelTypeName = "new";
68        tunnelType = "new";
[c586970]69      %><h2>Fail</h2><p>Tunnel not found</p><% 
[2a34d1c4]70    }
71    String b64 = editBean.getDestinationBase64(curTunnel);
72    String name = editBean.getSpoofedHost(curTunnel);
73    if (name == null || name.equals(""))
74        name = editBean.getTunnelName(curTunnel);
75%>
76                <input type="hidden" name="tunnel" value="<%=curTunnel%>" />
77                <input type="hidden" name="nonce" value="<%=net.i2p.i2ptunnel.web.IndexBean.getNextNonce()%>" />
78                <input type="hidden" name="type" value="<%=tunnelType%>" />
79                <input type="submit" class="default" name="action" value="Save changes" />
80<%
[017f66a]81    if (!"new".equals(tunnelType)) {
[2a34d1c4]82%>
[c586970]83
84<table>
85    <tr>
86        <td class="infohelp">
[0ac83bd]87    <%=intl._t("Please be sure to select, copy, and paste the entire contents of the appropriate authentication data into the form of your favorite registration site")%>
[c586970]88        </td>
89    </tr>
90    <tr>
91        <td>
[791bc9a]92            <b><%=intl._t("Tunnel name")%>:</b> <%=editBean.getTunnelName(curTunnel)%>
[c586970]93        </td>
94    </tr>
95
[017f66a]96<%
[2a34d1c4]97      if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) {
[c586970]98          %>
[791bc9a]99    <tr><td><b><%=intl._t("Website name")%>:</b> <%=editBean.getSpoofedHost(curTunnel)%></td></tr>
[2a34d1c4]100<%
101       }
102%>
[c586970]103
[359b457]104<!--
[c586970]105    <tr>
106        <th>
107            <b><%=intl._t("Local Destination")%></b>
108        </th>
109    </tr>
110    <tr>
111        <td>
112            <textarea rows="1" style="height: 3em;" cols="60" readonly="readonly" id="localDestination" title="Read Only: Local Destination (if known)" wrap="off" spellcheck="false"><%=editBean.getDestinationBase64(curTunnel)%></textarea>
113        </td>
114    </tr>
[359b457]115-->
[c586970]116
[2a34d1c4]117<%
118       if (b64 == null || b64.length() < 516) {
[c586970]119           %><tr><td class="infohelp"><%=intl._t("Local destination is not available. Start the tunnel.")%></td></tr><%
[2a34d1c4]120       } else if (name == null || name.equals("") || name.contains(" ") || !name.endsWith(".i2p")) {
121           if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) {
[c586970]122               %><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><%
[2a34d1c4]123           } else {
[c586970]124               %><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><%
[2a34d1c4]125           }
126       } else {
127           SigningPrivateKey spk = editBean.getSigningPrivateKey(curTunnel);
128           if (spk == null) {
[c586970]129               %><tr><td class="infohelp"><%=intl._t("Destination signing key is not available. Start the tunnel.")%></td></tr><%
[d6a53cc]130           } else if (spk.isOffline()) {
131               %><tr><td class="infohelp"><%=intl._t("Destination signing key is offline. Use CLI tools on the offline machine.")%></td></tr><%
[2a34d1c4]132           } else {
133               valid = true;
134               OrderedProperties props = new OrderedProperties();
135               HostTxtEntry he = new HostTxtEntry(name, b64, props);
136               he.sign(spk);
[c586970]137          %>
138
139    <tr>
140        <th>
141            <%=intl._t("Authentication for adding host {0}", name)%>
142        </th>
143    </tr>
144    <tr>
145        <td>
[017f66a]146            <div class="displayText" tabindex="0" title="<%=intl._t("Copy and paste this to the registration site")%>"><% he.write(out); %></div>
[c586970]147        </td>
148    </tr>
149</table>
150
151<h3><%=intl._t("Advanced authentication strings")%></h3>
152
[2a34d1c4]153<%
154               props.remove(HostTxtEntry.PROP_SIG);
155               props.setProperty(HostTxtEntry.PROP_ACTION, HostTxtEntry.ACTION_REMOVE);
156               he.signRemove(spk);
[c586970]157          %>
[017f66a]158
[c586970]159<table>
160    <tr>
161        <th>
162            <%=intl._t("Authentication for removing host {0}", name)%>
163        </th>
164    </tr>
165    <tr>
166        <td>
[017f66a]167            <div class="displayText" tabindex="0" title="<%=intl._t("Copy and paste this to the registration site")%>"><% he.writeRemove(out); %></div>
[c586970]168        </td>
169    </tr>
170
[0ac83bd]171<%
172               String oldname = wrequest.getParameter("oldname");
173               String olddestfile = wrequest.getFilename("olddestfile");
174               SigningPrivateKey spk2 = null;
175               String olddest = null;
176               if (olddestfile != null) {
177                   InputStream destIn = wrequest.getInputStream("olddestfile");
178                   if (destIn.available() > 0) {
179                       try {
180                           PrivateKeyFile pkf2 = new PrivateKeyFile(destIn);
181                           String oldb64 = pkf2.getDestination().toBase64();
182                           if (!b64.equals(oldb64)) {
183                               // disallow dup
[c09bfa0]184                               olddest = oldb64;
[0ac83bd]185                               spk2 = pkf2.getSigningPrivKey();
186                           }
187                       } catch (I2PSessionException ise) {
188                           throw new IllegalStateException("Unable to open private key file " + olddestfile, ise);
189                       }
190                   }
191               }
192               props.remove(HostTxtEntry.PROP_SIG);
[c586970]193          %>
194    <tr>
195        <th>
[0ac83bd]196                    <%=intl._t("Authentication for changing name")%>
[c586970]197        </th>
198    </tr>
[0ac83bd]199<%
200               if (oldname != null && oldname.length() > 0 && !oldname.equals(name)) {
201                   props.setProperty(HostTxtEntry.PROP_ACTION, HostTxtEntry.ACTION_CHANGENAME);
202                   props.setProperty(HostTxtEntry.PROP_OLDNAME, oldname);
203                   he.sign(spk);
[c586970]204                %>
205    <tr>
206        <td>
[017f66a]207            <div class="displayText" tabindex="0" title="<%=intl._t("Copy and paste this to the registration site")%>"><% he.write(out); %></div>
[c586970]208        </td>
209    </tr>
210    <tr>
211        <td class="infohelp">
212            <%=intl._t("This will change the name from {0} to {1}, using the same destination", oldname, name)%>
213        </td>
214    </tr>
215
[0ac83bd]216<%
217               } else {
[c586970]218                %><tr><td class="infohelp"><%=intl._t("This tunnel must be configured with the new host name.")%>
219                  &nbsp;<%=intl._t("Enter old hostname below.")%></td></tr>
[0ac83bd]220<%
221               }
[c586970]222          %>
223
[0ac83bd]224<%
225               props.remove(HostTxtEntry.PROP_SIG);
[c586970]226          %>
227    <tr>
228        <th>
[0ac83bd]229                    <%=intl._t("Authentication for adding alias")%>
[c586970]230        </th>
231    </tr>
[0ac83bd]232<%
233               if (oldname != null && oldname.length() > 0 && !oldname.equals(name)) {
234                   props.setProperty(HostTxtEntry.PROP_ACTION, HostTxtEntry.ACTION_ADDNAME);
235                   props.setProperty(HostTxtEntry.PROP_OLDNAME, oldname);
236                   he.sign(spk);
[c586970]237                %>
238    <tr>
239        <td>
[017f66a]240            <div class="displayText" tabindex="0" title="<%=intl._t("Copy and paste this to the registration site")%>"><% he.write(out); %></div>
[c586970]241        </td>
242    </tr>
243    <tr>
244        <td class="infohelp">
245            <%=intl._t("This will add an alias {0} for {1}, using the same destination", name, oldname)%>
246        </td>
247    </tr>
[0ac83bd]248<%
249               } else {
[c586970]250                %><tr> <td class="infohelp"><%=intl._t("This tunnel must be configured with the new host name.")%>
251                  &nbsp;<%=intl._t("Enter old hostname below.")%></td></tr>
[0ac83bd]252<%
253               }
[c586970]254          %>
[017f66a]255
[0ac83bd]256<%
257               props.remove(HostTxtEntry.PROP_SIG);
[c09bfa0]258               props.remove(HostTxtEntry.PROP_OLDNAME);
[c586970]259          %>
260
261    <tr>
262        <th>
[0ac83bd]263                    <%=intl._t("Authentication for changing destination")%>
[c586970]264        </th>
265    </tr>
266
[0ac83bd]267<%
268               if (spk2 != null) {
269                   props.setProperty(HostTxtEntry.PROP_ACTION, HostTxtEntry.ACTION_CHANGEDEST);
270                   props.setProperty(HostTxtEntry.PROP_OLDDEST, olddest);
271                   he.signInner(spk2);
272                   he.sign(spk);
[c586970]273                %>
274
275    <tr>
276        <td>
[017f66a]277            <div class="displayText" tabindex="0" title="<%=intl._t("Copy and paste this to the registration site")%>"><% he.write(out); %></div>
[c586970]278        </td>
279    </tr>
280    <tr>
281        <td class="infohelp">
282            <%=intl._t("This will change the destination for {0}", name)%>
283        </td>
284    </tr>
285
[0ac83bd]286<%
287               } else {
[c586970]288                %><tr><td class="infohelp"><%=intl._t("This tunnel must be configured with the new destination.")%>
289                  &nbsp;<%=intl._t("Enter old destination below.")%></td></tr>
[0ac83bd]290<%
291               }
[c586970]292          %>
293
[0ac83bd]294<%
295               props.remove(HostTxtEntry.PROP_SIG);
296               props.remove(HostTxtEntry.PROP_OLDSIG);
[c586970]297          %>
[017f66a]298
[c586970]299    <tr>
300        <th>
[0ac83bd]301                    <%=intl._t("Authentication for adding alternate destination")%>
[c586970]302        </th>
303    </tr>
304
[0ac83bd]305<%
306               if (spk2 != null) {
307                   props.setProperty(HostTxtEntry.PROP_ACTION, HostTxtEntry.ACTION_ADDDEST);
308                   props.setProperty(HostTxtEntry.PROP_OLDDEST, olddest);
309                   he.signInner(spk2);
310                   he.sign(spk);
[c586970]311                %>
312    <tr>
313        <td>
[017f66a]314            <div class="displayText" tabindex="0" title="<%=intl._t("Copy and paste this to the registration site")%>"><% he.write(out); %></div>
[c586970]315        </td>
316    </tr>
317    <tr>
318        <td class="infohelp">
319            <%=intl._t("This will add an alternate destination for {0}", name)%>
320        </td>
321    </tr>
[0ac83bd]322<%
323               } else {
[4b722c9]324                   // If set, use the configured alternate destination as the new alias destination,
325                   // and the configured primary destination as the inner signer.
326                   // This is backwards from all the other ones, so we have to make a second HostTxtEntry just for this.
327                   SigningPrivateKey spk3 = null;
328                   String altdest = null;
329                   String altdestfile = editBean.getAltPrivateKeyFile(curTunnel);
330                   if (altdestfile.length() > 0) {
331                       try {
332                           PrivateKeyFile pkf3 = new PrivateKeyFile(altdestfile);
333                           altdest = pkf3.getDestination().toBase64();
334                           if (!b64.equals(altdest)) {
335                               // disallow dup
336                               spk3 = pkf3.getSigningPrivKey();
337                           }
338                       } catch (Exception e) {}
339                   }
340                   if (spk3 != null) {
341                       OrderedProperties props2 = new OrderedProperties();
342                       HostTxtEntry he2 = new HostTxtEntry(name, altdest, props2);
343                       props2.setProperty(HostTxtEntry.PROP_ACTION, HostTxtEntry.ACTION_ADDDEST);
344                       props2.setProperty(HostTxtEntry.PROP_OLDDEST, b64);
345                       he2.signInner(spk);
346                       he2.sign(spk3);
[017f66a]347                %><tr><td><div class="displayText" tabindex="0" title="<%=intl._t("Copy and paste this to the registration site")%>"><% he2.write(out); %></div></td></tr>
[a3e146a8]348                <tr><td class="infohelp"><%=intl._t("This will add an alternate destination for {0}", name)%></td></tr>
[4b722c9]349<%
350                   } else {
[c586970]351                %><tr><td class="infohelp"><%=intl._t("This tunnel must be configured with the new destination.")%>
352                  &nbsp;<%=intl._t("Enter old destination below.")%></td></tr>
[0ac83bd]353<%
[4b722c9]354                   }  // spk3
355               }  // spk2
[c586970]356          %>
[a3e146a8]357
[0ac83bd]358<%
[c586970]359
360
[0ac83bd]361               props.remove(HostTxtEntry.PROP_SIG);
362               props.remove(HostTxtEntry.PROP_OLDSIG);
[c586970]363          %>
364
365    <tr>
366        <th>
[0ac83bd]367                    <%=intl._t("Authentication for adding subdomain")%>
[c586970]368        </th>
369    </tr>
[0ac83bd]370<%
371               if (oldname != null && oldname.length() > 0 && !oldname.equals(name) && spk2 != null) {
372                   props.setProperty(HostTxtEntry.PROP_ACTION, HostTxtEntry.ACTION_ADDSUBDOMAIN);
373                   props.setProperty(HostTxtEntry.PROP_OLDNAME, oldname);
374                   props.setProperty(HostTxtEntry.PROP_OLDDEST, olddest);
375                   he.signInner(spk2);
376                   he.sign(spk);
[c586970]377                %>
[017f66a]378
[c586970]379    <tr>
380        <td>
[017f66a]381            <div class="displayText" tabindex="0" title="<%=intl._t("Copy and paste this to the registration site")%>"><% he.write(out); %></div>
[c586970]382        </td>
383    </tr>
384    <tr>
385        <td class="infohelp">
386            <%=intl._t("This will add a subdomain {0} of {1}, with a different destination", name, oldname)%>
387        </td>
388    </tr>
389
[0ac83bd]390<%
391               } else {
[c586970]392                %>
393    <tr>
394        <td class="infohelp">
395            <%=intl._t("This tunnel must be configured with the new subdomain and destination.")%>
396            &nbsp;<%=intl._t("Enter higher-level domain and destination below.")%>
397        </td>
398    </tr>
399
[0ac83bd]400<%
401               }
[c586970]402          %>
[2a34d1c4]403
404<%
405          }  // spk != null
406       }  // valid b64 and name
407    }  // !"new".equals(tunnelType)
[0ac83bd]408    if (!valid && curTunnel >= 0) {
[c586970]409        %>
410    <tr>
411        <td>
412            <a href="edit?tunnel=<%=curTunnel%>"><%=intl._t("Go back and edit the tunnel")%></a>
413        </td>
414    </tr>
415        <%
[2a34d1c4]416    }
417%>
418
419<%
[0ac83bd]420    if (valid) {
[2a34d1c4]421%>
[c586970]422
423    <tr>
424        <th>
425            <%=intl._t("Specify old name and destination")%>
426        </th>
427    </tr>
428    <tr>
429        <td class="infohelp">
430            <%=intl._t("This is only required for advanced authentication.")%>
431            &nbsp;<%=intl._t("See above for required items.")%>
432        </td>
433    </tr>
[0ac83bd]434<%
435               String oldname = wrequest.getParameter("oldname");
436               if (oldname == null) oldname = "";
[c586970]437          %>
438    <tr>
439        <td>
[791bc9a]440            <b><%=intl._t("Old hostname")%>:</b>
[017f66a]441            <input type="text" size="30" maxlength="50" name="oldname" id="oldName" value="<%=oldname%>" class="freetext" />
[c586970]442        </td>
443    </tr>
444    <tr>
445        <td>
446            <b><%=intl._t("Private Key File for old Destination")%>:</b>
447            <input type="file" name="olddestfile" id="oldDestFile" value="" />
448        </td>
449    </tr>
450    <tr>
451        <td class="buttons">
[2a34d1c4]452                    <input type="hidden" value="true" name="removeConfirm" />
[017f66a]453                    <a class="control" href="list"><%=intl._t("Cancel")%></a>
454                    <button id="controlSave" class="control" type="submit" name="action" value="authenticate"  title="<%=intl._t("Generate Authentication")%>"><%=intl._t("Generate")%></button>
[c586970]455        </td>
456    </tr>
457
[2a34d1c4]458<%
459     } // valid
460%>
[c586970]461
462</table>
463</div>
[2a34d1c4]464    </form>
465<%
466
467  } else {
[c586970]468     %><div id="notReady"><%=intl._t("Tunnels are not initialized yet, please reload in two minutes.")%></div><%
[2a34d1c4]469  }  // isInitialized()
470
471%>
472</body>
473</html>
Note: See TracBrowser for help on using the repository browser.