package info.guardianproject.otr.app;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.List;
import net.java.otr4j.OtrEngineImpl;
import net.java.otr4j.OtrEngineListener;
import net.java.otr4j.OtrException;
import net.java.otr4j.OtrKeyManagerImpl;
import net.java.otr4j.OtrKeyManagerListener;
import net.java.otr4j.OtrPolicy;
import net.java.otr4j.OtrPolicyImpl;
import net.java.otr4j.session.OtrSm;
import net.java.otr4j.session.OtrSm.OtrSmEngineHost;
import net.java.otr4j.session.SessionID;
import net.java.otr4j.session.SessionStatus;
import net.java.otr4j.session.TLV;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.packet.Packet;
public class SampleApp implements OtrSmEngineHost {
private String peer;
private XMPPConnection con;
private OtrKeyManagerImpl otrKeyManager;
private OtrPolicy otrPolicy;
private SessionID sessionID;
private OtrSm otrSm;
private OtrEngineImpl otrEngine;
SampleApp(String domain, String user, String pass, String peer) throws Exception {
this.peer = peer;
con = new XMPPConnection(domain);
con.addPacketListener(new PacketListener() {
@Override
public void processPacket(Packet packet) {
org.jivesoftware.smack.packet.Message smackMessage = (org.jivesoftware.smack.packet.Message) packet;
String body = smackMessage.getBody();
String from = smackMessage.getFrom();
try {
body = otrEngine.transformReceiving(sessionID, body);
List<TLV> tlvs = otrSm.getPendingTlvs();
if (tlvs != null) {
sendMessage(from, otrEngine.transformSending(sessionID, "", tlvs));
}
} catch (OtrException ex) {
ex.printStackTrace();
}
if (body != null && !body.isEmpty()) {
System.out.println(from + " : " + body);
}
}
}, new MessageTypeFilter(org.jivesoftware.smack.packet.Message.Type.chat));
con.connect();
con.login(user, pass);
otrKeyManager = new OtrKeyManagerImpl("/tmp/sample-keystore");
otrKeyManager.addListener(new OtrKeyManagerListener() {
public void verificationStatusChanged(SessionID session) {
System.out.println(session + ": verification status=" + otrKeyManager.isVerified(session));
}
});
otrPolicy = new OtrPolicyImpl();
otrPolicy.setEnableAlways(true);
sessionID = new SessionID("default", peer, "xmpp");
otrEngine = new OtrEngineImpl(this);
otrEngine.addOtrEngineListener(new OtrEngineListener() {
@Override
public void sessionStatusChanged(SessionID sessionID) {
SessionStatus sessionStatus = otrEngine.getSessionStatus(sessionID);
System.out.println(sessionID + " : status=" + sessionStatus);
if (sessionStatus == SessionStatus.ENCRYPTED)
{
PublicKey remoteKey = otrEngine.getRemotePublicKey(sessionID);
otrKeyManager.savePublicKey(sessionID, remoteKey);
}
// SMP handler - make sure we only add this once per session!
otrSm = new OtrSm(otrEngine.getSession(sessionID), otrKeyManager, sessionID, SampleApp.this);
otrEngine.getSession(sessionID).addTlvHandler(otrSm);
}
});
}
public void sendMessage(String to, String body) {
org.jivesoftware.smack.packet.Message msg =
new org.jivesoftware.smack.packet.Message(
to,
org.jivesoftware.smack.packet.Message.Type.chat
);
msg.setBody(body);
con.sendPacket(msg);
}
public void disconnect() {
con.disconnect();
}
@Override
public void askForSecret(SessionID sessionID, String question) {
System.out.println("asked for secret with q=" + question);
System.out.println("enter /smpr SECRET");
}
@Override
public void showError(SessionID sessionID, String error) {
System.err.println(sessionID + ": error " + error);
}
@Override
public void showWarning(SessionID sessionID, String warn) {
System.err.println(sessionID + ": warn " + warn);
}
@Override
public OtrPolicy getSessionPolicy(SessionID sessionID) {
return otrPolicy;
}
@Override
public void injectMessage(SessionID sessionID, String msg) {
sendMessage(sessionID.getUserID(), msg);
}
@Override
public KeyPair getKeyPair(SessionID sessionID) {
KeyPair kp = null;
try {
kp = otrKeyManager.loadLocalKeyPair(sessionID);
} catch (NullPointerException ex) {
// ignore
}
if (kp == null)
{
otrKeyManager.generateLocalKeyPair(sessionID);
kp = otrKeyManager.loadLocalKeyPair(sessionID);
}
return kp;
}
public static void main(String[] args) throws Exception {
if (args.length != 4) {
System.err.println("Usage: SampleApp DOMAIN USER PASS PEER_ADDRESS");
return;
}
SampleApp app = new SampleApp(args[0], args[1], args[2], args[3]);
app.run();
}
private void run() throws IOException, OtrException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
System.out.print(">");
String line = reader.readLine().trim();
if ("/quit".equals(line)) {
disconnect();
return;
}
else if ("/otr".equals(line)) {
otrEngine.startSession(sessionID);
}
else if (line.startsWith("/smpr")) {
String secret = line.substring("/smpr ".length());
List<TLV> tlvs = otrSm.initRespondSmp(null, secret, false);
String encrypted = otrEngine.transformSending(sessionID, "", tlvs);
sendMessage(peer, encrypted);
}
else if (line.startsWith("/smpa")) {
if (otrEngine.getSessionStatus(sessionID) != SessionStatus.ENCRYPTED) {
System.err.println("Not currently encrypted - use /otr");
continue;
}
List<TLV> tlvs = otrSm.abortSmp();
String encrypted = otrEngine.transformSending(sessionID, "", tlvs);
sendMessage(peer, encrypted);
}
else if (line.startsWith("/smp")) {
if (otrEngine.getSessionStatus(sessionID) != SessionStatus.ENCRYPTED) {
System.err.println("Not currently encrypted - use /otr");
continue;
}
String[] splits = line.split(" ", 3);
if (splits.length < 2) {
System.err.println("missing arguments");
continue;
}
List<TLV> tlvs;
if (splits.length == 3) {
tlvs = otrSm.initRespondSmp(splits[1], splits[2], true);
} else {
tlvs = otrSm.initRespondSmp(null, splits[1], true);
}
String encrypted = otrEngine.transformSending(sessionID, "", tlvs);
sendMessage(peer, encrypted);
}
else if ("/help".equals(line)) {
System.out.println("/quit");
System.out.println("/otr");
System.out.println("/smpr SECRET - SMP response");
System.out.println("/smp [QUESTION] SECRET - SMP initiation");
System.out.println("/smpa - SMP abort");
}
else if (line.startsWith("/")) {
System.err.println("Unknown command");
}
else {
String encrypted = otrEngine.transformSending(sessionID, line, null);
sendMessage(peer, encrypted);
}
}
}
}