browserify-steam-totp
Version:
Steam-style generate totp codes by secret
162 lines • 12.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SteamTotp = exports.SteamAuthenticator = void 0;
const buffer_1 = require("buffer");
const axios_1 = __importDefault(require("axios"));
const crypto_js_1 = __importDefault(require("crypto-js"));
class SteamAuthenticator {
constructor() {
this._DIGITS = 5;
this._PERIOD = 30;
this._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_1.Buffer.allocUnsafe(8);
buffer.writeUInt32BE(0, 0);
buffer.writeUint32BE(time, 4);
const hmac = crypto_js_1.default.HmacSHA1(crypto_js_1.default.lib.WordArray.create(buffer), keyData);
const hmacResult = crypto_js_1.default.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_1.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 = crypto_js_1.default.HmacSHA1(crypto_js_1.default.lib.WordArray.create(buffer), crypto_js_1.default.lib.WordArray.create(buffer_1.Buffer.from(identitySecret, 'base64')));
return crypto_js_1.default.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 = crypto_js_1.default.SHA1(steamid.toString())
.toString(crypto_js_1.default.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_1.default.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_1.default
.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 crypto_js_1.default.enc.Hex.parse(secret);
}
else {
return crypto_js_1.default.enc.Base64.parse(secret);
}
}
return secret;
}
}
exports.SteamAuthenticator = SteamAuthenticator;
exports.SteamTotp = new SteamAuthenticator();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlYW10b3RwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9zdGVhbXRvdHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsbUNBQWdDO0FBRWhDLGtEQUEwQjtBQUMxQiwwREFBaUM7QUFFakMsTUFBYSxrQkFBa0I7SUFBL0I7UUFDbUIsWUFBTyxHQUFHLENBQUMsQ0FBQztRQUNaLFlBQU8sR0FBRyxFQUFFLENBQUM7UUFDYixjQUFTLEdBQUcsNEJBQTRCLENBQUM7SUFnTTVELENBQUM7SUE5TEM7Ozs7T0FJRztJQUNILE9BQU8sQ0FBQyxVQUFtQjtRQUN6QixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILGdCQUFnQixDQUFDLE1BQWMsRUFBRSxVQUFVLEdBQUcsQ0FBQztRQUM3QyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRTdDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFakUsTUFBTSxNQUFNLEdBQUcsZUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNyQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUMzQixNQUFNLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUU5QixNQUFNLElBQUksR0FBRyxtQkFBUSxDQUFDLFFBQVEsQ0FDNUIsbUJBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFDckMsT0FBTyxDQUNSLENBQUM7UUFDRixNQUFNLFVBQVUsR0FBRyxtQkFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBRTNELE1BQU0sU0FBUyxHQUFHLEVBQUUsQ0FBQztRQUNyQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3BELFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO1NBQ3pFO1FBRUQsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDO1FBRXJELElBQUksUUFBUSxHQUNWLENBQUMsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2pDLENBQUMsQ0FBQyxTQUFTLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNyQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDcEMsQ0FBQyxTQUFTLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO1FBRWhDLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNkLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3JDLElBQUksSUFBSSxJQUFJLENBQUMs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