-
-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: totp code validation #1228
Conversation
🦋 Changeset detectedLatest commit: b01244d The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Fixes #1227 |
@pozylon thanks for the pr! A couple of changes are needed for the ci to pass so I can merge and release:
|
@pradel Done. |
@pozylon looks like with the upgrade, tests are failing |
@pradel The new version of speakeasy started to throw a custom exception when the token length did not match, I guarded it now so tests of two-factor passed locally but let's see what the workflow says. |
Codecov Report
@@ Coverage Diff @@
## master #1228 +/- ##
=======================================
Coverage 95.31% 95.32%
=======================================
Files 106 106
Lines 2391 2396 +5
Branches 511 503 -8
=======================================
+ Hits 2279 2284 +5
Misses 103 103
Partials 9 9
Continue to review full report at Codecov.
|
@pozylon this looks like a breaking change to me, some people may be catching some errors to return specific error messages to users, could we rather fix the tests or make this specific error silent? |
@pradel It's not breaking because version 1.3.1 of speakeasy did not throw any exception during token validation, https://github.com/Levminer/speakeasy/blob/1.3.1/main.js (before) vs |
@pradel So to outline the changes in speakeasy, it's 3 things:
exports.hotp.verifyDelta = hotpVerifyDelta = (options) => {
let i
// shadow options
options = Object.create(options)
// unpack options
let token = String(options.token)
const digits = parseInt(options.digits, 10) || 6
const window = parseInt(options.window, 10) || 0
const counter = parseInt(options.counter, 10) || 0
// fail if token is not of correct length
if (token.length !== digits) {
return
}
// parse token to integer
token = parseInt(token, 10)
// fail if token is NA
if (isNaN(token)) {
return
}
// loop from C to C + W inclusive
// this is a temporary fix becaouse wrong codes return a value too
// FIX THIS LATER
// eslint-disable-next-line no-unreachable-loop
for (i = counter; i <= counter + window; ++i) {
options.counter = i
// domain-specific constant-time comparison for integer codes
if (parseInt(exports.hotp(options), 10) === token) {
// found a matching code, return delta
return { delta: i - counter }
} else {
return { delta: i - counter }
}
}
// no codes have matched
} exports.hotp.verifyDelta = hotpVerifyDelta = (options) => {
let i
// shadow options
options = Object.create(options)
// unpack options
let token = String(options.token)
const digits = parseInt(options.digits, 10) || 6
const window = parseInt(options.window, 10) || 0
const counter = parseInt(options.counter, 10) || 0
// fail if token is not of correct length
if (token.length !== digits) {
throw new Error("@levminer/speakeasy - hotpVerifyDelta - Wrong toke length")
}
// parse token to integer
token = parseInt(token, 10)
// fail if token is NA
if (isNaN(token)) {
throw new Error("@levminer/speakeasy - hotpVerifyDelta - Token is not a number")
}
// loop from C to C + W inclusive
for (i = counter; i <= counter + window; ++i) {
options.counter = i
// domain-specific constant-time comparison for integer codes
if (parseInt(exports.hotp(options), 10) === token) {
// found a matching code, return delta
return { delta: i - counter }
}
}
// no codes have matched
} |
Okay thanks for the explanation, let's go with it then! |
No description provided.