Merge pull request #1966 from exactlyaron/fix/generate-totp-issue-1964

Fix Generate TOTP & HOPT
This commit is contained in:
a3957273 2025-02-15 23:06:55 +00:00 committed by GitHub
commit 95c6406d05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 5247 additions and 3267 deletions

8416
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -160,7 +160,7 @@
"notepack.io": "^3.0.1",
"ntlm": "^0.1.3",
"nwmatcher": "^1.4.4",
"otp": "0.1.3",
"otpauth": "9.3.6",
"path": "^0.12.7",
"popper.js": "^1.16.1",
"process": "^0.11.10",

View file

@ -5,16 +5,14 @@
*/
import Operation from "../Operation.mjs";
import otp from "otp";
import ToBase32 from "./ToBase32.mjs";
import * as OTPAuth from "otpauth";
/**
* Generate HOTP operation
*/
class GenerateHOTP extends Operation {
/**
* GenerateHOTP constructor
*
*/
constructor() {
super();
@ -31,11 +29,6 @@ class GenerateHOTP extends Operation {
"type": "string",
"value": ""
},
{
"name": "Key size",
"type": "number",
"value": 32
},
{
"name": "Code length",
"type": "number",
@ -50,21 +43,26 @@ class GenerateHOTP extends Operation {
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*
*/
run(input, args) {
const otpObj = otp({
name: args[0],
keySize: args[1],
codeLength: args[2],
secret: (new ToBase32).run(input, []).split("=")[0],
});
const counter = args[3];
return `URI: ${otpObj.hotpURL}\n\nPassword: ${otpObj.hotp(counter)}`;
}
const secretStr = new TextDecoder("utf-8").decode(input).trim();
const secret = secretStr ? secretStr.toUpperCase().replace(/\s+/g, "") : "";
const hotp = new OTPAuth.HOTP({
issuer: "",
label: args[0],
algorithm: "SHA1",
digits: args[1],
counter: args[2],
secret: OTPAuth.Secret.fromBase32(secret)
});
const uri = hotp.toString();
const code = hotp.generate();
return `URI: ${uri}\n\nPassword: ${code}`;
}
}
export default GenerateHOTP;

View file

@ -5,20 +5,17 @@
*/
import Operation from "../Operation.mjs";
import otp from "otp";
import ToBase32 from "./ToBase32.mjs";
import * as OTPAuth from "otpauth";
/**
* Generate TOTP operation
*/
class GenerateTOTP extends Operation {
/**
* GenerateTOTP constructor
*
*/
constructor() {
super();
this.name = "Generate TOTP";
this.module = "Default";
this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
@ -31,11 +28,6 @@ class GenerateTOTP extends Operation {
"type": "string",
"value": ""
},
{
"name": "Key size",
"type": "number",
"value": 32
},
{
"name": "Code length",
"type": "number",
@ -55,22 +47,27 @@ class GenerateTOTP extends Operation {
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*
*/
run(input, args) {
const otpObj = otp({
name: args[0],
keySize: args[1],
codeLength: args[2],
secret: (new ToBase32).run(input, []).split("=")[0],
epoch: args[3],
timeSlice: args[4]
});
return `URI: ${otpObj.totpURL}\n\nPassword: ${otpObj.totp()}`;
}
const secretStr = new TextDecoder("utf-8").decode(input).trim();
const secret = secretStr ? secretStr.toUpperCase().replace(/\s+/g, "") : "";
const totp = new OTPAuth.TOTP({
issuer: "",
label: args[0],
algorithm: "SHA1",
digits: args[1],
period: args[3],
epoch: args[2] * 1000, // Convert seconds to milliseconds
secret: OTPAuth.Secret.fromBase32(secret)
});
const uri = totp.toString();
const code = totp.generate();
return `URI: ${uri}\n\nPassword: ${code}`;
}
}
export default GenerateTOTP;

View file

@ -575,12 +575,11 @@ Top Drawer`, {
}),
it("Generate HOTP", () => {
const result = chef.generateHOTP("Cut The Mustard", {
name: "colonel",
const result = chef.generateHOTP("JBSWY3DPEHPK3PXP", {
});
const expected = `URI: otpauth://hotp/colonel?secret=IN2XIICUNBSSATLVON2GC4TE
const expected = `URI: otpauth://hotp/?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0
Password: 034148`;
Password: 282760`;
assert.strictEqual(result.toString(), expected);
}),

View file

@ -11,12 +11,12 @@ import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Generate HOTP",
input: "12345678901234567890",
expectedOutput: "URI: otpauth://hotp/OTPAuthentication?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ\n\nPassword: 755224",
input: "JBSWY3DPEHPK3PXP",
expectedOutput: `URI: otpauth://hotp/?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0\n\nPassword: 282760`,
recipeConfig: [
{
op: "Generate HOTP",
args: ["", 32, 6, 0],
args: ["", 6, 0], // [Name, Code length, Counter]
},
],
},