package edu.washington.cs.publickey; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; public abstract class PublicKeyClient { private final static String DEFAULT_EXISTING_FRIENDS = "friends.publickeyfriends"; public static boolean logToStdOut = false; private static void log(String msg) { if (logToStdOut) { System.out.println(msg); } } private final File existingFriendsFile; protected List<PublicKeyFriend> knownFriends; protected List<byte[]> knownKeys; public PublicKeyClient(File existingFriendsFile, List<byte[]> knownKeys) { this.existingFriendsFile = existingFriendsFile; this.knownKeys = knownKeys; this.loadKnownFriends(); } protected void addKnownFriends(List<PublicKeyFriend> newFriends) throws IOException { log("adding friends:" + newFriends.size()); HashMap<String, PublicKeyFriend> netUidHashToUid = new HashMap<String, PublicKeyFriend>(); HashMap<String, Boolean> knownPubKeys = new HashMap<String, Boolean>(); for (PublicKeyFriend f : knownFriends) { String netUid = Base64.encode(f.getSourceNetworkUid()); netUidHashToUid.put(netUid, f); if (f.getPublicKey() != null) { String publicKey = Base64.encode(f.getPublicKey()); knownPubKeys.put(publicKey, true); } /* * check if any of the known friends does not have any realname, in * that case search for it */ if (f.getRealName() == null) { for (PublicKeyFriend newFriend : newFriends) { if (Arrays.equals(newFriend.getSourceNetworkUid(), f.getSourceNetworkUid())) { if (f.getRealName() == null) { log("Updating friend, just got the realname"); f.setRealName(newFriend.getRealName()); } } } } } // for each entry, check if we already know about that friend // if not, add, if we do, update or ignore for (PublicKeyFriend newFriend : newFriends) { // users can either be added if they are the first user with a // certain uid String netUid = Base64.encode(newFriend.getSourceNetworkUid()); if (!netUidHashToUid.containsKey(netUid)) { knownFriends.add(newFriend); log("adding: " + newFriend); } else if (newFriend.getPublicKey() != null) { // or if we don't have that public key String publicKey = Base64.encode(newFriend.getPublicKey()); if (!knownPubKeys.containsKey(publicKey)) { // check if we need to add the real name // we might have a dummy user in there PublicKeyFriend existing = netUidHashToUid.get(netUid); if (existing.getPublicKey() == null) { log("updating: " + existing); existing.setPublicKey(newFriend.getPublicKey()); existing.setPublicKeySha1(newFriend.getPublicKeySha1()); existing.setKeyNick(newFriend.getKeyNick()); log(existing.toString()); } else { // the existing one already has a public key // this must mean that this is the second+ for that user newFriend.setRealName(existing.getRealName()); knownFriends.add(newFriend); log("adding: " + newFriend); } } else { if (newFriend.getRealName() == null) { log("strange, new public key but no uid->realname mapping: " + newFriend); } } } } File friendPath = existingFriendsFile; if (friendPath == null) { friendPath = new File(DEFAULT_EXISTING_FRIENDS); } /* * create the parent directory if not exists */ if (!friendPath.exists()) { File parent = friendPath.getParentFile(); if (parent != null && !parent.exists()) { parent.mkdirs(); } } String serialized = PublicKeyFriend.serialize(knownFriends.toArray(new PublicKeyFriend[knownFriends.size()])); BufferedWriter out = new BufferedWriter(new FileWriter(friendPath)); out.write(serialized); out.close(); } public abstract void connect() throws Exception; public abstract void disconnect() throws Exception; public List<PublicKeyFriend> getFriends() { return knownFriends; } protected List<byte[]> getKnownKeySha1s() { List<byte[]> knownKeyList = new ArrayList<byte[]>(); for (byte[] key : knownKeys) { try { knownKeyList.add(Tools.getSha1(key)); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return knownKeyList; } private void loadKnownFriends() { knownFriends = new ArrayList<PublicKeyFriend>(); File friendPath = existingFriendsFile; if (friendPath == null) { friendPath = new File(DEFAULT_EXISTING_FRIENDS); } StringBuilder b = new StringBuilder(); BufferedReader in; try { in = new BufferedReader(new FileReader(friendPath)); String line; while ((line = in.readLine()) != null) { b.append(line); } in.close(); knownFriends.addAll(Arrays.asList(PublicKeyFriend.deserialize(b.toString()))); } catch (FileNotFoundException e) { log("existing friends file not found: " + friendPath); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public abstract void updateFriends() throws Exception; }