forked from I2P_Developers/i2p.i2p
* susidns:
- Enforce basic rules on host name additions - Split up form - IDN toASCII improvements - Log message improvements
This commit is contained in:
@@ -72,13 +72,23 @@ public class AddressBean
|
||||
|
||||
/**
|
||||
* The Unicode name, translated from Punycode
|
||||
* @return the original string on error
|
||||
* @since 0.8.6
|
||||
*/
|
||||
public String getDisplayName()
|
||||
{
|
||||
return toUnicode(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Unicode name, translated from Punycode
|
||||
* @return the original string on error
|
||||
* @since 0.8.6
|
||||
*/
|
||||
public static String toUnicode(String host) {
|
||||
if (haveIDN)
|
||||
return IDN.toUnicode(name);
|
||||
return name;
|
||||
return IDN.toUnicode(host);
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +100,65 @@ public class AddressBean
|
||||
return haveIDN && !IDN.toUnicode(name).equals(name);
|
||||
}
|
||||
|
||||
private static final char DOT = '.';
|
||||
private static final char DOT2 = 0x3002;
|
||||
private static final char DOT3 = 0xFF0E;
|
||||
private static final char DOT4 = 0xFF61;
|
||||
|
||||
/**
|
||||
* Ref: java.net.IDN and RFC 3940
|
||||
* @param name will be converted to lower case
|
||||
* @return name converted to lower case and punycoded if necessary
|
||||
* @throws IAE on various errors or if IDN is needed but not available
|
||||
* @since 0.8.6
|
||||
*/
|
||||
static String toASCII(String host) throws IllegalArgumentException {
|
||||
host = host.toLowerCase();
|
||||
|
||||
boolean needsIDN = false;
|
||||
// Here we do easy checks and throw translated exceptions.
|
||||
// We do checks on the whole host name, not on each "label", so
|
||||
// we allow '.', and some untranslated errors will be thrown by IDN.toASCII()
|
||||
for (int i = 0; i < host.length(); i++) {
|
||||
char c = host.charAt(i);
|
||||
if (c <= 0x2c ||
|
||||
c == 0x2f ||
|
||||
c >= 0x3a && c <= 0x40 ||
|
||||
c >= 0x5b && c <= 0x60 ||
|
||||
c >= 0x7b && c <= 0x7f) {
|
||||
String bad = "\"" + c + "\" (0x" + Integer.toHexString(c) + ')';
|
||||
throw new IllegalArgumentException(_("Host name \"{0}\" contains illegal character {1}",
|
||||
host, bad));
|
||||
}
|
||||
if (c == DOT2)
|
||||
host = host.replace(DOT2, DOT);
|
||||
else if (c == DOT3)
|
||||
host = host.replace(DOT3, DOT);
|
||||
else if (c == DOT4)
|
||||
host = host.replace(DOT4, DOT);
|
||||
else if (c > 0x7f)
|
||||
needsIDN = true;
|
||||
}
|
||||
if (host.startsWith("-"))
|
||||
throw new IllegalArgumentException(_("Host name cannot start with \"{0}\"", "-"));
|
||||
if (host.startsWith("."))
|
||||
throw new IllegalArgumentException(_("Host name cannot start with \"{0}\"", "."));
|
||||
if (host.endsWith("-"))
|
||||
throw new IllegalArgumentException(_("Host name cannot end with \"{0}\"", "-"));
|
||||
if (host.endsWith("."))
|
||||
throw new IllegalArgumentException(_("Host name cannot end with \"{0}\"", "."));
|
||||
if (needsIDN) {
|
||||
if (host.startsWith("xn--"))
|
||||
throw new IllegalArgumentException(_("Host name cannot start with \"{0}\"", "xn--"));
|
||||
if (host.contains(".xn--"))
|
||||
throw new IllegalArgumentException(_("Host name cannot contain \"{0}\"", ".xn--"));
|
||||
if (haveIDN)
|
||||
return IDN.toASCII(host, IDN.ALLOW_UNASSIGNED);
|
||||
throw new IllegalArgumentException(_("Host name \"{0}\" requires conversion to ASCII but the conversion library is unavailable in this JVM", host));
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
/** @since 0.8.6 */
|
||||
public String getB32()
|
||||
{
|
||||
@@ -183,4 +252,9 @@ public class AddressBean
|
||||
private static String _(String s, Object o) {
|
||||
return Messages.getString(s, o);
|
||||
}
|
||||
|
||||
/** translate */
|
||||
private static String _(String s, Object o, Object o2) {
|
||||
return Messages.getString(s, o, o2);
|
||||
}
|
||||
}
|
||||
|
@@ -58,7 +58,7 @@ public class AddressbookBean
|
||||
return search;
|
||||
}
|
||||
public void setSearch(String search) {
|
||||
this.search = search;
|
||||
this.search = DataHelper.stripHTML(search).trim(); // XSS;
|
||||
}
|
||||
public boolean isHasFilter()
|
||||
{
|
||||
@@ -331,6 +331,8 @@ public class AddressbookBean
|
||||
} else {
|
||||
message = _("No entries selected to delete.");
|
||||
}
|
||||
if (action.equals(_("Delete Entry")))
|
||||
search = null;
|
||||
}
|
||||
if( changed ) {
|
||||
try {
|
||||
@@ -390,7 +392,7 @@ public class AddressbookBean
|
||||
filter = null;
|
||||
search = null;
|
||||
}
|
||||
this.filter = filter;
|
||||
this.filter = DataHelper.stripHTML(filter); // XSS
|
||||
}
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
@@ -405,7 +407,7 @@ public class AddressbookBean
|
||||
deletionMarks.clear();
|
||||
}
|
||||
public void setMarkedForDeletion( String name ) {
|
||||
deletionMarks.addLast( name );
|
||||
deletionMarks.addLast( DataHelper.stripHTML(name) ); // XSS
|
||||
}
|
||||
public void setHostname(String hostname) {
|
||||
this.hostname = DataHelper.stripHTML(hostname).trim(); // XSS
|
||||
|
@@ -221,20 +221,20 @@ public class NamingServiceBean extends AddressbookBean
|
||||
boolean changed = false;
|
||||
if (action.equals(_("Add")) || action.equals(_("Replace"))) {
|
||||
if(hostname != null && destination != null) {
|
||||
try {
|
||||
// throws IAE with translated message
|
||||
String host = AddressBean.toASCII(hostname);
|
||||
String displayHost = host.equals(hostname) ? hostname :
|
||||
hostname + " (" + host + ')';
|
||||
|
||||
Properties outProperties= new Properties();
|
||||
Destination oldDest = getNamingService().lookup(hostname, nsOptions, outProperties);
|
||||
Destination oldDest = getNamingService().lookup(host, nsOptions, outProperties);
|
||||
if (oldDest != null && destination.equals(oldDest.toBase64())) {
|
||||
message = _("Host name {0} is already in addressbook, unchanged.", hostname);
|
||||
message = _("Host name {0} is already in addressbook, unchanged.", displayHost);
|
||||
} else if (oldDest != null && !action.equals(_("Replace"))) {
|
||||
message = _("Host name {0} is already in addressbook with a different destination. Click \"Replace\" to overwrite.", hostname);
|
||||
message = _("Host name {0} is already in addressbook with a different destination. Click \"Replace\" to overwrite.", displayHost);
|
||||
} else {
|
||||
try {
|
||||
String host = hostname;
|
||||
if (AddressBean.haveIDN) {
|
||||
try {
|
||||
host = IDN.toASCII(hostname, IDN.ALLOW_UNASSIGNED);
|
||||
} catch (IllegalArgumentException iae) {}
|
||||
}
|
||||
Destination dest = new Destination(destination);
|
||||
if (oldDest != null) {
|
||||
nsOptions.putAll(outProperties);
|
||||
@@ -245,19 +245,24 @@ public class NamingServiceBean extends AddressbookBean
|
||||
if (success) {
|
||||
changed = true;
|
||||
if (oldDest == null)
|
||||
message = _("Destination added for {0}.", hostname);
|
||||
message = _("Destination added for {0}.", displayHost);
|
||||
else
|
||||
message = _("Destination changed for {0}.", hostname);
|
||||
message = _("Destination changed for {0}.", displayHost);
|
||||
// clear form
|
||||
hostname = null;
|
||||
destination = null;
|
||||
} else {
|
||||
message = _("Failed to add Destination for {0} to naming service {1}", hostname, getNamingService()) + "<br>";
|
||||
message = _("Failed to add Destination for {0} to naming service {1}", displayHost, getNamingService()) + "<br>";
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
message = _("Invalid Base 64 destination.");
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
message = iae.getMessage();
|
||||
if (message == null)
|
||||
message = _("Invalid host name \"{0}\".", hostname);
|
||||
}
|
||||
} else {
|
||||
message = _("Please enter a host name and destination");
|
||||
}
|
||||
@@ -268,15 +273,18 @@ public class NamingServiceBean extends AddressbookBean
|
||||
int deleted = 0;
|
||||
for (String n : deletionMarks) {
|
||||
boolean success = getNamingService().remove(n, nsOptions);
|
||||
String uni = AddressBean.toUnicode(n);
|
||||
String displayHost = uni.equals(n) ? n : uni + " (" + n + ')';
|
||||
if (!success) {
|
||||
message += _("Failed to delete Destination for {0} from naming service {1}", name, getNamingService()) + "<br>";
|
||||
message += _("Failed to delete Destination for {0} from naming service {1}", displayHost, getNamingService()) + "<br>";
|
||||
} else if (deleted++ == 0) {
|
||||
changed = true;
|
||||
name = n;
|
||||
name = displayHost;
|
||||
}
|
||||
}
|
||||
if( changed ) {
|
||||
if (deleted == 1)
|
||||
// parameter is a host name
|
||||
message += _("Destination {0} deleted.", name);
|
||||
else
|
||||
// parameter will always be >= 2
|
||||
@@ -284,6 +292,9 @@ public class NamingServiceBean extends AddressbookBean
|
||||
} else {
|
||||
message = _("No entries selected to delete.");
|
||||
}
|
||||
// clear search when deleting
|
||||
if (action.equals(_("Delete Entry")))
|
||||
search = null;
|
||||
}
|
||||
if( changed ) {
|
||||
message += "<br>" + _("Addressbook saved.");
|
||||
|
@@ -110,29 +110,29 @@ ${book.loadBookMessages}
|
||||
</c:if>
|
||||
</div>
|
||||
|
||||
<div id="search">
|
||||
<form method="POST" action="addressbook.jsp">
|
||||
<input type="hidden" name="begin" value="0">
|
||||
<input type="hidden" name="end" value="99">
|
||||
<div id="search">
|
||||
<table><tr>
|
||||
<td class="search"><%=intl._("Search")%>: <input type="text" name="search" value="${book.search}" size="20" ></td>
|
||||
<td class="search"><input type="submit" name="submitsearch" value="<%=intl._("Search")%>" ></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</form></div>
|
||||
</c:if>
|
||||
|
||||
<%
|
||||
// have to only do this once per page
|
||||
String susiNonce = book.getSerial();
|
||||
%>
|
||||
<c:if test="${book.notEmpty}">
|
||||
<form method="POST" action="addressbook.jsp">
|
||||
<input type="hidden" name="serial" value="${book.serial}">
|
||||
<input type="hidden" name="serial" value="<%=susiNonce%>">
|
||||
<input type="hidden" name="begin" value="0">
|
||||
<input type="hidden" name="end" value="99">
|
||||
|
||||
<c:if test="${book.notEmpty}">
|
||||
|
||||
<div id="book">
|
||||
<jsp:setProperty name="book" property="trClass" value="0" />
|
||||
<div id="book">
|
||||
<table class="book" cellspacing="0" cellpadding="5">
|
||||
<tr class="head">
|
||||
|
||||
@@ -150,11 +150,11 @@ ${book.loadBookMessages}
|
||||
<c:if test="${book.master || book.router || book.published || book.private}">
|
||||
<td class="checkbox"><input type="checkbox" name="checked" value="${addr.name}" title="<%=intl._("Mark for deletion")%>"></td>
|
||||
</c:if>
|
||||
<td class="names"><a href="http://${addr.name}/">${addr.displayName}</a>
|
||||
<td class="names"><a href="${addr.uri}">${addr.displayName}</a>
|
||||
</td><td class="names">
|
||||
<span class="addrhlpr"><a href="http://${addr.b32}/" title="<%=intl._("Base 32 address")%>">b32</a></span>
|
||||
</td><td class="names">
|
||||
<span class="addrhlpr"><a href="details.jsp?h=${addr.name}" title="<%=intl._("More information on this entry")%>"><%=intl._("details")%></a></span>
|
||||
<span class="addrhlpr"><a href="details.jsp?h=${addr.query}" title="<%=intl._("More information on this entry")%>"><%=intl._("details")%></a></span>
|
||||
</td>
|
||||
<td class="destinations"><textarea rows="1" style="height: 3em;" cols="40" wrap="off" readonly="readonly" name="dest_${addr.name}" >${addr.destination}</textarea></td>
|
||||
</tr>
|
||||
@@ -168,7 +168,7 @@ ${book.loadBookMessages}
|
||||
<input type="reset" value="<%=intl._("Cancel")%>" >
|
||||
<input type="submit" name="action" value="<%=intl._("Delete Selected")%>" >
|
||||
</p>
|
||||
</div>
|
||||
</div></form>
|
||||
</c:if>
|
||||
|
||||
</c:if>
|
||||
@@ -179,6 +179,10 @@ ${book.loadBookMessages}
|
||||
</div>
|
||||
</c:if>
|
||||
|
||||
<form method="POST" action="addressbook.jsp">
|
||||
<input type="hidden" name="serial" value="<%=susiNonce%>">
|
||||
<input type="hidden" name="begin" value="0">
|
||||
<input type="hidden" name="end" value="99">
|
||||
<div id="add">
|
||||
<h3><%=intl._("Add new destination")%>:</h3>
|
||||
<table><tr><td>
|
||||
@@ -186,14 +190,13 @@ ${book.loadBookMessages}
|
||||
</td></tr><tr><td>
|
||||
<b><%=intl._("Destination")%></b></td><td><textarea name="destination" rows="1" style="height: 3em;" cols="70" wrap="off" spellcheck="false">${book.destination}</textarea>
|
||||
</td></tr></table>
|
||||
<p>
|
||||
<p class="buttons">
|
||||
<input type="reset" value="<%=intl._("Cancel")%>" >
|
||||
<input type="submit" name="action" value="<%=intl._("Replace")%>" >
|
||||
<input type="submit" name="action" value="<%=intl._("Add")%>" >
|
||||
</p>
|
||||
</div>
|
||||
</div></form>
|
||||
|
||||
</form>
|
||||
<hr>
|
||||
<div id="footer">
|
||||
<p class="footer">susidns v${version.version} © <a href="${version.url}">susi</a> 2005</p>
|
||||
|
@@ -126,11 +126,13 @@
|
||||
</div>
|
||||
<div id="buttons">
|
||||
<form method="POST" action="addressbook.jsp">
|
||||
<p class="buttons">
|
||||
<input type="hidden" name="serial" value="${book.serial}">
|
||||
<input type="hidden" name="begin" value="0">
|
||||
<input type="hidden" name="end" value="99">
|
||||
<input type="hidden" name="checked" value="<%=detail%>">
|
||||
<input type="submit" name="action" value="<%=intl._("Delete Entry")%>" >
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
<%
|
||||
|
Reference in New Issue
Block a user