package thaw.plugins.webOfTrust; import thaw.plugins.Hsqldb; import thaw.plugins.Signatures; import thaw.plugins.signatures.Identity; import thaw.plugins.signatures.TrustListParser; import thaw.core.Config; import thaw.core.Logger; import thaw.fcp.FCPQueueManager; import thaw.fcp.FCPClientPut; import thaw.fcp.FCPGenerateSSK; import thaw.fcp.FreenetURIHelper; import java.io.File; import java.io.FileOutputStream; import java.util.Date; import java.util.Observer; import java.util.Observable; import java.util.Vector; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.Element; public class TrustListUploader implements Signatures.SignaturesObserver, Observer { public final static long UPLOAD_AFTER_MS = 10*60*1000; /* 10 min */ private final FCPQueueManager queueManager; private final Config config; private final Hsqldb db; private Date lastUpload = null; private Date lastTrustChange = null; private Identity identity; private String privateKey; private String publicKey; private FCPClientPut upload; public TrustListUploader(Hsqldb db, FCPQueueManager queueManager, Config config) { this.queueManager = queueManager; this.config = config; this.db = db; lastUpload = null; lastTrustChange = null; identity = null; try { if (config.getValue("wotIdentityUsed") != null) identity = Identity.getIdentity(db, Integer.parseInt(config.getValue("wotIdentityUsed"))); } catch(Exception e) { Logger.error(this, "Error in the config : can't find the identity to use to upload the trust list (or its keys) => won't insert the trust list ; Exception throwed: "+e.toString()); } publicKey = null; privateKey = null; } public Identity getIdentityUsed() { return identity; } public void init() { lastUpload = null; if (config.getValue("wotLastUpload") != null) lastUpload = new Date(Long.parseLong(config.getValue("wotLastUpload"))); lastTrustChange = null; if (config.getValue("wotLastTrustChange") != null) lastTrustChange = new Date(Long.parseLong(config.getValue("wotLastTrustChange"))); if (config.getValue("wotPublicKey") != null) publicKey = config.getValue("wotPublicKey"); if (config.getValue("wotPrivateKey") != null) privateKey = config.getValue("wotPrivateKey"); if (publicKey == null || privateKey == null) { regenerateKeys(); } Signatures.addObserver(this); } public void regenerateKeys() { publicKey = null; privateKey = null; lastUpload = null; Logger.notice(this, "Regenerating a key pair for the wot of trust"); FCPGenerateSSK sskGenerator = new FCPGenerateSSK(); sskGenerator.addObserver(this); sskGenerator.start(queueManager); } /** * @return true if a trust change was done more than some times ago and no * trust list upload has been done between this change and now */ private boolean mustUpload() { /* never uploaded => we must do it for the first time */ if (lastUpload == null) return true; /* no change => no upload */ if (lastTrustChange == null) return false; /* if the last upload is older than the last trust change */ if (lastUpload.compareTo(lastTrustChange) < 0) { /* last change was done more than UPLOAD_AFTER_MS ms (for example 30min) */ if (new Date().getTime() - lastTrustChange.getTime() >= UPLOAD_AFTER_MS) return true; } return false; } /** * @return true if the list was already uploaded once or if we have more * than 1 identity with a trust != 0 and != dev trust */ private boolean hasSomethingToUpload() { /* if no identity selected, can't insert */ if (identity == null) return false; /* if a trust was changed at a given time */ /* then we must upload, even if it's to say we trust nobody anymore */ if (lastUpload != null || lastTrustChange != null) return true; return Identity.hasAtLeastATrustDefined(db); } private boolean addHeaders(Element rootEl, Document xmlDoc) { Element trustListOwnerEl = xmlDoc.createElement("trustListOwner"); Element nickEl = xmlDoc.createElement("nick"); nickEl.appendChild(xmlDoc.createTextNode(identity.getNick())); Element publicKeyEl = xmlDoc.createElement("publicKey"); publicKeyEl.appendChild(xmlDoc.createTextNode(identity.getPublicKey())); trustListOwnerEl.appendChild(nickEl); trustListOwnerEl.appendChild(publicKeyEl); rootEl.appendChild(trustListOwnerEl); return true; } private boolean exportTrustList(Vector identities, File file) { try { FileOutputStream out = new FileOutputStream(file); StreamResult streamResult; streamResult = new StreamResult(out); Document xmlDoc; final DocumentBuilderFactory xmlFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder xmlBuilder; try { xmlBuilder = xmlFactory.newDocumentBuilder(); } catch(final javax.xml.parsers.ParserConfigurationException e) { Logger.error(this, "Unable to generate the index because : "+e.toString()); return false; } final DOMImplementation impl = xmlBuilder.getDOMImplementation(); xmlDoc = impl.createDocument(null, "trustList", null); final Element rootEl = xmlDoc.getDocumentElement(); /**** DOM Tree generation ****/ addHeaders(rootEl, xmlDoc); TrustListParser.fillInRootElement(identities, rootEl, xmlDoc); /* Serialization */ final DOMSource domSource = new DOMSource(xmlDoc); final TransformerFactory transformFactory = TransformerFactory.newInstance(); Transformer serializer; try { serializer = transformFactory.newTransformer(); } catch(final javax.xml.transform.TransformerConfigurationException e) { Logger.error(this, "Unable to save index because: "+e.toString()); return false; } serializer.setOutputProperty(OutputKeys.ENCODING,"UTF-8"); serializer.setOutputProperty(OutputKeys.INDENT,"yes"); /* final step */ try { serializer.transform(domSource, streamResult); } catch(final javax.xml.transform.TransformerException e) { Logger.error(this, "Unable to save index because: "+e.toString()); return false; } out.close(); return true; } catch(java.io.FileNotFoundException e) { Logger.error(this, "File not found exception ?!"); } catch(java.io.IOException e) { Logger.error(this, "IOException while generating the index: "+e.toString()); } return false; } /** * called ~ each second */ public synchronized void process() { /* an upload is already running => can't upload */ if (upload != null) return; /* no private key => can't upload anyway */ if (privateKey == null || identity == null) return; if (mustUpload() && hasSomethingToUpload()) { Logger.notice(this, "MARK : Uploading your trust list ..."); try { File file = File.createTempFile("thaw-", "-trustList.xml"); Vector ids = Identity.getOtherIdentities(db); if (!exportTrustList(ids, file)) return; upload = new FCPClientPut(file, FCPClientPut.KEY_TYPE_SSK, 0, "trustList", FreenetURIHelper.convertSSKtoUSK(privateKey)+"/", /* the convertion fonction forget the '/' */ 2, /* priority */ false, /* global */ FCPClientPut.PERSISTENCE_UNTIL_DISCONNECT, /* persistence */ true, /* doCompress */ -1 ); /* compression codec */ upload.addObserver(this); queueManager.addQueryToTheRunningQueue(upload); } catch(java.io.IOException e) { Logger.error(this, "Can't upload your trust list because : "+e.toString()); e.printStackTrace(); } } } public void stop() { Signatures.deleteObserver(this); if (lastUpload == null) config.setValue("wotLastUpload", null); else config.setValue("wotLastUpload", Long.toString(lastUpload.getTime())); if (lastTrustChange == null) config.setValue("wotLastTrustChange", null); else config.setValue("wotLastTrustChange", Long.toString(lastTrustChange.getTime())); } public void identityUpdated(Identity i) { /* a dev was added => ignore */ if (i.getTrustLevel() == Identity.trustLevelInt[0]) return; lastTrustChange = new Date(); } public void privateIdentityAdded(Identity i) { /* a dev was added => ignore */ if (i.getTrustLevel() == Identity.trustLevelInt[0]) return; /* by default, new private identity have no trust, so we don't care */ identityUpdated(i); } public void publicIdentityAdded(Identity i) { /* by default, new public identity have no trust, so we don't care */ } public void update(Observable o, Object param) { if (o instanceof FCPGenerateSSK) { Logger.notice(this, "Key pair generated"); FCPGenerateSSK sskGenerator = (FCPGenerateSSK)o; publicKey = sskGenerator.getPublicKey(); privateKey = sskGenerator.getPrivateKey(); config.setValue("wotPrivateKey", privateKey); config.setValue("wotPublicKey", publicKey); } else if (o instanceof FCPClientPut) { if (upload.isFinished()) { upload.deleteObserver(this); if (upload.isSuccessful()) { Logger.notice(this, "Trust list inserted"); lastUpload = new Date(); } else Logger.warning(this, "Unable to insert trust list !"); upload.stop(queueManager); queueManager.remove(upload); if (upload.getPath() != null) new File(upload.getPath()).delete(); upload = null; } } } }