Skip to content

Commit 3104e60

Browse files
authored
Fixes #2446 hotp otpauth uri validation (#2614)
1 parent 6f95a2e commit 3104e60

3 files changed

Lines changed: 83 additions & 8 deletions

File tree

src/core/operations/GenerateHOTP.mjs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,23 @@ class GenerateHOTP extends Operation {
2727
{
2828
"name": "Name",
2929
"type": "string",
30-
"value": ""
30+
"value": "Account",
31+
"allowEmpty": false
3132
},
3233
{
3334
"name": "Code length",
3435
"type": "number",
35-
"value": 6
36+
"value": 6,
37+
"min": 6,
38+
"max": 8,
39+
"integer": true
3640
},
3741
{
3842
"name": "Counter",
3943
"type": "number",
40-
"value": 0
44+
"value": 0,
45+
"min": 0,
46+
"integer": true
4147
}
4248
];
4349
}
@@ -47,15 +53,17 @@ class GenerateHOTP extends Operation {
4753
*/
4854
run(input, args) {
4955
const secretStr = new TextDecoder("utf-8").decode(input).trim();
50-
const secret = secretStr ? secretStr.toUpperCase().replace(/\s+/g, "") : "";
56+
const secret = secretStr ?
57+
OTPAuth.Secret.fromBase32(secretStr.toUpperCase().replace(/\s+/g, "")) :
58+
new OTPAuth.Secret();
5159

5260
const hotp = new OTPAuth.HOTP({
5361
issuer: "",
5462
label: args[0],
5563
algorithm: "SHA1",
5664
digits: args[1],
5765
counter: args[2],
58-
secret: OTPAuth.Secret.fromBase32(secret)
66+
secret
5967
});
6068

6169
const uri = hotp.toString();

tests/node/tests/operations.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,9 @@ Top Drawer`, {
605605

606606
it("Generate HOTP", () => {
607607
const result = chef.generateHOTP("JBSWY3DPEHPK3PXP", {
608+
name: "Account",
608609
});
609-
const expected = `URI: otpauth://hotp/?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0
610+
const expected = `URI: otpauth://hotp/Account?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0
610611
611612
Password: 282760`;
612613
assert.strictEqual(result.toString(), expected);

tests/operations/tests/OTP.mjs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,77 @@ TestRegister.addTests([
1212
{
1313
name: "Generate HOTP",
1414
input: "JBSWY3DPEHPK3PXP",
15-
expectedOutput: `URI: otpauth://hotp/?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0\n\nPassword: 282760`,
15+
expectedOutput: `URI: otpauth://hotp/Account?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0\n\nPassword: 282760`,
1616
recipeConfig: [
1717
{
1818
op: "Generate HOTP",
19-
args: ["", 6, 0], // [Name, Code length, Counter]
19+
args: ["Account", 6, 0], // [Name, Code length, Counter]
20+
},
21+
],
22+
},
23+
{
24+
name: "Generate HOTP - empty name rejected",
25+
input: "JBSWY3DPEHPK3PXP",
26+
expectedOutput: "Name cannot be empty.",
27+
recipeConfig: [
28+
{
29+
op: "Generate HOTP",
30+
args: ["", 6, 0],
31+
},
32+
],
33+
},
34+
{
35+
name: "Generate HOTP - code length below minimum rejected",
36+
input: "JBSWY3DPEHPK3PXP",
37+
expectedOutput: "Code length must be greater than or equal to 6.",
38+
recipeConfig: [
39+
{
40+
op: "Generate HOTP",
41+
args: ["Account", -6, 0],
42+
},
43+
],
44+
},
45+
{
46+
name: "Generate HOTP - code length above maximum rejected",
47+
input: "JBSWY3DPEHPK3PXP",
48+
expectedOutput: "Code length must be less than or equal to 8.",
49+
recipeConfig: [
50+
{
51+
op: "Generate HOTP",
52+
args: ["Account", 9, 0],
53+
},
54+
],
55+
},
56+
{
57+
name: "Generate HOTP - non-integer code length rejected",
58+
input: "JBSWY3DPEHPK3PXP",
59+
expectedOutput: "Code length must be an integer.",
60+
recipeConfig: [
61+
{
62+
op: "Generate HOTP",
63+
args: ["Account", 6.5, 0],
64+
},
65+
],
66+
},
67+
{
68+
name: "Generate HOTP - negative counter rejected",
69+
input: "JBSWY3DPEHPK3PXP",
70+
expectedOutput: "Counter must be greater than or equal to 0.",
71+
recipeConfig: [
72+
{
73+
op: "Generate HOTP",
74+
args: ["Account", 6, -1],
75+
},
76+
],
77+
},
78+
{
79+
name: "Generate HOTP - special characters in name are URI-encoded",
80+
input: "JBSWY3DPEHPK3PXP",
81+
expectedOutput: `URI: otpauth://hotp/user%40example.com?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0\n\nPassword: 282760`,
82+
recipeConfig: [
83+
{
84+
op: "Generate HOTP",
85+
args: ["user@example.com", 6, 0],
2086
},
2187
],
2288
},

0 commit comments

Comments
 (0)