UNPKG

browserify-steam-totp

Version:
153 lines 12.3 kB
import { Buffer } from 'buffer'; import axios from 'axios'; import CryptoJS from 'crypto-js'; export class SteamAuthenticator { _DIGITS = 5; _PERIOD = 30; _ALPHABET = '23456789BCDFGHJKMNPQRTVWXY'; /** * Get the current time in seconds, optionally with a time offset * @param timeOffset Time offset in seconds (optional) * @returns The current time in seconds `number` */ getTime(timeOffset) { return Math.floor(Date.now() / 1000) + (timeOffset || 0); } /** * Generate a one-time authentication code (TOTP) * @param secret The secret key as a string * @param timeOffset Time offset in seconds (optional) * @returns The generated one-time authentication code `string` */ generateAuthCode(secret, timeOffset = 0) { const keyData = this.bufferizeSecret(secret); const time = Math.floor(this.getTime(timeOffset) / this._PERIOD); const buffer = Buffer.allocUnsafe(8); buffer.writeUInt32BE(0, 0); buffer.writeUint32BE(time, 4); const hmac = CryptoJS.HmacSHA1(CryptoJS.lib.WordArray.create(buffer), keyData); const hmacResult = CryptoJS.enc.Hex.parse(hmac.toString()); const hmacBytes = []; for (let i = 0; i < hmacResult.words.length * 4; i++) { hmacBytes.push((hmacResult.words[i >> 2] >> (24 - (i % 4) * 8)) & 0xff); } const start = hmacBytes[hmacBytes.length - 1] & 0x0f; let material = ((hmacBytes[start] & 0x7f) << 24) | ((hmacBytes[start + 1] & 0xff) << 16) | ((hmacBytes[start + 2] & 0xff) << 8) | (hmacBytes[start + 3] & 0xff); let code = ''; for (let i = 0; i < this._DIGITS; i++) { code += this._ALPHABET[material % this._ALPHABET.length]; material = Math.floor(material / this._ALPHABET.length); } return code; } /** * Generate a confirmation key for Steam * @param identitySecret The secret key for Steam authentication * @param time Unix time in seconds * @param tag The tag for the key (e.g., 'conf') * @returns The confirmation key `string` */ generateConfirmationKey(identitySecret, time, tag) { let dataLen = 8; if (tag) { dataLen += tag.length > 32 ? 32 : tag.length; } const buffer = Buffer.allocUnsafe(dataLen); if (typeof buffer.writeBigUInt64BE === 'function') { buffer.writeBigUInt64BE(BigInt(time), 0); } else { buffer.writeUInt32BE(0, 0); buffer.writeUInt32BE(time, 4); } if (tag) { buffer.write(tag, 8); } const hmac = CryptoJS.HmacSHA1(CryptoJS.lib.WordArray.create(buffer), CryptoJS.lib.WordArray.create(Buffer.from(identitySecret, 'base64'))); return CryptoJS.enc.Base64.stringify(hmac); } /** * Generate the device ID based on the SteamID * @param steamid The user's SteamID * @returns The device ID `string` */ getDeviceId(steamid) { const hash = CryptoJS.SHA1(steamid.toString()) .toString(CryptoJS.enc.Hex) .replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12}).*$/, '$1-$2-$3-$4-$5'); return `android:${hash}`; } /** * Asynchronously get the time offset from Steam servers * @returns An object with the time offset and the request time */ async getTimeOffsetAsync() { try { const start = Date.now(); const response = await axios.post('https://api.steampowered.com/ITwoFactorService/QueryTime/v1/', null, { headers: { 'Content-Length': '0', }, }); const data = response.data.response; if (!data || !data.server_time) { throw new Error('Malformed response'); } const end = Date.now(); const offset = data.server_time - this.getTime(); return { offset, time: end - start, }; } catch (error) { throw new Error(error.message || 'Request failed'); } } /** * Get the time offset from Steam servers using a callback * @param callback The callback function to return the error or result */ getTimeOffset(callback) { const start = Date.now(); axios .post('https://api.steampowered.com/ITwoFactorService/QueryTime/v1/', null, { headers: { 'Content-Length': '0', }, }) .then((response) => { const data = response.data.response; if (!data || !data.server_time) { return callback(new Error('Malformed response')); } const end = Date.now(); const offset = data.server_time - this.getTime(); callback(null, offset, end - start); }) .catch((error) => { callback(new Error(error.message || 'Request failed')); }); } /** * Convert the secret string into a format that can be used by CryptoJS * @param secret The secret string (in hex or base64) * @returns The parsed secret as a CryptoJS `WordArray` */ bufferizeSecret(secret) { if (typeof secret === 'string') { if (secret.match(/[0-9a-f]{40}/i)) { return CryptoJS.enc.Hex.parse(secret); } else { return CryptoJS.enc.Base64.parse(secret); } } return secret; } } export const SteamTotp = new SteamAuthenticator(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlYW10b3RwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9zdGVhbXRvdHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUVoQyxPQUFPLEtBQUssTUFBTSxPQUFPLENBQUM7QUFDMUIsT0FBTyxRQUFRLE1BQU0sV0FBVyxDQUFDO0FBRWpDLE1BQU0sT0FBTyxrQkFBa0I7SUFDWixPQUFPLEdBQUcsQ0FBQyxDQUFDO0lBQ1osT0FBTyxHQUFHLEVBQUUsQ0FBQztJQUNiLFNBQVMsR0FBRyw0QkFBNEIsQ0FBQztJQUUxRDs7OztPQUlHO0lBQ0gsT0FBTyxDQUFDLFVBQW1CO1FBQ3pCLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDM0QsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsZ0JBQWdCLENBQUMsTUFBYyxFQUFFLFVBQVUsR0FBRyxDQUFDO1FBQzdDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFN0MsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUVqRSxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzNCLE1BQU0sQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRTlCLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQzVCLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFDckMsT0FBTyxDQUNSLENBQUM7UUFDRixNQUFNLFVBQVUsR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFFM0QsTUFBTSxTQUFTLEdBQUcsRUFBRSxDQUFDO1FBQ3JCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDcEQsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7U0FDekU7UUFFRCxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUM7UUFFckQsSUFBSSxRQUFRLEdBQ1YsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDakMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ3JDLENBQUMsQ0FBQyxTQUFTLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNwQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7UUFFaEMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ2QsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUs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