package io.bitsquare.p2p.storage.storageentry; import com.google.common.annotations.VisibleForTesting; import io.bitsquare.app.Version; import io.bitsquare.common.crypto.Sig; import io.bitsquare.common.wire.Payload; import io.bitsquare.p2p.storage.payload.StoragePayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; public class ProtectedStorageEntry implements Payload { // That object is sent over the wire, so we need to take care of version compatibility. private static final long serialVersionUID = Version.P2P_NETWORK_VERSION; private static final Logger log = LoggerFactory.getLogger(ProtectedStorageEntry.class); protected final StoragePayload storagePayload; private final byte[] ownerPubKeyBytes; public transient PublicKey ownerPubKey; public int sequenceNumber; public byte[] signature; @VisibleForTesting public long creationTimeStamp; public ProtectedStorageEntry(StoragePayload storagePayload, PublicKey ownerPubKey, int sequenceNumber, byte[] signature) { this.storagePayload = storagePayload; this.ownerPubKey = ownerPubKey; this.sequenceNumber = sequenceNumber; this.signature = signature; this.creationTimeStamp = System.currentTimeMillis(); this.ownerPubKeyBytes = new X509EncodedKeySpec(this.ownerPubKey.getEncoded()).getEncoded(); } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { try { in.defaultReadObject(); ownerPubKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(ownerPubKeyBytes)); checkCreationTimeStamp(); } catch (Throwable t) { log.warn("Exception at readObject: " + t.getMessage()); } } public StoragePayload getStoragePayload() { return storagePayload; } public void checkCreationTimeStamp() { // We don't allow creation date in the future, but we cannot be too strict as clocks are not synced // The 0 test is needed to be backward compatible as creationTimeStamp (timeStamp) was transient before 0.4.7 // TODO "|| creationTimeStamp == 0" can removed after we don't support 0.4.6 anymore if (creationTimeStamp > System.currentTimeMillis() || creationTimeStamp == 0) creationTimeStamp = System.currentTimeMillis(); } public void refreshTTL() { creationTimeStamp = System.currentTimeMillis(); } public void backDate() { creationTimeStamp -= storagePayload.getTTL() / 2; } public void updateSequenceNumber(int sequenceNumber) { this.sequenceNumber = sequenceNumber; } public void updateSignature(byte[] signature) { this.signature = signature; } public boolean isExpired() { return (System.currentTimeMillis() - creationTimeStamp) > storagePayload.getTTL(); } @Override public String toString() { return "ProtectedStorageEntry{" + "expirablePayload=" + storagePayload + ", creationTimeStamp=" + creationTimeStamp + ", sequenceNumber=" + sequenceNumber + ", ownerPubKey.hashCode()=" + (ownerPubKey != null ? ownerPubKey.hashCode() : "null") + ", signature.hashCode()=" + (signature != null ? Arrays.toString(signature).hashCode() : "null") + '}'; } }