diff --git a/package.json b/package.json index 9c94a64..bbb4a02 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "memdb": "^1.3.1", "mkdirp": "^1.0.4", "monotonic-timestamp": "0.0.9", + "paperslip": "^3.0.0", "pump": "^3.0.0", "qrcode": "^1.4.4", "random-access-memory": "^3.1.1", diff --git a/src/client.js b/src/client.js index 30d2640..45c9f45 100644 --- a/src/client.js +++ b/src/client.js @@ -10,6 +10,7 @@ const path = require('path') const mkdirp = require('mkdirp') const os = require('os') const defaultCommands = require('./commands') +const paperslip = require("paperslip") class Client { /** @@ -104,17 +105,34 @@ class Client { /** * Resolve the DNS shortname `name`. If `name` is already a cabal key, it will * be returned and the DNS lookup is aborted. + * If `name` is a whisper:// key, a DHT lookup for the passed-in key will occur. + * Once a match is found, it is assumed to be a cabal key, which is returned. * Returns the cabal key in `cb`. If `cb` is null a Promise is returned. - * @param {string} name the DNS shortname - * @param {function(string)} [cb] The callback to be called when DNS lookup succeeds + * @param {string} name the DNS shortname, or whisper:// shortname + * @param {function(string)} [cb] The callback to be called when lookup succeeds */ resolveName (name, cb) { - return this.cabalDns.resolveName(name).then((key) => { - if (key === null) return null - key = Client.scrubKey(key) - if (!cb) return key - else cb(key) - }) + if (name.startsWith('whisper://') || + // whisperlink heuristic: ends with - + name.slice(-4).toLowerCase().match(/-[0-9a-f]{3}/)) { + return new Promise((resolve, reject) => { + let key = '' + const topic = name.startsWith('whisper://') ? name.slice(10) : name + const stream = paperslip.read(topic) + stream.on('data', (data) => { + if (data) { key += data.toString() } + }) + stream.on('end', () => { resolve(key) }) + stream.once('error', (err) => { reject(err) }) + }) + } else { + return this.cabalDns.resolveName(name).then((key) => { + if (key === null) return null + key = Client.scrubKey(key) + if (!cb) return key + else cb(key) + }) + } } /** diff --git a/src/commands.js b/src/commands.js index c9f1d7c..a6764d7 100644 --- a/src/commands.js +++ b/src/commands.js @@ -2,6 +2,7 @@ const qr = require('qrcode') const pump = require('pump') const to = require('to2') const strftime = require('strftime') +const paperslip = require("paperslip") module.exports = { add: { @@ -19,6 +20,23 @@ module.exports = { } } }, + whisper: { + help: () => 'create a whisper link, a shortlived shortname alias for this cabal\'s key', + call: (cabal, res, arg) => { + if (arg === '') { + return res.error("you need to provide a shortname, e.g. 'workshop'") + } + const topic = `${arg}-${cabal.key.slice(0,3)}` + const whisperlink = `whisper://${topic}` + res.info("whispering on " + whisperlink + " for the next 5 minutes") + // currently this will logout ip addresses that join via the whisper key + const swarm = paperslip.write(topic, `cabal://${cabal.key}`, res.info) + setTimeout(() => { + paperslip.stop(swarm) + res.info("stopped whispering " + topic) + }, 5 * 60 * 1000) + } + }, new: { help: () => 'create a new cabal', call: (cabal, res, arg) => {