package i5.las2peer.persistency;

import java.security.PublicKey;

import i5.las2peer.security.Agent;
import i5.las2peer.security.L2pSecurityException;
import i5.las2peer.tools.CryptoException;
import i5.las2peer.tools.CryptoTools;
import rice.p2p.commonapi.Id;
import rice.p2p.past.ContentHashPastContent;
import rice.p2p.past.PastContent;
import rice.p2p.past.PastException;

/**
 * A network artifact is a bunch of arbitrary data in the shared storage. It is signed to help detect manipulations.
 * Note that this signature is self signed, one has to check if the used key is in a list of trusted keys.
 */
public abstract class NetworkArtifact extends ContentHashPastContent {

	public static final int MAX_SIZE = 500 * 1000; // = 500 KB

	private static final long serialVersionUID = 1L;

	private final int partIndex;
	// TODO test different content types, String seems the fastest, also check BASE64, Serializable, byte[]
	private final byte[] content;
	private final byte[] signature;
	private final PublicKey key;
	private final byte[] keySignature;

	protected NetworkArtifact(Id id, int partIndex, byte[] content, Agent author)
			throws CryptoException, L2pSecurityException {
		super(id);
		int size = content.length;
		if (size > MAX_SIZE) {
			throw new IllegalArgumentException(
					"Given content has " + size + " bytes and is too big for maximum size " + MAX_SIZE);
		}
		this.partIndex = partIndex;
		this.content = content;
		this.signature = author.signContent(content);
		this.key = author.getPublicKey();
		this.keySignature = author.signContent(key.getEncoded());
	}

	public int getPartIndex() {
		return partIndex;
	}

	public byte[] getContent() throws VerificationFailedException {
		verify();
		return content;
	}

	public PublicKey getAuthorPublicKey() throws VerificationFailedException {
		verifyAuthorKey();
		return key;
	}

	public void verify() throws VerificationFailedException {
		// first we verify the contained public key is correct
		verifyAuthorKey();
		// after we verify the actual content is correct
		CryptoTools.verifySignature(signature, content, key);
	}

	private void verifyAuthorKey() throws VerificationFailedException {
		CryptoTools.verifySignature(keySignature, key.getEncoded(), key);
	}

	public boolean hasSameAuthor(NetworkArtifact other) {
		if (this == other) {
			return true;
		} else if (other == null) {
			return false;
		} else {
			return this.key.equals(other.key);
		}
	}

	@Override
	public PastContent checkInsert(Id id, PastContent existingContent) throws PastException {
		try {
			this.verify();
		} catch (VerificationFailedException e) {
			throw new PastException(e.toString());
		}
		return super.checkInsert(id, existingContent);
	}

	@Override
	public String toString() {
		return getId().toStringFull();
	}

}

@@ -48,25 +48,227 @@
 ecurity.
-PublicKey
+KeyFactory;%0Aimport java.security.NoSuchAlgorithmException;%0Aimport java.security.PublicKey;%0Aimport java.security.spec.InvalidKeySpecException;%0Aimport java.security.spec.X509EncodedKeySpec;%0Aimport java.util.Arrays
 ;%0A%0Aimpor
@@ -1207,22 +1207,101 @@
 nal 
-PublicKey key;
+byte%5B%5D encodedAuthorKey; // the PublicKey class contains enum and can't be serialized by Java
 %0A%09pr
@@ -1774,17 +1774,30 @@
 %0A%09%09this.
-k
+encodedAuthorK
 ey = aut
@@ -1810,24 +1810,37 @@
 tPublicKey()
+.getEncoded()
 ;%0A%09%09this.key
@@ -1870,32 +1870,32 @@
 Content(
-key.getEncoded()
+encodedAuthorKey
 );%0A%09%7D%0A%0A%09
@@ -2123,35 +2123,244 @@
 ion %7B%0A%09%09
-verifyAuthorKey(
+try %7B%0A%09%09%09PublicKey decoded = KeyFactory.getInstance(CryptoTools.getAsymmetricAlgorithm())%0A%09%09%09%09%09.generatePublic(new X509EncodedKeySpec(encodedAuthorKey));%0A%09%09%09CryptoTools.verifySignature(keySignature, encodedAuthorKey, decoded
 );%0A
+%09
 %09%09return
@@ -2364,12 +2364,171 @@
 urn 
-key;
+decoded;%0A%09%09%7D catch (InvalidKeySpecException %7C NoSuchAlgorithmException e) %7B%0A%09%09%09throw new VerificationFailedException(%22Decoding authors public key failed!%22, e);%0A%09%09%7D
 %0A%09%7D%0A
@@ -2597,24 +2597,35 @@
 // first we 
+decode and 
 verify the c
@@ -2657,28 +2657,59 @@
 rrect%0A%09%09
-verifyAuthor
+PublicKey authorPublicKey = getAuthorPublic
 Key();%0A%09
@@ -2812,150 +2812,21 @@
 nt, 
-key);%0A%09%7D%0A%0A%09private void verifyAuthorKey() throws VerificationFailedException %7B%0A%09%09CryptoTools.verifySignature(keySignature, key.getEncoded(), k
+authorPublicK
 ey);
@@ -2996,31 +2996,60 @@
 urn 
-this.key.equals(other.k
+Arrays.equals(encodedAuthorKey, other.encodedAuthorK
 ey);

remove PublicKey member from NetworkArtifact to fix serialization issues