nymi-roaming-authenticator
Version:
An illustration of how one might write a roaming authenticator for Nymi Bands
153 lines (117 loc) • 5.89 kB
JavaScript
;
const
NeaHelpers = require('nea-helpers'),
RoamingAuth = NeaHelpers.RoamingAuth,
UserModel = require('./UserModel'),
Authorize = require('./Authorize'),
NonceModel = require('./NonceModel'),
Server = require('./../lib/Server'),
fs = require('fs'),
path = require('path'),
crypto = require('crypto'),
Database = path.resolve(__dirname, '../database/nymiroaming.db'),
PemFile = path.resolve(__dirname, './roaming.pem');
(!fs.existsSync(PemFile) ? RoamingAuth.generatePem(PemFile, Infinity, 'roamingauth') : Promise.resolve()).then(() => {
let server = new Server(),
respond = (req, res, data) => res.send({request: req.body, response: data, successful: true}),
error = (req, res, error) => res.send({response: `error: ${error}`, successful: false}),
router = server.router('roamingauth');
router.get('shutdown', (req, res) => !res.send({successful: true}) && setTimeout(() => process.exit(), 1000));
router.get('ping', (req, res) => res.send({successful: true}));
router.get('provision/getpubkey', (req, res) => {
return respond(req, res, {partnerPublicKey: RoamingAuth.getPublicKey(PemFile)});
});
router.post('provision/newuser', (req, res) => {
let um = new UserModel(Database),
request = req.body.request;
if (request !== undefined) {
if (request.nbPublicKeyID === undefined) {
return error(req, res, 'Request field "nbPublicKeyID" missing"');
}
if (request.nbPublicKey === undefined) {
return error(req, res, 'Request field "nbPublicKey" missing"');
}
if (request.userID === undefined) {
return error(req, res, 'Request field "userID" missing"');
}
if (um.getUserIDFromKeyID(request.nbPublicKeyID) !== '') {
return error(req, res, `User with Key ID ${request.nbPublicKeyID} already exists`);
}
if (um.createNewUser(request.userID, request.nbPublicKey, request.nbPublicKeyID)) {
return respond(req, res, `User ${request.userID} successfully added`);
}
return error(req, res, 'Failed to create new user');
}
return error(req, res, 'Request field missing');
});
router.post('sign', (req, res) => {
let request = req.body.request;
if (request !== undefined) {
if (request.nymibandNonce === undefined) {
return error(req, res, 'Missing nymibandNonce field');
}
if (request.exchange === undefined) {
return error(req, res, 'Missing exchange field');
}
let nm = new NonceModel(Database),
serverNonce = crypto.randomBytes(32).toString('hex'),
hashSig = RoamingAuth.sign(PemFile, request.nymibandNonce + serverNonce);
if (!nm.saveNonce(request.exchange, serverNonce)) {
return error(req, res, 'Failed to save server nonce');
}
return respond(req, res, {
serverSignature: hashSig,
serverNonce: serverNonce,
partnerPublicKey: RoamingAuth.getPublicKey(PemFile)
});
}
return error(req, res, 'Request field missing');
});
router.post('auth', (req, res) => {
let request = req.body.request;
if (request !== undefined) {
if (request.nbPublicKeyID === undefined) {
return error(req, res, 'Request field "nbPublicKeyID" missing');
}
if (request.signedNonces === undefined) {
return error(req, res, 'Request field "signedNonces" missing');
}
if (request.exchange === undefined) {
return error(req, res, 'Request field "exchange" missing');
}
let serverNonce, userId,
um = new UserModel(Database),
nm = new NonceModel(Database),
nbPublicKey = um.getUserKeyFromKeyID(request.nbPublicKeyID);
if (nbPublicKey.length === 0) {
return error(req, res, `User with Key ID ${request.nbPublicKeyID} not found`);
}
serverNonce = nm.getNonce(request.exchange);
if (serverNonce.length === 0) {
return error(req, res, `Could not find saved nonce for exchange ${request.exchange}`);
}
if (RoamingAuth.verify(serverNonce, request.signedNonces, nbPublicKey)) {
if (!nm.deleteNonceByExchange(request.exchange)) {
process.stderr.write(
'WARNING: Unable to remove used nonce from database. It should clean up on its own shortly'
);
}
userId = um.getUserIDFromKeyID(request.nbPublicKeyID);
Authorize.user(userId);
return respond(req, res, {userId});
}
if (!nm.deleteNonceByExchange(request.exchange)) {
process.stderr.write(
'WARNING: Unable to remove used nonce from database. It should clean up on its own shortly'
);
}
return error(
req,
res,
`Signature verification failed so user with keyid ${request.nbPublicKeyID} is not authenticated`
);
}
return error(req, res, 'Request field missing');
});
server.listen(9090, '127.0.0.1', () => process.stdout.write('Listening on http://localhost:9090'));
}).catch(err => process.stderr.write(err) && process.exit(1));