/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const otrl_version = [4, 1, 1]; import { CLib } from "resource:///modules/CLib.sys.mjs"; import { ctypes } from "resource://gre/modules/ctypes.sys.mjs"; var systemOS = Services.appinfo.OS.toLowerCase(); var abi = ctypes.default_abi; var libotr, libotrPath; function getLibraryFilename(baseName, suffix) { return ctypes.libraryName(baseName) + suffix; } function getSystemVersionedFilename() { let baseName; let suffix; switch (systemOS) { case "winnt": baseName = "libotr-5"; suffix = ""; break; case "darwin": baseName = "otr.5"; suffix = ""; break; default: baseName = "otr"; suffix = ".5"; break; } return getLibraryFilename(baseName, suffix); } function getDistributionFilename() { let baseName; let suffix; if (systemOS === "winnt") { baseName = "libotr"; suffix = ""; } else { baseName = "otr"; suffix = ""; } return getLibraryFilename(baseName, suffix); } function getDistributionFullPath() { let binPath = Services.dirsvc.get("XpcomLib", Ci.nsIFile).path; let binDir = PathUtils.parent(binPath); return PathUtils.join(binDir, getDistributionFilename()); } function tryLoadOTR(filename, info) { libotrPath = filename; try { libotr = ctypes.open(filename); } catch (e) { return `Tried to load ${filename}${info}`; } return ""; } function loadExternalOTRLib() { const systemInfo = " from system's standard library locations."; let info = ""; // Try to load using an absolute path from our install directory if (!libotr) { info += tryLoadOTR(getDistributionFullPath(), ""); } // Try to load using our expected filename from system directories if (!libotr) { info += ", " + tryLoadOTR(getDistributionFilename(), systemInfo); } // Try to load using a versioned library name if (!libotr) { info += ", " + tryLoadOTR(getSystemVersionedFilename(), systemInfo); } // Try other filenames if (!libotr && systemOS == "winnt") { info += ", " + tryLoadOTR(getLibraryFilename("otr.5", ""), systemInfo); } if (!libotr && systemOS == "winnt") { info += ", " + tryLoadOTR(getLibraryFilename("otr-5", ""), systemInfo); } if (!libotr) { info += ", " + tryLoadOTR(getLibraryFilename("otr", ""), systemInfo); } if (!libotr) { throw new Error("Cannot load required OTR library; " + info); } } export var OTRLibLoader = { init() { loadExternalOTRLib(); if (libotr) { enableOTRLibJS(); } return OTRLib; }, }; // Helper function to open files with the path properly encoded. var callWithFILEp = function () { // Windows filenames are in UTF-16. let charType = systemOS === "winnt" ? "jschar" : "char"; let args = Array.from(arguments); let func = args.shift() + "_FILEp"; let mode = ctypes[charType].array()(args.shift()); let ind = args.shift(); let filename = ctypes[charType].array()(args[ind]); let file = CLib.fopen(filename, mode); if (file.isNull()) { return 1; } // Swap filename with file. args[ind] = file; let ret = OTRLib[func].apply(OTRLib, args); CLib.fclose(file); return ret; }; // type defs const FILE = CLib.FILE; const time_t = ctypes.long; const gcry_error_t = ctypes.unsigned_int; const gcry_cipher_hd_t = ctypes.StructType("gcry_cipher_handle").ptr; const gcry_md_hd_t = ctypes.StructType("gcry_md_handle").ptr; const gcry_mpi_t = ctypes.StructType("gcry_mpi").ptr; const otrl_instag_t = ctypes.unsigned_int; const OtrlPolicy = ctypes.unsigned_int; const OtrlTLV = ctypes.StructType("s_OtrlTLV"); const ConnContext = ctypes.StructType("context"); const ConnContextPriv = ctypes.StructType("context_priv"); const OtrlMessageAppOps = ctypes.StructType("s_OtrlMessageAppOps"); const OtrlAuthInfo = ctypes.StructType("OtrlAuthInfo"); const Fingerprint = ctypes.StructType("s_fingerprint"); const s_OtrlUserState = ctypes.StructType("s_OtrlUserState"); const OtrlUserState = s_OtrlUserState.ptr; const OtrlSMState = ctypes.StructType("OtrlSMState"); const DH_keypair = ctypes.StructType("DH_keypair"); const OtrlPrivKey = ctypes.StructType("s_OtrlPrivKey"); const OtrlInsTag = ctypes.StructType("s_OtrlInsTag"); const OtrlPendingPrivKey = ctypes.StructType("s_OtrlPendingPrivKey"); const OTRL_PRIVKEY_FPRINT_HUMAN_LEN = 45; const fingerprint_t = ctypes.char.array(OTRL_PRIVKEY_FPRINT_HUMAN_LEN); const hash_t = ctypes.unsigned_char.array(20); const app_data_free_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ]).ptr; // enums const OtrlErrorCode = ctypes.int; const OtrlSMPEvent = ctypes.int; const OtrlMessageEvent = ctypes.int; const OtrlFragmentPolicy = ctypes.int; const OtrlConvertType = ctypes.int; const OtrlMessageState = ctypes.int; const OtrlAuthState = ctypes.int; const OtrlSessionIdHalf = ctypes.int; const OtrlSMProgState = ctypes.int; const NextExpectedSMP = ctypes.int; // callback signatures const policy_cb_t = ctypes.FunctionType(abi, OtrlPolicy, [ ctypes.void_t.ptr, ConnContext.ptr, ]).ptr; const create_privkey_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr, ]).ptr; const is_logged_in_cb_t = ctypes.FunctionType(abi, ctypes.int, [ ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, ]).ptr; const inject_message_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, ]).ptr; const update_context_list_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ]).ptr; const new_fingerprint_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, OtrlUserState, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.unsigned_char.array(20), ]).ptr; const write_fingerprint_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ]).ptr; const gone_secure_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ConnContext.ptr, ]).ptr; const gone_insecure_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ConnContext.ptr, ]).ptr; const still_secure_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ConnContext.ptr, ctypes.int, ]).ptr; const max_message_size_cb_t = ctypes.FunctionType(abi, ctypes.int, [ ctypes.void_t.ptr, ConnContext.ptr, ]).ptr; const account_name_cb_t = ctypes.FunctionType(abi, ctypes.char.ptr, [ ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr, ]).ptr; const account_name_free_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ctypes.char.ptr, ]).ptr; const received_symkey_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ConnContext.ptr, ctypes.unsigned_int, ctypes.unsigned_char.ptr, ctypes.size_t, ctypes.unsigned_char.ptr, ]).ptr; const otr_error_message_cb_t = ctypes.FunctionType(abi, ctypes.char.ptr, [ ctypes.void_t.ptr, ConnContext.ptr, OtrlErrorCode, ]).ptr; const otr_error_message_free_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ctypes.char.ptr, ]).ptr; const resent_msg_prefix_cb_t = ctypes.FunctionType(abi, ctypes.char.ptr, [ ctypes.void_t.ptr, ConnContext.ptr, ]).ptr; const resent_msg_prefix_free_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ctypes.char.ptr, ]).ptr; const handle_smp_event_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, OtrlSMPEvent, ConnContext.ptr, ctypes.unsigned_short, ctypes.char.ptr, ]).ptr; const handle_msg_event_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, OtrlMessageEvent, ConnContext.ptr, ctypes.char.ptr, gcry_error_t, ]).ptr; const create_instag_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr, ]).ptr; const convert_msg_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ConnContext.ptr, OtrlConvertType, ctypes.char.ptr.ptr, ctypes.char.ptr, ]).ptr; const convert_free_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ConnContext.ptr, ctypes.char.ptr, ]).ptr; const timer_control_cb_t = ctypes.FunctionType(abi, ctypes.void_t, [ ctypes.void_t.ptr, ctypes.unsigned_int, ]).ptr; // defines s_OtrlUserState.define([ { context_root: ConnContext.ptr }, { privkey_root: OtrlPrivKey.ptr }, { instag_root: OtrlInsTag.ptr }, { pending_root: OtrlPendingPrivKey.ptr }, { timer_running: ctypes.int }, ]); Fingerprint.define([ { next: Fingerprint.ptr }, { tous: Fingerprint.ptr.ptr }, { fingerprint: ctypes.unsigned_char.ptr }, { context: ConnContext.ptr }, { trust: ctypes.char.ptr }, ]); DH_keypair.define([ { groupid: ctypes.unsigned_int }, { priv: gcry_mpi_t }, { pub: gcry_mpi_t }, ]); OtrlSMState.define([ { secret: gcry_mpi_t }, { x2: gcry_mpi_t }, { x3: gcry_mpi_t }, { g1: gcry_mpi_t }, { g2: gcry_mpi_t }, { g3: gcry_mpi_t }, { g3o: gcry_mpi_t }, { p: gcry_mpi_t }, { q: gcry_mpi_t }, { pab: gcry_mpi_t }, { qab: gcry_mpi_t }, { nextExpected: NextExpectedSMP }, { received_question: ctypes.int }, { sm_prog_state: OtrlSMProgState }, ]); OtrlAuthInfo.define([ { authstate: OtrlAuthState }, { context: ConnContext.ptr }, { our_dh: DH_keypair }, { our_keyid: ctypes.unsigned_int }, { encgx: ctypes.unsigned_char.ptr }, { encgx_len: ctypes.size_t }, { r: ctypes.unsigned_char.array(16) }, { hashgx: ctypes.unsigned_char.array(32) }, { their_pub: gcry_mpi_t }, { their_keyid: ctypes.unsigned_int }, { enc_c: gcry_cipher_hd_t }, { enc_cp: gcry_cipher_hd_t }, { mac_m1: gcry_md_hd_t }, { mac_m1p: gcry_md_hd_t }, { mac_m2: gcry_md_hd_t }, { mac_m2p: gcry_md_hd_t }, { their_fingerprint: ctypes.unsigned_char.array(20) }, { initiated: ctypes.int }, { protocol_version: ctypes.unsigned_int }, { secure_session_id: ctypes.unsigned_char.array(20) }, { secure_session_id_len: ctypes.size_t }, { session_id_half: OtrlSessionIdHalf }, { lastauthmsg: ctypes.char.ptr }, { commit_sent_time: time_t }, ]); ConnContext.define([ { next: ConnContext.ptr }, { tous: ConnContext.ptr.ptr }, { context_priv: ConnContextPriv.ptr }, { username: ctypes.char.ptr }, { accountname: ctypes.char.ptr }, { protocol: ctypes.char.ptr }, { m_context: ConnContext.ptr }, { recent_rcvd_child: ConnContext.ptr }, { recent_sent_child: ConnContext.ptr }, { recent_child: ConnContext.ptr }, { our_instance: otrl_instag_t }, { their_instance: otrl_instag_t }, { msgstate: OtrlMessageState }, { auth: OtrlAuthInfo }, { fingerprint_root: Fingerprint }, { active_fingerprint: Fingerprint.ptr }, { sessionid: ctypes.unsigned_char.array(20) }, { sessionid_len: ctypes.size_t }, { sessionid_half: OtrlSessionIdHalf }, { protocol_version: ctypes.unsigned_int }, { otr_offer: ctypes.int }, { app_data: ctypes.void_t.ptr }, { app_data_free: app_data_free_t }, { smstate: OtrlSMState.ptr }, ]); OtrlMessageAppOps.define([ { policy: policy_cb_t }, { create_privkey: create_privkey_cb_t }, { is_logged_in: is_logged_in_cb_t }, { inject_message: inject_message_cb_t }, { update_context_list: update_context_list_cb_t }, { new_fingerprint: new_fingerprint_cb_t }, { write_fingerprint: write_fingerprint_cb_t }, { gone_secure: gone_secure_cb_t }, { gone_insecure: gone_insecure_cb_t }, { still_secure: still_secure_cb_t }, { max_message_size: max_message_size_cb_t }, { account_name: account_name_cb_t }, { account_name_free: account_name_free_cb_t }, { received_symkey: received_symkey_cb_t }, { otr_error_message: otr_error_message_cb_t }, { otr_error_message_free: otr_error_message_free_cb_t }, { resent_msg_prefix: resent_msg_prefix_cb_t }, { resent_msg_prefix_free: resent_msg_prefix_free_cb_t }, { handle_smp_event: handle_smp_event_cb_t }, { handle_msg_event: handle_msg_event_cb_t }, { create_instag: create_instag_cb_t }, { convert_msg: convert_msg_cb_t }, { convert_free: convert_free_cb_t }, { timer_control: timer_control_cb_t }, ]); OtrlTLV.define([ { type: ctypes.unsigned_short }, { len: ctypes.unsigned_short }, { data: ctypes.unsigned_char.ptr }, { next: OtrlTLV.ptr }, ]); // policies // const OTRL_POLICY_ALLOW_V1 = 0x01; const OTRL_POLICY_ALLOW_V2 = 0x02; // const OTRL_POLICY_ALLOW_V3 = 0x04; // See https://bugzilla.mozilla.org/show_bug.cgi?id=1550474 re v3. const OTRL_POLICY_REQUIRE_ENCRYPTION = 0x08; const OTRL_POLICY_SEND_WHITESPACE_TAG = 0x10; const OTRL_POLICY_WHITESPACE_START_AKE = 0x20; // const OTRL_POLICY_ERROR_START_AKE = 0x40; // Disabled to avoid automatic resend and MITM, as explained in // https://github.com/arlolra/ctypes-otr/issues/55 var OTRLib; function enableOTRLibJS() { // this must be delayed until after "libotr" is initialized OTRLib = { path: libotrPath, // libotr API version otrl_version, init() { // apply version array as arguments to the init function if (this.otrl_init.apply(this, this.otrl_version)) { throw new Error("Couldn't initialize libotr."); } return true; }, // proto.h // If we ever see this sequence in a plaintext message, we'll assume the // other side speaks OTR, and try to establish a connection. OTRL_MESSAGE_TAG_BASE: " \t \t\t\t\t \t \t \t ", OTRL_POLICY_OPPORTUNISTIC: new ctypes.unsigned_int( OTRL_POLICY_ALLOW_V2 | // OTRL_POLICY_ALLOW_V3 | OTRL_POLICY_SEND_WHITESPACE_TAG | OTRL_POLICY_WHITESPACE_START_AKE | // OTRL_POLICY_ERROR_START_AKE | 0 ), OTRL_POLICY_ALWAYS: new ctypes.unsigned_int( OTRL_POLICY_ALLOW_V2 | // OTRL_POLICY_ALLOW_V3 | OTRL_POLICY_REQUIRE_ENCRYPTION | OTRL_POLICY_WHITESPACE_START_AKE | // OTRL_POLICY_ERROR_START_AKE | 0 ), fragPolicy: { OTRL_FRAGMENT_SEND_SKIP: 0, OTRL_FRAGMENT_SEND_ALL: 1, OTRL_FRAGMENT_SEND_ALL_BUT_FIRST: 2, OTRL_FRAGMENT_SEND_ALL_BUT_LAST: 3, }, // Return a pointer to a newly-allocated OTR query message, customized // with our name. The caller should free() the result when he's done // with it. otrl_proto_default_query_msg: libotr.declare( "otrl_proto_default_query_msg", abi, ctypes.char.ptr, ctypes.char.ptr, OtrlPolicy ), // Initialize the OTR library. Pass the version of the API you are using. otrl_init: libotr.declare( "otrl_init", abi, gcry_error_t, ctypes.unsigned_int, ctypes.unsigned_int, ctypes.unsigned_int ), // instag.h instag: { OTRL_INSTAG_MASTER: new ctypes.unsigned_int(0), OTRL_INSTAG_BEST: new ctypes.unsigned_int(1), OTRL_INSTAG_RECENT: new ctypes.unsigned_int(2), OTRL_INSTAG_RECENT_RECEIVED: new ctypes.unsigned_int(3), OTRL_INSTAG_RECENT_SENT: new ctypes.unsigned_int(4), OTRL_MIN_VALID_INSTAG: new ctypes.unsigned_int(0x100), }, // Get a new instance tag for the given account and write to file. The FILE* // must be open for writing. otrl_instag_generate: callWithFILEp.bind( null, "otrl_instag_generate", "wb", 1 ), otrl_instag_generate_FILEp: libotr.declare( "otrl_instag_generate_FILEp", abi, gcry_error_t, OtrlUserState, FILE.ptr, ctypes.char.ptr, ctypes.char.ptr ), // Read our instance tag from a file on disk into the given OtrlUserState. // The FILE* must be open for reading. otrl_instag_read: callWithFILEp.bind(null, "otrl_instag_read", "rb", 1), otrl_instag_read_FILEp: libotr.declare( "otrl_instag_read_FILEp", abi, gcry_error_t, OtrlUserState, FILE.ptr ), // Write our instance tags to a file on disk. The FILE* must be open for // writing. otrl_instag_write: callWithFILEp.bind(null, "otrl_instag_write", "wb", 1), otrl_instag_write_FILEp: libotr.declare( "otrl_instag_write_FILEp", abi, gcry_error_t, OtrlUserState, FILE.ptr ), // auth.h authState: { OTRL_AUTHSTATE_NONE: 0, OTRL_AUTHSTATE_AWAITING_DHKEY: 1, OTRL_AUTHSTATE_AWAITING_REVEALSIG: 2, OTRL_AUTHSTATE_AWAITING_SIG: 3, OTRL_AUTHSTATE_V1_SETUP: 4, }, // b64.h // base64 encode data. Insert no linebreaks or whitespace. // The buffer base64data must contain at least ((datalen+2)/3)*4 bytes of // space. This function will return the number of bytes actually used. otrl_base64_encode: libotr.declare( "otrl_base64_encode", abi, ctypes.size_t, ctypes.char.ptr, ctypes.unsigned_char.ptr, ctypes.size_t ), // base64 decode data. Skip non-base64 chars, and terminate at the // first '=', or the end of the buffer. // The buffer data must contain at least ((base64len+3) / 4) * 3 bytes // of space. This function will return the number of bytes actually // used. otrl_base64_decode: libotr.declare( "otrl_base64_decode", abi, ctypes.size_t, ctypes.unsigned_char.ptr, ctypes.char.ptr, ctypes.size_t ), // context.h otr_offer: { OFFER_NOT: 0, OFFER_SENT: 1, OFFER_REJECTED: 2, OFFER_ACCEPTED: 3, }, messageState: { OTRL_MSGSTATE_PLAINTEXT: 0, OTRL_MSGSTATE_ENCRYPTED: 1, OTRL_MSGSTATE_FINISHED: 2, }, // Look up a connection context by name/account/protocol/instance from the // given OtrlUserState. otrl_context_find: libotr.declare( "otrl_context_find", abi, ConnContext.ptr, OtrlUserState, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, otrl_instag_t, ctypes.int, ctypes.int.ptr, ctypes.void_t.ptr, ctypes.void_t.ptr ), // Set the trust level for a given fingerprint. otrl_context_set_trust: libotr.declare( "otrl_context_set_trust", abi, ctypes.void_t, Fingerprint.ptr, ctypes.char.ptr ), // Find a fingerprint in a given context, perhaps adding it if not present. otrl_context_find_fingerprint: libotr.declare( "otrl_context_find_fingerprint", abi, Fingerprint.ptr, ConnContext.ptr, hash_t, ctypes.int, ctypes.int.ptr ), // Forget a fingerprint (and maybe the whole context). otrl_context_forget_fingerprint: libotr.declare( "otrl_context_forget_fingerprint", abi, ctypes.void_t, Fingerprint.ptr, ctypes.int ), // Return true iff the given fingerprint is marked as trusted. otrl_context_is_fingerprint_trusted: libotr.declare( "otrl_context_is_fingerprint_trusted", abi, ctypes.int, Fingerprint.ptr ), // dh.h sessionIdHalf: { OTRL_SESSIONID_FIRST_HALF_BOLD: 0, OTRL_SESSIONID_SECOND_HALF_BOLD: 1, }, // sm.h nextExpectedSMP: { OTRL_SMP_EXPECT1: 0, OTRL_SMP_EXPECT2: 1, OTRL_SMP_EXPECT3: 2, OTRL_SMP_EXPECT4: 3, OTRL_SMP_EXPECT5: 4, }, smProgState: { OTRL_SMP_PROG_OK: 0, OTRL_SMP_PROG_CHEATED: -2, OTRL_SMP_PROG_FAILED: -1, OTRL_SMP_PROG_SUCCEEDED: 1, }, // userstate.h // Create a new OtrlUserState. otrl_userstate_create: libotr.declare( "otrl_userstate_create", abi, OtrlUserState ), // privkey.h // Generate a private DSA key for a given account, storing it into a file on // disk, and loading it into the given OtrlUserState. Overwrite any // previously generated keys for that account in that OtrlUserState. otrl_privkey_generate: callWithFILEp.bind( null, "otrl_privkey_generate", "w+b", 1 ), otrl_privkey_generate_FILEp: libotr.declare( "otrl_privkey_generate_FILEp", abi, gcry_error_t, OtrlUserState, FILE.ptr, ctypes.char.ptr, ctypes.char.ptr ), // Begin a private key generation that will potentially take place in // a background thread. This routine must be called from the main // thread. It will set *newkeyp, which you can pass to // otrl_privkey_generate_calculate in a background thread. If it // returns gcry_error(GPG_ERR_EEXIST), then a privkey creation for // this accountname/protocol is already in progress, and *newkeyp will // be set to NULL. otrl_privkey_generate_start: libotr.declare( "otrl_privkey_generate_start", abi, gcry_error_t, OtrlUserState, ctypes.char.ptr, ctypes.char.ptr, ctypes.void_t.ptr.ptr ), // Do the private key generation calculation. You may call this from a // background thread. When it completes, call // otrl_privkey_generate_finish from the _main_ thread. otrl_privkey_generate_calculate: libotr.declare( "otrl_privkey_generate_calculate", abi, gcry_error_t, ctypes.void_t.ptr ), // Call this from the main thread only. It will write the newly created // private key into the given file and store it in the OtrlUserState. otrl_privkey_generate_finish: callWithFILEp.bind( null, "otrl_privkey_generate_finish", "w+b", 2 ), otrl_privkey_generate_finish_FILEp: libotr.declare( "otrl_privkey_generate_finish_FILEp", abi, gcry_error_t, OtrlUserState, ctypes.void_t.ptr, FILE.ptr ), // Call this from the main thread only, in the event that the background // thread generating the key is cancelled. The newkey is deallocated, // and must not be used further. otrl_privkey_generate_cancelled: libotr.declare( "otrl_privkey_generate_cancelled", abi, gcry_error_t, OtrlUserState, ctypes.void_t.ptr ), // Read a sets of private DSA keys from a file on disk into the given // OtrlUserState. otrl_privkey_read: callWithFILEp.bind(null, "otrl_privkey_read", "rb", 1), otrl_privkey_read_FILEp: libotr.declare( "otrl_privkey_read_FILEp", abi, gcry_error_t, OtrlUserState, FILE.ptr ), // Read the fingerprint store from a file on disk into the given // OtrlUserState. otrl_privkey_read_fingerprints: callWithFILEp.bind( null, "otrl_privkey_read_fingerprints", "rb", 1 ), otrl_privkey_read_fingerprints_FILEp: libotr.declare( "otrl_privkey_read_fingerprints_FILEp", abi, gcry_error_t, OtrlUserState, FILE.ptr, ctypes.void_t.ptr, ctypes.void_t.ptr ), // Write the fingerprint store from a given OtrlUserState to a file on disk. otrl_privkey_write_fingerprints: callWithFILEp.bind( null, "otrl_privkey_write_fingerprints", "wb", 1 ), otrl_privkey_write_fingerprints_FILEp: libotr.declare( "otrl_privkey_write_fingerprints_FILEp", abi, gcry_error_t, OtrlUserState, FILE.ptr ), // The length of a string representing a human-readable version of a // fingerprint (including the trailing NUL). OTRL_PRIVKEY_FPRINT_HUMAN_LEN, // Human readable fingerprint type fingerprint_t, // fingerprint value hash_t, // Calculate a human-readable hash of our DSA public key. Return it in the // passed fingerprint buffer. Return NULL on error, or a pointer to the given // buffer on success. otrl_privkey_fingerprint: libotr.declare( "otrl_privkey_fingerprint", abi, ctypes.char.ptr, OtrlUserState, fingerprint_t, ctypes.char.ptr, ctypes.char.ptr ), // Convert a 20-byte hash value to a 45-byte human-readable value. otrl_privkey_hash_to_human: libotr.declare( "otrl_privkey_hash_to_human", abi, ctypes.void_t, fingerprint_t, hash_t ), // Calculate a raw hash of our DSA public key. Return it in the passed // fingerprint buffer. Return NULL on error, or a pointer to the given // buffer on success. otrl_privkey_fingerprint_raw: libotr.declare( "otrl_privkey_fingerprint_raw", abi, ctypes.unsigned_char.ptr, OtrlUserState, hash_t, ctypes.char.ptr, ctypes.char.ptr ), // uiOps callbacks policy_cb_t, create_privkey_cb_t, is_logged_in_cb_t, inject_message_cb_t, update_context_list_cb_t, new_fingerprint_cb_t, write_fingerprint_cb_t, gone_secure_cb_t, gone_insecure_cb_t, still_secure_cb_t, max_message_size_cb_t, account_name_cb_t, account_name_free_cb_t, received_symkey_cb_t, otr_error_message_cb_t, otr_error_message_free_cb_t, resent_msg_prefix_cb_t, resent_msg_prefix_free_cb_t, handle_smp_event_cb_t, handle_msg_event_cb_t, create_instag_cb_t, convert_msg_cb_t, convert_free_cb_t, timer_control_cb_t, // message.h OtrlMessageAppOps, errorCode: { OTRL_ERRCODE_NONE: 0, OTRL_ERRCODE_ENCRYPTION_ERROR: 1, OTRL_ERRCODE_MSG_NOT_IN_PRIVATE: 2, OTRL_ERRCODE_MSG_UNREADABLE: 3, OTRL_ERRCODE_MSG_MALFORMED: 4, }, smpEvent: { OTRL_SMPEVENT_NONE: 0, OTRL_SMPEVENT_ERROR: 1, OTRL_SMPEVENT_ABORT: 2, OTRL_SMPEVENT_CHEATED: 3, OTRL_SMPEVENT_ASK_FOR_ANSWER: 4, OTRL_SMPEVENT_ASK_FOR_SECRET: 5, OTRL_SMPEVENT_IN_PROGRESS: 6, OTRL_SMPEVENT_SUCCESS: 7, OTRL_SMPEVENT_FAILURE: 8, }, messageEvent: { OTRL_MSGEVENT_NONE: 0, OTRL_MSGEVENT_ENCRYPTION_REQUIRED: 1, OTRL_MSGEVENT_ENCRYPTION_ERROR: 2, OTRL_MSGEVENT_CONNECTION_ENDED: 3, OTRL_MSGEVENT_SETUP_ERROR: 4, OTRL_MSGEVENT_MSG_REFLECTED: 5, OTRL_MSGEVENT_MSG_RESENT: 6, OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE: 7, OTRL_MSGEVENT_RCVDMSG_UNREADABLE: 8, OTRL_MSGEVENT_RCVDMSG_MALFORMED: 9, OTRL_MSGEVENT_LOG_HEARTBEAT_RCVD: 10, OTRL_MSGEVENT_LOG_HEARTBEAT_SENT: 11, OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR: 12, OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED: 13, OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED: 14, OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE: 15, }, convertType: { OTRL_CONVERT_SENDING: 0, OTRL_CONVERT_RECEIVING: 1, }, // Deallocate a message allocated by other otrl_message_* routines. otrl_message_free: libotr.declare( "otrl_message_free", abi, ctypes.void_t, ctypes.char.ptr ), // Handle a message about to be sent to the network. otrl_message_sending: libotr.declare( "otrl_message_sending", abi, gcry_error_t, OtrlUserState, OtrlMessageAppOps.ptr, ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, otrl_instag_t, ctypes.char.ptr, OtrlTLV.ptr, ctypes.char.ptr.ptr, OtrlFragmentPolicy, ConnContext.ptr.ptr, ctypes.void_t.ptr, ctypes.void_t.ptr ), // Handle a message just received from the network. otrl_message_receiving: libotr.declare( "otrl_message_receiving", abi, ctypes.int, OtrlUserState, OtrlMessageAppOps.ptr, ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr.ptr, OtrlTLV.ptr.ptr, ConnContext.ptr.ptr, ctypes.void_t.ptr, ctypes.void_t.ptr ), // Put a connection into the PLAINTEXT state, first sending the // other side a notice that we're doing so if we're currently ENCRYPTED, // and we think he's logged in. Affects only the specified instance. otrl_message_disconnect: libotr.declare( "otrl_message_disconnect", abi, ctypes.void_t, OtrlUserState, OtrlMessageAppOps.ptr, ctypes.void_t.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.char.ptr, otrl_instag_t ), // Call this function every so often, to clean up stale private state that // may otherwise stick around in memory. otrl_message_poll: libotr.declare( "otrl_message_poll", abi, ctypes.void_t, OtrlUserState, OtrlMessageAppOps.ptr, ctypes.void_t.ptr ), // Initiate the Socialist Millionaires' Protocol. otrl_message_initiate_smp: libotr.declare( "otrl_message_initiate_smp", abi, ctypes.void_t, OtrlUserState, OtrlMessageAppOps.ptr, ctypes.void_t.ptr, ConnContext.ptr, ctypes.char.ptr, ctypes.size_t ), // Initiate the Socialist Millionaires' Protocol and send a prompt // question to the buddy. otrl_message_initiate_smp_q: libotr.declare( "otrl_message_initiate_smp_q", abi, ctypes.void_t, OtrlUserState, OtrlMessageAppOps.ptr, ctypes.void_t.ptr, ConnContext.ptr, ctypes.char.ptr, ctypes.char.ptr, ctypes.size_t ), // Respond to a buddy initiating the Socialist Millionaires' Protocol. otrl_message_respond_smp: libotr.declare( "otrl_message_respond_smp", abi, ctypes.void_t, OtrlUserState, OtrlMessageAppOps.ptr, ctypes.void_t.ptr, ConnContext.ptr, ctypes.char.ptr, ctypes.size_t ), // Abort the SMP. Called when an unexpected SMP message breaks the // normal flow. otrl_message_abort_smp: libotr.declare( "otrl_message_abort_smp", abi, ctypes.void_t, OtrlUserState, OtrlMessageAppOps.ptr, ctypes.void_t.ptr, ConnContext.ptr ), // tlv.h tlvs: { OTRL_TLV_PADDING: new ctypes.unsigned_short(0x0000), OTRL_TLV_DISCONNECTED: new ctypes.unsigned_short(0x0001), OTRL_TLV_SMP1: new ctypes.unsigned_short(0x0002), OTRL_TLV_SMP2: new ctypes.unsigned_short(0x0003), OTRL_TLV_SMP3: new ctypes.unsigned_short(0x0004), OTRL_TLV_SMP4: new ctypes.unsigned_short(0x0005), OTRL_TLV_SMP_ABORT: new ctypes.unsigned_short(0x0006), OTRL_TLV_SMP1Q: new ctypes.unsigned_short(0x0007), OTRL_TLV_SYMKEY: new ctypes.unsigned_short(0x0008), }, OtrlTLV, // Return the first TLV with the given type in the chain, or NULL if one // isn't found. otrl_tlv_find: libotr.declare( "otrl_tlv_find", abi, OtrlTLV.ptr, OtrlTLV.ptr, ctypes.unsigned_short ), // Deallocate a chain of TLVs. otrl_tlv_free: libotr.declare( "otrl_tlv_free", abi, ctypes.void_t, OtrlTLV.ptr ), }; } // exports