mirror of https://codeberg.org/pzp/pzp-hub.git
members db and tokens db
This commit is contained in:
parent
a03950ac30
commit
80f2a3afb0
|
@ -2,4 +2,4 @@ node_modules
|
|||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
TODO
|
||||
keypair
|
||||
data
|
|
@ -0,0 +1,71 @@
|
|||
const Crypto = require('node:crypto')
|
||||
const Path = require('node:path')
|
||||
const AtomicFileRW = require('atomic-file-rw')
|
||||
const Base58 = require('bs58')
|
||||
|
||||
class Tokens {
|
||||
static #filePath
|
||||
|
||||
/**
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
static #set
|
||||
|
||||
static #loaded = false
|
||||
|
||||
static #save(cb) {
|
||||
const json = JSON.stringify([...this.#set])
|
||||
AtomicFileRW.writeFile(this.#filePath, json, cb)
|
||||
}
|
||||
|
||||
static load(parentPath) {
|
||||
if (this.#loaded) return
|
||||
this.#filePath = Path.join(parentPath, 'members.json')
|
||||
this.#set = new Set()
|
||||
|
||||
AtomicFileRW.readFile(this.#filePath, (err, buf) => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
this.#loaded = true
|
||||
} else {
|
||||
console.warn('Problem loading members file:', err)
|
||||
}
|
||||
return
|
||||
}
|
||||
const json = typeof buf === 'string' ? buf : buf.toString('utf-8')
|
||||
const arr = JSON.parse(json)
|
||||
for (const token of arr) {
|
||||
this.#set.add(token)
|
||||
}
|
||||
this.#loaded = true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} token
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static has(token) {
|
||||
if (!this.#loaded) {
|
||||
throw new Error('Members not loaded yet, cannot call has()')
|
||||
}
|
||||
return this.#set.has(token)
|
||||
}
|
||||
|
||||
static create() {
|
||||
if (!this.#loaded) {
|
||||
throw new Error('Members not loaded yet, cannot call create()')
|
||||
}
|
||||
let token
|
||||
do {
|
||||
token = Base58.encode(Crypto.randomBytes(32))
|
||||
} while (this.#set.has(token))
|
||||
this.#set.add(token)
|
||||
this.#save((err, _) => {
|
||||
if (err) console.warn('Problem saving members file:', err)
|
||||
})
|
||||
return token
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Tokens
|
|
@ -1,8 +1,12 @@
|
|||
const Path = require('node:path')
|
||||
const Keypair = require('ppppp-keypair')
|
||||
const caps = require('ppppp-caps')
|
||||
const SSAPI = require('secret-stack/lib/api')
|
||||
|
||||
module.exports = function startPeer() {
|
||||
const keypair = Keypair.loadOrCreateSync('./keypair')
|
||||
const path = Path.join(__dirname, '..', 'data')
|
||||
const keypairPath = Path.join(path, 'keypair')
|
||||
const keypair = Keypair.loadOrCreateSync(keypairPath)
|
||||
|
||||
SSAPI([], {})
|
||||
.use(require('secret-stack/lib/core'))
|
||||
|
@ -11,7 +15,8 @@ module.exports = function startPeer() {
|
|||
.use(require('ssb-conn'))
|
||||
.use(require('./plugin-hub.cjs'))
|
||||
.call(null, {
|
||||
caps: { shse: 'p2pLq5VZKvNWaaafMUEcxH9BKm2WjNBCxsc8TRQV5gS' },
|
||||
path,
|
||||
caps,
|
||||
keypair,
|
||||
conn: {
|
||||
autostart: false,
|
||||
|
|
|
@ -2,6 +2,8 @@ const cat = require('pull-cat')
|
|||
const Notify = require('pull-notify')
|
||||
const pull = require('pull-stream')
|
||||
const debug = require('debug')('ppppp:hub')
|
||||
const Tokens = require('./tokens.cjs')
|
||||
const Members = require('./members.cjs')
|
||||
|
||||
function ErrorDuplex(message) {
|
||||
const err = new Error(message)
|
||||
|
@ -22,32 +24,36 @@ module.exports = {
|
|||
createTunnel: 'duplex',
|
||||
ping: 'sync',
|
||||
attendants: 'source',
|
||||
createToken: 'async',
|
||||
createToken: 'sync',
|
||||
},
|
||||
permissions: {
|
||||
anonymous: {
|
||||
allow: ['createTunnel', 'ping', 'attendants', 'createToken'],
|
||||
},
|
||||
},
|
||||
init(sstack) {
|
||||
init(sstack, config) {
|
||||
if (!sstack.conn || !sstack.conn.connect) {
|
||||
throw new Error('tunnel plugin is missing the required ssb-conn plugin')
|
||||
}
|
||||
debug('running multiserver at %s', sstack.getAddress('public'))
|
||||
|
||||
// Ensure that incoming connections are only from members
|
||||
sstack.auth.hook(function (fn, args) {
|
||||
const [incomingId, cb] = args
|
||||
cb(null, true)
|
||||
// fn.apply(this, args)
|
||||
Tokens.load(config.path)
|
||||
Members.load(config.path)
|
||||
|
||||
// FIXME:
|
||||
// if (members.has(incomingId)) {
|
||||
// fn.apply(this, args);
|
||||
// } else {
|
||||
// debug('prevented stranger %s from connecting to us', incomingId);
|
||||
// cb(new Error('client is a stranger'));
|
||||
// }
|
||||
// Ensure that client connections are only from members or to-be members
|
||||
sstack.auth.hook(function (fn, args) {
|
||||
const [clientMetadata, cb] = args
|
||||
const {pubkey, extra} = clientMetadata
|
||||
if (Members.has(pubkey)) {
|
||||
cb(null, true)
|
||||
} else if (extra && Tokens.has(extra)) {
|
||||
Tokens.delete(extra)
|
||||
Members.add(pubkey)
|
||||
cb(null, true)
|
||||
} else {
|
||||
debug('prevented stranger %s from connecting to us', pubkey)
|
||||
cb(new Error('client is a stranger'))
|
||||
}
|
||||
})
|
||||
|
||||
const attendants = new Map()
|
||||
|
@ -101,8 +107,8 @@ module.exports = {
|
|||
return Date.now()
|
||||
},
|
||||
|
||||
createToken(cb) {
|
||||
cb(new Error('not implemented'))
|
||||
createToken() {
|
||||
return Tokens.create()
|
||||
},
|
||||
}
|
||||
},
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
const Crypto = require('node:crypto')
|
||||
const Path = require('node:path')
|
||||
const AtomicFileRW = require('atomic-file-rw')
|
||||
const Base58 = require('bs58')
|
||||
|
||||
class Tokens {
|
||||
static #filePath
|
||||
|
||||
/**
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
static #set
|
||||
|
||||
static #loaded = false
|
||||
|
||||
static #save(cb) {
|
||||
const json = JSON.stringify([...this.#set])
|
||||
AtomicFileRW.writeFile(this.#filePath, json, cb)
|
||||
}
|
||||
|
||||
static load(parentPath) {
|
||||
if (this.#loaded) return
|
||||
this.#filePath = Path.join(parentPath, 'tokens.json')
|
||||
this.#set = new Set()
|
||||
|
||||
AtomicFileRW.readFile(this.#filePath, (err, buf) => {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
this.#loaded = true
|
||||
} else {
|
||||
console.log('Problem loading tokens file:', err)
|
||||
}
|
||||
return
|
||||
}
|
||||
const json = typeof buf === 'string' ? buf : Buffer.toString(buf, 'utf-8')
|
||||
const arr = JSON.parse(json)
|
||||
for (const token of arr) {
|
||||
this.#set.add(token)
|
||||
}
|
||||
this.#loaded = true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} token
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static has(token) {
|
||||
if (!this.#loaded) {
|
||||
throw new Error('Tokens not loaded yet, cannot call has()')
|
||||
}
|
||||
return this.#set.has(token)
|
||||
}
|
||||
|
||||
static create() {
|
||||
if (!this.#loaded) {
|
||||
throw new Error('Tokens not loaded yet, cannot call create()')
|
||||
}
|
||||
let token
|
||||
do {
|
||||
token = Base58.encode(Crypto.randomBytes(32))
|
||||
} while (this.#set.has(token))
|
||||
this.#set.add(token)
|
||||
this.#save((err, _) => {
|
||||
if (err) console.log('Problem saving tokens file:', err)
|
||||
})
|
||||
return token
|
||||
}
|
||||
|
||||
static delete(token) {
|
||||
if (!this.#loaded) {
|
||||
throw new Error('Tokens not loaded yet, cannot call delete()')
|
||||
}
|
||||
this.#set.delete(token)
|
||||
this.#save((err, _) => {
|
||||
if (err) console.log('Problem saving tokens file:', err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Tokens
|
|
@ -11,10 +11,13 @@
|
|||
"dependencies": {
|
||||
"@fastify/static": "6.10.2",
|
||||
"@fastify/view": "7.4.1",
|
||||
"atomic-file-rw": "~0.3.0",
|
||||
"bs58": "5.0.0",
|
||||
"debug": "4.3.4",
|
||||
"ejs": "3.1.9",
|
||||
"fastify": "4.17.0",
|
||||
"pino": "8.14.1",
|
||||
"ppppp-caps": "github:staltz/ppppp-caps",
|
||||
"ppppp-keypair": "github:staltz/ppppp-keypair",
|
||||
"pull-cat": "1.1.11",
|
||||
"pull-notify": "0.1.2",
|
||||
|
@ -2347,6 +2350,11 @@
|
|||
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.1.tgz",
|
||||
"integrity": "sha512-wHuWB+CvSVb2XqXM0W/WOYUkVSPbiJb9S5fNB7TBhd8s892Xq910bRxwHtC4l71hgztObTjXL6ZheZXFjhDrDQ=="
|
||||
},
|
||||
"node_modules/ppppp-caps": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "git+ssh://git@github.com/staltz/ppppp-caps.git#a2111355a1d2bddfc4d5f82267257fe99c14f608",
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/ppppp-keypair": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "git+ssh://git@github.com/staltz/ppppp-keypair.git#2d0cd86dae6df2fa33eb14c836ab706244807f43",
|
||||
|
@ -5533,6 +5541,10 @@
|
|||
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.1.tgz",
|
||||
"integrity": "sha512-wHuWB+CvSVb2XqXM0W/WOYUkVSPbiJb9S5fNB7TBhd8s892Xq910bRxwHtC4l71hgztObTjXL6ZheZXFjhDrDQ=="
|
||||
},
|
||||
"ppppp-caps": {
|
||||
"version": "git+ssh://git@github.com/staltz/ppppp-caps.git#a2111355a1d2bddfc4d5f82267257fe99c14f608",
|
||||
"from": "ppppp-caps@github:staltz/ppppp-caps"
|
||||
},
|
||||
"ppppp-keypair": {
|
||||
"version": "git+ssh://git@github.com/staltz/ppppp-keypair.git#2d0cd86dae6df2fa33eb14c836ab706244807f43",
|
||||
"from": "ppppp-keypair@github:staltz/ppppp-keypair",
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
"dependencies": {
|
||||
"@fastify/static": "6.10.2",
|
||||
"@fastify/view": "7.4.1",
|
||||
"atomic-file-rw": "~0.3.0",
|
||||
"bs58": "5.0.0",
|
||||
"debug": "4.3.4",
|
||||
"ejs": "3.1.9",
|
||||
"fastify": "4.17.0",
|
||||
"ppppp-caps": "github:staltz/ppppp-caps",
|
||||
"ppppp-keypair": "github:staltz/ppppp-keypair",
|
||||
"pino": "8.14.1",
|
||||
"pull-cat": "1.1.11",
|
||||
|
|
Loading…
Reference in New Issue