lintry

定义生成totp和验证

/**
* Created by lintry on 2017/5/19.
*/
module.exports = require('./lib/totp');
/**
* Created by lintry on 2017/5/19.
*/
const Authenticator = function (secret, options) {
if (!(this instanceof Authenticator)) {
return new Authenticator(secret, options)
}
const _ = require('lodash'),
path = require('path'),
crypto_utils = require('kml-crypto-utils'),
speakeasy = require('speakeasy'),
qr = require('qr-image');
options = options || {};
this.secret = crypto_utils.AESDecode(secret);
const TOTP_OPTIONS = this.totp_options = {
secret: this.secret,
encoding: options.encoding || 'base32',
step: options.step || 30
};
/**
* 验证token有效性
* @type {Authenticator.verify}
*/
const verify = this.verify = function(token) {
return speakeasy.totp.verify(_.merge({token: token}, TOTP_OPTIONS));
};
/**
* 在options.window的范围内验证token的有效性
* @type {Authenticator.verifyDelta}
*/
const verifyDelta = this.verifyDelta = function(token) {
return speakeasy.totp.verifyDelta(_.merge({token: token}, TOTP_OPTIONS));
};
/**
* 获取QR显示值
* @type {Authenticator.getOtpAuth}
*/
const getOtpAuth = this.getOtpAuth = function (title, issuer) {
let _title = title || 'HowAreU';
let _issuer = encodeURIComponent(issuer || 'TOTP-KEY');
return `otpauth://totp/${_title}?secret=${this.secret}&issuer=${_issuer}`;
};
/**
* 生成svg的QR图片内容
* @type {Authenticator.getQR}
*/
const getQR = this.getQR = function(title, issuer) {
return qr.imageSync(getOtpAuth(title, issuer), { type: 'svg' });
};
/**
* 生成新的token
* @type {Authenticator.totp}
*/
const totp = this.totp = function () {
return speakeasy.totp(_.merge({}, TOTP_OPTIONS));
};
return this;
};
module.exports = Authenticator;
\ No newline at end of file
/**
* Created by lintry on 2017/5/19.
*/
const TOTP = function (options) {
if (!(this instanceof TOTP)) {
return new TOTP(options)
}
const _ = require('lodash'),
crypto_utils = require('kml-crypto-utils'),
speakeasy = require('speakeasy'),
Authenticator = require('./authenticator');
options = options || {};
const TOTP_OPTIONS = {
encoding: options.encoding || 'base32',
step: options.step || 30
};
/**
* 生成密钥并加密
* @return {*}
*/
this.createSecret = function() {
return crypto_utils.AESEncode(speakeasy.generateSecret({length: 20}).base32);
};
/**
* 解析密钥
* @param secret
* @return {Authenticator}
*/
this.parse = function (secret) {
return new Authenticator(secret, TOTP_OPTIONS)
};
return this;
};
module.exports = TOTP;
\ No newline at end of file
......@@ -13,7 +13,15 @@
"keywords": [],
"author": "lintry <shenlin00@gmail.com>",
"license": "MIT",
"files": [
"/*",
"!/.*",
"!/test"
],
"dependencies": {
"kml-crypto-utils": "git+ssh://git@gitlab.kmlab.com:comm/crypto-utils.git#1.1.7",
"lodash": "^4.17.4",
"qr-image": "^3.2.0",
"speakeasy": "^2.0.0"
}
}
......
/**
* Created by lintry on 2017/5/19.
*/
const Authenticator = require('../lib/authenticator');
const chalk = require('chalk');
const fs = require('fs-extra');
const path = require('path');
let secret = 'vH6OdbUEjSukTqlDvW3TYdusjiOIkxRnAHNTjJewfZa5yNueG9wx1N9pJMFOmPAV';
let authenticator = new Authenticator(secret);
console.log(chalk.cyan('totp的secret'));
console.log(secret);
let token = process.argv[2];
if (!token) {
token = authenticator.totp();
console.error(chalk.red('none token found, we generate a new token instead'), token);
return;
}
console.log(chalk.green('token is'), token);
let verify = authenticator.verify(token);
console.log(chalk.magenta('verify is '), (verify ? chalk.green : chalk.red)(verify));
console.log(chalk.blue('verifyDelta is '), authenticator.verifyDelta(token));
let img_path = path.resolve(process.cwd(), 'img');
let qr = path.resolve(img_path, 'qr.svg');
fs.ensureDir(img_path, function (err, added_root) {
if (err) {
return console.error(chalk.red('create folder error'), chalk.red(JSON.stringify(err, null, 4)));
}
added_root && console.log(chalk.green(img_path + ' is created'));
let fd = fs.openSync(qr, 'w');
fs.writeSync(fd, authenticator.getQR('totp@gitlab.kmlab.com', '通行密钥'));
fs.closeSync(fd);
console.log(chalk.yellow(authenticator.getOtpAuth('totp@gitlab.kmlab.com', '通行密钥')))
});
console.log('QR SVG output is', img_path, qr);
\ No newline at end of file
/**
* Created by lintry on 2017/5/19.
*/
const TOTP = require('../lib/totp');
const chalk = require('chalk');
const fs = require('fs-extra');
let totp = new TOTP();
let secret = totp.createSecret();
console.log(chalk.cyan('创建totp的secret'));
console.log(secret);
console.log(chalk.magenta('secret'), secret);
let authenticator = totp.parse(secret);
console.log(authenticator.totp_options);
let token = authenticator.totp();
console.log(chalk.green('token is'), token);
console.log(chalk.magenta('verify is '), authenticator.verify(token));
\ No newline at end of file