package net.i2p.router;
import java.io.IOException;
import java.io.Writer;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.LeaseSet;
import net.i2p.data.SessionKey;
import net.i2p.util.KeyRing;
/**
* ConcurrentHashMap with backing in the router.config file.
* router.keyring.key.{base64 hash, with = replaced with $}={base64 session key}
* Caution - not all HashMap methods are overridden.
*/
public class PersistentKeyRing extends KeyRing {
private static final long serialVersionUID = 1L;
private transient final RouterContext _ctx;
private static final String PROP_PFX = "router.keyring.key.";
public PersistentKeyRing(RouterContext ctx) {
super();
_ctx = ctx;
addFromProperties();
}
@Override
public SessionKey put(Hash h, SessionKey sk) {
SessionKey old = super.put(h, sk);
if (!sk.equals(old)) {
_ctx.router().saveConfig(PROP_PFX + h.toBase64().replace("=", "$"),
sk.toBase64());
}
return old;
}
public SessionKey remove(Hash h) {
_ctx.router().saveConfig(PROP_PFX + h.toBase64().replace("=", "$"), null);
return super.remove(h);
}
private void addFromProperties() {
for (String prop : _ctx.getPropertyNames()) {
if (!prop.startsWith(PROP_PFX))
continue;
String key = _ctx.getProperty(prop);
if (key == null || key.length() != 44)
continue;
String hb = prop.substring(PROP_PFX.length());
hb = hb.replace("$", "=");
Hash dest = new Hash();
SessionKey sk = new SessionKey();
try {
dest.fromBase64(hb);
sk.fromBase64(key);
super.put(dest, sk);
} catch (DataFormatException dfe) { continue; }
}
}
@Override
public void renderStatusHTML(Writer out) throws IOException {
StringBuilder buf = new StringBuilder(1024);
buf.append("\n<table><tr><th align=\"left\">Destination Hash<th align=\"left\">Name or Dest.<th align=\"left\">Encryption Key</tr>");
for (Entry<Hash, SessionKey> e : entrySet()) {
buf.append("\n<tr><td>");
Hash h = e.getKey();
buf.append(h.toBase64().substring(0, 6)).append("…");
buf.append("<td>");
Destination dest = _ctx.netDb().lookupDestinationLocally(h);
if (dest != null) {
if (_ctx.clientManager().isLocal(dest)) {
TunnelPoolSettings in = _ctx.tunnelManager().getInboundSettings(h);
if (in != null && in.getDestinationNickname() != null)
buf.append(in.getDestinationNickname());
else
buf.append(dest.toBase64().substring(0, 6)).append("…");
} else {
String host = _ctx.namingService().reverseLookup(dest);
if (host != null)
buf.append(host);
else
buf.append(dest.toBase64().substring(0, 6)).append("…");
}
}
buf.append("<td>");
SessionKey sk = e.getValue();
buf.append(sk.toBase64());
}
buf.append("\n</table>\n");
out.write(buf.toString());
out.flush();
}
}