forked from camfou/connect
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Use Jose & @tsed/jwks to generate keys
- Loading branch information
Showing
6 changed files
with
236 additions
and
13,169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,55 +1,26 @@ | ||
/** | ||
* Module dependencies | ||
*/ | ||
|
||
var User = require('../models/User') | ||
var AnvilConnectKeys = require('anvil-connect-keys') | ||
var keygen = new AnvilConnectKeys() | ||
const User = require('../models/User') | ||
const { KeyGen } = require('../lib/keygen') | ||
|
||
/** | ||
* Check if server is in out-of-box mode | ||
*/ | ||
|
||
function isOOB (cb) { | ||
User.listByRoles('authority', function (err, users) { | ||
if (err) { return cb(err) } | ||
if (err) { | ||
return cb(err) | ||
} | ||
// return true if there are no authority users | ||
return cb(null, !users || !users.length) | ||
}) | ||
} | ||
|
||
exports.isOOB = isOOB | ||
|
||
/** | ||
* Read setup token from filesystem or create if missing | ||
*/ | ||
|
||
function readSetupToken (cb) { | ||
var token | ||
var write = false | ||
|
||
exports.readSetupToken = (cb) => { | ||
try { | ||
// try to read setup token from filesystem | ||
token = keygen.loadSetupToken() | ||
// if token is blank, try to generate a new token and save it | ||
if (!token.trim()) { | ||
write = true | ||
} | ||
const keyGen = new KeyGen() | ||
cb(null, keyGen.getSetupToken()) | ||
} catch (err) { | ||
// if unable to read, try to generate a new token and save it | ||
write = true | ||
} | ||
|
||
if (write) { | ||
try { | ||
token = keygen.generateSetupToken() | ||
} catch (err) { | ||
// if we can't write the token to disk, something is very wrong | ||
return cb(err) | ||
} | ||
cb(err) | ||
} | ||
|
||
// return the token | ||
cb(null, token) | ||
} | ||
exports.readSetupToken = readSetupToken |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
const fs = require('fs-extra') | ||
const { join, dirname } = require('path') | ||
const { JWK, generateJwks } = require('@tsed/jwks') | ||
const crypto = require('crypto') | ||
|
||
class Keygen { | ||
constructor (directory) { | ||
// base directory for keys to be read from and written to | ||
this.directory = join(directory || process.cwd(), 'keys') | ||
|
||
// signature key pair file paths | ||
this.sig = { | ||
pub: join(this.directory, 'sig.rsa.pub.pem'), | ||
prv: join(this.directory, 'sig.rsa.prv.pem') | ||
} | ||
|
||
// encryption key pair file paths | ||
this.enc = { | ||
pub: join(this.directory, 'enc.rsa.pub.pem'), | ||
prv: join(this.directory, 'enc.rsa.prv.pem') | ||
} | ||
|
||
// setup token | ||
this.setup = join(this.directory, 'setup.token') | ||
} | ||
|
||
generateKeyPairs () { | ||
const sigKeys = JWK.generateSync('RSA', 4096, { use: 'sig' }) | ||
fs.ensureDirSync(dirname(this.sig.pub)) | ||
|
||
fs.writeFileSync(this.sig.prv, sigKeys.toPEM(true)) | ||
fs.writeFileSync(this.sig.pub, sigKeys.toPEM(false)) | ||
|
||
const encKeys = JWK.generateSync('RSA', 4096, { use: 'sig' }) | ||
fs.writeFileSync(this.enc.prv, encKeys.toPEM(true)) | ||
fs.writeFileSync(this.enc.pub, encKeys.toPEM(false)) | ||
} | ||
|
||
loadKeyPairs () { | ||
const jwks = generateJwks({ | ||
certificates: [ | ||
{ path: this.sig.pub, alg: 'RS256', use: 'sig', kid: 'key-0' }, | ||
{ path: this.enc.pub, alg: 'RS256', use: 'enc', kid: 'key-1' } | ||
] | ||
}) | ||
|
||
return { | ||
sig: { | ||
pub: fs.readFileSync(this.sig.pub, { encoding: 'utf8' }), | ||
prv: fs.readFileSync(this.sig.prv, { encoding: 'utf8' }) | ||
}, | ||
enc: { | ||
pub: fs.readFileSync(this.enc.pub, { encoding: 'utf8' }), | ||
prv: fs.readFileSync(this.enc.prv, { encoding: 'utf8' }) | ||
}, | ||
jwks | ||
} | ||
} | ||
|
||
loadSetupToken () { | ||
return fs.readFileSync(this.setup, { encoding: 'utf8' }).toString().trim() | ||
} | ||
|
||
generateSetupToken () { | ||
fs.ensureDirSync(dirname(this.setup)) | ||
|
||
const token = crypto.randomBytes(256).toString('hex') | ||
try { | ||
fs.writeFileSync(this.setup, token, 'utf8') | ||
} catch (e) { | ||
throw new Error(`Unable to save setup token to ${this.setup}`) | ||
} | ||
return token | ||
} | ||
|
||
getSetupToken () { | ||
try { | ||
// try to read setup token from filesystem | ||
const token = this.loadSetupToken() | ||
// if token is blank, try to generate a new token and save it | ||
if (token) { | ||
return token | ||
} | ||
} catch (err) { | ||
} | ||
|
||
return this.generateSetupToken() | ||
} | ||
|
||
getKeys () { | ||
const exists = fs.existsSync(this.sig.pub) | ||
|
||
if (!exists) { | ||
this.generateKeyPairs() | ||
} | ||
|
||
return this.loadKeyPairs() | ||
} | ||
} | ||
|
||
exports.KeyGen = Keygen |
Oops, something went wrong.