@inkandswitch/backchannel
    TypeScript icon, indicating that this package has built-in type declarations

    1.0.1 • Public • Published

    Backchannel

    THIS IS A PROOF OF CONCEPT PROTOTYPE. IT HAS NOT HAD ANY KIND OF SECURITY OR CRYPTOGRAPHY REVIEW. THIS SOFTWARE MIGHT BE UNSAFE.

    Netlify Status CI

    Identities in Backchannel are created by redeeming a one-time invitation code. The code, much like the role of a phone number, is a lookup method to connect two people. Unlike a phone number, the code is temporary, and immediately discarded after use. The expiration of invitation codes gives certain advantages. There is no equivalent of “giving someone your permanent address or number” with this design. Although perhaps inconvenient for some use cases, this property can also be a strength. This design is inherently resistant to anonymous spam.

    Once a user passes this code to another, both of their applications generate a strong shared cryptographic secret using SPAKE2, a PAKE protocol. This shared secret represents the relationships between those two users, and is used to generate a secure end-to-end encrypted connection.

    Users then assign a name for each other, rather than naming themselves. Names in Backchannel are private – i.e., they are only seen by the person who created them, just like in a phone’s contact list. Naming contacts privately is important. Because there is no self-described user profile system, a user cannot be impersonated by someone else within the application.

    Read more about Backchannel in our paper, at https://www.inkandswitch.com/backchannel/

    Application prototype examples

    Usage

    This library is intended for use in a browser-like environment (progressive web app and electron would work too) as a websocket client.

    npm install @inkandswitch/backchannel
    

    Basics

    Get a list of contacts

    import Backchannel, { EVENTS } from '@inkandswitch/backchannel';
    
    const DBNAME = 'myapp'
    const SETTINGS = {
      relay: 'ws://localhost:3001'
    }
    let backchannel = new Backchannel(DBNAME, SETTINGS)
    backchannel.once(EVENTS.OPEN, () => {
      let contacts = backchannel.listContacts()
    })

    Two users decide upon a single number that is at least 6 characters long OR generate a one-time invitation code for them:

    let random = crypto.randomBytes(3)
    let code = parseInt(Buffer.from(random).toString('hex'), 16)

    Once both users have entered in a code, split the code into 'mailbox' and 'password' pieces. The password should be kept secret! The mailbox is public to the relay and so should not be derivative or in any way related to the password.

    let mailbox = code.slice(0, 3)
    let password = code.slice(3)
    let key = await backchannel.accept(mailbox, password)

    Add a contact and assign them a name and avatar

    let id = await backchannel.addContact(key)
    await backchannel.editName(id, 'jennie')
    await backchannel.editAvatar(id, [avatarbytes])

    Send an end to end encrypted message

    let message = await backchannel.sendMessage(id, 'hi jennie')

    Link a device, this works the same as adding a contact, but you call addDevice instead

    let key = await backchannel.accept(mailbox, password)
    let id = await backchannel.addDevice(key)

    Unlink all devices

    backchannel.on(EVENTS.ACK, ({ contactId }) => {
      console.log('Unlinked device with id=', contactId)
    })
    await backchannel.unlinkDevice()

    Running a Relay

    Backchannel depends upon @local-first/relay, which is a websocket relay. Clients need to connect to the same relay in order to find each other. You can run the relay either on the local machine or in the cloud. One way to do this in the cloud quickly is to remix it on Glitch.

    You can use the relay provided in this repository at bin/server.js:

    const { Server } = require('@localfirst/relay/dist')
    
    const DEFAULT_PORT = 3001 
    const port = Number(process.env.PORT) || DEFAULT_PORT
    
    const server = new Server({ port })
    
    server.listen()

    And run it with

    $ node bin/server.js

    Contributing

    Viewing the Documentation

    The docs can be auto-generated locally. The following command outputs the generated documentation into build/docs/api.

    npm run docs
    

    Then you can view the docs locally with an http-server, you can use something like the node http-server.

    npm i -g http-server
    http-server build/docs/api
    

    Or with npx:

    npx http-server build/docs/api
    

    You can then view the main documentation locally at http://localhost:port/classes/backend_backchannel.backchannel.html

    Testing

    Open two browser windows that are not in private browsing mode. They can be tabs in the same browser program. Opening a private window doesn't work with IndexedDB.

    Because we're using IndexedDB, to do local testing with the same browser on the same machine, you should open one of the tabs or windows at localhost:3000 and the other at 127.0.0.1:3000. This will ensure that they both have their own isolated database.

    To run automated tests,

    npm run relay
    

    and then

    npm test
    

    Deployment

    To deploy the minified production build, run

    npm run build

    To build the api documentation, run

    npm run docs

    Contributors

    • Karissa McKelvey, @okdistribute, Lead
    • Ben Royer, Design
    • Chris Sun, @daiyi, Frontend/UI

    Advisors

    • Cade Diehm
    • Peter van Hardenberg, @pvh
    • سلمان الجماز, @saljam
    • Herb Caudill, @herbcaudill
    • Martin Kleppman, @ept

    License

    MIT

    Keywords

    none

    Install

    npm i @inkandswitch/backchannel

    DownloadsWeekly Downloads

    6

    Version

    1.0.1

    License

    MIT

    Unpacked Size

    13.3 MB

    Total Files

    41

    Last publish

    Collaborators

    • karissa
    • pvh
    • jeffpeterson
    • mjtognetti
    • szymon_k