package proof;

import java.io.*;
import java.util.*;
import java.security.*;

import sdsi.*;
import proof.*;
import servlet.*;

/**
 * An authenticator closure that works by invoking a private key
 * (stored in a local file) to sign a request. The stored key
 * may be encrypted with a passphrase, in which case this authenticator
 * will query the user through a UI for the passphrase to unlock the
 * stored key.
 *
 * @deprecated part of the original {@link Prover} class.
 * {@link Prover2} is the tool clients should use now.
 */
public class BasicUnlockKey
	implements AuthClosure {

	String filename;
	SDSIPrivateKey privateKey;
	SDSIPublicKey publicKey;

	public BasicUnlockKey(SDSIPrivateKey privateKey, SDSIPublicKey publicKey) {
		this.privateKey = privateKey;
		this.publicKey = publicKey;
	}

	public BasicUnlockKey(SDSIKeyPair kp) {
		this.privateKey = kp.getPrivateKey();
		this.publicKey = kp.getPublicKey();
	}

	public boolean equals(Object o) {
		if (o instanceof BasicUnlockKey) {
			return ((BasicUnlockKey) o).publicKey.equals(this.publicKey);
		}
		return false;
	}

	public int hashCode() {
		return publicKey.hashCode();
	}

	public BasicUnlockKey(String filename)
		throws FileNotFoundException {
		this.filename = filename;

		// just a quick hint beforehand.
		if (!new File(this.filename+".private").exists()) {
			throw new FileNotFoundException(filename);
		}
		publicKey = KeyTools.getPublicKey(filename);
	}

	public Subject getIssuer() { return publicKey; }

	/**
	 * This method returns null. What I mean to say is "we don't need
	 * anyone to speak for us, because we have the private key, so we
	 * can speak for ourselves."
	 */
	public Subject getSubject() { return null; }

	SDSIPublicKey getPublicKey() { return publicKey; }

	SDSIPrivateKey getPrivateKey() {
		if (privateKey != null) {
			return privateKey;
		} else {
			try {
				return KeyTools.getPrivateKey(filename);
			} catch (FileNotFoundException ex) {
				ex.printStackTrace();
			}
		}
		return null;
	}

	public Proof getProof(SDSIPrincipal issuer, Subject subject) {
		// It should be the case that issuer, myKey are same (or
		// issuer is the hash of myKey)
		// OR myKey => issuer, in which case we have to provide a proof
		// of such. (Handoff "rule" [notquiteanaxiom])
		// Otherwise this will generate a sillily signed sertificate.
		// (well, uselessly, unverifiably)

		try {
			SDSIPrivateKey myPrivateKey = getPrivateKey();
			SDSIPublicKey myPublicKey = getPublicKey();
			// TODO: here is where we would request & use a passphrase.
	
			// 30 seconds of validity. no notion of time synchronization.
			Validity v = new Validity();
			v.updateAfter(new Date(System.currentTimeMillis()+30000L));
	
			Auth authCert = new Auth(issuer, subject, Tag.getTagStar(),
				true, v);
	
			SDSISignature ss = new SDSISignature(authCert,
				myPrivateKey, myPublicKey);
			SignedCertificate sc = new SignedCertificate(authCert, ss);
			Proof handoff = null;
				// null handoff proof okay if principals are equivalent
			if (!KeyTools.arePrincipalsEquivalent(myPublicKey, issuer)) {
				// Need to also show that myPublicKey => issuer, to
				// show that my statement reflects truth. (handoff rule)
				if (issuer instanceof Quoting) {
					Quoting q = (Quoting) issuer;
					if (KeyTools.arePrincipalsEquivalent(myPublicKey,
						(SDSIPrincipal) q.getQuoter())) {
						// Use axiom: X => X | Y for all X, Y and
						// HandoffRule.
						handoff = new QuotingRule(q, myPublicKey);
					} else {
						System.err.println("Erk -- can't prove handoff!");
					}
				}
			}
			return new SignedCertificateProof(sc, handoff);
		} catch (SignatureException ex) {
			ex.printStackTrace();
		}
		return null;
	}

	public boolean isUsefulForAuth(Tag authTag) {
		return true;
	}
}
