validateCode method
Validates TOTP code with ±1 time window (90-second tolerance).
Implementation
Future<bool> validateCode(String inputCode) async {
final secret = (await _resolveSecret())?.toUpperCase();
if (secret == null || secret.isEmpty) {
log('No TOTP secret found.');
return false;
}
final cleanCode = inputCode.trim();
if (cleanCode.length != _digits || !RegExp(r'^\d+$').hasMatch(cleanCode)) {
log('Invalid code format: $cleanCode');
return false;
}
// Use milliseconds since epoch (most otp packages expect ms)
final nowMs = DateTime.now().millisecondsSinceEpoch;
// check -1, 0, +1 windows
for (int offset = -1; offset <= 1; offset++) {
final testTimeMs = nowMs + (offset * _period * 1000);
final expected = OTP.generateTOTPCodeString(
secret,
testTimeMs, // milliseconds
interval: _period,
length: _digits,
algorithm: Algorithm.SHA1,
isGoogle: true,
);
log('offset=$offset, testTimeMs=$testTimeMs, expected=$expected');
if (_constantTimeEquals(expected, cleanCode)) {
log('TOTP valid (offset $offset)');
return true;
}
}
log('TOTP code invalid. Current nowMs=$nowMs, entered=$cleanCode');
return false;
}