homebridge-sense-energy-monitor
Version:
Enhanced Homebridge plugin for Sense Home Energy Monitor with comprehensive API integration and real-time monitoring
38 lines • 1.52 kB
JavaScript
import { createHmac } from 'node:crypto';
const BASE32_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
export function base32Decode(encoded) {
let bits = '';
for (const char of encoded) {
const val = BASE32_CHARS.indexOf(char);
if (val === -1) {
continue;
}
bits += val.toString(2).padStart(5, '0');
}
const bytes = [];
for (let i = 0; i + 8 <= bits.length; i += 8) {
bytes.push(parseInt(bits.substring(i, i + 8), 2));
}
return Buffer.from(bytes);
}
// RFC 6238 TOTP: HMAC-SHA1, 30-second window, 6 digits.
// `now` is injectable for testing.
export function generateTotp(secret, now = Date.now()) {
const normalized = secret.replace(/\s/g, '').toUpperCase();
const key = base32Decode(normalized);
if (key.length === 0) {
throw new Error('Invalid TOTP secret: base32 decoding produced no data');
}
const timeCounter = Math.floor(now / 1000 / 30);
const counterBuffer = Buffer.alloc(8);
counterBuffer.writeUInt32BE(Math.floor(timeCounter / 0x100000000), 0);
counterBuffer.writeUInt32BE(timeCounter % 0x100000000, 4);
const hash = createHmac('sha1', key).update(counterBuffer).digest();
const offset = hash[hash.length - 1] & 0xf;
const binary = ((hash[offset] & 0x7f) << 24) |
((hash[offset + 1] & 0xff) << 16) |
((hash[offset + 2] & 0xff) << 8) |
(hash[offset + 3] & 0xff);
return (binary % 1000000).toString().padStart(6, '0');
}
//# sourceMappingURL=totp.js.map