Updates the otr plugin to use the latest version of the OTR protocol.

cusax-fix
Marin 12 years ago
parent 8ac9024568
commit c164b0aa0a

Binary file not shown.

@ -1611,6 +1611,10 @@ plugin.otr.activator.fallbackmessage=<span style="font-weight: bold;">{0} is try
<a href="http://en.wikipedia.org/wiki/Off-the-Record_Messaging">Off-The-Record conversation</a> with you. However, your software does not support \
Off-The-Record messaging. For more information see <a href="http://en.wikipedia.org/wiki/Off-the-Record_Messaging">\
http://en.wikipedia.org/wiki/Off-the-Record_Messaging</a></span>
plugin.otr.activator.multipleinstancesdetected=Your buddy {0} is logged in multiple times and OTR has established multiple sessions. You can select \
an outgoing session from the menu above.
plugin.otr.activator.msgfromanotherinstance={0} sent you a message that was intended for another session. If you are logged in multiple times \
another session may have received this message.
# global proxy plugin
plugin.globalproxy.GLOBAL_PROXY_CONFIG=Global Proxy

@ -323,6 +323,7 @@ public void actionPerformed(ActionEvent arg0)
topSplitPane.setRightComponent(rightPanel);
topPanel.add(topSplitPane);
}
else
{
@ -354,6 +355,7 @@ public void actionPerformed(ActionEvent arg0)
this.repaint();
}
writeMessagePanel.initPluginComponents();
writeMessagePanel.setTransportSelectorBoxVisible(true);
//Enables to change the protocol provider by simply pressing the

@ -6,6 +6,7 @@
package net.java.sip.communicator.impl.gui.main.chat;
import java.awt.*;
import java.awt.Container;
import java.awt.event.*;
import java.io.*;
import java.util.*;
@ -18,10 +19,13 @@
import javax.swing.undo.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.event.*;
import net.java.sip.communicator.impl.gui.main.chat.conference.*;
import net.java.sip.communicator.impl.gui.main.chat.menus.*;
import net.java.sip.communicator.impl.gui.utils.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.event.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
@ -29,6 +33,7 @@
import net.java.sip.communicator.util.skin.*;
import org.jitsi.service.configuration.*;
import org.osgi.framework.*;
/**
* The <tt>ChatWritePanel</tt> is the panel, where user writes her messages.
@ -46,6 +51,7 @@ public class ChatWritePanel
MouseListener,
UndoableEditListener,
DocumentListener,
PluginComponentListener,
Skinnable
{
/**
@ -1518,4 +1524,102 @@ public void run()
isOutdatedResource = true;
}
}
/**
* Initializes plug-in components for this container.
*/
void initPluginComponents()
{
// Search for plugin components registered through the OSGI bundle
// context.
ServiceReference[] serRefs = null;
String osgiFilter = "("
+ net.java.sip.communicator.service.gui.Container.CONTAINER_ID
+ "="+net.java.sip.communicator.service.gui.Container.
CONTAINER_CHAT_WRITE_PANEL.getID()+")";
try
{
serRefs = GuiActivator.bundleContext.getServiceReferences(
PluginComponentFactory.class.getName(),
osgiFilter);
}
catch (InvalidSyntaxException exc)
{
logger.error("Could not obtain plugin reference.", exc);
}
if (serRefs != null)
{
for (int i = 0; i < serRefs.length; i ++)
{
PluginComponentFactory factory =
(PluginComponentFactory) GuiActivator
.bundleContext.getService(serRefs[i]);
PluginComponent component =
factory.getPluginComponentInstance(this);
ChatSession chatSession = chatPanel.getChatSession();
if (chatSession instanceof MetaContactChatSession)
{
MetaContact metaContact =
(MetaContact) chatSession.getDescriptor();
component.setCurrentContact(metaContact);
}
if (component.getComponent() == null)
continue;
centerPanel.add((Component)component.getComponent());
}
}
GuiActivator.getUIService().addPluginComponentListener(this);
this.centerPanel.repaint();
}
/**
* Indicates that a new plugin component has been added. Adds it to this
* container if it belongs to it.
*
* @param event the <tt>PluginComponentEvent</tt> that notified us
*/
public void pluginComponentAdded(PluginComponentEvent event)
{
PluginComponentFactory factory = event.getPluginComponentFactory();
if (!factory.getContainer().equals(
net.java.sip.communicator.service.
gui.Container.CONTAINER_CHAT_WRITE_PANEL))
return;
PluginComponent c = factory.getPluginComponentInstance(this);
ChatSession chatSession = chatPanel.getChatSession();
if (chatSession instanceof MetaContactChatSession)
{
MetaContact metaContact = (MetaContact) chatSession.getDescriptor();
c.setCurrentContact(metaContact);
}
centerPanel.add((Component) c.getComponent());
this.centerPanel.repaint();
}
/**
* Removes the according plug-in component from this container.
*
* @param event the <tt>PluginComponentEvent</tt> that notified us
*/
public void pluginComponentRemoved(PluginComponentEvent event)
{
PluginComponentFactory factory = event.getPluginComponentFactory();
if (!factory.getContainer().equals(
net.java.sip.communicator.service.
gui.Container.CONTAINER_CHAT_WRITE_PANEL))
return;
Component c =
(Component)factory.getPluginComponentInstance(this)
.getComponent();
this.centerPanel.remove(c);
this.centerPanel.repaint();
}
}

@ -8,13 +8,14 @@
import java.util.*;
import net.java.sip.communicator.plugin.otr.authdialog.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
import org.jitsi.service.configuration.*;
import org.jitsi.service.resources.*;
import org.jitsi.util.*;
@ -370,6 +371,20 @@ public void start(Object dependentService)
bundleContext.registerService(
OtrActionHandler.class.getName(),
new SwingOtrActionHandler(), null);
containerFilter.put(Container.CONTAINER_ID,
Container.CONTAINER_CHAT_WRITE_PANEL.getID());
bundleContext.registerService(
PluginComponentFactory.class.getName(),
new PluginComponentFactory( Container.CONTAINER_CHAT_WRITE_PANEL)
{
protected PluginComponent getPluginInstance()
{
return new OtrV3OutgoingSessionSwitcher(
getContainer(), this);
}
},
containerFilter);
}
// If the general configuration form is disabled don't register it.
@ -384,7 +399,8 @@ public void start(Object dependentService)
// Register the configuration form.
bundleContext.registerService(ConfigurationForm.class.getName(),
new LazyConfigurationForm(
"net.java.sip.communicator.plugin.otr.OtrConfigurationPanel",
"net.java.sip.communicator.plugin.otr.authdialog." +
"OtrConfigurationPanel",
getClass().getClassLoader(),
"plugin.otr.configform.ICON",
"service.gui.CHAT", 1),

@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.plugin.otr;
import java.util.*;
import org.bouncycastle.util.encoders.*;
import org.jitsi.service.configuration.*;
@ -142,4 +144,31 @@ public int getPropertyInt(String id, int defaultValue)
{
return OtrActivator.configService.getInt(getID(id), defaultValue);
}
/**
* Appends <tt>value</tt> to the old value of the property with the
* specified name. The two values will be comma separated.
*
* @param id the name of the property to append to
* @param value the value to append
*/
public void appendProperty(String id, Object value)
{
Object oldValue = OtrActivator.configService.getProperty(getID(id));
String newValue =
oldValue == null ? value.toString() : oldValue + "," + value;
setProperty(id, newValue);
}
public List<String> getAppendedProperties(String id)
{
String listProperties =
(String) OtrActivator.configService.getProperty(getID(id));
if (listProperties == null) return new ArrayList<String>();
return Arrays.asList(listProperties.split(","));
}
}

@ -7,6 +7,7 @@
package net.java.sip.communicator.plugin.otr;
import java.awt.event.*;
import java.security.*;
import javax.swing.*;
@ -470,8 +471,13 @@ private void updateIcon()
switch (sessionStatus)
{
case ENCRYPTED:
PublicKey pubKey =
OtrActivator.scOtrEngine.getRemotePublicKey(contact);
String fingerprint =
OtrActivator.scOtrKeyManager.
getFingerprintFromPublicKey(pubKey);
imageID
= OtrActivator.scOtrKeyManager.isVerified(contact)
= OtrActivator.scOtrKeyManager.isVerified(contact, fingerprint)
? "plugin.otr.ENCRYPTED_ICON_16x16"
: "plugin.otr.ENCRYPTED_UNVERIFIED_ICON_16x16";
break;
@ -490,4 +496,14 @@ private void updateIcon()
separateMenu.setIcon(OtrActivator.resourceService.getImage(imageID));
}
@Override
public void multipleInstancesDetected(Contact contact) {}
@Override
public void outgoingSessionChanged(Contact contact)
{
if (contact.equals(OtrContactMenu.this.contact))
setSessionStatus(OtrActivator.scOtrEngine.getSessionStatus(contact));
}
}

@ -9,6 +9,7 @@
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.security.*;
import javax.imageio.*;
@ -272,12 +273,17 @@ private void setStatus(ScSessionStatus status)
switch (status)
{
case ENCRYPTED:
PublicKey pubKey =
OtrActivator.scOtrEngine.getRemotePublicKey(contact);
String fingerprint =
OtrActivator.scOtrKeyManager.
getFingerprintFromPublicKey(pubKey);
image
= OtrActivator.scOtrKeyManager.isVerified(contact)
= OtrActivator.scOtrKeyManager.isVerified(contact, fingerprint)
? verifiedLockedPadlockImage
: unverifiedLockedPadlockImage;
tipKey =
OtrActivator.scOtrKeyManager.isVerified(contact)
OtrActivator.scOtrKeyManager.isVerified(contact, fingerprint)
? "plugin.otr.menu.VERIFIED"
: "plugin.otr.menu.UNVERIFIED";
break;
@ -308,4 +314,19 @@ private void setStatus(ScSessionStatus status)
.getI18NString(tipKey));
button.repaint();
}
@Override
public void multipleInstancesDetected(Contact contact)
{}
@Override
public void outgoingSessionChanged(Contact contact)
{
// OtrMetaContactButton.this.contact can be null.
if (contact.equals(OtrMetaContactButton.this.contact))
{
setStatus(
OtrActivator.scOtrEngine.getSessionStatus(contact));
}
}
}

@ -152,4 +152,28 @@ public void sessionStatusChanged(Contact contact)
if (l != null)
l.sessionStatusChanged(contact);
}
/**
* Forwards the event/notification to the associated
* <tt>T</tt> if it is still needed by the application.
*/
public void multipleInstancesDetected(Contact contact)
{
ScOtrEngineListener l = getListener();
if (l != null)
l.multipleInstancesDetected(contact);
}
/**
* Forwards the event/notification to the associated
* <tt>T</tt> if it is still needed by the application.
*/
public void outgoingSessionChanged(Contact contact)
{
ScOtrEngineListener l = getListener();
if (l != null)
l.outgoingSessionChanged(contact);
}
}

@ -6,7 +6,11 @@
*/
package net.java.sip.communicator.plugin.otr;
import java.security.*;
import java.util.*;
import net.java.otr4j.*;
import net.java.otr4j.session.*;
import net.java.sip.communicator.service.protocol.*;
/**
@ -99,6 +103,42 @@ public abstract void respondSmp(
*/
public abstract void refreshSession(Contact contact);
/**
* Some IM networks always relay all messages to all sessions of a client
* who is logged in multiple times. OTR version 3 deals with this problem
* with introducing instance tags.
* <a href="https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html">
* https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html</a>
* <p>
* Returns a list containing all instances of a session. The 'master'
* session is always first in the list.
*
* @param contact the {@link Contact} for whom we want to get the instances
*
* @return A list of all instances of the session for the specified contact.
*/
public abstract List<Session> getSessionInstances(Contact contact);
/**
* Some IM networks always relay all messages to all sessions of a client
* who is logged in multiple times. OTR version 3 deals with this problem
* with introducing instance tags.
* <a href="https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html">
* https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html</a>
* <p>
* When the client wishes to start sending OTRv3 encrypted messages to a
* specific session of his buddy who is logged in multiple times, he can set
* the outgoing instance of his buddy by specifying his <tt>InstanceTag</tt>.
*
* @param contact the {@link Contact} to whom we want to set the outgoing
* instance tag.
* @param tag the outgoing {@link InstanceTag}
*
* @return true if an outgoing session with such {@link InstanceTag} exists
* . Otherwise false
*/
public abstract boolean setOutgoingSession(Contact contact, InstanceTag tag);
/**
* Gets the {@link ScSessionStatus} for the given {@link Contact}.
*
@ -135,6 +175,8 @@ public abstract void respondSmp(
*/
public abstract void removeListener(ScOtrEngineListener listener);
public abstract PublicKey getRemotePublicKey(Contact contact);
// New Methods (Policy management)
/**
* Gets the global {@link OtrPolicy}.

@ -12,6 +12,7 @@
import java.util.concurrent.*;
import net.java.otr4j.*;
import net.java.otr4j.crypto.*;
import net.java.otr4j.session.*;
import net.java.sip.communicator.plugin.otr.authdialog.*;
import net.java.sip.communicator.service.browserlauncher.*;
@ -265,19 +266,20 @@ public void askForSecret(SessionID sessionID, String question)
progressDialog = new SmpProgressDialog(contact);
progressDialogMap.put(contact, progressDialog);
}
progressDialog.init();
progressDialog.setVisible(true);
}
@Override
public void verify(SessionID sessionID, boolean approved)
public void verify(
SessionID sessionID, String fingerprint, boolean approved)
{
Contact contact = getContact(sessionID);
if (contact == null)
return;
OtrActivator.scOtrKeyManager.verify(contact);
OtrActivator.scOtrKeyManager.verify(contact, fingerprint);
SmpProgressDialog progressDialog = progressDialogMap.get(contact);
if (progressDialog == null)
@ -285,20 +287,20 @@ public void verify(SessionID sessionID, boolean approved)
progressDialog = new SmpProgressDialog(contact);
progressDialogMap.put(contact, progressDialog);
}
progressDialog.setProgressSuccess();
progressDialog.setVisible(true);
}
@Override
public void unverify(SessionID sessionID)
public void unverify(SessionID sessionID, String fingerprint)
{
Contact contact = getContact(sessionID);
if (contact == null)
return;
OtrActivator.scOtrKeyManager.unverify(contact);
OtrActivator.scOtrKeyManager.unverify(contact, fingerprint);
SmpProgressDialog progressDialog = progressDialogMap.get(contact);
if (progressDialog == null)
{
@ -332,6 +334,42 @@ public String getFallbackMessage(SessionID sessionID)
"plugin.otr.activator.fallbackmessage",
new String[] {accountID.getDisplayName()});
}
@Override
public void multipleInstancesDetected(SessionID sessionID)
{
Contact contact = getContact(sessionID);
if (contact == null)
return;
String message =
OtrActivator.resourceService.getI18NString(
"plugin.otr.activator.multipleinstancesdetected",
new String[] {contact.getDisplayName()});
OtrActivator.uiService.getChat(contact).addMessage(
contact.getDisplayName(),
new Date(), Chat.SYSTEM_MESSAGE,
message,
OperationSetBasicInstantMessaging.HTML_MIME_TYPE);
}
@Override
public void messageFromAnotherInstanceReceived(SessionID sessionID)
{
Contact contact = getContact(sessionID);
if (contact == null)
return;
String message =
OtrActivator.resourceService.getI18NString(
"plugin.otr.activator.msgfromanotherinstance",
new String[] {contact.getDisplayName()});
OtrActivator.uiService.getChat(contact).addMessage(
contact.getDisplayName(),
new Date(), Chat.SYSTEM_MESSAGE,
message,
OperationSetBasicInstantMessaging.HTML_MIME_TYPE);
}
}
/**
@ -453,15 +491,38 @@ public void sessionStatusChanged(SessionID sessionID)
PublicKey remotePubKey =
otrEngine.getRemotePublicKey(sessionID);
PublicKey storedPubKey =
OtrActivator.scOtrKeyManager.loadPublicKey(contact);
String remoteFingerprint = null;
try
{
remoteFingerprint =
new OtrCryptoEngineImpl().
getFingerprint(remotePubKey);
}
catch (OtrCryptoException e)
{
logger.debug(
"Could not get the fingerprint from the "
+ "public key of contact: " + contact);
}
if (!remotePubKey.equals(storedPubKey))
OtrActivator.scOtrKeyManager.savePublicKey(contact,
remotePubKey);
List<String> allFingerprintsOfContact =
OtrActivator.scOtrKeyManager.
getAllRemoteFingerprints(contact);
if (allFingerprintsOfContact != null)
{
if (!allFingerprintsOfContact.contains(
remoteFingerprint))
{
OtrActivator.scOtrKeyManager.saveFingerprint(
contact, remoteFingerprint);
}
}
if (!OtrActivator.scOtrKeyManager.isVerified(contact))
if (!OtrActivator.scOtrKeyManager.isVerified(
contact, remoteFingerprint))
{
OtrActivator.scOtrKeyManager.unverify(
contact, remoteFingerprint);
UUID sessionGuid = null;
for(ScSessionID scSessionID : contactsMap.keySet())
{
@ -531,7 +592,8 @@ public void sessionStatusChanged(SessionID sessionID)
message
= OtrActivator.resourceService.getI18NString(
OtrActivator.scOtrKeyManager.isVerified(contact)
OtrActivator.scOtrKeyManager.isVerified(
contact, remoteFingerprint)
? "plugin.otr.activator.sessionstared"
: "plugin.otr.activator"
+ ".unverifiedsessionstared",
@ -565,6 +627,26 @@ public void sessionStatusChanged(SessionID sessionID)
for (ScOtrEngineListener l : getListeners())
l.sessionStatusChanged(contact);
}
public void multipleInstancesDetected(SessionID sessionID)
{
Contact contact = getContact(sessionID);
if (contact == null)
return;
for (ScOtrEngineListener l : getListeners())
l.multipleInstancesDetected(contact);
}
public void outgoingSessionChanged(SessionID sessionID)
{
Contact contact = getContact(sessionID);
if (contact == null)
return;
for (ScOtrEngineListener l : getListeners())
l.outgoingSessionChanged(contact);
}
});
}
@ -1036,6 +1118,34 @@ public void abortSmp(Contact contact)
+ contact.getDisplayName(), e);
showError(session.getSessionID(), e.getMessage());
}
}
public PublicKey getRemotePublicKey(Contact contact)
{
if (contact == null)
return null;
Session session = getSession(contact);
return session.getRemotePublicKey();
}
public List<Session> getSessionInstances(Contact contact)
{
if (contact == null)
return null;
return getSession(contact).getInstances();
}
public boolean setOutgoingSession(Contact contact, InstanceTag tag)
{
if (contact == null)
return false;
Session session = getSession(contact);
scSessionStatusMap.remove(session.getSessionID());
return session.setOutgoingInstance(tag);
}
}

@ -19,4 +19,8 @@ public interface ScOtrEngineListener
public void globalPolicyChanged();
public void sessionStatusChanged(Contact contact);
public void multipleInstancesDetected(Contact contact);
public void outgoingSessionChanged(Contact contact);
}

@ -7,6 +7,7 @@
package net.java.sip.communicator.plugin.otr;
import java.security.*;
import java.util.*;
import net.java.sip.communicator.service.protocol.*;
@ -22,19 +23,21 @@ public interface ScOtrKeyManager
public abstract void removeListener(ScOtrKeyManagerListener l);
public abstract void verify(Contact contact);
public abstract void verify(Contact contact, String fingerprint);
public abstract void unverify(Contact contact);
public abstract void unverify(Contact contact, String fingerprint);
public abstract boolean isVerified(Contact contact);
public abstract boolean isVerified(Contact contact, String fingerprint);
public abstract String getRemoteFingerprint(Contact contact);
public abstract String getFingerprintFromPublicKey(PublicKey pubKey);
public abstract List<String> getAllRemoteFingerprints(Contact contact);
public abstract String getLocalFingerprint(AccountID account);
public abstract byte[] getLocalFingerprintRaw(AccountID account);
public abstract void savePublicKey(Contact contact, PublicKey pubKey);
public abstract void saveFingerprint(Contact contact, String fingerprint);
public abstract PublicKey loadPublicKey(Contact contact);

@ -62,47 +62,113 @@ public void removeListener(ScOtrKeyManagerListener l)
}
}
public void verify(Contact contact)
public void verify(Contact contact, String fingerprint)
{
if ((contact == null) || isVerified(contact))
if ((fingerprint == null) || contact == null)
return;
this.configurator.setProperty(contact.getAddress()
+ ".publicKey.verified", true);
this.configurator.setProperty(contact.getAddress() + fingerprint
+ ".fingerprint.verified", true);
for (ScOtrKeyManagerListener l : getListeners())
l.contactVerificationStatusChanged(contact);
}
public void unverify(Contact contact)
public void unverify(Contact contact, String fingerprint)
{
if ((contact == null) || !isVerified(contact))
if ((fingerprint == null) || contact == null)
return;
this.configurator.removeProperty(contact.getAddress()
+ ".publicKey.verified");
this.configurator.setProperty(contact.getAddress() + fingerprint
+ ".fingerprint.verified", false);
for (ScOtrKeyManagerListener l : getListeners())
l.contactVerificationStatusChanged(contact);
}
public boolean isVerified(Contact contact)
public boolean isVerified(Contact contact, String fingerprint)
{
if (contact == null)
if (fingerprint == null || contact == null)
return false;
return this.configurator.getPropertyBoolean(contact.getAddress()
+ ".publicKey.verified", false);
return this.configurator.getPropertyBoolean(
contact.getAddress() + fingerprint
+ ".fingerprint.verified", false);
}
public String getRemoteFingerprint(Contact contact)
public List<String> getAllRemoteFingerprints(Contact contact)
{
PublicKey remotePublicKey = loadPublicKey(contact);
if (remotePublicKey == null)
if (contact == null)
return null;
/*
* The following lines are needed for backward compatibility with old
* versions of the otr plugin. Instead of lists of fingerprints the otr
* plugin used to store one public key for every contact in the form of
* "userID.publicKey=..." and one boolean property in the form of
* "userID.publicKey.verified=...". In order not to loose these old
* properties we have to convert them to match the new format.
*/
String userID = contact.getAddress();
byte[] b64PubKey =
this.configurator.getPropertyBytes(userID + ".publicKey");
if (b64PubKey != null)
{
// We delete the old format property because we are going to convert
// it in the new format
this.configurator.removeProperty(userID + ".publicKey");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(b64PubKey);
KeyFactory keyFactory;
try
{
keyFactory = KeyFactory.getInstance("DSA");
PublicKey pubKey = keyFactory.generatePublic(publicKeySpec);
boolean isVerified =
this.configurator.getPropertyBoolean(userID
+ ".publicKey.verified", false);
// We also make sure to delete this old format property if it
// exists.
this.configurator.removeProperty(userID + ".publicKey.verified");
String fingerprint = getFingerprintFromPublicKey(pubKey);
// Now we can store the old properties in the new format.
if (isVerified)
verify(contact, fingerprint);
else
unverify(contact, fingerprint);
// Finally we append the new fingerprint to out stored list of
// fingerprints.
this.configurator.appendProperty(
userID + ".fingerprints", fingerprint);
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (InvalidKeySpecException e)
{
e.printStackTrace();
}
}
// Now we can safely return our list of fingerprints for this contact
// without worrying that we missed an old format property.
return this.configurator.getAppendedProperties(
contact.getAddress() + ".fingerprints");
}
public String getFingerprintFromPublicKey(PublicKey pubKey)
{
try
{
return new OtrCryptoEngineImpl().getFingerprint(remotePublicKey);
return new OtrCryptoEngineImpl().getFingerprint(pubKey);
}
catch (OtrCryptoException e)
{
@ -151,19 +217,16 @@ public byte[] getLocalFingerprintRaw(AccountID account)
}
}
public void savePublicKey(Contact contact, PublicKey pubKey)
public void saveFingerprint(Contact contact, String fingerprint)
{
if (contact == null)
return;
X509EncodedKeySpec x509EncodedKeySpec =
new X509EncodedKeySpec(pubKey.getEncoded());
this.configurator.setProperty(contact.getAddress() + ".publicKey",
x509EncodedKeySpec.getEncoded());
this.configurator.appendProperty(contact.getAddress() + ".fingerprints",
fingerprint);
this.configurator.removeProperty(contact.getAddress()
+ ".publicKey.verified");
this.configurator.setProperty(contact.getAddress() + fingerprint
+ ".fingerprint.verified", false);
}
public PublicKey loadPublicKey(Contact contact)

@ -7,6 +7,7 @@
package net.java.sip.communicator.plugin.otr.authdialog;
import java.awt.*;
import java.security.*;
import javax.swing.*;
import javax.swing.event.*;
@ -107,8 +108,13 @@ private void initComponents()
cbAction = new JComboBox();
cbAction.addItem(actionIHave);
cbAction.addItem(actionIHaveNot);
PublicKey pubKey = OtrActivator.scOtrEngine.getRemotePublicKey(contact);
String remoteFingerprint =
OtrActivator.scOtrKeyManager.getFingerprintFromPublicKey(pubKey);
cbAction.setSelectedItem(OtrActivator.scOtrKeyManager
.isVerified(contact) ? actionIHave : actionIHaveNot);
.isVerified(contact, remoteFingerprint)
? actionIHave : actionIHaveNot);
pnlAction.add(cbAction, c);
@ -152,8 +158,9 @@ private void loadContact()
// Remote fingerprint.
String user = contact.getDisplayName();
PublicKey pubKey = OtrActivator.scOtrEngine.getRemotePublicKey(contact);
String remoteFingerprint =
OtrActivator.scOtrKeyManager.getRemoteFingerprint(contact);
OtrActivator.scOtrKeyManager.getFingerprintFromPublicKey(pubKey);
txtRemoteFingerprint.setText(OtrActivator.resourceService
.getI18NString("plugin.otr.authbuddydialog.REMOTE_FINGERPRINT",
new String[]
@ -182,6 +189,10 @@ public void changedUpdate(DocumentEvent e)
public void compareFingerprints()
{
PublicKey pubKey = OtrActivator.scOtrEngine.getRemotePublicKey(contact);
String remoteFingerprint =
OtrActivator.scOtrKeyManager.getFingerprintFromPublicKey(pubKey);
if(txtRemoteFingerprintComparison.getText() == null
|| txtRemoteFingerprintComparison.getText().length() == 0)
{
@ -189,8 +200,7 @@ public void compareFingerprints()
return;
}
if(txtRemoteFingerprintComparison.getText().toLowerCase().contains(
OtrActivator.scOtrKeyManager
.getRemoteFingerprint(contact).toLowerCase()))
remoteFingerprint.toLowerCase()))
{
txtRemoteFingerprintComparison.setBackground(Color.green);
cbAction.setSelectedItem(actionIHave);

@ -13,9 +13,9 @@
import javax.swing.border.*;
import javax.swing.event.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.otr.*;
import net.java.sip.communicator.service.protocol.*;
/**
* @author @George Politis
@ -44,7 +44,7 @@ public KnownFingerprintsPanel()
this.setPreferredSize(new Dimension(400, 200));
openContact(getSelectedContact());
openContact(getSelectedContact(), getSelectedFingerprint());
}
/**
@ -74,7 +74,7 @@ public void valueChanged(ListSelectionEvent e)
if (e.getValueIsAdjusting())
return;
openContact(getSelectedContact());
openContact(getSelectedContact(), getSelectedFingerprint());
}
});
@ -88,14 +88,15 @@ public void valueChanged(ListSelectionEvent e)
btnVerifyFingerprint = new JButton();
btnVerifyFingerprint.setText(OtrActivator.resourceService
.getI18NString("plugin.otr.configform.VERIFY_FINGERPRINT"));
btnVerifyFingerprint.setEnabled(false);
btnVerifyFingerprint.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
OtrActivator.scOtrKeyManager
.verify(getSelectedContact());
openContact(getSelectedContact());
.verify(getSelectedContact(), getSelectedFingerprint());
openContact(getSelectedContact(), getSelectedFingerprint());
contactsTable.updateUI();
}
});
@ -105,13 +106,15 @@ public void actionPerformed(ActionEvent arg0)
btnForgetFingerprint = new JButton();
btnForgetFingerprint.setText(OtrActivator.resourceService
.getI18NString("plugin.otr.configform.FORGET_FINGERPRINT"));
btnForgetFingerprint.setEnabled(false);
btnForgetFingerprint.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
OtrActivator.scOtrKeyManager
.unverify(getSelectedContact());
openContact(getSelectedContact());
.unverify(getSelectedContact(), getSelectedFingerprint());
openContact(getSelectedContact(), getSelectedFingerprint());
contactsTable.updateUI();
}
});
@ -129,10 +132,27 @@ private Contact getSelectedContact()
KnownFingerprintsTableModel model =
(KnownFingerprintsTableModel) contactsTable.getModel();
int index = contactsTable.getSelectedRow();
if (index < 0 || index > model.allContacts.size())
if (index < 0 || index > model.getRowCount())
return null;
return model.getContactFromRow(index);
}
/**
* Gets the selected fingerprint for this
* {@link KnownFingerprintsTableModel}
*
* return the selected fingerprint
*/
private String getSelectedFingerprint()
{
KnownFingerprintsTableModel model =
(KnownFingerprintsTableModel) contactsTable.getModel();
int index = contactsTable.getSelectedRow();
if (index < 0 || index > model.getRowCount())
return null;
return model.allContacts.get(index);
return model.getFingerprintFromRow(index);
}
/**
@ -140,11 +160,11 @@ private Contact getSelectedContact()
* reflect the {@link Contact} param.
*
* @param contact the {@link Contact} to setup the components for.
* @param fingerprint the fingerprint to setup the components for.
*/
private void openContact(Contact contact)
private void openContact(Contact contact, String fingerprint)
{
if (contact == null
|| OtrActivator.scOtrKeyManager.getRemoteFingerprint(contact) == null)
if (contact == null || fingerprint == null)
{
btnForgetFingerprint.setEnabled(false);
btnVerifyFingerprint.setEnabled(false);
@ -153,7 +173,7 @@ private void openContact(Contact contact)
{
boolean verified
= OtrActivator.scOtrKeyManager
.isVerified(contact);
.isVerified(contact, fingerprint);
btnForgetFingerprint.setEnabled(verified);
btnVerifyFingerprint.setEnabled(!verified);

@ -8,6 +8,7 @@
import java.awt.*;
import java.util.*;
import java.util.List;
import javax.swing.table.*;
@ -25,6 +26,7 @@
*/
public class KnownFingerprintsTableModel
extends AbstractTableModel
implements ScOtrKeyManagerListener
{
/**
* Serial version UID.
@ -37,7 +39,8 @@ public class KnownFingerprintsTableModel
public static final int FINGERPRINT_INDEX = 2;
public final java.util.List<Contact> allContacts = new Vector<Contact>();
public final LinkedHashMap<Contact, List<String>> allContactsFingerprints =
new LinkedHashMap<Contact, List<String>>();
public KnownFingerprintsTableModel()
{
@ -76,10 +79,15 @@ public KnownFingerprintsTableModel()
Iterator<Contact> contacts = metaContact.getContacts();
while (contacts.hasNext())
{
allContacts.add(contacts.next());
Contact contact = contacts.next();
allContactsFingerprints.put(
contact,
OtrActivator.scOtrKeyManager.getAllRemoteFingerprints(
contact));
}
}
}
OtrActivator.scOtrKeyManager.addListener(this);
}
/**
@ -112,10 +120,8 @@ public String getColumnName(int column)
*/
public Object getValueAt(int row, int column)
{
if (row < 0)
return null;
Contact contact = allContacts.get(row);
Contact contact = getContactFromRow(row);
String fingerprint = getFingerprintFromRow(row);
switch (column)
{
case CONTACTNAME_INDEX:
@ -123,25 +129,84 @@ public Object getValueAt(int row, int column)
case VERIFIED_INDEX:
// TODO: Maybe use a CheckBoxColumn?
return (OtrActivator.scOtrKeyManager
.isVerified(contact))
.isVerified(contact, fingerprint))
? OtrActivator.resourceService.getI18NString(
"plugin.otr.configform.COLUMN_VALUE_VERIFIED_TRUE")
: OtrActivator.resourceService.getI18NString(
"plugin.otr.configform.COLUMN_VALUE_VERIFIED_FALSE");
case FINGERPRINT_INDEX:
return OtrActivator.scOtrKeyManager
.getRemoteFingerprint(contact);
return fingerprint;
default:
return null;
}
}
Contact getContactFromRow(int row)
{
if (row < 0 || row >= getRowCount())
return null;
int index = -1;
Contact contact = null;
for (Map.Entry<Contact, List<String>> entry :
allContactsFingerprints.entrySet())
{
boolean found = false;
contact = entry.getKey();
List<String> fingerprints = entry.getValue();
for (String f : fingerprints)
{
index++;
if (index == row)
{
found = true;
break;
}
}
if (found) break;
}
return contact;
}
String getFingerprintFromRow(int row)
{
if (row < 0 || row >= getRowCount())
return null;
int index = -1;
String fingerprint = null;
for (Map.Entry<Contact, List<String>> entry :
allContactsFingerprints.entrySet())
{
boolean found = false;
List<String> fingerprints = entry.getValue();
for (String f : fingerprints)
{
index++;
fingerprint = f;
if (index == row)
{
found = true;
break;
}
}
if (found) break;
}
return fingerprint;
}
/**
* Implements AbstractTableModel#getRowCount().
*/
public int getRowCount()
{
return allContacts.size();
int rowCount = 0;
for (Map.Entry<Contact, List<String>> entry :
allContactsFingerprints.entrySet())
rowCount += entry.getValue().size();
return rowCount;
}
/**
@ -151,4 +216,13 @@ public int getColumnCount()
{
return 3;
}
@Override
public void contactVerificationStatusChanged(Contact contact)
{
allContactsFingerprints.put(
contact,
OtrActivator.scOtrKeyManager.getAllRemoteFingerprints(contact));
this.fireTableDataChanged();
}
}

@ -8,12 +8,13 @@
import java.awt.*;
import java.awt.event.*;
import java.security.*;
import javax.swing.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.otr.*;
import net.java.sip.communicator.plugin.otr.authdialog.FingerprintAuthenticationPanel.*;
import net.java.sip.communicator.plugin.otr.authdialog.FingerprintAuthenticationPanel.ActionComboBoxItem;
import net.java.sip.communicator.service.protocol.*;
/**
@ -178,13 +179,20 @@ else if (authenticationMethod.equals(am[2]))
ActionComboBoxItem actionItem =
(ActionComboBoxItem) fingerprintPanel.
getCbAction().getSelectedItem();
PublicKey pubKey =
OtrActivator.scOtrEngine.getRemotePublicKey(contact);
String fingerprint =
OtrActivator.scOtrKeyManager.
getFingerprintFromPublicKey(pubKey);
switch (actionItem.action)
{
case I_HAVE:
OtrActivator.scOtrKeyManager.verify(contact);
OtrActivator.scOtrKeyManager.verify(
contact, fingerprint);
break;
case I_HAVE_NOT:
OtrActivator.scOtrKeyManager.unverify(contact);
OtrActivator.scOtrKeyManager.unverify(
contact, fingerprint);
break;
}
dispose();

@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.plugin.otr;
package net.java.sip.communicator.plugin.otr.authdialog;
import java.awt.*;
import java.awt.event.*;
@ -16,6 +16,7 @@
import net.java.otr4j.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.otr.*;
import net.java.sip.communicator.plugin.otr.authdialog.*;
/**

@ -0,0 +1,319 @@
package net.java.sip.communicator.plugin.otr.authdialog;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.security.*;
import java.util.*;
import javax.imageio.*;
import javax.swing.*;
import javax.swing.Timer;
import net.java.otr4j.session.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.otr.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.gui.Container;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
public class OtrV3OutgoingSessionSwitcher
extends SIPCommMenuBar
implements PluginComponent,
ActionListener,
ScOtrEngineListener,
ScOtrKeyManagerListener
{
private static final Logger logger
= Logger.getLogger(OtrV3OutgoingSessionSwitcher.class);
private static final long serialVersionUID = 0L;
private final SelectorMenu menu = new SelectorMenu();
private ButtonGroup buttonGroup = new ButtonGroup();
Contact contact;
private final Map<Session, JMenuItem> outgoingSessions
= new HashMap<Session, JMenuItem>();
private static class SelectorMenu
extends SIPCommMenu
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
Image image = OtrActivator.resourceService.getImage(
"service.gui.icons.DOWN_ARROW_ICON").getImage();
private static float alpha = 0.95f;
private final Timer alphaChanger = new Timer(20, new ActionListener() {
private float incrementer = -.03f;
private int fadeCycles = 0;
@Override
public void actionPerformed(ActionEvent e)
{
float newAlpha = alpha + incrementer;
if (newAlpha < 0.2f)
{
newAlpha = 0.2f;
incrementer = -incrementer;
} else if (newAlpha > 0.85f)
{
newAlpha = 0.85f;
incrementer = -incrementer;
fadeCycles++;
}
alpha = newAlpha;
if (fadeCycles == 3)
{
alphaChanger.stop();
alpha = 1f;
}
SelectorMenu.this.repaint();
}
});
@Override
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
g.drawImage(image, getWidth() - image.getWidth(this) - 1,
(getHeight() - image.getHeight(this) - 1) / 2, this);
super.paintComponent(g2d);
}
public void fadeAnimation()
{
alphaChanger.stop();
alpha = 0.85f;
repaint();
alphaChanger.start();
}
};
private final PluginComponentFactory parentFactory;
public OtrV3OutgoingSessionSwitcher(Container container,
PluginComponentFactory parentFactory)
{
this.parentFactory = parentFactory;
setPreferredSize(new Dimension(30, 28));
setMaximumSize(new Dimension(30, 28));
setMinimumSize(new Dimension(30, 28));
this.menu.setPreferredSize(new Dimension(30, 45));
this.menu.setMaximumSize(new Dimension(30, 45));
this.add(menu);
this.setBorder(null);
this.menu.setBorder(null);
this.menu.setOpaque(false);
this.setOpaque(false);
this.menu.setVisible(false);
buildMenu(contact);
/*
* XXX This OtrV3OutgoingSessionSwitcher instance cannot be added as a
* listener to scOtrEngine and scOtrKeyManager without being removed
* later on because the latter live forever. Unfortunately, the
* dispose() method of this instance is never executed. OtrWeakListener
* will keep this instance as a listener of scOtrEngine and
* scOtrKeyManager for as long as this instance is necessary. And this
* instance will be strongly referenced by the JMenuItems which depict
* it. So when the JMenuItems are gone, this instance will become
* obsolete and OtrWeakListener will remove it as a listener of
* scOtrEngine and scOtrKeyManager.
*/
new OtrWeakListener<OtrV3OutgoingSessionSwitcher>(
this,
OtrActivator.scOtrEngine, OtrActivator.scOtrKeyManager);
try
{
finishedPadlockImage = new ImageIcon(ImageIO.read(
OtrActivator.resourceService.getImageURL(
"plugin.otr.FINISHED_ICON_16x16")));
verifiedLockedPadlockImage = new ImageIcon(ImageIO.read(
OtrActivator.resourceService.getImageURL(
"plugin.otr.ENCRYPTED_ICON_16x16")));
unverifiedLockedPadlockImage = new ImageIcon(ImageIO.read(
OtrActivator.resourceService.getImageURL(
"plugin.otr.ENCRYPTED_UNVERIFIED_ICON_16x16")));
unlockedPadlockImage = new ImageIcon(ImageIO.read(
OtrActivator.resourceService.getImageURL(
"plugin.otr.PLAINTEXT_ICON_16x16")));
} catch (IOException e)
{
logger.debug("Failed to load padlock image");
}
}
@Override
public int getPositionIndex()
{
return -1;
}
@Override
public void setCurrentContact(Contact contact)
{
if (this.contact == contact)
return;
this.contact = contact;
System.out.println("ot tuk1");
buildMenu(contact);
}
@Override
public void setCurrentContact(MetaContact metaContact)
{
setCurrentContact((metaContact == null) ? null : metaContact
.getDefaultContact());
}
@Override
public void setCurrentContactGroup(MetaContactGroup metaGroup) {}
@Override
public void setCurrentAccountID(AccountID accountID) {}
@Override
public PluginComponentFactory getParentFactory()
{
return parentFactory;
}
@Override
public void contactVerificationStatusChanged(Contact contact)
{
if (contact == null || this.contact != contact) return;
}
@Override
public void contactPolicyChanged(Contact contact) {}
@Override
public void globalPolicyChanged() {}
@Override
public void sessionStatusChanged(Contact contact)
{
System.out.println("ot tuk2");
buildMenu(contact);
}
@Override
public void multipleInstancesDetected(Contact contact)
{
System.out.println("ot tuk3");
buildMenu(contact);
}
private ImageIcon verifiedLockedPadlockImage;
private ImageIcon unverifiedLockedPadlockImage;
private ImageIcon finishedPadlockImage;
private ImageIcon unlockedPadlockImage;
void buildMenu(Contact contact)
{
if (contact == null || this.contact != contact) {
return;
}
menu.removeAll();
java.util.List<Session> multipleInstances =
OtrActivator.scOtrEngine.getSessionInstances(contact);
int index = 0;
for (Session session : multipleInstances)
{
index++;
if (!outgoingSessions.containsKey(session))
outgoingSessions.put(session, new JRadioButtonMenuItem());
JMenuItem menuItem = outgoingSessions.get(session);
menuItem.setText("Session " + index);
ImageIcon imageIcon = null;
switch (session.getSessionStatus(session.getReceiverInstanceTag()))
{
case ENCRYPTED:
PublicKey pubKey =
session.getRemotePublicKey(session.getReceiverInstanceTag());
String fingerprint =
OtrActivator.scOtrKeyManager.
getFingerprintFromPublicKey(pubKey);
imageIcon
= OtrActivator.scOtrKeyManager.isVerified(contact, fingerprint)
? verifiedLockedPadlockImage
: unverifiedLockedPadlockImage;
break;
case FINISHED:
imageIcon = finishedPadlockImage;
break;
case PLAINTEXT:
imageIcon = unlockedPadlockImage;
break;
}
menuItem.setIcon(imageIcon);
menu.add(menuItem);
SelectedObject selectedObject =
new SelectedObject(imageIcon, session);
this.menu.setSelected(selectedObject);
buttonGroup.add(menuItem);
menuItem.addActionListener(this);
setSelected(menu.getItem(0));
}
System.out.println("da");
updateEnableStatus();
}
@Override
public void actionPerformed(ActionEvent e)
{
for (Map.Entry<Session, JMenuItem> entry : outgoingSessions.entrySet())
{
JMenuItem menuItem = (JRadioButtonMenuItem) e.getSource();
if (menuItem.equals(entry.getValue()))
{
OtrActivator.scOtrEngine.setOutgoingSession(
contact, entry.getKey().getReceiverInstanceTag());
break;
}
}
}
@Override
public void outgoingSessionChanged(Contact contact)
{
buildMenu(contact);
}
/**
* Sets the menu to enabled or disabled. The menu is enabled, as soon as it
* contains two or more items. If it is empty, it is disabled.
*/
private void updateEnableStatus()
{
this.menu.setVisible(this.menu.getItemCount() > 1);
this.menu.fadeAnimation();
}
}

@ -83,6 +83,11 @@ public class Container
public static final Container CONTAINER_GROUP_RIGHT_BUTTON_MENU
= new Container("CONTAINER_GROUP_RIGHT_BUTTON_MENU");
/**
* Chat write panel container.
*/
public static final Container CONTAINER_CHAT_WRITE_PANEL
= new Container("CONTAINER_CHAT_WRITE_PANEL");
/**
* Chat window "menu bar" container.
*/

Loading…
Cancel
Save