package edu.washington.cs.oneswarm.f2f.friends;
import java.io.File;
import java.security.PublicKey;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.net.ssl.SSLContext;
import org.bouncycastle.util.encoders.Base64;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.FileUtil;
import org.gudy.azureus2.core3.util.SystemProperties;
import com.aelitis.azureus.core.networkmanager.impl.osssl.OneSwarmSslKeyManager;
import edu.washington.cs.oneswarm.f2f.Log;
import edu.washington.cs.publickey.CryptoHandler;
import edu.washington.cs.publickey.PublicKeyFriend;
import edu.washington.cs.publickey.ssl.client.PublicKeySSLClient;
import edu.washington.cs.publickey.xmpp.XMPPNetwork;
import edu.washington.cs.publickey.xmpp.client.PublicKeyXmppClient;
public class FriendImportManager {
public final static String OSF2F_ENABLE_FRIEND_NOTIFICATIONS = "OSF2F.FriendNotifications";
private final static String SSL_PUBLIC_KEY_publickey_cs_washington_edu = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCv9or8xCzErICJ5PI3IzQveXIlgNb0zsgeP4UhpuOQgwFjPuvuCi2LK6CmZ2LR0feGdacX9uNF8UDMsGAcqQL8sToGyKnnINzO9uDjfeVMETQSjZpDtkWqpSEKTGoSqK92RJPQaNGz1l785sVYfheQ4/yh6tOCE2A8u9Ah66FcJwIDAQAB";
private final static int SSL_PORT = 5221;
private final static int CHECK_PERIOD = 15 * 60 * 1000;
private final static String SSL_HOSTNAME = "publickey.oneswarm.org";
public static File importedFriendsFile;
public final static String FRIENDS_CACHE_FILE_NAME = "importedFriends.xml";
public static final File FRIENDS_CACHE_DIR;
public static boolean logToStdOut = false;
static {
FRIENDS_CACHE_DIR = new File(SystemProperties.getUserPath() + File.separator
+ FriendManager.OSF2F_DIR_NAME);
if (!FRIENDS_CACHE_DIR.isDirectory()) {
FRIENDS_CACHE_DIR.mkdirs();
}
importedFriendsFile = new File(FRIENDS_CACHE_DIR, FRIENDS_CACHE_FILE_NAME);
}
private List<PublicKeyFriend> newFriends = new LinkedList<PublicKeyFriend>();
final FriendManager friendManager;
public FriendImportManager(final FriendManager friendManager) {
this.friendManager = friendManager;
COConfigurationManager.addParameterListener(OSF2F_ENABLE_FRIEND_NOTIFICATIONS,
new ParameterListener() {
@Override
public void parameterChanged(String parameterName) {
boolean enabled = isNotificationsEnabled();
if (enabled) {
checkForNewFriends();
} else {
newFriends = new LinkedList<PublicKeyFriend>();
}
}
});
// TimerTask timerTask = new TimerTask() {
// @Override
// public void run() {
// checkForNewFriends();
// }
// };
// Timer t = new Timer("FriendImportManager", true);
//
// t.schedule(timerTask, 20 * 1000, CHECK_PERIOD);
}
private synchronized void checkForNewFriends() {
try {
if (isNotificationsEnabled()) {
Log.log("autochecking for new friends", logToStdOut);
newFriends = checkForNewFriends(friendManager.getKnownKeysForFriendImport());
Log.log("autocheck says: " + newFriends.size(), true);
} else {
Log.log("Skipping new friend auto check due to privacy settings", logToStdOut);
}
// Log.log("Counts: " + countUsersPerNetwork(newFriends),
// logToStdOut);
} catch (Exception e) {
Debug.out("Friend request check failed: " + e.getMessage());
}
}
private boolean isNotificationsEnabled() {
return COConfigurationManager.getBooleanParameter(OSF2F_ENABLE_FRIEND_NOTIFICATIONS);
}
public List<PublicKeyFriend> getNewFriends() {
return newFriends;
}
public static String[] getXmppNetworks() {
List<String> networks = new LinkedList<String>();
for (XMPPNetwork net : XMPPNetwork.networks) {
networks.add(net.getDisplayName());
}
return networks.toArray(new String[networks.size()]);
}
public static List<PublicKeyFriend> checkForNewFriends(List<byte[]> knownKeys) throws Exception {
PublicKeySSLClient client = new PublicKeySSLClient(importedFriendsFile, knownKeys,
SSL_HOSTNAME, SSL_PORT, Base64.decode(SSL_PUBLIC_KEY_publickey_cs_washington_edu),
new CryptoHandler() {
@Override
public PublicKey getPublicKey() {
return OneSwarmSslKeyManager.getInstance().getOwnPublicKey();
}
@Override
public SSLContext getSSLContext() throws Exception {
return OneSwarmSslKeyManager.getInstance().getSSLContext();
}
@Override
public byte[] sign(byte[] data) throws Exception {
return null;
}
});
Log.log("autochecking: connecting", logToStdOut);
client.connect();
Log.log("autochecking: updateFriends", logToStdOut);
client.updateFriends();
Log.log("autochecking: disconnect", logToStdOut);
client.disconnect();
List<PublicKeyFriend> friends = client.getFriends();
Log.log("autochecking: got: " + friends.size(), logToStdOut);
return friends;
}
/*
* use many of them so that we don't cause any load balancing issues for our
* friends at gtalk...
*/
public final static String[] GTALK_KEY_SERVER_BOTS = new String[] {
"publickey.cs.washington.edu@gmail.com", "publickey1.cs.washington.edu@gmail.com",
"publickey2.cs.washington.edu@gmail.com", "publickey3.cs.washington.edu@gmail.com",
"publickey4.cs.washington.edu@gmail.com", "publickey5.cs.washington.edu@gmail.com",
"publickey6.cs.washington.edu@gmail.com", "publickey7.cs.washington.edu@gmail.com",
"publickey8.cs.washington.edu@gmail.com", "publickey9.cs.washington.edu@gmail.com" };
private static String gtalkStatus = null;
public static List<PublicKeyFriend> importXMPPFriends(List<byte[]> knownKeys,
String networkName, String username, char[] password, String machineName)
throws Exception {
File tempImportFile = new File(FRIENDS_CACHE_FILE_NAME, FRIENDS_CACHE_FILE_NAME + "_"
+ Long.toHexString(System.currentTimeMillis()) + ".xml");
tempImportFile.deleteOnExit();
try {
XMPPNetwork net = XMPPNetwork.getFromName(networkName);
final PublicKeyXmppClient client = new PublicKeyXmppClient(tempImportFile, knownKeys,
net, username, password, machineName, new CryptoHandler() {
@Override
public PublicKey getPublicKey() {
return OneSwarmSslKeyManager.getInstance().getOwnPublicKey();
}
@Override
public SSLContext getSSLContext() throws Exception {
return OneSwarmSslKeyManager.getInstance().getSSLContext();
}
@Override
public byte[] sign(byte[] data) throws Exception {
return OneSwarmSslKeyManager.getInstance().sign(data);
}
});
client.setServerBotName("OneSwarm Friend Finder");
client.setServerBotUserId(GTALK_KEY_SERVER_BOTS[new Random()
.nextInt(GTALK_KEY_SERVER_BOTS.length)]);
gtalkStatus = "connecting...";
/*
* start a thread to update the status, we will want to do this
* using an object and a manager later
*/
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 30; i++) {
if (gtalkStatus == null) {
return;
}
gtalkStatus = client.getStatus();
Thread.sleep(500);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t.setDaemon(true);
t.setName("gtalk status checker");
t.start();
/*
* the do the actual work
*/
client.connect();
client.updateFriends();
client.disconnect();
gtalkStatus = null;
List<PublicKeyFriend> importedFriends = client.getFriends();
FileUtil.copyFile(tempImportFile, importedFriendsFile);
return importedFriends;
} finally {
tempImportFile.delete();
}
}
public static String getGtalkStatus() {
return gtalkStatus;
}
}