mirror of
https://github.com/LanceGin/jsotp.git
synced 2026-05-05 00:00:03 +08:00
fix: auto fix some lint error
This commit is contained in:
+14
-14
@@ -4,35 +4,35 @@
|
||||
* @author : Gin (gin.lance.inside@hotmail.com)
|
||||
*/
|
||||
|
||||
const nibbler = require("./nibbler/nibbler");
|
||||
const nibbler = require('./nibbler/nibbler');
|
||||
|
||||
export class Base32 {
|
||||
/**
|
||||
/* *
|
||||
* Base32 decode function
|
||||
*
|
||||
* @param {secret}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc input string
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
static decode(secret) {
|
||||
return nibbler.b32decode(secret);
|
||||
}
|
||||
static decode(secret) {
|
||||
return nibbler.b32decode(secret);
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Base32 generate random b32 encoded string function
|
||||
*
|
||||
* @param {length}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc the length of random b32 encoded string
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
static random_gen(length=16) {
|
||||
let random_str = Math.random().toString(36);
|
||||
random_str = nibbler.b32encode(random_str);
|
||||
static random_gen(length = 16) {
|
||||
let random_str = Math.random().toString(36);
|
||||
random_str = nibbler.b32encode(random_str);
|
||||
|
||||
return random_str.substring(0, length);
|
||||
}
|
||||
}
|
||||
return random_str.substring(0, length);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-22
@@ -6,11 +6,11 @@
|
||||
import { OTP } from './otp';
|
||||
|
||||
export class HOTP extends OTP {
|
||||
/**
|
||||
/* *
|
||||
* Generate the OTP with the given count
|
||||
*
|
||||
* @param {count}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc the OTP HMAC counter
|
||||
*
|
||||
* @return {OTP}
|
||||
@@ -21,20 +21,20 @@ export class HOTP extends OTP {
|
||||
* hotp.at(0); // => 432143
|
||||
* ```
|
||||
*/
|
||||
at(count) {
|
||||
let digit = super.generate_otp(count);
|
||||
return digit;
|
||||
}
|
||||
at(count) {
|
||||
const digit = super.generate_otp(count);
|
||||
return digit;
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Verifies the OTP passed in against the current counter.
|
||||
*
|
||||
* @param {otp}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc the OTP waiting for checking
|
||||
*
|
||||
* @param {counter}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc the OTP HMAC counter
|
||||
*
|
||||
* @return {Boolean}
|
||||
@@ -47,26 +47,25 @@ export class HOTP extends OTP {
|
||||
* hotp.verify(432143, 1); // => false
|
||||
* ```
|
||||
*/
|
||||
verify(otp, counter) {
|
||||
let otp_count = this.at(counter);
|
||||
verify(otp, counter) {
|
||||
const otp_count = this.at(counter);
|
||||
|
||||
if (otp === otp_count) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (otp === otp_count) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Generate a url with HOTP instance.
|
||||
*
|
||||
* @param {issuer}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc maybe it is the Service name
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
url_gen(issuer="") {
|
||||
return super.url_gen(issuer, "hotp");
|
||||
}
|
||||
}
|
||||
url_gen(issuer = '') {
|
||||
return super.url_gen(issuer, 'hotp');
|
||||
}
|
||||
}
|
||||
|
||||
+16
-16
@@ -10,42 +10,42 @@ import { HOTP } from './hotp';
|
||||
import { Base32 } from './base32';
|
||||
import { Util } from './util';
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Generate and return HOTP object
|
||||
*
|
||||
* @param {secret}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc random base32-encoded key to generate OTP.
|
||||
*
|
||||
* @return {OTP}
|
||||
*/
|
||||
function hotp_gen(secret, digits=6, digest="SHA-1") {
|
||||
let hotp = new HOTP(secret, digits, digest);
|
||||
return hotp;
|
||||
function hotp_gen(secret, digits = 6, digest = 'SHA-1') {
|
||||
const hotp = new HOTP(secret, digits, digest);
|
||||
return hotp;
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Generate and return TOTP object
|
||||
*
|
||||
* @param {secret}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc random base32-encoded key to generate OTP.
|
||||
*
|
||||
* @param {interval}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc the time interval in seconds for OTP.
|
||||
* This defaults to 30.
|
||||
*
|
||||
* @return {OTP}
|
||||
*/
|
||||
function totp_gen(secret, interval=30) {
|
||||
let totp = new TOTP(secret, interval);
|
||||
return totp;
|
||||
function totp_gen(secret, interval = 30) {
|
||||
const totp = new TOTP(secret, interval);
|
||||
return totp;
|
||||
}
|
||||
|
||||
export {
|
||||
hotp_gen as HOTP,
|
||||
totp_gen as TOTP,
|
||||
Base32,
|
||||
Util
|
||||
};
|
||||
hotp_gen as HOTP,
|
||||
totp_gen as TOTP,
|
||||
Base32,
|
||||
Util,
|
||||
};
|
||||
|
||||
+164
-150
@@ -3,174 +3,188 @@ Adapted for Node.js by Matt Robenolt
|
||||
Reference: http://www.tumuski.com/2010/04/nibbler/
|
||||
*/
|
||||
|
||||
var Nibbler = function (options) {
|
||||
var construct,
|
||||
|
||||
// options
|
||||
pad, dataBits, codeBits, keyString, arrayData,
|
||||
|
||||
// private instance variables
|
||||
mask, group, max,
|
||||
|
||||
// private methods
|
||||
gcd, translate,
|
||||
|
||||
// public methods
|
||||
encode, decode;
|
||||
|
||||
const Nibbler = function (options) {
|
||||
let construct,
|
||||
|
||||
// options
|
||||
pad,
|
||||
dataBits,
|
||||
codeBits,
|
||||
keyString,
|
||||
arrayData,
|
||||
|
||||
// private instance variables
|
||||
mask,
|
||||
group,
|
||||
max,
|
||||
|
||||
// private methods
|
||||
gcd,
|
||||
translate,
|
||||
|
||||
// public methods
|
||||
encode,
|
||||
decode;
|
||||
|
||||
// pseudo-constructor
|
||||
construct = function () {
|
||||
var i, mag, prev;
|
||||
construct = function () {
|
||||
let i,
|
||||
mag,
|
||||
prev;
|
||||
|
||||
// options
|
||||
pad = options.pad || '';
|
||||
dataBits = options.dataBits;
|
||||
codeBits = options.codeBits;
|
||||
keyString = options.keyString;
|
||||
arrayData = options.arrayData;
|
||||
|
||||
// bitmasks
|
||||
mag = Math.max(dataBits, codeBits);
|
||||
prev = 0;
|
||||
mask = [];
|
||||
for (i = 0; i < mag; i += 1) {
|
||||
mask.push(prev);
|
||||
prev += prev + 1;
|
||||
}
|
||||
max = prev;
|
||||
|
||||
// ouput code characters in multiples of this number
|
||||
group = dataBits / gcd(dataBits, codeBits);
|
||||
// options
|
||||
pad = options.pad || '';
|
||||
dataBits = options.dataBits;
|
||||
codeBits = options.codeBits;
|
||||
keyString = options.keyString;
|
||||
arrayData = options.arrayData;
|
||||
|
||||
// bitmasks
|
||||
mag = Math.max(dataBits, codeBits);
|
||||
prev = 0;
|
||||
mask = [];
|
||||
for (i = 0; i < mag; i += 1) {
|
||||
mask.push(prev);
|
||||
prev += prev + 1;
|
||||
}
|
||||
max = prev;
|
||||
|
||||
// ouput code characters in multiples of this number
|
||||
group = dataBits / gcd(dataBits, codeBits);
|
||||
};
|
||||
|
||||
// greatest common divisor
|
||||
gcd = function (a, b) {
|
||||
let t;
|
||||
while (b !== 0) {
|
||||
t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
// the re-coder
|
||||
translate = function (input, bitsIn, bitsOut, decoding) {
|
||||
let i,
|
||||
len,
|
||||
chr,
|
||||
byteIn,
|
||||
buffer,
|
||||
size,
|
||||
output,
|
||||
write;
|
||||
|
||||
// append a byte to the output
|
||||
write = function (n) {
|
||||
if (!decoding) {
|
||||
output.push(keyString.charAt(n));
|
||||
} else if (arrayData) {
|
||||
output.push(n);
|
||||
} else {
|
||||
output.push(String.fromCharCode(n));
|
||||
}
|
||||
};
|
||||
|
||||
// greatest common divisor
|
||||
gcd = function (a, b) {
|
||||
var t;
|
||||
while (b !== 0) {
|
||||
t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
buffer = 0;
|
||||
size = 0;
|
||||
output = [];
|
||||
|
||||
len = input.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
// the new size the buffer will be after adding these bits
|
||||
size += bitsIn;
|
||||
|
||||
// read a character
|
||||
if (decoding) {
|
||||
// decode it
|
||||
chr = input.charAt(i);
|
||||
byteIn = keyString.indexOf(chr);
|
||||
if (chr === pad) {
|
||||
break;
|
||||
} else if (byteIn < 0) {
|
||||
throw `the character "${chr}" is not a member of ${keyString}`;
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
// the re-coder
|
||||
translate = function (input, bitsIn, bitsOut, decoding) {
|
||||
var i, len, chr, byteIn,
|
||||
buffer, size, output,
|
||||
write;
|
||||
|
||||
// append a byte to the output
|
||||
write = function (n) {
|
||||
if (!decoding) {
|
||||
output.push(keyString.charAt(n));
|
||||
} else if (arrayData) {
|
||||
output.push(n);
|
||||
} else {
|
||||
output.push(String.fromCharCode(n));
|
||||
}
|
||||
};
|
||||
|
||||
buffer = 0;
|
||||
size = 0;
|
||||
output = [];
|
||||
|
||||
len = input.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
// the new size the buffer will be after adding these bits
|
||||
size += bitsIn;
|
||||
|
||||
// read a character
|
||||
if (decoding) {
|
||||
// decode it
|
||||
chr = input.charAt(i);
|
||||
byteIn = keyString.indexOf(chr);
|
||||
if (chr === pad) {
|
||||
break;
|
||||
} else if (byteIn < 0) {
|
||||
throw 'the character "' + chr + '" is not a member of ' + keyString;
|
||||
}
|
||||
} else {
|
||||
if (arrayData) {
|
||||
byteIn = input[i];
|
||||
} else {
|
||||
byteIn = input.charCodeAt(i);
|
||||
}
|
||||
if ((byteIn | max) !== max) {
|
||||
throw byteIn + " is outside the range 0-" + max;
|
||||
}
|
||||
}
|
||||
|
||||
// shift the buffer to the left and add the new bits
|
||||
buffer = (buffer << bitsIn) | byteIn;
|
||||
|
||||
// as long as there's enough in the buffer for another output...
|
||||
while (size >= bitsOut) {
|
||||
// the new size the buffer will be after an output
|
||||
size -= bitsOut;
|
||||
|
||||
// output the part that lies to the left of that number of bits
|
||||
// by shifting the them to the right
|
||||
write(buffer >> size);
|
||||
|
||||
// remove the bits we wrote from the buffer
|
||||
// by applying a mask with the new size
|
||||
buffer &= mask[size];
|
||||
}
|
||||
} else {
|
||||
if (arrayData) {
|
||||
byteIn = input[i];
|
||||
} else {
|
||||
byteIn = input.charCodeAt(i);
|
||||
}
|
||||
|
||||
// If we're encoding and there's input left over, pad the output.
|
||||
// Otherwise, leave the extra bits off, 'cause they themselves are padding
|
||||
if (!decoding && size > 0) {
|
||||
|
||||
// flush the buffer
|
||||
write(buffer << (bitsOut - size));
|
||||
|
||||
// add padding keyString for the remainder of the group
|
||||
len = output.length % group;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
output.push(pad);
|
||||
}
|
||||
if ((byteIn | max) !== max) {
|
||||
throw `${byteIn} is outside the range 0-${max}`;
|
||||
}
|
||||
}
|
||||
|
||||
// string!
|
||||
return (arrayData && decoding) ? output : output.join('');
|
||||
};
|
||||
|
||||
/**
|
||||
// shift the buffer to the left and add the new bits
|
||||
buffer = (buffer << bitsIn) | byteIn;
|
||||
|
||||
// as long as there's enough in the buffer for another output...
|
||||
while (size >= bitsOut) {
|
||||
// the new size the buffer will be after an output
|
||||
size -= bitsOut;
|
||||
|
||||
// output the part that lies to the left of that number of bits
|
||||
// by shifting the them to the right
|
||||
write(buffer >> size);
|
||||
|
||||
// remove the bits we wrote from the buffer
|
||||
// by applying a mask with the new size
|
||||
buffer &= mask[size];
|
||||
}
|
||||
}
|
||||
|
||||
// If we're encoding and there's input left over, pad the output.
|
||||
// Otherwise, leave the extra bits off, 'cause they themselves are padding
|
||||
if (!decoding && size > 0) {
|
||||
// flush the buffer
|
||||
write(buffer << (bitsOut - size));
|
||||
|
||||
// add padding keyString for the remainder of the group
|
||||
len = output.length % group;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
output.push(pad);
|
||||
}
|
||||
}
|
||||
|
||||
// string!
|
||||
return (arrayData && decoding) ? output : output.join('');
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode. Input and output are strings.
|
||||
*/
|
||||
encode = function (input) {
|
||||
return translate(input, dataBits, codeBits, false);
|
||||
};
|
||||
|
||||
/**
|
||||
encode = function (input) {
|
||||
return translate(input, dataBits, codeBits, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode. Input and output are strings.
|
||||
*/
|
||||
decode = function (input) {
|
||||
return translate(input, codeBits, dataBits, true);
|
||||
};
|
||||
|
||||
this.encode = encode;
|
||||
this.decode = decode;
|
||||
construct();
|
||||
decode = function (input) {
|
||||
return translate(input, codeBits, dataBits, true);
|
||||
};
|
||||
|
||||
this.encode = encode;
|
||||
this.decode = decode;
|
||||
construct();
|
||||
};
|
||||
|
||||
var Base32 = new Nibbler({
|
||||
dataBits: 8,
|
||||
codeBits: 5,
|
||||
keyString: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
|
||||
pad: '='
|
||||
const Base32 = new Nibbler({
|
||||
dataBits: 8,
|
||||
codeBits: 5,
|
||||
keyString: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
|
||||
pad: '=',
|
||||
});
|
||||
var Base64 = new Nibbler({
|
||||
dataBits: 8,
|
||||
codeBits: 6,
|
||||
keyString: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
|
||||
pad: '='
|
||||
const Base64 = new Nibbler({
|
||||
dataBits: 8,
|
||||
codeBits: 6,
|
||||
keyString: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
|
||||
pad: '=',
|
||||
});
|
||||
|
||||
exports.Nibbler = Nibbler;
|
||||
exports.b32encode = Base32.encode;
|
||||
exports.b32decode = Base32.decode;
|
||||
exports.b64encode = Base64.encode;
|
||||
exports.b64decode = Base64.decode;
|
||||
exports.b64decode = Base64.decode;
|
||||
|
||||
+46
-45
@@ -2,96 +2,97 @@
|
||||
* @module : OTP module to generate the password
|
||||
* @author : Gin (gin.lance.inside@hotmail.com)
|
||||
*/
|
||||
const jsSHA = require("jssha");
|
||||
const jsSHA = require('jssha');
|
||||
|
||||
import { Base32 } from './base32';
|
||||
import { Util } from './util';
|
||||
|
||||
export class OTP {
|
||||
/**
|
||||
export class OTP {
|
||||
/* *
|
||||
* This constructor will create OTP instance.
|
||||
*
|
||||
* @param {secret}
|
||||
* @type {String}
|
||||
* @desc random base32-encoded key, it is the
|
||||
* @desc random base32-encoded key, it is the
|
||||
* key that be used to verify.
|
||||
*
|
||||
* @param {digits}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc the length of the one-time password, default to be 6
|
||||
*
|
||||
* @param {digest}
|
||||
* @type {String}
|
||||
* @desc the key that be used to do HMAC encoding, dedault and
|
||||
* @desc the key that be used to do HMAC encoding, dedault and
|
||||
* only to be "sha1"
|
||||
*
|
||||
*/
|
||||
constructor(secret, digits=6, digest="SHA-1") {
|
||||
this.secret = secret;
|
||||
this.digits = digits;
|
||||
this.digest = digest;
|
||||
}
|
||||
constructor(secret, digits = 6, digest = 'SHA-1') {
|
||||
this.secret = secret;
|
||||
this.digits = digits;
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* When class HOTP or TOTP pass the input params to this
|
||||
* function, it will generate the OTP object with params,
|
||||
* the params may be counter or time.
|
||||
* the params may be counter or time.
|
||||
*
|
||||
* @param {input}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc input params to generate OTP object, maybe
|
||||
* counter or time.
|
||||
*
|
||||
* @return {OTP}
|
||||
*/
|
||||
generate_otp(input) {
|
||||
// generate HMAC object with SHA-1 digest
|
||||
let hmacObj = new jsSHA(this.digest, "BYTES");
|
||||
// set hmac token
|
||||
hmacObj.setHMACKey(Util.byte_secret(this.secret), "BYTES");
|
||||
// hamc encode the input param
|
||||
hmacObj.update(Util.int_to_bytestring(input));
|
||||
generate_otp(input) {
|
||||
// generate HMAC object with SHA-1 digest
|
||||
const hmacObj = new jsSHA(this.digest, 'BYTES');
|
||||
// set hmac token
|
||||
hmacObj.setHMACKey(Util.byte_secret(this.secret), 'BYTES');
|
||||
// hamc encode the input param
|
||||
hmacObj.update(Util.int_to_bytestring(input));
|
||||
|
||||
// get HMAC ans
|
||||
let hmac = hmacObj.getHMAC("BYTES");
|
||||
// get HMAC ans
|
||||
const hmac = hmacObj.getHMAC('BYTES');
|
||||
|
||||
// transfer hmac to Array
|
||||
let hmac_a = hmac.split("");
|
||||
// transfer hmac to Array
|
||||
const hmac_a = hmac.split('');
|
||||
|
||||
// calculate the init offset
|
||||
let offset = hmac_a[hmac_a.length - 1].charCodeAt() & 0xf;
|
||||
// calculate the init offset
|
||||
const offset = hmac_a[hmac_a.length - 1].charCodeAt() & 0xf;
|
||||
|
||||
// calculate the code
|
||||
let code = (
|
||||
(hmac_a[offset].charCodeAt() & 0x7f) << 24 |
|
||||
// calculate the code
|
||||
const code = (
|
||||
(hmac_a[offset].charCodeAt() & 0x7f) << 24 |
|
||||
(hmac_a[offset + 1].charCodeAt() & 0xff) << 16 |
|
||||
(hmac_a[offset + 2].charCodeAt() & 0xff) << 8 |
|
||||
(hmac_a[offset + 2].charCodeAt() & 0xff) << 8 |
|
||||
(hmac_a[offset + 3].charCodeAt() & 0xff)
|
||||
);
|
||||
);
|
||||
|
||||
// get the init str code
|
||||
let str_code = (code % 10 ** this.digits).toString();
|
||||
// get the init str code
|
||||
let str_code = (code % 10 ** this.digits).toString();
|
||||
|
||||
// rjust format
|
||||
str_code = Util.rjust(str_code, this.digits);
|
||||
// rjust format
|
||||
str_code = Util.rjust(str_code, this.digits);
|
||||
|
||||
return str_code;
|
||||
}
|
||||
return str_code;
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Generate a url with TOTP or HOTP instance.
|
||||
*
|
||||
* @param {issuer}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc maybe it is the Service name
|
||||
*
|
||||
* @param {type}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc type of OTP instance
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
url_gen(issuer, type) {
|
||||
return `otpauth://${type}/SK?secret=${this.secret}&issuer=${issuer}`;
|
||||
}
|
||||
}
|
||||
url_gen(issuer, type) {
|
||||
return `otpauth://${type}/SK?secret=${this.secret}&issuer=${issuer}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+35
-36
@@ -7,24 +7,24 @@ import { OTP } from './otp';
|
||||
import { Util } from './util';
|
||||
|
||||
export class TOTP extends OTP {
|
||||
/**
|
||||
/* *
|
||||
* @param {secret}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc random base32-encoded key to generate OTP.
|
||||
*
|
||||
* @param {interval}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc the time interval in seconds for OTP.
|
||||
* This defaults to 30.
|
||||
*
|
||||
* @return {OTP}
|
||||
*/
|
||||
constructor(secret, interval=30) {
|
||||
super(secret);
|
||||
this.interval = interval;
|
||||
}
|
||||
constructor(secret, interval = 30) {
|
||||
super(secret);
|
||||
this.interval = interval;
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Generate the OTP with current time.
|
||||
*
|
||||
* @return {OTP}
|
||||
@@ -35,24 +35,24 @@ export class TOTP extends OTP {
|
||||
* totp.now(); // => 432143
|
||||
* ```
|
||||
*/
|
||||
now() {
|
||||
// get now time string
|
||||
let now = Util.timecode(new Date(), this.interval);
|
||||
now() {
|
||||
// get now time string
|
||||
const now = Util.timecode(new Date(), this.interval);
|
||||
|
||||
// generate the one-time password
|
||||
let digit = super.generate_otp(now);
|
||||
return digit;
|
||||
}
|
||||
// generate the one-time password
|
||||
const digit = super.generate_otp(now);
|
||||
return digit;
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Verifies the OTP passed in against the current time OTP.
|
||||
*
|
||||
* @param {otp}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc the OTP waiting for checking
|
||||
*
|
||||
* @param {time}
|
||||
* @type {int or datetime}
|
||||
* @type {int or datetime}
|
||||
* @desc Time to check OTP at (defaults to now)
|
||||
*
|
||||
* @return {Boolean}
|
||||
@@ -67,31 +67,30 @@ export class TOTP extends OTP {
|
||||
* totp.verify(432143); // => false
|
||||
* ```
|
||||
*/
|
||||
verify(otp, time=null) {
|
||||
let otp_time;
|
||||
verify(otp, time = null) {
|
||||
let otp_time;
|
||||
|
||||
if (null == time) {
|
||||
time = new Date();
|
||||
otp_time = this.now()
|
||||
}
|
||||
|
||||
if (otp === otp_time) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (time == null) {
|
||||
time = new Date();
|
||||
otp_time = this.now();
|
||||
}
|
||||
|
||||
/**
|
||||
if (otp === otp_time) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* *
|
||||
* Generate a url with TOTP instance.
|
||||
*
|
||||
* @param {issuer}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc maybe it is the Service name
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
url_gen(issuer="") {
|
||||
return super.url_gen(issuer, "totp");
|
||||
}
|
||||
}
|
||||
url_gen(issuer = '') {
|
||||
return super.url_gen(issuer, 'totp');
|
||||
}
|
||||
}
|
||||
|
||||
+52
-54
@@ -6,113 +6,111 @@
|
||||
import { Base32 } from './base32';
|
||||
|
||||
export class Util {
|
||||
/**
|
||||
/* *
|
||||
* Util rjust number with 0
|
||||
*
|
||||
* @param {num}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc input number
|
||||
*
|
||||
* @param {n}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc wanted length
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
static rjust(num, n) {
|
||||
let len = num.toString().length;
|
||||
static rjust(num, n) {
|
||||
let len = num.toString().length;
|
||||
|
||||
while (len < n) {
|
||||
num = "0" + num;
|
||||
len++;
|
||||
}
|
||||
|
||||
return num;
|
||||
while (len < n) {
|
||||
num = `0${num}`;
|
||||
len++;
|
||||
}
|
||||
|
||||
/**
|
||||
return num;
|
||||
}
|
||||
|
||||
/* *
|
||||
* Util rjust array with ""
|
||||
*
|
||||
* @param {arr}
|
||||
* @type {Array}
|
||||
* @type {Array}
|
||||
* @desc input array
|
||||
*
|
||||
* @param {n}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc wanted length
|
||||
*
|
||||
* @return {BYTES}
|
||||
*/
|
||||
static arr_rjust(arr, n) {
|
||||
if (n <= arr.length) {
|
||||
arr = arr.splice(arr.length - 1 - n);
|
||||
return arr;
|
||||
} else {
|
||||
let diff = n - arr.length;
|
||||
for (let i = 0; i < diff; i++) {
|
||||
arr.unshift(String.fromCharCode(0));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
static arr_rjust(arr, n) {
|
||||
if (n <= arr.length) {
|
||||
arr = arr.splice(arr.length - 1 - n);
|
||||
return arr;
|
||||
}
|
||||
const diff = n - arr.length;
|
||||
for (let i = 0; i < diff; i++) {
|
||||
arr.unshift(String.fromCharCode(0));
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* Base32 decode the init secret
|
||||
*
|
||||
* @param {secret}
|
||||
* @type {String}
|
||||
* @type {String}
|
||||
* @desc input param, the init secret
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
static byte_secret(secret) {
|
||||
return Base32.decode(secret.toUpperCase());
|
||||
}
|
||||
static byte_secret(secret) {
|
||||
return Base32.decode(secret.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
/* *
|
||||
* transfer the int type to BYTES type
|
||||
*
|
||||
* @param {input}
|
||||
* @type {int}
|
||||
* @type {int}
|
||||
* @desc input param, maybe counter or time
|
||||
*
|
||||
* @return {BYTES}
|
||||
*/
|
||||
static int_to_bytestring(input, padding=8) {
|
||||
let result = [];
|
||||
static int_to_bytestring(input, padding = 8) {
|
||||
let result = [];
|
||||
|
||||
while (0 != input) {
|
||||
result.push(String.fromCharCode(input & 0xFF));
|
||||
input >>= 8;
|
||||
}
|
||||
|
||||
result = result.reverse();
|
||||
result = Util.arr_rjust(result, padding).join("");
|
||||
|
||||
return result;
|
||||
while (input != 0) {
|
||||
result.push(String.fromCharCode(input & 0xFF));
|
||||
input >>= 8;
|
||||
}
|
||||
|
||||
/**
|
||||
result = result.reverse();
|
||||
result = Util.arr_rjust(result, padding).join('');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* *
|
||||
* format the time string to int
|
||||
*
|
||||
* @param {time}
|
||||
* @type {Date}
|
||||
* @type {Date}
|
||||
* @desc the time need to be format
|
||||
*
|
||||
* @param {interval}
|
||||
* @type {Int}
|
||||
* @type {Int}
|
||||
* @desc interval means the one-time password's life,
|
||||
* default to be 30.
|
||||
*
|
||||
* @return {Int}
|
||||
*/
|
||||
static timecode(time, interval) {
|
||||
let time_str = Date.parse(time).toString();
|
||||
static timecode(time, interval) {
|
||||
const time_str = Date.parse(time).toString();
|
||||
|
||||
// fotmat the time, the ms is not needed.
|
||||
let format_time = time_str.substring(0, time_str.length-3);
|
||||
// fotmat the time, the ms is not needed.
|
||||
const format_time = time_str.substring(0, time_str.length - 3);
|
||||
|
||||
return parseInt(parseInt(format_time) / interval);
|
||||
}
|
||||
|
||||
}
|
||||
return parseInt(parseInt(format_time) / interval);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user