{"id":13624681,"url":"https://github.com/arlolra/otr","last_synced_at":"2025-04-04T10:10:02.441Z","repository":{"id":3865302,"uuid":"4950746","full_name":"arlolra/otr","owner":"arlolra","description":"Off-the-Record Messaging Protocol implemented in JavaScript","archived":false,"fork":false,"pushed_at":"2020-12-01T12:28:33.000Z","size":1108,"stargazers_count":457,"open_issues_count":10,"forks_count":61,"subscribers_count":25,"default_branch":"master","last_synced_at":"2024-10-29T19:41:46.393Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://arlolra.github.io/otr/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arlolra.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.md","contributing":"contributing.md","funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-07-08T22:59:50.000Z","updated_at":"2024-10-25T09:23:27.000Z","dependencies_parsed_at":"2022-08-31T04:22:58.381Z","dependency_job_id":null,"html_url":"https://github.com/arlolra/otr","commit_stats":null,"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arlolra%2Fotr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arlolra%2Fotr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arlolra%2Fotr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arlolra%2Fotr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arlolra","download_url":"https://codeload.github.com/arlolra/otr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247157283,"owners_count":20893220,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T21:01:45.144Z","updated_at":"2025-04-04T10:10:02.412Z","avatar_url":"https://github.com/arlolra.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/arlolra/otr.svg?branch=master)](https://travis-ci.org/arlolra/otr)\n\n[Off-the Record Messaging Protocol](http://www.cypherpunks.ca/otr/) in JavaScript\n==================================================\n\n### Warning\n\nThis library hasn't been properly vetted by security researchers. Do not use\nin life and death situations!\n\n### Install\n\nInclude the build files on the page,\n\n    \u003c!-- Load dependencies --\u003e\n    \u003cscript src=\"build/dep/bigint.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"build/dep/crypto.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"build/dep/eventemitter.js\"\u003e\u003c/script\u003e\n\n    \u003c!-- Load otr.js or otr.min.js --\u003e\n    \u003cscript src=\"build/otr.min.js\"\u003e\u003c/script\u003e\n\nHere's an [example](https://github.com/arlolra/otr/blob/master/test/browser.html) use in the browser.\n\nAlthough this is a client library, it can be used [on the server](https://github.com/arlolra/otr/blob/master/test/xmpp.js).\n\n    npm install otr\n\nAnd then,\n\n    var DSA = require('otr').DSA\n    var OTR = require('otr').OTR\n\n### Build\n\nThe contents of `build/` are the result of calling `make build` and are only\nupdated with releases. Please submit patches against `lib/` and `vendor/`.\n\n### Release\n\nThe normal flow for making a release is as follows,\n\n    make test\n    // bump the version numbers in package.json / bower.json\n    make build\n    git changelog  // cleanup the changelog\n    git commit -m \"bump version\"\n    git tag -a vX.X.X -m \"version X.X.X\"\n    git push origin master\n    git push --tags\n    npm publish\n    // update github releases and pages\n\n### Usage\n\n**Initial setup**: Compute your long-lived key beforehand. Currently this is\nexpensive and can take several seconds.\n\n    // precompute your DSA key\n    var myKey = new DSA()\n\nFor each user you're communicating with, instantiate an OTR object.\n\n    // provide options\n    var options = {\n        fragment_size: 140\n      , send_interval: 200\n      , priv: myKey\n    }\n\n    var buddy = new OTR(options)\n\n    buddy.on('ui', function (msg, encrypted, meta) {\n      console.log(\"message to display to the user: \" + msg)\n      // encrypted === true, if the received msg was encrypted\n      console.log(\"(optional) with receiveMsg attached meta data: \" + meta)\n    })\n\n    buddy.on('io', function (msg, meta) {\n      console.log(\"message to send to buddy: \" + msg)\n      console.log(\"(optional) with sendMsg attached meta data: \" + meta)\n    })\n\n    buddy.on('error', function (err, severity) {\n      if (severity === 'error')  // either 'error' or 'warn'\n        console.error(\"error occurred: \" + err)\n    })\n\n**New message from buddy received**: Pass the received message to the `receiveMsg`\nmethod.\n\n    var rcvmsg = \"Message from buddy.\"\n    var meta = \"optional some meta data, like delay\"\n    buddy.receiveMsg(rcvmsg, meta)\n\n**Send a message to buddy**: Pass the message to the `sendMsg` method.\n\n    var newmsg = \"Message to userA.\"\n    var meta = \"optional some meta data, like message id\"\n    buddy.sendMsg(newmsg, meta)\n\n**Going encrypted**: Initially, messages are sent in plaintext. To manually\ninitiate the authenticated key exchange.\n\n    buddy.sendQueryMsg()\n\nAlternatively, one can set the policy `REQUIRE_ENCRYPTION` and send a plaintext\nmessage. This will store the message, initiate the authentication and then,\nupon success, send it out.\n\n    buddy.REQUIRE_ENCRYPTION = true\n    buddy.sendMsg('My plaintext message to be encrypted.')\n\nAnother policy, `SEND_WHITESPACE_TAG`, will append tags to plaintext messages,\nindicating a willingness to speak OTR. If the recipient in turn has set the\npolicy `WHITESPACE_START_AKE`, the AKE will be initiated.\n\n**Close private connection**: To end an encrypted communication session,\n\n    buddy.endOtr(function() {\n      // calls back when the 'disconnect' message has been sent\n    })\n\nwill return the message state to plaintext and notify the correspondent.\n\n**Options**: A dictionary of the current options accepted by the OTR constructor.\n\n    var options = {\n\n      // long-lived private key\n      priv: new DSA(),\n\n      // turn on some debuggin logs\n      debug: false,\n\n      // fragment the message in case of char limits\n      fragment_size: 140,\n\n      // ms delay between sending fragmented msgs, avoid rate limits\n      send_interval: 200\n\n    }\n\n### Status\n\nA listener can be attached for status changes. These are non-standard codes,\nspecific to this OTR library, indicating various things like the AKE success.\n\n    buddy.on('status', function (state) {\n      switch (state) {\n        case OTR.CONST.STATUS_AKE_SUCCESS:\n          // sucessfully ake'd with buddy\n          // check if buddy.msgstate === OTR.CONST.MSGSTATE_ENCRYPTED\n          break\n        case OTR.CONST.STATUS_END_OTR:\n          // if buddy.msgstate === OTR.CONST.MSGSTATE_FINISHED\n          // inform the user that his correspondent has closed his end\n          // of the private connection and the user should do the same\n          break\n      }\n    })\n\n### Policies\n\nTo be set on a per-correspondent basis. The defaults are as follows:\n\n    // Allow version 2 or 3 of the OTR protocol to be used.\n    ALLOW_V2 = true\n    ALLOW_V3 = true\n\n    // Refuse to send unencrypted messages.\n    REQUIRE_ENCRYPTION = false\n\n    // Advertise your support of OTR using the whitespace tag.\n    SEND_WHITESPACE_TAG = false\n\n    // Start the OTR AKE when you receive a whitespace tag.\n    WHITESPACE_START_AKE = false\n\n    // Start the OTR AKE when you receive an OTR Error Message.\n    ERROR_START_AKE = false\n\n### Instance Tags\n\nThese are intended to be persistent and can be precomputed.\n\n    var myTag = OTR.makeInstanceTag()\n    var options = { instance_tag: myTag }\n\n    var buddy = new OTR(options)\n\n### Fingerprints\n\nOTR public key fingerprints can be obtained as follows:\n\n    // assume you've gone through the ake with buddy\n    var buddy = new OTR({ priv: myKey })\n    // buddy.msgstate === OTR.CONST.MSGSTATE_ENCRYPTED\n\n    // for my key, either one of the following\n    myKey.fingerprint()\n    // or,\n    buddy.priv.fingerprint()\n\n    // for their key\n    buddy.their_priv_pk.fingerprint()\n\n### Socialist Millionaire Protocol\n\nAt any time after establishing encryption, either party can initiate SMP to\ndetect impersonation or man-in-the-middle attacks. A shared secret,\nexchanged through an out-of-band channel prior to starting the conversation,\nis required.\n\n    var secret = \"ghostbusters\"\n    buddy.smpSecret(secret)\n\nA question can be supplied, as a reminder of the shared secret.\n\n    var question = \"who are you going to call?\"\n    buddy.smpSecret(secret, question)\n\nIf you plan on using SMP, as opposed to just allowing fingerprints for\nverification, provide on optional callback when initiating OTR,\notherwise a no-opt is fired.\n\n    var buddy = new OTR()\n\n    buddy.on('smp', function (type, data, act) {\n      switch (type) {\n        case 'question':\n          // call(data) some function with question?\n          // return the user supplied data to\n          // userA.smpSecret(secret)\n          break\n        case 'trust':\n          // smp completed\n          // check data (true|false) and update ui accordingly\n          // act (\"asked\"|\"answered\") provides info one who initiated the smp\n          break\n        case 'abort':\n          // smp was aborted. notify the user or update ui\n        default:\n          throw new Error('Unknown type.')\n      }\n    })\n\nBoth users should run the SMP to establish trust. Further, it should be run each time a partner presents a fresh long-lived key.\n\n### Private Keys\n\nTo export a private, long-lived key:\n\n    var myKey = new DSA()\n    var string = myKey.packPrivate()  // returns a Base64 encoded string\n\nIt can then be imported as follows,\n\n    string = \"AAAAAACA4COdKHpU/np9F8EDdnGiJJmc89p ... I9BzTkQduFA7ovXAMY=\"\n    myKey = DSA.parsePrivate(string)\n\nImporting the (somewhat) standard libotr s-expression format works as well,\n\n    // in node.js\n    var fs = require('fs')\n    string = fs.readFileSync(\"~/.purple/otr.private_key\", 'utf8')\n\n    // leaving out the terminal backslashes needed for multiline strings in js\n    string = \"(privkeys\n      (account\n        (name \"foo@example.com\")\n        (protocol prpl-jabber)\n        (private-key\n          (dsa\n            (p #00FC07 ... 2AEFD07A2081#)\n            (q #ASD5FF ... LKJDF898DK12#)\n            (g #535E3E ... 1E3BC1FC6F26#)\n            (y #0AC867 ... 8969009B6ECF#)\n            (x #14D034 ... F72D79043216#)\n          )\n        )\n      )\n    )\"\n\n    myKey = DSA.parsePrivate(string, true)\n\n### Extra Symmetric Key\n\nIn version 3 of the protocol, an extra symmetric key is derived during the AKE. This may be used for secure communication over a different channel (e.g., file transfer, voice chat).\n\n    var filename = \"test.zip\"\n    var buddy = new OTR()\n    buddy.sendFile(filename)\n    buddy.on('file', function (type, key, filename) {\n      // type === 'send'\n      // key should be used to encrypt filename\n      // and sent through a different channel\n    })\n\nOn the other end,\n\n    var friend = new OTR()\n    friend.on('file', function (type, key, filename) {\n      // type === 'receive'\n      // decrypt filename with key, once received\n    })\n\n### WebWorkers\n\nSome support exists for calling computationally expensive work off the main\nthread. However, some feedback on these APIs would be appreciated.\n\n    // generate a DSA key in a web worker\n    DSA.createInWebWorker(null, function (key) {\n\t\t\tvar buddy = new OTR({\n\t\t\t\tpriv: key,\n\t\t\t\t// setting `smw` to a truthy value will perform the socialist\n\t\t\t\t// millionaire protocol in a webworker.\n\t\t\t\tsmw: {}\n\t\t\t})\n\t  })\n\nWebWorkers don't have access to `window.crypto.getRandomValues()`, so they will\nneed to include Salsa20.\n\n    \u003cscript src=\"build/dep/salsa20.js\"\u003e\u003c/script\u003e\n\n### Links\n\nSpec:\n\n- http://www.cypherpunks.ca/otr/Protocol-v3-4.0.0.html\n- http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html\n- See: `specs/`\n\nUsing:\n\n- [crypto-js](http://code.google.com/p/crypto-js/)\n- [bigint.js](http://leemon.com/crypto/BigInt.html)\n- [salsa20.js](https://gist.github.com/dchest/4582374)\n- [eventemitter.js](https://github.com/Wolfy87/EventEmitter)\n\n### In The Wild\n\nA sampling of projects that use this library:\n\n- [Cryptocat](https://github.com/cryptocat/cryptocat)\n- [Yabasta](https://github.com/jonkri/yabasta)\n- [Diaspora](https://github.com/sualko/diaspora)\n- [Converse.js](https://github.com/jcbrand/converse.js)\n- [WebRTCCopy](https://github.com/erbbysam/webRTCCopy)\n- [OTRon](https://github.com/osnr/otron)\n- [ojsxc (owncloud)](https://github.com/sualko/ojsxc)\n- [sjsxc (SOGo)](https://github.com/sualko/sjsxc)\n- [LoquiIM](https://loqui.im/)\n- [Salut à Toi](http://salut-a-toi.org/) ([Python wrapper][0] for Pyjamas)\n- [HackTunnel](https://github.com/devhq-io/hacktunnel)\n\n[0]: http://repos.goffi.org/libervia/file/tip/src/browser/sat_browser/otrjs_wrapper.py\n\n### Donate\n\nBitcoins: 1BWLnnig89fpn8hCcASd2B1YbfK6j1vtX3\n\n### License\n\nMPL v2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farlolra%2Fotr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farlolra%2Fotr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farlolra%2Fotr/lists"}