ssb-invite
Advanced tools
Comparing version 2.1.5 to 2.1.6
@@ -31,3 +31,3 @@ module.exports = { | ||
invite: { | ||
type:'InviteCode', | ||
type: 'InviteCode', | ||
description: 'the invite code to accept' | ||
@@ -39,2 +39,1 @@ } | ||
} | ||
201
index.js
@@ -10,3 +10,2 @@ 'use strict' | ||
var level = require('level') | ||
var sublevel = require('level-sublevel/bytewise') | ||
var path = require('path') | ||
@@ -21,11 +20,11 @@ | ||
function isFunction (f) { | ||
return 'function' === typeof f | ||
return typeof f === 'function' | ||
} | ||
function isObject(o) { | ||
return o && 'object' === typeof o | ||
function isObject (o) { | ||
return o && typeof o === 'object' | ||
} | ||
function isNumber(n) { | ||
return 'number' === typeof n && !isNaN(n) | ||
function isNumber (n) { | ||
return typeof n === 'number' && !isNaN(n) | ||
} | ||
@@ -38,22 +37,16 @@ | ||
permissions: { | ||
master: {allow: ['create']}, | ||
//temp: {allow: ['use']} | ||
master: { allow: ['create'] } | ||
// temp: {allow: ['use']} | ||
}, | ||
init: function (server, config) { | ||
let codesDB | ||
if(server.sublevel) | ||
codesDB = server.sublevel('codes') | ||
else { | ||
var db = sublevel(level(path.join(config.path, 'db'), { | ||
valueEncoding: 'json' | ||
})) | ||
codesDB = db.sublevel('codes') | ||
} | ||
//add an auth hook. | ||
server.auth.hook(function (fn, args) { | ||
var pubkey = args[0], cb = args[1] | ||
const codesDB = level(path.join(config.path, 'invites'), { | ||
valueEncoding: 'json' | ||
}) | ||
// add an auth hook. | ||
server.auth.hook((fn, args) => { | ||
var pubkey = args[0]; var cb = args[1] | ||
// run normal authentication | ||
fn(pubkey, function (err, auth) { | ||
if(err || auth) return cb(err, auth) | ||
if (err || auth) return cb(err, auth) | ||
@@ -63,4 +56,4 @@ // if no rights were already defined for this pubkey | ||
codesDB.get(pubkey, function (_, code) { | ||
//disallow if this invite has already been used. | ||
if(code && (code.used >= code.total)) cb() | ||
// disallow if this invite has already been used. | ||
if (code && (code.used >= code.total)) cb() | ||
else cb(null, code && code.permissions) | ||
@@ -81,36 +74,38 @@ }) | ||
opts = opts || {} | ||
if(isNumber(opts)) | ||
opts = {uses: opts} | ||
else if(isObject(opts)) { | ||
if(opts.modern) | ||
opts.uses = 1 | ||
if (isNumber(opts)) { | ||
opts = { uses: opts } | ||
} else if (isObject(opts) && opts.modern) { | ||
opts.uses = 1 | ||
} else if (isFunction(opts)) { | ||
cb = opts | ||
opts = {} | ||
} | ||
else if(isFunction(opts)) | ||
cb = opts, opts = {} | ||
var addr = getInviteAddress() | ||
if(!addr) return cb(new Error( | ||
'no address available for creating an invite,'+ | ||
'configuration needed for server.\n'+ | ||
if (!addr) { | ||
return cb(new Error( | ||
'no address available for creating an invite,' + | ||
'configuration needed for server.\n' + | ||
'see: https://github.com/ssbc/ssb-config/#connections' | ||
)) | ||
)) | ||
} | ||
addr = addr.split(';').shift() | ||
var host = ref.parseAddress(addr).host | ||
if(typeof host !== 'string') { | ||
if (typeof host !== 'string') { | ||
return cb(new Error('Could not parse host portion from server address:' + addr)) | ||
} | ||
if (opts.external) | ||
host = opts.external | ||
if (opts.external) { host = opts.external } | ||
if(!config.allowPrivate && (ip.isPrivate(host) || 'localhost' === host || host === '')) | ||
if (!config.allowPrivate && (ip.isPrivate(host) || host === 'localhost' || host === '')) { | ||
return cb(new Error( | ||
'Server has no public ip address, cannot create useable invitation') | ||
) | ||
} | ||
//this stuff is SECURITY CRITICAL | ||
//so it should be moved into the main app. | ||
//there should be something that restricts what | ||
//permissions the plugin can create also: | ||
//it should be able to diminish it's own permissions. | ||
// this stuff is SECURITY CRITICAL | ||
// so it should be moved into the main app. | ||
// there should be something that restricts what | ||
// permissions the plugin can create also: | ||
// it should be able to diminish it's own permissions. | ||
@@ -122,3 +117,3 @@ // generate a key-seed and its key | ||
// store metadata under the generated pubkey | ||
codesDB.put(keyCap.id, { | ||
codesDB.put(keyCap.id, { | ||
id: keyCap.id, | ||
@@ -128,16 +123,14 @@ total: +opts.uses || 1, | ||
used: 0, | ||
permissions: {allow: ['invite.use', 'getAddress'], deny: null} | ||
permissions: { allow: ['invite.use', 'getAddress'], deny: null } | ||
}, function (err) { | ||
// emit the invite code: our server address, plus the key-seed | ||
if(err) cb(err) | ||
else if(opts.modern) { | ||
var ws_addr = getInviteAddress().split(';').sort(function (a, b) { | ||
if (err) cb(err) | ||
else if (opts.modern) { | ||
var wsAddr = getInviteAddress().split(';').sort(function (a, b) { | ||
return +/^ws/.test(b) - +/^ws/.test(a) | ||
}).shift() | ||
if(!/^ws/.test(ws_addr)) throw new Error('not a ws address:'+ws_addr) | ||
cb(null, ws_addr+':'+seed.toString('base64')) | ||
} | ||
else { | ||
if (!/^ws/.test(wsAddr)) throw new Error('not a ws address:' + wsAddr) | ||
cb(null, wsAddr + ':' + seed.toString('base64')) | ||
} else { | ||
addr = ref.parseAddress(addr) | ||
@@ -152,35 +145,34 @@ cb(null, [opts.external ? opts.external : addr.host, addr.port, addr.key].join(':') + '~' + seed.toString('base64')) | ||
// fetch the code | ||
codesDB.get(rpc.id, function(err, invite) { | ||
if(err) return cb(err) | ||
codesDB.get(rpc.id, function (err, invite) { | ||
if (err) return cb(err) | ||
// check if we're already following them | ||
server.friends.get(function (err, follows) { | ||
server.friends.get((err, follows) => { | ||
if (err) return cb(err) | ||
// server.friends.all('follow', function(err, follows) { | ||
// if(hops[req.feed] == 1) | ||
if (follows && follows[server.id] && follows[server.id][req.feed]) | ||
return cb(new Error('already following')) | ||
if (follows && follows[server.id] && follows[server.id][req.feed]) { return cb(new Error('already following')) } | ||
// although we already know the current feed | ||
// it's included so that request cannot be replayed. | ||
if(!req.feed) | ||
return cb(new Error('feed to follow is missing')) | ||
if (!req.feed) { return cb(new Error('feed to follow is missing')) } | ||
if(invite.used >= invite.total) | ||
return cb(new Error('invite has expired')) | ||
if (invite.used >= invite.total) { return cb(new Error('invite has expired')) } | ||
invite.used ++ | ||
invite.used++ | ||
//never allow this to be used again | ||
if(invite.used >= invite.total) { | ||
invite.permissions = {allow: [], deny: null} | ||
// never allow this to be used again | ||
if (invite.used >= invite.total) { | ||
invite.permissions = { allow: [], deny: null } | ||
} | ||
//TODO | ||
//okay so there is a small race condition here | ||
//if people use a code massively in parallel | ||
//then it may not be counted correctly... | ||
//this is not a big enough deal to fix though. | ||
//-dominic | ||
// TODO | ||
// okay so there is a small race condition here | ||
// if people use a code massively in parallel | ||
// then it may not be counted correctly... | ||
// this is not a big enough deal to fix though. | ||
// -dominic | ||
// update code metadata | ||
codesDB.put(rpc.id, invite, function (err) { | ||
codesDB.put(rpc.id, invite, (err) => { | ||
if (err) return cb(err) | ||
server.emit('log:info', ['invite', rpc.id, 'use', req]) | ||
@@ -200,31 +192,32 @@ | ||
}, 'object'), | ||
accept: valid.async(function (invite, cb) { | ||
accept: valid.async((invite, cb) => { | ||
// remove surrounding quotes, if found | ||
if(isObject(invite)) | ||
invite = invite.invite | ||
if (isObject(invite)) { invite = invite.invite } | ||
if (invite.charAt(0) === '"' && invite.charAt(invite.length - 1) === '"') | ||
invite = invite.slice(1, -1) | ||
if (invite.charAt(0) === '"' && invite.charAt(invite.length - 1) === '"') { invite = invite.slice(1, -1) } | ||
var opts | ||
// connect to the address in the invite code | ||
// using a keypair generated from the key-seed in the invite code | ||
if(ref.isInvite(invite)) { //legacy ivite | ||
if(ref.isLegacyInvite(invite)) { | ||
if (ref.isInvite(invite)) { // legacy invite | ||
if (ref.isLegacyInvite(invite)) { | ||
var parts = invite.split('~') | ||
opts = ref.parseAddress(parts[0])//.split(':') | ||
//convert legacy code to multiserver invite code. | ||
opts = ref.parseAddress(parts[0])// .split(':') | ||
// convert legacy code to multiserver invite code. | ||
var protocol = 'net:' | ||
if (opts.host.endsWith(".onion")) | ||
protocol = 'onion:' | ||
invite = protocol+opts.host+':'+opts.port+'~shs:'+opts.key.slice(1, -8)+':'+parts[1] | ||
if (opts.host.endsWith('.onion')) { protocol = 'onion:' } | ||
invite = protocol + opts.host + ':' + opts.port + '~shs:' + opts.key.slice(1, -8) + ':' + parts[1] | ||
} | ||
} | ||
opts = ref.parseAddress(ref.parseInvite(invite).remote) | ||
const parsedInvite = ref.parseInvite(invite) | ||
if (!parsedInvite || !parsedInvite.remote) { | ||
return cb(new Error(`ssb-invite failed to parse invite ${invite}`)) | ||
} | ||
opts = ref.parseAddress(parsedInvite.remote) | ||
function connect (cb) { | ||
createClient({ | ||
keys: true, //use seed from invite instead. | ||
keys: true, // use seed from invite instead. | ||
remote: invite, | ||
config: config, | ||
manifest: {invite: {use: 'async'}, getAddress: 'async'} | ||
manifest: { invite: { use: 'async' }, getAddress: 'async' } | ||
}, cb) | ||
@@ -244,4 +237,4 @@ } | ||
n++ | ||
if(n >= 3) cb(err, value) | ||
else if(err) setTimeout(next, 500 + (Date.now()-start)*n) | ||
if (n >= 3) cb(err, value) | ||
else if (err) setTimeout(next, 500 + (Date.now() - start) * n) | ||
else cb(null, value) | ||
@@ -252,9 +245,8 @@ }) | ||
retry(connect, function (err, rpc) { | ||
retry(connect, (err, rpc) => { | ||
if (err) return cb(explain(err, 'could not connect to server')) | ||
if(err) return cb(explain(err, 'could not connect to server')) | ||
// command the peer to follow me | ||
rpc.invite.use({ feed: server.id }, function (err, msg) { | ||
if(err) return cb(explain(err, 'invite not accepted')) | ||
rpc.invite.use({ feed: server.id }, (err, msg) => { | ||
if (err) return cb(explain(err, 'invite not accepted')) | ||
@@ -271,14 +263,14 @@ // follow and announce the pub | ||
opts.host | ||
? cont(server.publish)({ | ||
type: 'pub', | ||
address: opts | ||
}) | ||
: function (cb) { cb() } | ||
? cont(server.publish)({ | ||
type: 'pub', | ||
address: opts | ||
}) | ||
: (cb) => cb() | ||
) | ||
])(function (err, results) { | ||
if(err) return cb(err) | ||
])((err, results) => { | ||
if (err) return cb(err) | ||
rpc.close() | ||
rpc.close() | ||
//ignore err if this is new style invite | ||
if(server.gossip) server.gossip.add(ref.parseInvite(invite).remote, 'seed') | ||
// ignore err if this is new style invite | ||
if (server.gossip) server.gossip.add(ref.parseInvite(invite).remote, 'seed') | ||
cb(null, results) | ||
@@ -292,2 +284,1 @@ }) | ||
} | ||
{ | ||
"name": "ssb-invite", | ||
"description": "", | ||
"version": "2.1.5", | ||
"version": "2.1.6", | ||
"homepage": "https://github.com/ssbc/ssb-invite", | ||
@@ -10,2 +10,7 @@ "repository": { | ||
}, | ||
"scripts": { | ||
"test": "npm run test:js && npm run lint", | ||
"test:js": "tape test/*.test.js", | ||
"lint": "standard --fix" | ||
}, | ||
"dependencies": { | ||
@@ -16,21 +21,18 @@ "cont": "^1.0.3", | ||
"level": "^6.0.1", | ||
"level-sublevel": "^6.6.5", | ||
"muxrpc-validation": "^3.0.0", | ||
"ssb-client": "^4.7.4", | ||
"ssb-keys": "^7.1.3", | ||
"ssb-ref": "^2.13.9" | ||
"muxrpc-validation": "^3.0.2", | ||
"ssb-client": "^4.9.0", | ||
"ssb-keys": "^7.2.2", | ||
"ssb-ref": "^2.14.0" | ||
}, | ||
"devDependencies": { | ||
"pull-stream": "^3.6.11", | ||
"ssb-friends": "^4.1.0", | ||
"ssb-replicate": "^1.0.1", | ||
"ssb-server": "^14.1.0", | ||
"ssb-ws": "^6.2.0", | ||
"tape": "^4.9.2" | ||
"pull-stream": "^3.6.14", | ||
"scuttle-testbot": "^1.2.3", | ||
"ssb-friends": "^4.1.4", | ||
"ssb-replicate": "^1.3.2", | ||
"ssb-ws": "^6.2.3", | ||
"standard": "^14.3.4", | ||
"tape": "^4.13.2" | ||
}, | ||
"scripts": { | ||
"test": "set -e; for t in test/*.js; do node $t; done" | ||
}, | ||
"author": "Dominic Tarr <dominic.tarr@gmail.com> (http://dominictarr.com)", | ||
"license": "MIT" | ||
} |
@@ -26,3 +26,4 @@ # ssb-invite | ||
- `modern` (boolean): if true the invite code will be a valid multiserver address. | ||
if modern is enabled, uses will be set to 1. | ||
- if modern is enabled, uses will be set to 1. | ||
- :warning: "modern" invites with ipv6 addresses currently have some problems | ||
@@ -29,0 +30,0 @@ This produces an invite-code which encodes the ssb-server instance's public address, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
25798
8
11
61
7
582
- Removedlevel-sublevel@^6.6.5
- Removedabstract-leveldown@0.12.4(transitive)
- Removedbl@0.8.2(transitive)
- Removedbytewise@1.1.0(transitive)
- Removedbytewise-core@1.2.3(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removeddeferred-leveldown@0.2.0(transitive)
- Removedisarray@0.0.1(transitive)
- Removedlevel-post@1.0.7(transitive)
- Removedlevel-sublevel@6.6.5(transitive)
- Removedlevelup@0.19.1(transitive)
- Removedlooper@2.0.0(transitive)
- Removedltgt@2.1.3(transitive)
- Removedprr@0.0.0(transitive)
- Removedpull-defer@0.2.3(transitive)
- Removedpull-level@2.0.4(transitive)
- Removedpull-live@1.0.1(transitive)
- Removedpull-window@2.1.4(transitive)
- Removedreadable-stream@1.0.34(transitive)
- Removedsemver@5.1.1(transitive)
- Removedstring_decoder@0.10.31(transitive)
- Removedtypewise@1.0.3(transitive)
- Removedtypewise-core@1.2.0(transitive)
- Removedtypewiselite@1.0.0(transitive)
- Removedxtend@3.0.0(transitive)
Updatedmuxrpc-validation@^3.0.2
Updatedssb-client@^4.9.0
Updatedssb-keys@^7.2.2
Updatedssb-ref@^2.14.0