Fixes #2446 hotp otpauth uri validation (#2614)

This commit is contained in:
alleria173 2026-07-03 09:54:38 +01:00 committed by GitHub
parent 6f95a2e17d
commit 3104e6073f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 83 additions and 8 deletions

View File

@ -27,17 +27,23 @@ class GenerateHOTP extends Operation {
{
"name": "Name",
"type": "string",
"value": ""
"value": "Account",
"allowEmpty": false
},
{
"name": "Code length",
"type": "number",
"value": 6
"value": 6,
"min": 6,
"max": 8,
"integer": true
},
{
"name": "Counter",
"type": "number",
"value": 0
"value": 0,
"min": 0,
"integer": true
}
];
}
@ -47,7 +53,9 @@ class GenerateHOTP extends Operation {
*/
run(input, args) {
const secretStr = new TextDecoder("utf-8").decode(input).trim();
const secret = secretStr ? secretStr.toUpperCase().replace(/\s+/g, "") : "";
const secret = secretStr ?
OTPAuth.Secret.fromBase32(secretStr.toUpperCase().replace(/\s+/g, "")) :
new OTPAuth.Secret();
const hotp = new OTPAuth.HOTP({
issuer: "",
@ -55,7 +63,7 @@ class GenerateHOTP extends Operation {
algorithm: "SHA1",
digits: args[1],
counter: args[2],
secret: OTPAuth.Secret.fromBase32(secret)
secret
});
const uri = hotp.toString();

View File

@ -605,8 +605,9 @@ Top Drawer`, {
it("Generate HOTP", () => {
const result = chef.generateHOTP("JBSWY3DPEHPK3PXP", {
name: "Account",
});
const expected = `URI: otpauth://hotp/?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0
const expected = `URI: otpauth://hotp/Account?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0
Password: 282760`;
assert.strictEqual(result.toString(), expected);

View File

@ -12,11 +12,77 @@ TestRegister.addTests([
{
name: "Generate HOTP",
input: "JBSWY3DPEHPK3PXP",
expectedOutput: `URI: otpauth://hotp/?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0\n\nPassword: 282760`,
expectedOutput: `URI: otpauth://hotp/Account?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0\n\nPassword: 282760`,
recipeConfig: [
{
op: "Generate HOTP",
args: ["", 6, 0], // [Name, Code length, Counter]
args: ["Account", 6, 0], // [Name, Code length, Counter]
},
],
},
{
name: "Generate HOTP - empty name rejected",
input: "JBSWY3DPEHPK3PXP",
expectedOutput: "Name cannot be empty.",
recipeConfig: [
{
op: "Generate HOTP",
args: ["", 6, 0],
},
],
},
{
name: "Generate HOTP - code length below minimum rejected",
input: "JBSWY3DPEHPK3PXP",
expectedOutput: "Code length must be greater than or equal to 6.",
recipeConfig: [
{
op: "Generate HOTP",
args: ["Account", -6, 0],
},
],
},
{
name: "Generate HOTP - code length above maximum rejected",
input: "JBSWY3DPEHPK3PXP",
expectedOutput: "Code length must be less than or equal to 8.",
recipeConfig: [
{
op: "Generate HOTP",
args: ["Account", 9, 0],
},
],
},
{
name: "Generate HOTP - non-integer code length rejected",
input: "JBSWY3DPEHPK3PXP",
expectedOutput: "Code length must be an integer.",
recipeConfig: [
{
op: "Generate HOTP",
args: ["Account", 6.5, 0],
},
],
},
{
name: "Generate HOTP - negative counter rejected",
input: "JBSWY3DPEHPK3PXP",
expectedOutput: "Counter must be greater than or equal to 0.",
recipeConfig: [
{
op: "Generate HOTP",
args: ["Account", 6, -1],
},
],
},
{
name: "Generate HOTP - special characters in name are URI-encoded",
input: "JBSWY3DPEHPK3PXP",
expectedOutput: `URI: otpauth://hotp/user%40example.com?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0\n\nPassword: 282760`,
recipeConfig: [
{
op: "Generate HOTP",
args: ["user@example.com", 6, 0],
},
],
},