forked from I2P_Developers/i2p.i2p
Router: Implement expiration for BlindData entries
This commit is contained in:
@ -63,7 +63,7 @@ public abstract class LocalHTTPServer {
|
|||||||
"Add to addressbook failed - bad parameters";
|
"Add to addressbook failed - bad parameters";
|
||||||
|
|
||||||
private final static String ERR_B32 =
|
private final static String ERR_B32 =
|
||||||
"HTTP/1.1 409 Bad\r\n"+
|
"HTTP/1.1 400 Bad\r\n"+
|
||||||
"Content-Type: text/plain\r\n"+
|
"Content-Type: text/plain\r\n"+
|
||||||
"Connection: close\r\n"+
|
"Connection: close\r\n"+
|
||||||
"Proxy-Connection: close\r\n"+
|
"Proxy-Connection: close\r\n"+
|
||||||
@ -271,8 +271,13 @@ public abstract class LocalHTTPServer {
|
|||||||
SigningPublicKey spk = bd.getUnblindedPubKey();
|
SigningPublicKey spk = bd.getUnblindedPubKey();
|
||||||
SigType bt = bd.getBlindedSigType();
|
SigType bt = bd.getBlindedSigType();
|
||||||
bd = new BlindData(context, spk, bt, secret, authType, privateKey);
|
bd = new BlindData(context, spk, bt, secret, authType, privateKey);
|
||||||
|
long now = context.clock().now();
|
||||||
|
bd.setDate(now);
|
||||||
|
long exp = now + ((bd.getAuthRequired() || bd.getSecretRequired()) ? 365*24*60*60*1000L
|
||||||
|
: 90*24*68*60*1000L);
|
||||||
|
bd.setExpiration(exp);
|
||||||
I2PSession sess = sockMgr.getSession();
|
I2PSession sess = sockMgr.getSession();
|
||||||
sess.sendBlindingInfo(bd, 365*60*60*1000);
|
sess.sendBlindingInfo(bd);
|
||||||
writeRedirectPage(out, success, host, "FIXME", url);
|
writeRedirectPage(out, success, host, "FIXME", url);
|
||||||
return;
|
return;
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
|
@ -439,10 +439,9 @@ public interface I2PSession {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param expiration ms from now, 0 means forever
|
|
||||||
* @since 0.9.43
|
* @since 0.9.43
|
||||||
*/
|
*/
|
||||||
public void sendBlindingInfo(BlindData bd, int expiration) throws I2PSessionException;
|
public void sendBlindingInfo(BlindData bd) throws I2PSessionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen on specified protocol and port.
|
* Listen on specified protocol and port.
|
||||||
|
@ -1860,10 +1860,9 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param expiration ms from now, 0 means forever
|
|
||||||
* @since 0.9.43
|
* @since 0.9.43
|
||||||
*/
|
*/
|
||||||
public void sendBlindingInfo(BlindData bd, int expiration) throws I2PSessionException {
|
public void sendBlindingInfo(BlindData bd) throws I2PSessionException {
|
||||||
if (!_routerSupportsBlindingInfo)
|
if (!_routerSupportsBlindingInfo)
|
||||||
throw new I2PSessionException("Router does not support BlindingInfo");
|
throw new I2PSessionException("Router does not support BlindingInfo");
|
||||||
if (_log.shouldInfo())
|
if (_log.shouldInfo())
|
||||||
@ -1871,7 +1870,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
|||||||
SessionId id = _sessionId;
|
SessionId id = _sessionId;
|
||||||
if (id == null)
|
if (id == null)
|
||||||
id = DUMMY_SESSION;
|
id = DUMMY_SESSION;
|
||||||
sendMessage_unchecked(new BlindingInfoMessage(bd, id, expiration));
|
sendMessage_unchecked(new BlindingInfoMessage(bd, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateActivity() {
|
protected void updateActivity() {
|
||||||
|
@ -28,6 +28,7 @@ public class BlindData {
|
|||||||
private boolean _secretRequired;
|
private boolean _secretRequired;
|
||||||
private boolean _authRequired;
|
private boolean _authRequired;
|
||||||
private long _date;
|
private long _date;
|
||||||
|
private long _expiration;
|
||||||
private String _b32;
|
private String _b32;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,6 +258,7 @@ public class BlindData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Creation date. Absolute timestamp.
|
||||||
* @since 0.9.41
|
* @since 0.9.41
|
||||||
*/
|
*/
|
||||||
public void setDate(long date) {
|
public void setDate(long date) {
|
||||||
@ -264,6 +266,9 @@ public class BlindData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Creation date. Absolute timestamp.
|
||||||
|
* Returns zero if not specified.
|
||||||
|
*
|
||||||
* @return creation date or as overridden by setDate()
|
* @return creation date or as overridden by setDate()
|
||||||
* @since 0.9.41
|
* @since 0.9.41
|
||||||
*/
|
*/
|
||||||
@ -271,14 +276,33 @@ public class BlindData {
|
|||||||
return _date;
|
return _date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expiration date. Absolute timestamp.
|
||||||
|
* @since 0.9.43
|
||||||
|
*/
|
||||||
|
public void setExpiration(long date) {
|
||||||
|
_expiration = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expiration date. Absolute timestamp.
|
||||||
|
* Returns zero if not specified.
|
||||||
|
*
|
||||||
|
* @return expiration date or as overridden by setExpiration()
|
||||||
|
* @since 0.9.43
|
||||||
|
*/
|
||||||
|
public long getExpiration() {
|
||||||
|
return _expiration;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String toString() {
|
public synchronized String toString() {
|
||||||
calculate();
|
calculate();
|
||||||
StringBuilder buf = new StringBuilder(1024);
|
StringBuilder buf = new StringBuilder(1024);
|
||||||
buf.append("[BlindData: ");
|
buf.append("[BlindData: ");
|
||||||
buf.append("\n\tSigningPublicKey: ").append(_clearSPK);
|
buf.append("\n\tSigningPublicKey: ").append(_clearSPK);
|
||||||
buf.append("\n\tAlpha : ").append(_alpha);
|
buf.append("\n\tAlpha : ").append(getAlpha());
|
||||||
buf.append("\n\tAlpha valid for : ").append((new Date(_date)).toString());
|
buf.append("\n\tAlpha valid for : ").append((new Date(_routingKeyGenMod)).toString());
|
||||||
buf.append("\n\tBlindedPublicKey: ").append(_blindSPK);
|
buf.append("\n\tBlindedPublicKey: ").append(_blindSPK);
|
||||||
buf.append("\n\tBlinded Hash : ").append(_blindHash);
|
buf.append("\n\tBlinded Hash : ").append(_blindHash);
|
||||||
if (_secret != null)
|
if (_secret != null)
|
||||||
@ -305,6 +329,10 @@ public class BlindData {
|
|||||||
buf.append("\n\t + secret : ").append(Blinding.encode(_clearSPK, true, _authRequired));
|
buf.append("\n\t + secret : ").append(Blinding.encode(_clearSPK, true, _authRequired));
|
||||||
if (!(_authRequired || _secretRequired))
|
if (!(_authRequired || _secretRequired))
|
||||||
buf.append("\n\t + auth,secret : ").append(Blinding.encode(_clearSPK, true, true));
|
buf.append("\n\t + auth,secret : ").append(Blinding.encode(_clearSPK, true, true));
|
||||||
|
if (_date > 0)
|
||||||
|
buf.append("\n\tCreated : ").append((new Date(_date)).toString());
|
||||||
|
if (_expiration > 0)
|
||||||
|
buf.append("\n\tExpires : ").append((new Date(_expiration)).toString());
|
||||||
buf.append(']');
|
buf.append(']');
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
@ -60,9 +60,8 @@ public class BlindingInfoMessage extends I2CPMessageImpl {
|
|||||||
*
|
*
|
||||||
* @param expiration ms from now or 0 for forever
|
* @param expiration ms from now or 0 for forever
|
||||||
*/
|
*/
|
||||||
public BlindingInfoMessage(BlindData bd,
|
public BlindingInfoMessage(BlindData bd, SessionId id) {
|
||||||
SessionId id, int expiration) {
|
this(id, bd.getExpiration(), bd.getAuthType(), bd.getBlindedSigType(), bd.getAuthPrivKey(), bd.getSecret());
|
||||||
this(id, expiration, bd.getAuthType(), bd.getBlindedSigType(), bd.getAuthPrivKey(), bd.getSecret());
|
|
||||||
Destination dest = bd.getDestination();
|
Destination dest = bd.getDestination();
|
||||||
if (dest != null) {
|
if (dest != null) {
|
||||||
_dest = dest;
|
_dest = dest;
|
||||||
@ -157,13 +156,13 @@ public class BlindingInfoMessage extends I2CPMessageImpl {
|
|||||||
_endpointType = TYPE_KEY;
|
_endpointType = TYPE_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlindingInfoMessage(SessionId id, int expiration, int authType, SigType blindType,
|
private BlindingInfoMessage(SessionId id, long expiration, int authType, SigType blindType,
|
||||||
PrivateKey privKey, String secret) {
|
PrivateKey privKey, String secret) {
|
||||||
if (id == null || blindType == null)
|
if (id == null || blindType == null)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if (authType != BlindData.AUTH_NONE && authType != BlindData.AUTH_DH &&
|
if (authType != BlindData.AUTH_NONE && authType != BlindData.AUTH_DH &&
|
||||||
authType != BlindData.AUTH_PSK)
|
authType != BlindData.AUTH_PSK)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException("Bad auth type");
|
||||||
if (authType == BlindData.AUTH_NONE && privKey != null)
|
if (authType == BlindData.AUTH_NONE && privKey != null)
|
||||||
throw new IllegalArgumentException("no key required");
|
throw new IllegalArgumentException("no key required");
|
||||||
if (authType != BlindData.AUTH_NONE && privKey == null)
|
if (authType != BlindData.AUTH_NONE && privKey == null)
|
||||||
@ -171,8 +170,9 @@ public class BlindingInfoMessage extends I2CPMessageImpl {
|
|||||||
_sessionId = id;
|
_sessionId = id;
|
||||||
_authType = authType;
|
_authType = authType;
|
||||||
_blindType = blindType;
|
_blindType = blindType;
|
||||||
if (expiration > 0)
|
_expiration = expiration;
|
||||||
_expiration = expiration + I2PAppContext.getGlobalContext().clock().now();
|
if (expiration > 0 && expiration < Integer.MAX_VALUE)
|
||||||
|
_expiration += I2PAppContext.getGlobalContext().clock().now();
|
||||||
_privkey = privKey;
|
_privkey = privKey;
|
||||||
_secret = secret;
|
_secret = secret;
|
||||||
}
|
}
|
||||||
@ -262,6 +262,10 @@ public class BlindingInfoMessage extends I2CPMessageImpl {
|
|||||||
_blindData = new BlindData(I2PAppContext.getGlobalContext(), _dest, _blindType, _secret, _authType, _privkey);
|
_blindData = new BlindData(I2PAppContext.getGlobalContext(), _dest, _blindType, _secret, _authType, _privkey);
|
||||||
else if (_endpointType == TYPE_KEY)
|
else if (_endpointType == TYPE_KEY)
|
||||||
_blindData = new BlindData(I2PAppContext.getGlobalContext(), _pubkey, _blindType, _secret, _authType, _privkey);
|
_blindData = new BlindData(I2PAppContext.getGlobalContext(), _pubkey, _blindType, _secret, _authType, _privkey);
|
||||||
|
if (_blindData != null) {
|
||||||
|
_blindData.setDate(I2PAppContext.getGlobalContext().clock().now());
|
||||||
|
_blindData.setExpiration(_expiration);
|
||||||
|
}
|
||||||
// HASH and HOST not supported by router yet
|
// HASH and HOST not supported by router yet
|
||||||
return _blindData;
|
return _blindData;
|
||||||
}
|
}
|
||||||
@ -278,7 +282,7 @@ public class BlindingInfoMessage extends I2CPMessageImpl {
|
|||||||
_blindType = SigType.getByCode(bt);
|
_blindType = SigType.getByCode(bt);
|
||||||
if (_blindType == null)
|
if (_blindType == null)
|
||||||
throw new I2CPMessageException("unsupported sig type " + bt);
|
throw new I2CPMessageException("unsupported sig type " + bt);
|
||||||
_expiration = DataHelper.readLong(in, 4);
|
_expiration = DataHelper.readLong(in, 4) * 1000;
|
||||||
if (_endpointType == TYPE_HASH) {
|
if (_endpointType == TYPE_HASH) {
|
||||||
_hash = Hash.create(in);
|
_hash = Hash.create(in);
|
||||||
} else if (_endpointType == TYPE_HOST) {
|
} else if (_endpointType == TYPE_HOST) {
|
||||||
@ -338,7 +342,7 @@ public class BlindingInfoMessage extends I2CPMessageImpl {
|
|||||||
os.write(flags);
|
os.write(flags);
|
||||||
os.write((byte) _endpointType);
|
os.write((byte) _endpointType);
|
||||||
DataHelper.writeLong(os, 2, _blindType.getCode());
|
DataHelper.writeLong(os, 2, _blindType.getCode());
|
||||||
DataHelper.writeLong(os, 4, _expiration);
|
DataHelper.writeLong(os, 4, _expiration / 1000);
|
||||||
if (_endpointType == TYPE_HASH) {
|
if (_endpointType == TYPE_HASH) {
|
||||||
_hash.writeBytes(os);
|
_hash.writeBytes(os);
|
||||||
} else if (_endpointType == TYPE_HOST) {
|
} else if (_endpointType == TYPE_HOST) {
|
||||||
|
@ -838,10 +838,18 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
|||||||
_context.netDb().setBlindData(bd);
|
_context.netDb().setBlindData(bd);
|
||||||
if (_log.shouldWarn())
|
if (_log.shouldWarn())
|
||||||
_log.warn("Updated: " + bd);
|
_log.warn("Updated: " + bd);
|
||||||
|
} else {
|
||||||
|
long oexp = obd.getExpiration();
|
||||||
|
long nexp = bd.getExpiration();
|
||||||
|
if (nexp > oexp) {
|
||||||
|
obd.setExpiration(nexp);
|
||||||
|
if (_log.shouldWarn())
|
||||||
|
_log.warn("Updated expiration: " + obd);
|
||||||
} else {
|
} else {
|
||||||
if (_log.shouldWarn())
|
if (_log.shouldWarn())
|
||||||
_log.warn("No change: " + obd);
|
_log.warn("No change: " + obd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,11 @@ class LookupDestJob extends JobImpl {
|
|||||||
bd = bd2;
|
bd = bd2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
long now = getContext().clock().now();
|
||||||
|
bd.setDate(now);
|
||||||
|
long exp = now + ((bd.getAuthRequired() || bd.getSecretRequired()) ? 365*24*60*60*1000L
|
||||||
|
: 90*24*68*60*1000L);
|
||||||
|
bd.setExpiration(exp);
|
||||||
getContext().netDb().setBlindData(bd);
|
getContext().netDb().setBlindData(bd);
|
||||||
}
|
}
|
||||||
h = bd.getBlindedHash();
|
h = bd.getBlindedHash();
|
||||||
|
@ -275,13 +275,17 @@ class BlindCache {
|
|||||||
/**
|
/**
|
||||||
* Load from file.
|
* Load from file.
|
||||||
* Format:
|
* Format:
|
||||||
* sigtype,bsigtype,b64 pubkey,[b64 secret],[b64 dest]
|
* sigtype,bsigtype,authtype,timestamp,b64 pubkey,[b64 secret],[b64 auth privkey],[b64 dest]
|
||||||
|
*
|
||||||
|
* If timestamp is positive, it's a creation date;
|
||||||
|
* if negative, it's a negative expiration date.
|
||||||
*/
|
*/
|
||||||
private synchronized void load() {
|
private synchronized void load() {
|
||||||
File file = new File(_context.getConfigDir(), PERSIST_FILE);
|
File file = new File(_context.getConfigDir(), PERSIST_FILE);
|
||||||
if (!file.exists())
|
if (!file.exists())
|
||||||
return;
|
return;
|
||||||
Log log = _context.logManager().getLog(BlindCache.class);
|
Log log = _context.logManager().getLog(BlindCache.class);
|
||||||
|
long now = _context.clock().now();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
BufferedReader br = null;
|
BufferedReader br = null;
|
||||||
try {
|
try {
|
||||||
@ -292,7 +296,14 @@ class BlindCache {
|
|||||||
if (line.startsWith("#"))
|
if (line.startsWith("#"))
|
||||||
continue;
|
continue;
|
||||||
try {
|
try {
|
||||||
storeInCache(fromPersistentString(line));
|
BlindData bd = fromPersistentString(line);
|
||||||
|
long exp = bd.getExpiration();
|
||||||
|
if (exp > 0 && exp < now) {
|
||||||
|
if (log.shouldInfo())
|
||||||
|
log.info("Skipping expired entry " + bd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
storeInCache(bd);
|
||||||
count++;
|
count++;
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
if (log.shouldLog(Log.WARN))
|
if (log.shouldLog(Log.WARN))
|
||||||
@ -341,6 +352,9 @@ class BlindCache {
|
|||||||
/**
|
/**
|
||||||
* Format:
|
* Format:
|
||||||
* sigtype,bsigtype,authtype,timestamp,b64 pubkey,[b64 secret],[b64 auth privkey],[b64 dest]
|
* sigtype,bsigtype,authtype,timestamp,b64 pubkey,[b64 secret],[b64 auth privkey],[b64 dest]
|
||||||
|
*
|
||||||
|
* If timestamp is positive, it's a creation date;
|
||||||
|
* if negative, it's a negative expiration date.
|
||||||
*/
|
*/
|
||||||
private BlindData fromPersistentString(String line) throws DataFormatException {
|
private BlindData fromPersistentString(String line) throws DataFormatException {
|
||||||
String[] ss = DataHelper.split(line, ",", 8);
|
String[] ss = DataHelper.split(line, ",", 8);
|
||||||
@ -389,13 +403,21 @@ class BlindCache {
|
|||||||
} else {
|
} else {
|
||||||
rv = new BlindData(_context, spk, st2, secret, auth, privkey);
|
rv = new BlindData(_context, spk, st2, secret, auth, privkey);
|
||||||
}
|
}
|
||||||
|
if (time >= 0) {
|
||||||
rv.setDate(time);
|
rv.setDate(time);
|
||||||
|
} else {
|
||||||
|
rv.setDate(_context.clock().now());
|
||||||
|
rv.setExpiration(0 - time);
|
||||||
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format:
|
* Format:
|
||||||
* sigtype,bsigtype,authtype,timestamp,b64 pubkey,[b64 secret],[b64 auth privkey],[b64 dest]
|
* sigtype,bsigtype,authtype,timestamp,b64 pubkey,[b64 secret],[b64 auth privkey],[b64 dest]
|
||||||
|
*
|
||||||
|
* If timestamp is positive, it's a creation date;
|
||||||
|
* if negative, it's a negative expiration date.
|
||||||
*/
|
*/
|
||||||
private static String toPersistentString(BlindData bd) {
|
private static String toPersistentString(BlindData bd) {
|
||||||
StringBuilder buf = new StringBuilder(1024);
|
StringBuilder buf = new StringBuilder(1024);
|
||||||
@ -403,7 +425,12 @@ class BlindCache {
|
|||||||
buf.append(spk.getType().getCode()).append(',');
|
buf.append(spk.getType().getCode()).append(',');
|
||||||
buf.append(bd.getBlindedSigType().getCode()).append(',');
|
buf.append(bd.getBlindedSigType().getCode()).append(',');
|
||||||
buf.append(bd.getAuthType()).append(',');
|
buf.append(bd.getAuthType()).append(',');
|
||||||
buf.append(bd.getDate()).append(',');
|
long time = bd.getExpiration();
|
||||||
|
if (time > 0)
|
||||||
|
time = 0 - time;
|
||||||
|
else
|
||||||
|
time = bd.getDate();
|
||||||
|
buf.append(time).append(',');
|
||||||
buf.append(spk.toBase64()).append(',');
|
buf.append(spk.toBase64()).append(',');
|
||||||
String secret = bd.getSecret();
|
String secret = bd.getSecret();
|
||||||
if (secret != null && secret.length() > 0)
|
if (secret != null && secret.length() > 0)
|
||||||
|
Reference in New Issue
Block a user