Bootstrap
++ Congratulations on successfully installing this Hub server! + Below is the bootstrap invite link, a one-time invite that will + set you up as the admin of this Hub. +
+ Claim invite + +diff --git a/lib/index.js b/lib/index.js index 22a384e..c4a5a2c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -11,18 +11,22 @@ const fastifyStatic = require('@fastify/static') const ejs = require('ejs') const logger = require('./logger.cjs') const startPeer = require('./peer.cjs') +const peer = startPeer() const staticsPath = path.join(__dirname, 'public') const viewsPath = path.join(__dirname, 'views') const app = fastify({ logger }) - app.register(fastifyView, { engine: { ejs }, root: viewsPath }) - app.register(fastifyStatic, { root: staticsPath }) app.get('/', (req, reply) => { - reply.view('homepage.ejs', { markdown: homepageHTML }) + if (peer.hub.numMembers() === 0) { + const { port, pubkey, token } = peer.hub.getBootstrap() + reply.view('bootstrap.ejs', { port, pubkey, token }) + } else { + reply.view('homepage.ejs', { markdown: homepageHTML }) + } }) app.get('/invite', (req, reply) => { @@ -36,6 +40,5 @@ app.listen( app.log.error(err) process.exit(1) } - startPeer() } ) diff --git a/lib/members.cjs b/lib/members.cjs index ccfc068..f02d080 100644 --- a/lib/members.cjs +++ b/lib/members.cjs @@ -60,6 +60,10 @@ class Members { if (err) console.warn('Problem saving members file:', err) }) } + + static size() { + return this.#set.size + } } module.exports = Members diff --git a/lib/peer.cjs b/lib/peer.cjs index 67c2d43..a194725 100644 --- a/lib/peer.cjs +++ b/lib/peer.cjs @@ -8,7 +8,7 @@ module.exports = function startPeer() { const keypairPath = Path.join(path, 'keypair') const keypair = Keypair.loadOrCreateSync(keypairPath) - SecretStack() + return SecretStack() .use(require('secret-stack/plugins/net')) .use(require('secret-handshake-ext/secret-stack')) .use(require('ssb-conn')) diff --git a/lib/plugin-hub.cjs b/lib/plugin-hub.cjs index aab6761..f00f751 100644 --- a/lib/plugin-hub.cjs +++ b/lib/plugin-hub.cjs @@ -53,6 +53,10 @@ module.exports = { Tokens.delete(extra) Members.add(pubkey) cb(null, true) + } else if (Members.size() === 0) { + debug('authorized BOOTSTRAP member %s to connect', pubkey) + Members.add(pubkey) + cb(null, true) } else { debug('denied stranger %s from connecting', pubkey) cb(new Error('client is a stranger')) @@ -117,6 +121,17 @@ module.exports = { createToken() { return Tokens.create() }, + + numMembers() { + return Members.size() + }, + + getBootstrap() { + const port = config.global.connections.incoming.net[0].port + const pubkey = local.shse.pubkey + const token = 'none' + return { port, pubkey, token } + }, } }, } diff --git a/lib/public/bootstrap.js b/lib/public/bootstrap.js new file mode 100644 index 0000000..6e153f6 --- /dev/null +++ b/lib/public/bootstrap.js @@ -0,0 +1,31 @@ +let hasFocus = true +window.addEventListener('blur', () => { + hasFocus = false +}) +window.addEventListener('focus', () => { + hasFocus = true +}) + +const host = window.location.hostname +const { port, pubkey, token } = window.hubInvite +const uri = `ppppp://invite/join/${host}/${port}/${pubkey}/${token}` + +const inviteLinkElem = document.getElementById('invite') +inviteLinkElem.href = uri +// Autoredirect to the PPPPP URI as soon as possible +setTimeout(() => { + window.location.replace(uri) +}, 100) + +// Redirect to uri or show failure state +inviteLinkElem.onclick = function handleURI(ev) { + ev.preventDefault() + const uri = inviteLinkElem.href + inviteLinkElem.classList.remove('hidden') + setTimeout(function () { + if (hasFocus) { + inviteLinkElem.classList.add('hidden') + } + }, 5000) + window.location.replace(uri) +} diff --git a/lib/views/bootstrap.ejs b/lib/views/bootstrap.ejs new file mode 100644 index 0000000..54ee7f2 --- /dev/null +++ b/lib/views/bootstrap.ejs @@ -0,0 +1,26 @@ + + +
+ + + ++ Congratulations on successfully installing this Hub server! + Below is the bootstrap invite link, a one-time invite that will + set you up as the admin of this Hub. +
+ Claim invite + +