feat: changed TOTP and base32 library to self-writed special for quick-js, fixed BigInt incompatibility
This commit is contained in:
parent
ab13957cb0
commit
f16d7374f4
@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2023, Chris Umbel, Lisoveliy
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
@ -1,10 +0,0 @@
|
|||||||
# base32
|
|
||||||
|
|
||||||
Implementation of RFC 3548 Base32 encoding/decoding for zepp quickjs.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
import {encode, decode} from 'base32/index.js'
|
|
||||||
base32.encode('node');
|
|
||||||
// output: NZXWIZI=
|
|
||||||
base32.decode('NZXWIZI=');
|
|
||||||
//output: node
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2023, Chris Umbel, Lisoveliy
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export { encode, decode } from './lib/base32/base32.js'
|
|
@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2023, Chris Umbel, Lisoveliy
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var charTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
|
||||||
var byteTable = [
|
|
||||||
0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
|
||||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
|
||||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
||||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
|
||||||
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
|
||||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
|
||||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
|
||||||
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
||||||
];
|
|
||||||
|
|
||||||
function quintetCount(buff) {
|
|
||||||
var quintets = Math.floor(buff.length / 5);
|
|
||||||
return buff.length % 5 === 0 ? quintets : quintets + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function encode(plain) {
|
|
||||||
if (!Buffer.isBuffer(plain)) {
|
|
||||||
plain = new Buffer(plain);
|
|
||||||
}
|
|
||||||
var i = 0;
|
|
||||||
var j = 0;
|
|
||||||
var shiftIndex = 0;
|
|
||||||
var digit = 0;
|
|
||||||
var encoded = new Buffer(quintetCount(plain) * 8);
|
|
||||||
|
|
||||||
/* byte by byte isn't as pretty as quintet by quintet but tests a bit
|
|
||||||
faster. will have to revisit. */
|
|
||||||
while (i < plain.length) {
|
|
||||||
var current = plain[i];
|
|
||||||
|
|
||||||
if (shiftIndex > 3) {
|
|
||||||
digit = current & (0xff >> shiftIndex);
|
|
||||||
shiftIndex = (shiftIndex + 5) % 8;
|
|
||||||
digit = (digit << shiftIndex) | ((i + 1 < plain.length) ?
|
|
||||||
plain[i + 1] : 0) >> (8 - shiftIndex);
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
digit = (current >> (8 - (shiftIndex + 5))) & 0x1f;
|
|
||||||
shiftIndex = (shiftIndex + 5) % 8;
|
|
||||||
if (shiftIndex === 0) i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoded[j] = charTable.charCodeAt(digit);
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = j; i < encoded.length; i++) {
|
|
||||||
encoded[i] = 0x3d; //'='.charCodeAt(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
return encoded;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function decode(encoded) {
|
|
||||||
var shiftIndex = 0;
|
|
||||||
var plainDigit = 0;
|
|
||||||
var plainChar;
|
|
||||||
var plainPos = 0;
|
|
||||||
if (!Buffer.isBuffer(encoded)) {
|
|
||||||
encoded = new Buffer(encoded);
|
|
||||||
}
|
|
||||||
var decoded = new Buffer(Math.ceil(encoded.length * 5 / 8));
|
|
||||||
|
|
||||||
/* byte by byte isn't as pretty as octet by octet but tests a bit
|
|
||||||
faster. will have to revisit. */
|
|
||||||
for (var i = 0; i < encoded.length; i++) {
|
|
||||||
if (encoded[i] === 0x3d) { //'='
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var encodedByte = encoded[i] - 0x30;
|
|
||||||
|
|
||||||
if (encodedByte < byteTable.length) {
|
|
||||||
plainDigit = byteTable[encodedByte];
|
|
||||||
|
|
||||||
if (shiftIndex <= 3) {
|
|
||||||
shiftIndex = (shiftIndex + 5) % 8;
|
|
||||||
|
|
||||||
if (shiftIndex === 0) {
|
|
||||||
plainChar |= plainDigit;
|
|
||||||
decoded[plainPos] = plainChar;
|
|
||||||
plainPos++;
|
|
||||||
plainChar = 0;
|
|
||||||
} else {
|
|
||||||
plainChar |= 0xff & (plainDigit << (8 - shiftIndex));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
shiftIndex = (shiftIndex + 5) % 8;
|
|
||||||
plainChar |= 0xff & (plainDigit >>> shiftIndex);
|
|
||||||
decoded[plainPos] = plainChar;
|
|
||||||
plainPos++;
|
|
||||||
|
|
||||||
plainChar = 0xff & (plainDigit << (8 - shiftIndex));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error('Invalid input - it is not base32 encoded string');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return decoded.slice(0, plainPos);
|
|
||||||
};
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "base32",
|
|
||||||
"description": "Implementation RFC 3548 Base32 encoding/decoding for node.",
|
|
||||||
"version": "1.0.2-zepp",
|
|
||||||
"author": "Chris Umbel <chris@chrisumbel.com>",
|
|
||||||
"keywords": ["base32", "encoding"],
|
|
||||||
"main": "index.js",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git://github.com/chrisumbel/thirty-two.git"
|
|
||||||
}
|
|
||||||
}
|
|
54
lib/totp-quickjs/OTPGenerator.js
Normal file
54
lib/totp-quickjs/OTPGenerator.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { decode } from "./base32decoder.js";
|
||||||
|
import jsSHA from "jssha";
|
||||||
|
"use bigint"
|
||||||
|
/**
|
||||||
|
* get HOTP based on counter
|
||||||
|
* @param {BigInt} counter BigInt counter of HOTP
|
||||||
|
* @param {string} secret base32 encoded string
|
||||||
|
* @param {number} [digits=6] number of digits in OTP token
|
||||||
|
* @param {string} [hashType='SHA-1'] type of hash (more in jsSHA documentation)
|
||||||
|
* @returns HOTP string
|
||||||
|
*/
|
||||||
|
export function getHOTP(counter, secret, digits = 6, hashType = 'SHA-1'){
|
||||||
|
|
||||||
|
//Stage 1: Prepare data
|
||||||
|
const rawDataCounter = new DataView(new ArrayBuffer(8))
|
||||||
|
rawDataCounter.setUint32(0, counter >> 32)
|
||||||
|
rawDataCounter.setUint32(4, counter)
|
||||||
|
const bCounter = new Uint8Array(rawDataCounter.buffer)
|
||||||
|
|
||||||
|
const bSecret = new Uint8Array(decode(secret).match(/.{1,2}/g).map(chunk => parseInt(chunk, 16))); //confirmed
|
||||||
|
|
||||||
|
//Stage 2: Hash data
|
||||||
|
const jssha = new jsSHA(hashType, 'UINT8ARRAY')
|
||||||
|
jssha.setHMACKey(bSecret, 'UINT8ARRAY')
|
||||||
|
jssha.update(bCounter)
|
||||||
|
const hmacResult = jssha.getHMAC('UINT8ARRAY') //confirmed
|
||||||
|
|
||||||
|
//Stage 3: Dynamic truncate
|
||||||
|
const offsetB = hmacResult[19] & 0xf;
|
||||||
|
const P = hmacResult.slice(offsetB, offsetB + 4)
|
||||||
|
P[0] = P[0] & 0x7f;
|
||||||
|
|
||||||
|
//Stage 4: Format string
|
||||||
|
let res = (new DataView(P.buffer).getInt32(0) % Math.pow(10, digits)).toString()
|
||||||
|
while(res.length < digits)
|
||||||
|
res = '0' + res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get OTP based on current time
|
||||||
|
* @param {string} secret base32 encoded string
|
||||||
|
* @param {number} [digits=6] digits in OTP
|
||||||
|
* @param {number} [time=Date.now()] time for counter (default unix time epoch)
|
||||||
|
* @param {number} [fetchTime=30] period of token in seconds
|
||||||
|
* @param {number} [timeOffset=0] time offset for token in seconds
|
||||||
|
* @param {string} [hashType='SHA-1'] type of hash (more in jsSHA documentation)
|
||||||
|
* @returns TOTP string
|
||||||
|
*/
|
||||||
|
export function getTOTP(secret, digits = 6, time = Date.now(), fetchTime = 30, timeOffset = 0, hashType = 'SHA-1')
|
||||||
|
{
|
||||||
|
const unixTime = Math.round((time / 1000 + timeOffset) / fetchTime)
|
||||||
|
return getHOTP(BigInt(unixTime), secret, digits)
|
||||||
|
}
|
26
lib/totp-quickjs/base32decoder.js
Normal file
26
lib/totp-quickjs/base32decoder.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export function decode(base32) {
|
||||||
|
for (
|
||||||
|
var base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
|
||||||
|
bits = "",
|
||||||
|
hex = "",
|
||||||
|
i = 0;
|
||||||
|
i < base32.length;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
var val = base32chars.indexOf(base32.charAt(i).toUpperCase());
|
||||||
|
bits += leftpad(val.toString(2), 5, "0");
|
||||||
|
}
|
||||||
|
for (i = 0; i + 4 <= bits.length; i += 4) {
|
||||||
|
var chunk = bits.substr(i, 4);
|
||||||
|
hex += parseInt(chunk, 2).toString(16);
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
function leftpad(str, len, pad) {
|
||||||
|
return (
|
||||||
|
len + 1 >= str.length &&
|
||||||
|
(str = new Array(len + 1 - str.length).join(pad) + str),
|
||||||
|
str
|
||||||
|
);
|
||||||
|
}
|
61
lib/totp-quickjs/index.js
Normal file
61
lib/totp-quickjs/index.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { getHOTP } from "./OTPGenerator.js"
|
||||||
|
"use bigint"
|
||||||
|
/**
|
||||||
|
* TOTP instance
|
||||||
|
*/
|
||||||
|
export class TOTP{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} secret base32 encoded string
|
||||||
|
* @param {string} issuer issuer of TOTP
|
||||||
|
* @param {number} [digits=6] number of digits in OTP token
|
||||||
|
* @param {number} [fetchTime=30] period of token in seconds
|
||||||
|
* @param {number} [timeOffset=0] time offset for token in seconds
|
||||||
|
* @param {string} [hashType='SHA-1'] type of hash (more in jsSHA documentation)
|
||||||
|
*/
|
||||||
|
constructor(secret,
|
||||||
|
issuer,
|
||||||
|
digits = 6,
|
||||||
|
fetchTime = 30,
|
||||||
|
timeOffset = 0,
|
||||||
|
hashType = 'SHA-1')
|
||||||
|
{
|
||||||
|
this.secret = secret
|
||||||
|
this.issuer = issuer
|
||||||
|
this.digits = digits
|
||||||
|
this.fetchTime = fetchTime
|
||||||
|
this.timeOffset = timeOffset
|
||||||
|
this.hashType = hashType
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} time time for counter (default unix time epoch)
|
||||||
|
* @returns OTP instance
|
||||||
|
*/
|
||||||
|
getOTP(time = Date.now()){
|
||||||
|
const unixTime = (time / 1000 + this.timeOffset) / this.fetchTime
|
||||||
|
const otp = getHOTP(Math.floor(unixTime), this.secret, this.digits)
|
||||||
|
const expireTime = time +
|
||||||
|
(this.fetchTime -
|
||||||
|
(time / 1000 + this.timeOffset) %
|
||||||
|
this.fetchTime) * 1000
|
||||||
|
|
||||||
|
return new OTP(otp, expireTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for TOTP.getOTP result
|
||||||
|
*/
|
||||||
|
export class OTP{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} otp OTP string
|
||||||
|
* @param {number} expireTime time in seconds to reset OTP
|
||||||
|
*/
|
||||||
|
constructor(otp, expireTime)
|
||||||
|
{
|
||||||
|
this.otp = otp
|
||||||
|
this.expireTime = expireTime
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +0,0 @@
|
|||||||
export { HOTP } from './lib/hotp.js'
|
|
||||||
export { TOTP } from './lib/totp.js'
|
|
@ -1,72 +0,0 @@
|
|||||||
import { encode, decode } from '../../base32/index.js'
|
|
||||||
import jsSHA from 'jssha'
|
|
||||||
|
|
||||||
export class HOTP {
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} key secret key
|
|
||||||
* @param {*} digit lenth of otp code
|
|
||||||
*/
|
|
||||||
constructor(key, digit = 6) {
|
|
||||||
this.key = key;
|
|
||||||
this.digit = digit;
|
|
||||||
}
|
|
||||||
static encode(data){
|
|
||||||
return encode(data)
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* generate secret key
|
|
||||||
* @param {int} len
|
|
||||||
*/
|
|
||||||
static randomKey(len = 16) {
|
|
||||||
const str = Math.random().toString(36);
|
|
||||||
return encode(str).toString().substr(0, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* generate a OTP base on HMAC-SHA-1
|
|
||||||
* @param {int} movingFactor counter
|
|
||||||
*/
|
|
||||||
genOTP(movingFactor) {
|
|
||||||
const hmacSha = new jsSHA('SHA-1', 'BYTES');
|
|
||||||
hmacSha.setHMACKey(decode(this.key).toString(), 'BYTES');
|
|
||||||
|
|
||||||
const factorByte = this._factor2ByteText(movingFactor);
|
|
||||||
hmacSha.update(factorByte);
|
|
||||||
|
|
||||||
const hmac_result = hmacSha.getHMAC('BYTES');
|
|
||||||
return this._truncat(hmac_result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* verify a OPT code
|
|
||||||
* @param {string} opt opt code
|
|
||||||
* @param {int} movingFactor counter
|
|
||||||
*/
|
|
||||||
verify(opt, movingFactor) {
|
|
||||||
return opt === this.genOTP(movingFactor);
|
|
||||||
}
|
|
||||||
|
|
||||||
_truncat(hmac_result) {
|
|
||||||
const offset = hmac_result[19].charCodeAt() & 0xf;
|
|
||||||
const bin_code = (hmac_result[offset].charCodeAt() & 0x7f) << 24
|
|
||||||
| (hmac_result[offset + 1].charCodeAt() & 0xff) << 16
|
|
||||||
| (hmac_result[offset + 2].charCodeAt() & 0xff) << 8
|
|
||||||
| (hmac_result[offset + 3].charCodeAt() & 0xff);
|
|
||||||
let otp = (bin_code % 10 ** this.digit).toString();
|
|
||||||
while (otp.length < this.digit) {
|
|
||||||
otp = '0' + otp;
|
|
||||||
}
|
|
||||||
return otp;
|
|
||||||
}
|
|
||||||
|
|
||||||
_factor2ByteText(movingFactor) {
|
|
||||||
const text = new Array(8);
|
|
||||||
for (let i = text.length - 1; i >= 0; i--) {
|
|
||||||
text[i] = String.fromCharCode(movingFactor & 0xFF);
|
|
||||||
movingFactor >>= 8;
|
|
||||||
}
|
|
||||||
return text.join('');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
import { HOTP } from "./hotp.js";
|
|
||||||
|
|
||||||
export class TOTP extends HOTP {
|
|
||||||
constructor(key) {
|
|
||||||
super(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
genOTP(timeStep = 30, t0 = 0) {
|
|
||||||
const T = Math.floor((Date.now() / 1000 - t0) / timeStep);
|
|
||||||
return super.genOTP(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
verify(otp, timeStep = 30, t0 = 0) {
|
|
||||||
return otp === this.genOTP(timeStep, t0);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "totp.js",
|
|
||||||
"version": "1.0.1-zepp",
|
|
||||||
"description": "Two-factor authentication implementation in pure javascript. One-time password generator (HOTP/TOTP) with support for Google Authenticator. ",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "./node_modules/.bin/mocha"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/wuyanxin/totp.js.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"otp",
|
|
||||||
"hotp",
|
|
||||||
"totp",
|
|
||||||
"Two-factor authentication",
|
|
||||||
"Google authenticator"
|
|
||||||
],
|
|
||||||
"author": "wuyanxin",
|
|
||||||
"license": "MIT",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/wuyanxin/totp.js/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/wuyanxin/totp.js#readme",
|
|
||||||
"dependencies": {
|
|
||||||
"jssha": "^2.3.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"mocha": "^5.0.4"
|
|
||||||
}
|
|
||||||
}
|
|
@ -33,8 +33,9 @@ Page({
|
|||||||
const buttonHeight = height / 4;
|
const buttonHeight = height / 4;
|
||||||
const margin = 10;
|
const margin = 10;
|
||||||
let totpHeight = margin;
|
let totpHeight = margin;
|
||||||
|
|
||||||
for(let i = 0; i < buffer.length; i++){
|
for(let i = 0; i < buffer.length; i++){
|
||||||
|
console.log(buffer[i])
|
||||||
createWidget(widget.FILL_RECT, {
|
createWidget(widget.FILL_RECT, {
|
||||||
x: width / 2 - buttonWidth / 2,
|
x: width / 2 - buttonWidth / 2,
|
||||||
y: totpHeight,
|
y: totpHeight,
|
||||||
@ -53,7 +54,7 @@ Page({
|
|||||||
align_h: align.CENTER_H,
|
align_h: align.CENTER_H,
|
||||||
align_v: align.CENTER_V,
|
align_v: align.CENTER_V,
|
||||||
text_style: text_style.NONE,
|
text_style: text_style.NONE,
|
||||||
text: buffer[i].name
|
text: (buffer[i].expireTime - Date.now()) / 1000
|
||||||
})
|
})
|
||||||
createWidget(widget.TEXT, {
|
createWidget(widget.TEXT, {
|
||||||
x: 0,
|
x: 0,
|
||||||
@ -65,7 +66,7 @@ Page({
|
|||||||
align_h: align.CENTER_H,
|
align_h: align.CENTER_H,
|
||||||
align_v: align.CENTER_V,
|
align_v: align.CENTER_V,
|
||||||
text_style: text_style.NONE,
|
text_style: text_style.NONE,
|
||||||
text: buffer[i].data
|
text: buffer[i].otp
|
||||||
})
|
})
|
||||||
|
|
||||||
totpHeight += margin + buttonHeight;
|
totpHeight += margin + buttonHeight;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { TOTP } from "../../lib/totp.js/lib/totp";
|
import { TOTP } from "../../lib/totp-quickjs";
|
||||||
|
|
||||||
export class TOTPBuffer{
|
export class TOTPBuffer{
|
||||||
constructor(){
|
constructor(){
|
||||||
@ -6,15 +6,6 @@ export class TOTPBuffer{
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTOTPs(){
|
getTOTPs(){
|
||||||
return [new TOTPData("Contabo-Customer-Control-Panel-11755808: my.contabo.com", new TOTP(TOTP.encode('UU5WIIWKDNAHUNNL')).genOTP()),
|
return [new TOTP('JBSWY3DPEHPK3PXP').getOTP()]
|
||||||
new TOTPData("OTPData", new TOTP(TOTP.encode('LCHJZO23LT3Z2QYNYAYAJXH5HFDZ5YI2')).genOTP()),
|
|
||||||
new TOTPData("test", new TOTP(TOTP.encode('GAXHMZDEGJVG64LP')).genOTP())]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TOTPData{
|
|
||||||
constructor(name, data){
|
|
||||||
this.name = name;
|
|
||||||
this.data = data;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user