@@ -37,16 +37,16 @@ function profilePath(filename) {
// libotr context wrapper

function Context(context) {
this.context = context;
this._context = context;
}

Context.prototype = {
constructor: Context,
get username() this.context.contents.username.readString(),
get account() this.context.contents.accountname.readString(),
get protocol() this.context.contents.protocol.readString(),
get msgstate() this.context.contents.msgstate,
get fingerprint() this.context.contents.active_fingerprint,
get username() this._context.contents.username.readString(),
get account() this._context.contents.accountname.readString(),
get protocol() this._context.contents.protocol.readString(),
get msgstate() this._context.contents.msgstate,
get fingerprint() this._context.contents.active_fingerprint,
get fingerprint_hash() this.fingerprint.contents.fingerprint,
get trust() {
return (!this.fingerprint.isNull() &&
@@ -168,6 +168,10 @@ let otr = {
return; // ignore if no change in trust
libOTR.otrl_context_set_trust(context.fingerprint, trust ? "verified" : "");
this.writeFingerprints();
this.notifyTrust(context);
},

notifyTrust: function(context) {
this.notifyObservers(context, "otr:msg-state");
this.notifyObservers(context, "otr:trust-state");
},
@@ -406,7 +410,37 @@ let otr = {

// Update the authentication UI with respect to SMP events.
handle_smp_event_cb: function(opdata, smp_event, context, progress_percent, question) {
// TODO: implement SMP.
context = new Context(context);
switch(smp_event) {
case libOTR.smpEvent.OTRL_SMPEVENT_NONE:
break;
case libOTR.smpEvent.OTRL_SMPEVENT_ASK_FOR_ANSWER:
case libOTR.smpEvent.OTRL_SMPEVENT_ASK_FOR_SECRET:
this.notifyObservers({
context: context,
progress: progress_percent,
question: question.isNull() ? null : question.readString()
}, "otr:auth-ask");
break;
case libOTR.smpEvent.OTRL_SMPEVENT_CHEATED:
otr.abortSMP(context);
// fall through
case libOTR.smpEvent.OTRL_SMPEVENT_IN_PROGRESS:
case libOTR.smpEvent.OTRL_SMPEVENT_SUCCESS:
case libOTR.smpEvent.OTRL_SMPEVENT_FAILURE:
case libOTR.smpEvent.OTRL_SMPEVENT_ABORT:
this.notifyObservers({
context: context,
progress: progress_percent,
success: (smp_event === libOTR.smpEvent.OTRL_SMPEVENT_SUCCESS)
}, "otr:auth-update");
break;
case libOTR.smpEvent.OTRL_SMPEVENT_ERROR:
otr.abortSMP(context);
break;
default:
this.log("smp event: " + smp_event);
}
},

// Handle and send the appropriate message(s) to the sender/recipient
@@ -558,6 +592,42 @@ let otr = {
this.clearMsgs(uiConv.target.id);
},

sendSecret: function(context, secret, question) {
let str = ctypes.char.array()(secret);
let strlen = new ctypes.size_t(str.length - 1);
libOTR.otrl_message_initiate_smp_q(
this.userstate,
this.uiOps.address(),
null,
context._context,
question ? question : null,
str,
strlen
);
},

sendResponse: function(context, response) {
let str = ctypes.char.array()(response);
let strlen = new ctypes.size_t(str.length - 1);
libOTR.otrl_message_respond_smp(
this.userstate,
this.uiOps.address(),
null,
context._context,
str,
strlen
);
},

abortSMP: function(context) {
libOTR.otrl_message_abort_smp(
this.userstate,
this.uiOps.address(),
null,
context._context
);
},

onSend: function(om) {
if (om.cancelled)
return;
@@ -11,4 +11,11 @@
<!ENTITY authDialog.questionAndAnswer "Question and answer">
<!ENTITY authDialog.sharedSecret "Shared secret">
<!ENTITY authDialog.manualInstruction "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 dialog below that you have verified the fingerprint.">
<!ENTITY authDialog.choose "Choose">
<!ENTITY authDialog.choose "Choose">
<!ENTITY authDialog.how "How would you like to authenticate your buddy?">
<!ENTITY authDialog.qaInstruction "To authenticate using a question, pick a question whose answer is known only to you and your contact. Enter this question and answer, then wait for your contact to enter the answer as well. If the answers do not match, then you may be talking to an imposter.">
<!ENTITY authDialog.secretInstruction "To authenticate, pick a secret known only to you and your contact. Enter this secret, then wait for your contact to enter it as well. If the secrets do not match, then you may be talking to an imposter.">
<!ENTITY authDialog.question "Enter question here:">
<!ENTITY authDialog.answer "Enter secret answer here (case sensitive):">
<!ENTITY authDialog.secret "Enter secret here:">
<!ENTITY authDialog.waiting "Waiting for contact ...">
@@ -1,4 +1,10 @@
auth.yourFingerprint=Fingerprint for you, %S:\n%S
auth.theirFingerprint=Purported fingerprint for %S:\n%S
auth.help=Authenticating a contact helps ensure that the person you are talking to is who they claim to be.
auth.helpTitle=Authentication help
auth.helpTitle=Authentication help
auth.question=This is the question asked by your contact:\n\n%S\n\nEnter secret answer here (case sensitive):
auth.secret=Enter secret here:
auth.error=An error occurred during authentication.
auth.success=Authentication successful.
auth.successThem=Your contact has successfully authenticated you. You may want to authenticate your contact as well by asking your own question.
auth.fail=Authentication failed.