diff --git a/lib/installer-exclude/otr4j.jar b/lib/installer-exclude/otr4j.jar index 415a1dc45..561ac47e2 100644 Binary files a/lib/installer-exclude/otr4j.jar and b/lib/installer-exclude/otr4j.jar differ diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index 05355cf6d..bee961c46 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -1520,13 +1520,30 @@ plugin.otr.menu.CB_RESET=Reset plugin.otr.menu.OTR_TOOLTIP=Encrypt chats with OTR plugin.otr.authbuddydialog.HELP_URI=https://jitsi.org/GSOC2009/OTR plugin.otr.authbuddydialog.AUTHENTICATION_INFO=Authenticating a buddy helps \ -ensure that the person you are talking to is who he or she claims to be. \ -To verify the fingerprint, contact your buddy via some other authenticated \ +ensure that the person you are talking to is who he or she claims to be. +plugin.otr.authbuddydialog.AUTHENTICATION_METHOD=How would you like to authenticate? +plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_QUESTION=Question authentication +plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_SECRET=Shared secret authentication +plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_FINGERPRINT=Fingerprint authentication +plugin.otr.authbuddydialog.AUTHENTICATION_FINGERPRINT=To verify the fingerprint, contact your buddy via some other authenticated \ channel, such as the telephone or GPG-signed email. Each of you should tell \ your fingerprint to the other. If everything matches up, you should indicate \ in the following dialog that you *have* verified the fingerprint. plugin.otr.authbuddydialog.LOCAL_FINGERPRINT=Fingerprint for you, {0}: {1} plugin.otr.authbuddydialog.REMOTE_FINGERPRINT=Purported fingerprint for {0}: {1} +plugin.otr.authbuddydialog.AUTH_BY_QUESTION_INFO_INIT=To authenticate using a question, you should pick a question whose answer \ +is only known to you and your buddy. Your buddy will be asked this question and if the answers don't match then you may be talking \ +to an impostor. +plugin.otr.authbuddydialog.AUTH_BY_SECRET_INFO_INIT=To authenticate using a shared secret, you should pick a secret that is only known \ +to you and your buddy. Your buddy will then be asked to pick the secret too and if they don't match then you may be talking \ +to an impostor. +plugin.otr.authbuddydialog.AUTH_BY_SECRET_INFO_RESPOND=Your buddy is trying to determine if he or she is really talking to you and not an impostor. \ +Your buddy has asked you a question. If you want to authenticate, please enter the answer below. +plugin.otr.authbuddydialog.SHARED_SECRET=Enter your shared secret: +plugin.otr.authbuddydialog.QUESTION_RESPOND=Your buddy is asking you: +plugin.otr.authbuddydialog.QUESTION_INIT=Enter your question here: +plugin.otr.authbuddydialog.ANSWER=Enter your answer here (Case sensitive): +plugin.otr.authbuddydialog.AUTHENTICATION_FROM=Authentication from {0}. plugin.otr.authbuddydialog.CANCEL=Cancel plugin.otr.authbuddydialog.HELP=Help plugin.otr.authbuddydialog.TITLE=Authenticate Buddy @@ -1535,6 +1552,9 @@ plugin.otr.authbuddydialog.I_HAVE=I have plugin.otr.authbuddydialog.I_HAVE_NOT=I have not plugin.otr.authbuddydialog.VERIFY_ACTION=verified that this is in fact the correct fingerprint for {0}. plugin.otr.authbuddydialog.FINGERPRINT_CHECK=Please enter the fingerprint you recieved from {0}. +plugin.otr.smpprogressdialog.TITLE=Authentication Progress +plugin.otr.smpprogressdialog.AUTHENTICATION_SUCCESS=Authentication successful! +plugin.otr.smpprogressdialog.AUTHENTICATION_FAIL=Authentication failed! plugin.otr.configform.MY_PRIVATE_KEYS=My Private Keys plugin.otr.configform.KNOWN_FINGERPRINTS=Known Fingerprints plugin.otr.configform.CB_AUTO=Automatically initiate private messaging @@ -1557,6 +1577,17 @@ plugin.otr.activator.sessionfinished={0} has ended his/her private conversation plugin.otr.activator.sessionlost=Private conversation with {0} lost. plugin.otr.activator.historyon={0} is recording this conversation on your device. You can turn off chat history here. plugin.otr.activator.historyoff={0} is NOT recording this conversation. You can activate chat history here. +plugin.otr.activator.sessionfinishederror=Your message was not sent. Please end your private conversation with {0}. +plugin.otr.activator.smpaborted={0} has aborted the authentication process. +plugin.otr.activator.smperror=An error occurred in the authentication process. +plugin.otr.activator.unencryptedmsgreceived=The message was received unencrypted. +plugin.otr.activator.unreadablemsgreceived={0} sent you an unreadable encrypted message. +plugin.otr.activator.requireencryption=Your message was not sent. Private messaging is required. +plugin.otr.activator.unreadablemsgreply=You sent {0} an unreadable encrypted message. Please end your private conversation with {1} or refresh it. +plugin.otr.activator.fallbackmessage={0} is trying to initiate an encrypted \ +Off-The-Record conversation with you. However, your software does not support \ +Off-The-Record messaging. For more information see \ +http://en.wikipedia.org/wiki/Off-the-Record_Messaging # global proxy plugin plugin.globalproxy.GLOBAL_PROXY_CONFIG=Global Proxy diff --git a/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java b/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java index bdbd0ac16..79ce6bcf6 100644 --- a/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java +++ b/src/net/java/sip/communicator/plugin/otr/OtrConfigurationPanel.java @@ -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.authdialog.*; /** * A special {@link Panel} that manages the OTR configuration. diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java b/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java index 1e7b5e8e8..dfa0803c1 100644 --- a/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java +++ b/src/net/java/sip/communicator/plugin/otr/ScOtrEngine.java @@ -20,6 +20,41 @@ public interface ScOtrEngine { // Proxy methods OtrEngine. + /** + * Initializes Smp negotiation. + * @See http://en.wikipedia.org/wiki/Socialist_Millionaire_Problem + * + * @param contact The contact with whom we want to start the Smp negotiation + * @param question The question that is asked during the Smp negotiation + * @param secret The secret answer for the question. + */ + public abstract void initSmp( + Contact contact, String question, String secret); + + /** + * Responds to a question that is asked during the Smp negotiation process. + * @See http://en.wikipedia.org/wiki/Socialist_Millionaire_Problem + * + * @param contact The contact for whom we want to respond to a question + * during the Smp negotiation process. + * @param question The question that is asked during the Smp negotiation. + * @param secret The secret answer for the question. + */ + public abstract void respondSmp( + Contact contact, String question, String secret); + + /** + * Aborts the Smp negotiation process. + * @See http://en.wikipedia.org/wiki/Socialist_Millionaire_Problem + * + * @param contact The contact with whom we want to abort the + * Smp negotiation process. + */ + public abstract void abortSmp(Contact contact); + /** * Transforms an outgoing message. * diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java b/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java index f60ef331c..4e929b876 100644 --- a/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java +++ b/src/net/java/sip/communicator/plugin/otr/ScOtrEngineImpl.java @@ -9,10 +9,11 @@ import java.net.*; import java.security.*; import java.util.*; +import java.util.concurrent.*; import net.java.otr4j.*; import net.java.otr4j.session.*; - +import net.java.sip.communicator.plugin.otr.authdialog.*; import net.java.sip.communicator.service.browserlauncher.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.gui.*; @@ -36,7 +37,7 @@ public class ScOtrEngineImpl class ScOtrEngineHost implements OtrEngineHost { - public KeyPair getKeyPair(SessionID sessionID) + public KeyPair getLocalKeyPair(SessionID sessionID) { AccountID accountID = OtrActivator.getAccountIDByUID(sessionID.getAccountID()); @@ -83,11 +84,242 @@ public void showWarning(SessionID sessionID, String warn) Chat.SYSTEM_MESSAGE, warn, OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); } + + @Override + public void unreadableMessageReceived(SessionID sessionID) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + String error = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.unreadablemsgreceived", + new String[] {contact.getDisplayName()}); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.ERROR_MESSAGE, error, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + } + + @Override + public void unencryptedMessageReceived(SessionID sessionID, String msg) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + String warn = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.unencryptedmsgreceived"); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.SYSTEM_MESSAGE, warn, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + } + + @Override + public void smpError(SessionID sessionID, int tlvType, boolean cheated) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + logger.debug("SMP error occurred" + + ". Contact: " + contact.getDisplayName() + + ". TLV type: " + tlvType + + ". Cheated: " + cheated); + + String error = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.smperror"); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.ERROR_MESSAGE, error, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.setProgressFail(); + progressDialog.setVisible(true); + } + + @Override + public void smpAborted(SessionID sessionID) throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + Session session = otrEngine.getSession(sessionID); + if (session.isSmpInProgress()) + { + String warn = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.smpaborted", + new String[] {contact.getDisplayName()}); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.SYSTEM_MESSAGE, warn, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.setProgressFail(); + progressDialog.setVisible(true); + } + } + + @Override + public void finishedSessionMessage(SessionID sessionID) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + String error = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.sessionfinishederror", + new String[] {contact.getDisplayName()}); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.ERROR_MESSAGE, error, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + } + + @Override + public void requireEncryptedMessage(SessionID sessionID, String msgText) + throws OtrException + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + String error = + OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.requireencryption", + new String[] {contact.getDisplayName()}); + OtrActivator.uiService.getChat(contact).addMessage( + contact.getDisplayName(), new Date(), + Chat.ERROR_MESSAGE, error, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + } + + @Override + public byte[] getLocalFingerprintRaw(SessionID sessionID) + { + AccountID accountID = + OtrActivator.getAccountIDByUID(sessionID.getAccountID()); + return + OtrActivator.scOtrKeyManager.getLocalFingerprintRaw(accountID); + } + + @Override + public void askForSecret(SessionID sessionID, String question) + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + SmpAuthenticateBuddyDialog dialog = + new SmpAuthenticateBuddyDialog(contact, question); + dialog.setVisible(true); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.init(); + progressDialog.setVisible(true); + } + + @Override + public void verify(SessionID sessionID, boolean approved) + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + OtrActivator.scOtrKeyManager.verify(contact); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.setProgressSuccess(); + progressDialog.setVisible(true); + } + + @Override + public void unverify(SessionID sessionID) + { + Contact contact = getContact(sessionID); + if (contact == null) + return; + + OtrActivator.scOtrKeyManager.unverify(contact); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.setProgressFail(); + progressDialog.setVisible(true); + } + + @Override + public String getReplyForUnreadableMessage(SessionID sessionID) + { + AccountID accountID = + OtrActivator.getAccountIDByUID(sessionID.getAccountID()); + + return OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.unreadablemsgreply", + new String[] {accountID.getDisplayName(), + accountID.getDisplayName()}); + } + + @Override + public String getFallbackMessage(SessionID sessionID) + { + AccountID accountID = + OtrActivator.getAccountIDByUID(sessionID.getAccountID()); + + return OtrActivator.resourceService.getI18NString( + "plugin.otr.activator.fallbackmessage", + new String[] {accountID.getDisplayName()}); + } } private static final Map contactsMap = new Hashtable(); + private static final Map progressDialogMap = + new ConcurrentHashMap(); + public static Contact getContact(SessionID sessionID) { return contactsMap.get(new ScSessionID(sessionID)); @@ -145,11 +377,14 @@ public static SessionID getSessionID(Contact contact) */ private final Logger logger = Logger.getLogger(ScOtrEngineImpl.class); - private final OtrEngine otrEngine - = new OtrEngineImpl(new ScOtrEngineHost()); + final OtrEngineHost otrEngineHost = new ScOtrEngineHost(); + + private final OtrEngine otrEngine; public ScOtrEngineImpl() { + otrEngine = new OtrEngineImpl(otrEngineHost); + // Clears the map after previous instance // This is required because of OSGi restarts in the same VM on Android contactsMap.clear(); @@ -449,6 +684,9 @@ public void serviceChanged(ServiceEvent ev) logger.debug( "Unregistering a ProtocolProviderService, cleaning" + " OTR's ScSessionID to Contact map."); + logger.debug( + "Unregistering a ProtocolProviderService, cleaning" + + " OTR's Contact to SpmProgressDialog map."); } ProtocolProviderService provider @@ -464,6 +702,14 @@ public void serviceChanged(ServiceEvent ev) i.remove(); } } + + Iterator i = progressDialogMap.keySet().iterator(); + + while (i.hasNext()) + { + if (provider.equals(i.next().getProtocolProvider())) + i.remove(); + } } } @@ -545,4 +791,89 @@ public String transformSending(Contact contact, String msgText) return null; } } + + private Session getSession(Contact contact) + { + SessionID sessionID = getSessionID(contact); + return otrEngine.getSession(sessionID); + } + + @Override + public void initSmp(Contact contact, String question, String secret) + { + Session session = getSession(contact); + try + { + session.initSmp(question, secret); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.init(); + progressDialog.setVisible(true); + } + catch (OtrException e) + { + logger.error("Error initializing SMP session with contact " + + contact.getDisplayName(), e); + showError(session.getSessionID(), e.getMessage()); + } + } + + @Override + public void respondSmp(Contact contact, String question, String secret) + { + Session session = getSession(contact); + try + { + session.respondSmp(question, secret); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.incrementProgress(); + progressDialog.setVisible(true); + } + catch (OtrException e) + { + logger.error( + "Error occured when sending SMP response to contact " + + contact.getDisplayName(), e); + showError(session.getSessionID(), e.getMessage()); + } + } + + @Override + public void abortSmp(Contact contact) + { + Session session = getSession(contact); + try + { + session.abortSmp(); + + SmpProgressDialog progressDialog = progressDialogMap.get(contact); + if (progressDialog == null) + { + progressDialog = new SmpProgressDialog(contact); + progressDialogMap.put(contact, progressDialog); + } + + progressDialog.dispose(); + } + catch (OtrException e) + { + logger.error("Error aborting SMP session with contact " + + contact.getDisplayName(), e); + showError(session.getSessionID(), e.getMessage()); + } + + } } diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java index fef0f9f88..bc83cd7a5 100755 --- a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java +++ b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManager.java @@ -32,6 +32,8 @@ public interface ScOtrKeyManager public abstract String getLocalFingerprint(AccountID account); + public abstract byte[] getLocalFingerprintRaw(AccountID account); + public abstract void savePublicKey(Contact contact, PublicKey pubKey); public abstract PublicKey loadPublicKey(Contact contact); diff --git a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java index c461ad0d3..37adc6325 100755 --- a/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java +++ b/src/net/java/sip/communicator/plugin/otr/ScOtrKeyManagerImpl.java @@ -131,6 +131,26 @@ public String getLocalFingerprint(AccountID account) } } + public byte[] getLocalFingerprintRaw(AccountID account) + { + KeyPair keyPair = loadKeyPair(account); + + if (keyPair == null) + return null; + + PublicKey pubKey = keyPair.getPublic(); + + try + { + return new OtrCryptoEngineImpl().getFingerprintRaw(pubKey); + } + catch (OtrCryptoException e) + { + e.printStackTrace(); + return null; + } + } + public void savePublicKey(Contact contact, PublicKey pubKey) { if (contact == null) diff --git a/src/net/java/sip/communicator/plugin/otr/SwingOtrActionHandler.java b/src/net/java/sip/communicator/plugin/otr/SwingOtrActionHandler.java index 0a8bf2832..309e38750 100644 --- a/src/net/java/sip/communicator/plugin/otr/SwingOtrActionHandler.java +++ b/src/net/java/sip/communicator/plugin/otr/SwingOtrActionHandler.java @@ -6,6 +6,7 @@ */ package net.java.sip.communicator.plugin.otr; +import net.java.sip.communicator.plugin.otr.authdialog.*; import net.java.sip.communicator.service.protocol.*; import java.awt.*; diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/CustomTextArea.java b/src/net/java/sip/communicator/plugin/otr/authdialog/CustomTextArea.java new file mode 100644 index 000000000..aae37a419 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/CustomTextArea.java @@ -0,0 +1,26 @@ +package net.java.sip.communicator.plugin.otr.authdialog; + +import java.awt.*; + +import javax.swing.*; + +/** + * A special {@link JTextArea} for use in the OTR authentication panels. + * It is meant to be used for fingerprint representation and general + * information display. + * + * @author George Politis + */ + public class CustomTextArea + extends JTextArea + { + public CustomTextArea() + { + this.setBackground(new Color(0,0,0,0)); + this.setOpaque(false); + this.setColumns(20); + this.setEditable(false); + this.setLineWrap(true); + this.setWrapStyleWord(true); + } + } \ No newline at end of file diff --git a/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java b/src/net/java/sip/communicator/plugin/otr/authdialog/FingerprintAuthenticationPanel.java similarity index 60% rename from src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java rename to src/net/java/sip/communicator/plugin/otr/authdialog/FingerprintAuthenticationPanel.java index 5d5e06c87..26f88662f 100644 --- a/src/net/java/sip/communicator/plugin/otr/OtrBuddyAuthenticationDialog.java +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/FingerprintAuthenticationPanel.java @@ -4,184 +4,100 @@ * 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.*; import javax.swing.*; 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 + * @author Marin Dzhigarov */ @SuppressWarnings("serial") -public class OtrBuddyAuthenticationDialog - extends SIPCommDialog +public class FingerprintAuthenticationPanel + extends TransparentPanel implements DocumentListener { - private final Contact contact; /** - * The {@link OtrBuddyAuthenticationDialog} ctor. - * - * @param contact The {@link Contact} this - * {@link OtrBuddyAuthenticationDialog} refers to. + * The Contact that we are authenticating. */ - public OtrBuddyAuthenticationDialog(Contact contact) - { - super(false); - this.contact = contact; - - initComponents(); - loadContact(); - } + private final Contact contact; private SIPCommTextField txtRemoteFingerprintComparison; + /** + * Our fingerprint. + */ private JTextArea txtLocalFingerprint; + /** + * The purported fingerprint of the remote party. + */ private JTextArea txtRemoteFingerprint; - private JComboBox cbAction; - ActionComboBoxItem actionIHave = - new ActionComboBoxItem(ActionComboBoxItemIndex.I_HAVE); - ActionComboBoxItem actionIHaveNot = - new ActionComboBoxItem(ActionComboBoxItemIndex.I_HAVE_NOT); - - private JTextArea txtAction; - /** - * Sets up the {@link OtrBuddyAuthenticationDialog} components so that they - * reflect the {@link OtrBuddyAuthenticationDialog#contact} + * The "I have" / "I have not" combo box. */ - private void loadContact() - { - // Local fingerprint. - String account = - contact.getProtocolProvider().getAccountID().getDisplayName(); - String localFingerprint = - OtrActivator.scOtrKeyManager.getLocalFingerprint(contact - .getProtocolProvider().getAccountID()); - txtLocalFingerprint.setText(OtrActivator.resourceService.getI18NString( - "plugin.otr.authbuddydialog.LOCAL_FINGERPRINT", new String[] - { account, localFingerprint })); - - // Remote fingerprint. - String user = contact.getDisplayName(); - String remoteFingerprint = - OtrActivator.scOtrKeyManager.getRemoteFingerprint(contact); - txtRemoteFingerprint.setText(OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.REMOTE_FINGERPRINT", - new String[] - { user, remoteFingerprint })); + private JComboBox cbAction; - // Action - txtAction.setText(OtrActivator.resourceService.getI18NString( - "plugin.otr.authbuddydialog.VERIFY_ACTION", new String[] - { user })); - } + private ActionComboBoxItem actionIHave = + new ActionComboBoxItem(ActionComboBoxItemIndex.I_HAVE); - /** - * A special {@link JTextArea} for use in the - * {@link OtrBuddyAuthenticationDialog}. It is meant to be used for - * fingerprint representation and general information display. - * - * @author George Politis - */ - class CustomTextArea - extends JTextArea - { - public CustomTextArea() - { - this.setBackground(new Color(0,0,0,0)); - this.setOpaque(false); - this.setColumns(20); - this.setEditable(false); - this.setLineWrap(true); - this.setWrapStyleWord(true); - } - } + private ActionComboBoxItem actionIHaveNot = + new ActionComboBoxItem(ActionComboBoxItemIndex.I_HAVE_NOT); - /** - * A simple enumeration that is meant to be used with - * {@link ActionComboBoxItem} to distinguish them (like an ID). - * - * @author George Politis - */ - enum ActionComboBoxItemIndex - { - I_HAVE, I_HAVE_NOT - } + private JTextArea txtAction; /** - * A special {@link JComboBox} that is hosted in - * {@link OtrBuddyAuthenticationDialog#cbAction}. - * - * @author George Politis + * Creates an instance FingerprintAuthenticationPanel + * + * @param contact The contact that this panel refers to. */ - class ActionComboBoxItem + FingerprintAuthenticationPanel(Contact contact) { - public ActionComboBoxItemIndex action; - - private String text; - - public ActionComboBoxItem(ActionComboBoxItemIndex actionIndex) - { - this.action = actionIndex; - switch (action) - { - case I_HAVE: - text = - OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.I_HAVE"); - break; - case I_HAVE_NOT: - text = - OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.I_HAVE_NOT"); - break; - } - } - - @Override - public String toString() - { - return text; - } + this.contact = contact; + initComponents(); + loadContact(); + } /** - * Initializes the {@link OtrBuddyAuthenticationDialog} components. + * Initializes the {@link FingerprintAuthenticationPanel} components. */ private void initComponents() { - this.setTitle(OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.TITLE")); - - TransparentPanel mainPanel = new TransparentPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - mainPanel.setPreferredSize(new Dimension(350, 400)); + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + setPreferredSize(new Dimension(350, 300)); JTextArea generalInformation = new CustomTextArea(); generalInformation.setText(OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.AUTHENTICATION_INFO")); - mainPanel.add(generalInformation); + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_FINGERPRINT")); + this.add(generalInformation); + + add(Box.createVerticalStrut(10)); txtLocalFingerprint = new CustomTextArea(); - mainPanel.add(txtLocalFingerprint); + this.add(txtLocalFingerprint); + + add(Box.createVerticalStrut(10)); txtRemoteFingerprint = new CustomTextArea(); - mainPanel.add(txtRemoteFingerprint); + this.add(txtRemoteFingerprint); + + add(Box.createVerticalStrut(10)); // Action Panel (the panel that holds the I have/I have not dropdown) JPanel pnlAction = new JPanel(new GridBagLayout()); pnlAction.setBorder(BorderFactory.createEtchedBorder()); - mainPanel.add(pnlAction); + this.add(pnlAction); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.HORIZONTAL; @@ -211,69 +127,42 @@ private void initComponents() pnlAction.add(txtRemoteFingerprintComparison, c); c.gridwidth = 1; c.gridy = 0; + } - // Buttons panel. - JPanel buttonPanel = new TransparentPanel(new GridBagLayout()); - buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5)); - - JButton helpButton = - new JButton(OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.HELP")); - helpButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent arg0) - { - OtrActivator.scOtrEngine.launchHelp(); - } - }); - - buttonPanel.add(helpButton, c); - - // Provide space between help and the other two button, not sure if this - // is optimal.. - c.weightx = 1.0; - buttonPanel.add(new JLabel(), c); - c.weightx = 0.0; + public JComboBox getCbAction() + { + return cbAction; + } - JButton cancelButton = - new JButton(OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.CANCEL")); - cancelButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - dispose(); - } - }); - buttonPanel.add(cancelButton, c); + /** + * Sets up the {@link OtrBuddyAuthenticationDialog} components so that they + * reflect the {@link OtrBuddyAuthenticationDialog#contact} + */ + private void loadContact() + { + // Local fingerprint. + String account = + contact.getProtocolProvider().getAccountID().getDisplayName(); + String localFingerprint = + OtrActivator.scOtrKeyManager.getLocalFingerprint(contact + .getProtocolProvider().getAccountID()); + txtLocalFingerprint.setText(OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.LOCAL_FINGERPRINT", new String[] + { account, localFingerprint })); - JButton authenticateButton = - new JButton(OtrActivator.resourceService - .getI18NString("plugin.otr.authbuddydialog.AUTHENTICATE_BUDDY")); - authenticateButton.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - ActionComboBoxItem actionItem = - (ActionComboBoxItem) cbAction.getSelectedItem(); - switch (actionItem.action) - { - case I_HAVE: - OtrActivator.scOtrKeyManager.verify(contact); - break; - case I_HAVE_NOT: - OtrActivator.scOtrKeyManager.unverify(contact); - break; - } - - dispose(); - } - }); - buttonPanel.add(authenticateButton, c); + // Remote fingerprint. + String user = contact.getDisplayName(); + String remoteFingerprint = + OtrActivator.scOtrKeyManager.getRemoteFingerprint(contact); + txtRemoteFingerprint.setText(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.REMOTE_FINGERPRINT", + new String[] + { user, remoteFingerprint })); - this.getContentPane().add(mainPanel, BorderLayout.NORTH); - this.getContentPane().add(buttonPanel, BorderLayout.SOUTH); - this.pack(); + // Action + txtAction.setText(OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.VERIFY_ACTION", new String[] + { user })); } public void removeUpdate(DocumentEvent e) @@ -313,4 +202,52 @@ public void compareFingerprints() cbAction.setSelectedItem(actionIHaveNot); } } + + /** + * A simple enumeration that is meant to be used with + * {@link ActionComboBoxItem} to distinguish them (like an ID). + * + * @author George Politis + */ + enum ActionComboBoxItemIndex + { + I_HAVE, I_HAVE_NOT + } + + /** + * A special {@link JComboBox} that is hosted in + * {@link OtrBuddyAuthenticationDialog#cbAction}. + * + * @author George Politis + */ + class ActionComboBoxItem + { + public ActionComboBoxItemIndex action; + + private String text; + + public ActionComboBoxItem(ActionComboBoxItemIndex actionIndex) + { + this.action = actionIndex; + switch (action) + { + case I_HAVE: + text = + OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.I_HAVE"); + break; + case I_HAVE_NOT: + text = + OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.I_HAVE_NOT"); + break; + } + } + + @Override + public String toString() + { + return text; + } + } } diff --git a/src/net/java/sip/communicator/plugin/otr/KnownFingerprintsPanel.java b/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsPanel.java similarity index 97% rename from src/net/java/sip/communicator/plugin/otr/KnownFingerprintsPanel.java rename to src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsPanel.java index 821883875..256814a81 100644 --- a/src/net/java/sip/communicator/plugin/otr/KnownFingerprintsPanel.java +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsPanel.java @@ -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.*; @@ -15,6 +15,7 @@ import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.plugin.otr.*; /** * @author @George Politis diff --git a/src/net/java/sip/communicator/plugin/otr/KnownFingerprintsTableModel.java b/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsTableModel.java similarity index 97% rename from src/net/java/sip/communicator/plugin/otr/KnownFingerprintsTableModel.java rename to src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsTableModel.java index c158d0f1e..1b32f26dd 100644 --- a/src/net/java/sip/communicator/plugin/otr/KnownFingerprintsTableModel.java +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/KnownFingerprintsTableModel.java @@ -4,13 +4,14 @@ * 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.util.*; import javax.swing.table.*; +import net.java.sip.communicator.plugin.otr.*; import net.java.sip.communicator.service.contactlist.*; import net.java.sip.communicator.service.protocol.*; diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/OtrBuddyAuthenticationDialog.java b/src/net/java/sip/communicator/plugin/otr/authdialog/OtrBuddyAuthenticationDialog.java new file mode 100644 index 000000000..900335035 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/OtrBuddyAuthenticationDialog.java @@ -0,0 +1,200 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.otr.authdialog; + +import java.awt.*; +import java.awt.event.*; + +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.service.protocol.*; + +/** + * @author George Politis + * @author Marin Dzhigarov + */ +@SuppressWarnings("serial") +public class OtrBuddyAuthenticationDialog + extends SIPCommDialog +{ + private final Contact contact; + + /** + * The {@link OtrBuddyAuthenticationDialog} ctor. + * + * @param contact The {@link Contact} this + * {@link OtrBuddyAuthenticationDialog} refers to. + */ + public OtrBuddyAuthenticationDialog(Contact contact) + { + super(false); + this.contact = contact; + + initComponents(); + } + + /** + * Initializes the {@link OtrBuddyAuthenticationDialog} components. + */ + private void initComponents() + { + this.setTitle(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.TITLE")); + + TransparentPanel mainPanel = new TransparentPanel(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPanel.setPreferredSize(new Dimension(350, 400)); + + JTextArea generalInformation = new CustomTextArea(); + generalInformation.setText(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.AUTHENTICATION_INFO")); + mainPanel.add(generalInformation); + + mainPanel.add(Box.createVerticalStrut(10)); + + // Add authentication method label and combo box. + final String am[] = new String[]{ + OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_QUESTION"), + OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_SECRET"), + OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_METHOD_FINGERPRINT")}; + final JComboBox authenticationMethodComboBox = + new JComboBox(am); + JTextArea authMethodLabel = new CustomTextArea(); + authMethodLabel.setText( + OtrActivator.resourceService.getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_METHOD")); + mainPanel.add(authMethodLabel); + mainPanel.add(authenticationMethodComboBox); + mainPanel.add(Box.createVerticalStrut(10)); + + // Add authentication panels in a card layout so that the user can + // use the combo box to switch between authentication methods. + final JPanel authenticationPanel = + new TransparentPanel(new CardLayout()); + final FingerprintAuthenticationPanel fingerprintPanel = + new FingerprintAuthenticationPanel(contact); + final SecretQuestionAuthenticationPanel secretQuestionPanel = + new SecretQuestionAuthenticationPanel(); + final SharedSecretAuthenticationPanel sharedSecretPanel = + new SharedSecretAuthenticationPanel(); + authenticationPanel.add(secretQuestionPanel, am[0]); + authenticationPanel.add(sharedSecretPanel, am[1]); + authenticationPanel.add(fingerprintPanel, am[2]); + + authenticationMethodComboBox.addItemListener(new ItemListener() + { + @Override + public void itemStateChanged(ItemEvent e) + { + if (e.getStateChange() == ItemEvent.SELECTED) + { + CardLayout cl = + (CardLayout) (authenticationPanel.getLayout()); + cl.show(authenticationPanel, (String)e.getItem()); + } + } + }); + authenticationMethodComboBox.setSelectedIndex(0); + mainPanel.add(authenticationPanel); + + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(5, 5, 5, 5); + c.weightx = 1.0; + c.gridwidth = 1; + + // Buttons panel. + JPanel buttonPanel = new TransparentPanel(new GridBagLayout()); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5)); + + JButton helpButton = + new JButton(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.HELP")); + helpButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + OtrActivator.scOtrEngine.launchHelp(); + } + }); + + buttonPanel.add(helpButton, c); + + // Provide space between help and the other two button, not sure if this + // is optimal.. + c.weightx = 1.0; + buttonPanel.add(new JLabel(), c); + c.weightx = 0.0; + + JButton cancelButton = + new JButton(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.CANCEL")); + cancelButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + dispose(); + } + }); + buttonPanel.add(cancelButton, c); + + JButton authenticateButton = + new JButton(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.AUTHENTICATE_BUDDY")); + authenticateButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + String authenticationMethod = + (String)authenticationMethodComboBox.getSelectedItem(); + if (authenticationMethod.equals(am[0])) + { + String secret = secretQuestionPanel.getSecret(); + String question = secretQuestionPanel.getQuestion(); + + OtrActivator.scOtrEngine.initSmp(contact, question, secret); + dispose(); + } + else if (authenticationMethod.equals(am[1])) + { + String secret = secretQuestionPanel.getSecret(); + String question = null; + + OtrActivator.scOtrEngine.initSmp(contact, question, secret); + dispose(); + } + else if (authenticationMethod.equals(am[2])) + { + ActionComboBoxItem actionItem = + (ActionComboBoxItem) fingerprintPanel. + getCbAction().getSelectedItem(); + switch (actionItem.action) + { + case I_HAVE: + OtrActivator.scOtrKeyManager.verify(contact); + break; + case I_HAVE_NOT: + OtrActivator.scOtrKeyManager.unverify(contact); + break; + } + dispose(); + } + } + }); + buttonPanel.add(authenticateButton, c); + + this.getContentPane().add(mainPanel, BorderLayout.NORTH); + this.getContentPane().add(buttonPanel, BorderLayout.SOUTH); + this.pack(); + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/SecretQuestionAuthenticationPanel.java b/src/net/java/sip/communicator/plugin/otr/authdialog/SecretQuestionAuthenticationPanel.java new file mode 100644 index 000000000..aa6542f99 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/SecretQuestionAuthenticationPanel.java @@ -0,0 +1,118 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.otr.authdialog; + +import java.awt.*; + +import javax.swing.*; + +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.plugin.otr.*; + +/** + * @author Marin Dzhigarov + */ +@SuppressWarnings("serial") +public class SecretQuestionAuthenticationPanel + extends TransparentPanel +{ + /** + * The text field where the authentication initiator will type his question. + */ + private final JTextField question = new JTextField(); + + /** + * The text field where the authentication initiator will type his answer. + */ + private final JTextField answer = new JTextField(); + + + /** + * Creates an instance SecretQuestionAuthenticationPanel. + */ + SecretQuestionAuthenticationPanel() + { + initComponents(); + } + + /** + * Initializes the {@link SecretQuestionAuthenticationPanel} components. + */ + private void initComponents() + { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + JTextArea generalInformation = new CustomTextArea(); + generalInformation.setText( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTH_BY_QUESTION_INFO_INIT")); + this.add(generalInformation); + + this.add(Box.createVerticalStrut(10)); + + JPanel questionAnswerPanel = new JPanel(new GridBagLayout()); + questionAnswerPanel.setBorder(BorderFactory.createEtchedBorder()); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 0, 5); + c.weightx = 1; + + JLabel questionLabel = + new JLabel( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.QUESTION_INIT")); + questionAnswerPanel.add(questionLabel, c); + + c.gridy = 1; + c.insets = new Insets(0, 5, 5, 5); + questionAnswerPanel.add(question, c); + + c.gridy = 2; + c.insets = new Insets(5, 5, 0, 5); + JLabel answerLabel = + new JLabel( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.ANSWER")); + questionAnswerPanel.add(answerLabel, c); + + c.gridy = 3; + c.insets = new Insets(0, 5, 5, 5); + questionAnswerPanel.add(answer, c); + + this.add(questionAnswerPanel); + this.add(new Box.Filler( + new Dimension(300, 100), + new Dimension(300, 100), + new Dimension(300, 100))); + } + + /** + * Returns the secret answer text. + * + * @return The secret answer text. + */ + String getSecret() + { + return answer.getText(); + } + + /** + * Returns the secret question text. + * + * @return The secret question text. + */ + String getQuestion() + { + return question.getText(); + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/SharedSecretAuthenticationPanel.java b/src/net/java/sip/communicator/plugin/otr/authdialog/SharedSecretAuthenticationPanel.java new file mode 100644 index 000000000..63b9c78f7 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/SharedSecretAuthenticationPanel.java @@ -0,0 +1,90 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.otr.authdialog; + +import java.awt.*; + +import javax.swing.*; + +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.plugin.otr.*; + +/** + * @author Marin Dzhigarov + * + */ +@SuppressWarnings("serial") +public class SharedSecretAuthenticationPanel + extends TransparentPanel +{ + /** + * The text field where the authentication initiator will type his answer. + */ + private final JTextField secret = new JTextField(); + + /** + * Creates an instance SecretQuestionAuthenticationPanel. + */ + SharedSecretAuthenticationPanel() + { + initComponents(); + } + + /** + * Initializes the {@link SecretQuestionAuthenticationPanel} components. + */ + private void initComponents() + { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + JTextArea generalInformation = new CustomTextArea(); + generalInformation.setText( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTH_BY_SECRET_INFO_INIT")); + this.add(generalInformation); + + this.add(Box.createVerticalStrut(10)); + + JPanel questionAnswerPanel = new JPanel(new GridBagLayout()); + questionAnswerPanel.setBorder(BorderFactory.createEtchedBorder()); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 0, 5); + c.weightx = 1; + + JLabel questionLabel = + new JLabel( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.SHARED_SECRET")); + questionAnswerPanel.add(questionLabel, c); + + c.gridy = 1; + c.insets = new Insets(0, 5, 5, 5); + questionAnswerPanel.add(secret, c); + + this.add(questionAnswerPanel); + this.add(new Box.Filler( + new Dimension(300, 150), + new Dimension(300, 150), + new Dimension(300, 150))); + } + + /** + * Returns the shared secret text. + * + * @return The shared secret text. + */ + String getSecret() + { + return secret.getText(); + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/SmpAuthenticateBuddyDialog.java b/src/net/java/sip/communicator/plugin/otr/authdialog/SmpAuthenticateBuddyDialog.java new file mode 100644 index 000000000..7d91c7ff3 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/SmpAuthenticateBuddyDialog.java @@ -0,0 +1,202 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.otr.authdialog; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.plugin.otr.*; +import net.java.sip.communicator.service.protocol.*; + +/** + * The dialog that pops up when the remote party send us SMP + * request. It contains detailed information for the user about + * the authentication process and allows him to authenticate. + * + * @author Marin Dzhigarov + */ +@SuppressWarnings("serial") +public class SmpAuthenticateBuddyDialog + extends SIPCommDialog +{ + private final Contact contact; + + private final String question; + + public SmpAuthenticateBuddyDialog(Contact contact, String question) + { + this.contact = contact; + this.question = question; + initComponents(); + } + + private void initComponents() + { + this.setTitle( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.TITLE")); + + // The main panel that contains all components. + JPanel mainPanel = new TransparentPanel(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + mainPanel.setBorder( + BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPanel.setPreferredSize(new Dimension(300, 350)); + + // Add "authentication from contact" to the main panel. + JTextArea authenticationFrom = new CustomTextArea(); + Font newFont = + new Font( + UIManager.getDefaults().getFont("TextArea.font"). + getFontName() + , Font.BOLD + , 14); + authenticationFrom.setFont(newFont); + String authFromText = + String.format( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_FROM", + new String[] {contact.getDisplayName()})); + authenticationFrom.setText(authFromText); + mainPanel.add(authenticationFrom); + + // Add "general info" text to the main panel. + JTextArea generalInfo = new CustomTextArea(); + generalInfo.setText(OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_INFO")); + mainPanel.add(generalInfo); + + // Add "authentication-by-secret" info text to the main panel. + JTextArea authBySecretInfo = new CustomTextArea(); + newFont = + new Font( + UIManager.getDefaults().getFont("TextArea.font"). + getFontName() + , Font.ITALIC + , 10); + authBySecretInfo.setText(OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTH_BY_SECRET_INFO_RESPOND")); + authBySecretInfo.setFont(newFont); + mainPanel.add(authBySecretInfo); + + // Create a panel to add question/answer related components + JPanel questionAnswerPanel = new JPanel(new GridBagLayout()); + questionAnswerPanel.setBorder(BorderFactory.createEtchedBorder()); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 0, 5); + c.weightx = 0; + + // Add question label. + JLabel questionLabel = + new JLabel( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.QUESTION_RESPOND")); + questionAnswerPanel.add(questionLabel, c); + + // Add the question. + c.insets = new Insets(0, 5, 5, 5); + c.gridy = 1; + JTextArea questionArea = + new CustomTextArea(); + newFont = + new Font( + UIManager.getDefaults().getFont("TextArea.font"). + getFontName() + , Font.BOLD + , UIManager.getDefaults().getFont("TextArea.font") + .getSize()); + questionArea.setFont(newFont); + questionArea.setText(question); + questionAnswerPanel.add(questionArea, c); + + // Add answer label. + c.insets = new Insets(5, 5, 5, 5); + c.gridy = 2; + JLabel answerLabel = + new JLabel(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.ANSWER")); + questionAnswerPanel.add(answerLabel, c); + + // Add the answer text field. + c.gridy = 3; + final JTextField answerTextBox = new JTextField(); + questionAnswerPanel.add(answerTextBox, c); + + // Add the question/answer panel to the main panel. + mainPanel.add(questionAnswerPanel); + + // Buttons panel. + JPanel buttonPanel = new TransparentPanel(new GridBagLayout()); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5)); + + JButton helpButton = + new JButton(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.HELP")); + helpButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + OtrActivator.scOtrEngine.launchHelp(); + } + }); + + c.gridwidth = 1; + c.gridy = 0; + c.gridx = 0; + c.weightx = 0; + c.insets = new Insets(5, 5, 5, 20); + buttonPanel.add(helpButton, c); + + JButton cancelButton = + new JButton(OtrActivator.resourceService + .getI18NString("plugin.otr.authbuddydialog.CANCEL")); + cancelButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + OtrActivator.scOtrEngine.abortSmp(contact); + SmpAuthenticateBuddyDialog.this.dispose(); + } + }); + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 1; + buttonPanel.add(cancelButton, c); + + c.gridx = 2; + JButton authenticateButton = + new JButton(OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATE_BUDDY")); + authenticateButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + OtrActivator.scOtrEngine.respondSmp( + contact, question, answerTextBox.getText()); + SmpAuthenticateBuddyDialog.this.dispose(); + } + }); + + buttonPanel.add(authenticateButton, c); + + this.getContentPane().add(mainPanel, BorderLayout.NORTH); + this.getContentPane().add(buttonPanel, BorderLayout.SOUTH); + this.pack(); + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/authdialog/SmpProgressDialog.java b/src/net/java/sip/communicator/plugin/otr/authdialog/SmpProgressDialog.java new file mode 100644 index 000000000..99dd1e1a3 --- /dev/null +++ b/src/net/java/sip/communicator/plugin/otr/authdialog/SmpProgressDialog.java @@ -0,0 +1,143 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.plugin.otr.authdialog; + +import java.awt.*; + +import javax.swing.*; +import javax.swing.plaf.basic.*; + +import net.java.sip.communicator.plugin.desktoputil.*; +import net.java.sip.communicator.plugin.otr.*; +import net.java.sip.communicator.service.protocol.*; + + +/** + * The dialog that pops up when SMP negotiation starts. + * It contains a progress bar that indicates the status of the SMP + * authentication process. + * + * @author Marin Dzhigarov + */ +@SuppressWarnings("serial") +public class SmpProgressDialog + extends SIPCommDialog +{ + private final JProgressBar progressBar = new JProgressBar(0, 100); + + private final Color successColor = new Color(86, 140, 2); + + private final Color failColor = new Color(204, 0, 0); + + private final JLabel iconLabel = new JLabel(); + + /** + * Instantiates SmpProgressDialog. + * + * @param contact The contact that this dialog is associated with. + */ + public SmpProgressDialog(Contact contact) + { + setTitle( + OtrActivator.resourceService.getI18NString( + "plugin.otr.smpprogressdialog.TITLE")); + + JPanel mainPanel = new TransparentPanel(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + mainPanel.setBorder( + BorderFactory.createEmptyBorder(10, 10, 10, 10)); + mainPanel.setPreferredSize(new Dimension(300, 70)); + + String authFromText = + String.format( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.authbuddydialog.AUTHENTICATION_FROM", + new String[] {contact.getDisplayName()})); + + JPanel labelsPanel = new TransparentPanel(); + labelsPanel.setLayout(new BoxLayout(labelsPanel, BoxLayout.X_AXIS)); + + labelsPanel.add(iconLabel); + labelsPanel.add(Box.createRigidArea(new Dimension(5,0))); + labelsPanel.add(new JLabel(authFromText)); + + mainPanel.add(labelsPanel); + mainPanel.add(progressBar); + + init(); + + this.getContentPane().add(mainPanel); + this.pack(); + } + + /** + * Initializes the progress bar and sets it's progression to 1/3. + */ + public void init() + { + progressBar.setUI(new BasicProgressBarUI() { + private Rectangle r = new Rectangle(); + + @Override + protected void paintIndeterminate(Graphics g, JComponent c) { + Graphics2D g2d = (Graphics2D) g; + g2d.setRenderingHint( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + r = getBox(r); + g.setColor(progressBar.getForeground()); + g.fillOval(r.x, r.y, r.width, r.height); + } + }); + progressBar.setValue(33); + progressBar.setForeground(successColor); + progressBar.setStringPainted(false); + iconLabel.setIcon( + OtrActivator.resourceService.getImage( + "plugin.otr.ENCRYPTED_UNVERIFIED_ICON_22x22")); + } + + /** + * Sets the progress bar to 2/3 of completion. + */ + public void incrementProgress() + { + progressBar.setValue(66); + } + + /** + * Sets the progress bar to green. + */ + public void setProgressSuccess() + { + progressBar.setValue(100); + progressBar.setForeground(successColor); + progressBar.setStringPainted(true); + progressBar.setString( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.smpprogressdialog.AUTHENTICATION_SUCCESS")); + iconLabel.setIcon( + OtrActivator.resourceService.getImage( + "plugin.otr.ENCRYPTED_ICON_22x22")); + } + + /** + * Sets the progress bar to red. + */ + public void setProgressFail() + { + progressBar.setValue(100); + progressBar.setForeground(failColor); + progressBar.setStringPainted(true); + progressBar.setString( + OtrActivator.resourceService + .getI18NString( + "plugin.otr.smpprogressdialog.AUTHENTICATION_FAIL")); + } +} diff --git a/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf b/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf index 3e74c53ff..71c607c4d 100644 --- a/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf +++ b/src/net/java/sip/communicator/plugin/otr/otr.manifest.mf @@ -20,6 +20,8 @@ Import-Package: org.osgi.framework, javax.swing.table, javax.swing.text, javax.swing.event, + javax.swing.plaf, + javax.swing.plaf.basic, javax.crypto, javax.crypto.interfaces, javax.crypto.spec,