Generate server secret on first run. Closes #28

(The server secret is used to sign JSON Web Tokens.)
parent 5cbf0ac6
......@@ -2897,6 +2897,11 @@
"resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz",
"integrity": "sha1-YN20V3dOF48flBXwyrsOhbCzALI="
},
"doasync": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/doasync/-/doasync-2.0.0.tgz",
"integrity": "sha512-MRaZ9mvAnWoKFo5R1cMHa9Oi7uAM+9eujGClkicgwLzjdKPoL0ypAVDz58A77eTMNIodbTUG9Zcxzzm4/SFxPA=="
},
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
......@@ -6597,6 +6602,19 @@
"type-check": "0.3.2"
}
},
"libsodium": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.3.tgz",
"integrity": "sha512-ld+deUNqSsZYbAobUs63UyduPq8ICp/Ul/5lbvBIYpuSNWpPRU0PIxbW+xXipVZtuopR6fIz9e0tTnNuPMNeqw=="
},
"libsodium-wrappers": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.3.tgz",
"integrity": "sha512-dw5Jh6TZ5qc5rQVZe3JrSO/J05CE+DmAPnqD7Q2glBUE969xZ6o3fchnUxyPlp6ss3x0MFxmdJntveFN+XTg1g==",
"requires": {
"libsodium": "0.7.3"
}
},
"load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
......
......@@ -3,6 +3,12 @@ const logger = require('winston')
const app = require('./app')
const portFromConfiguration = app.get('port')
const path = require('path')
const os = require('os')
const fs = require('fs-extra')
const sodium = require('libsodium-wrappers')
const { argv } = require('yargs')
// Set the port:
......@@ -12,18 +18,73 @@ const { argv } = require('yargs')
// 3. Via the Feathers configuration file (fallback)
const port = argv.port || process.env.PORT || portFromConfiguration
process.on('unhandledRejection', (reason, p) =>
logger.error('Unhandled Rejection at: Promise ', p, reason)
)
// Once Nuxt is done rendering the client, start the FeathersJS Server.
process.on('nuxt:build:done', (err) => {
if (err) {
logger.error(err)
}
// Start the Feathers (API; REST + sockets) server.
// (This is called after Nuxt is done generating the client-side routes.)
function startFeathersServer () {
const server = app.listen(port)
server.on('listening', () => {
console.log(`🎈 Indie Site started on http://${app.get('host')}:${port}`)
console.log(`🎈 Indie Site running on http://${app.get('host')}:${port}`)
})
}
// File-based data (e.g., configuration, etc.) is saved at ~/.indie/site
const dataDirectoryPath = path.join(os.homedir(), '.indie', 'site')
const serverSecretFilePath = path.join(dataDirectoryPath, 'server-secret.json')
// On first run of the server only, create a server secret. This
// server secret is used to sign the JSON Web Tokens that we use
// for stateless authentication.
async function createAndPersitServerSecretIfItDoesntAlreadyExist () {
// Check for existence of the file synchronously so as to avoid a possible (if
// highly inprobable) race condition. Since this happens on server start, it
// will not have an impact on performance.
const serverSecretFileExists = fs.existsSync(serverSecretFilePath)
if (!serverSecretFileExists) {
//
// Server secret does not exist. This should be the first time the server
// is being run. Create and save the server.
//
logger.info('Server secret does not exist, creating this one time.')
// Create a server secret as the owner of the site is registering. This is
// the secret that we will use to sign JSON Web Tokens (JWTs).
const serverSecret = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES)
const serverSecretInHex = sodium.to_hex(serverSecret)
const serverSecretObject = { serverSecret: serverSecretInHex }
try {
// Write the keys file to a data file in a directory for this spike that
// we place in the home directory of the account that this spike is
// running under.
await fs.ensureDir(dataDirectoryPath)
await fs.writeJson(serverSecretFilePath, serverSecretObject)
} catch (error) {
throw new Error('Could not persist the server secret.', error)
}
logger.info('Initial run: server secret succesfully created and persisted.\n')
}
}
// Make sure that unhandled promise rejections are not silently ignored.
process.on('unhandledRejection', (reason, promise) =>
logger.error('Unhandled promise rejection: ', promise, reason)
)
// Once Nuxt is done initialising and setting up the client-side routes, carry
// our initial run tasks (if necessary) and then start the Feathers
// (API; REST + sockets) server.
process.on('nuxt:build:done', async error => {
if (error) { /* re- */ throw error }
// Initial run tasks.
try {
await createAndPersitServerSecretIfItDoesntAlreadyExist()
} catch (error) {
/* re- */ throw error
}
startFeathersServer()
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment