authy-extractor
Version:
Extract 2FA tokens from Authy
76 lines (75 loc) • 3.56 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.exportQR = exports.exportJSON = exports.exportCSV = exports.generateTokenURI = void 0;
const qrcode_1 = __importDefault(require("qrcode"));
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
// https://github.com/google/google-authenticator/wiki/Key-Uri-Format
function generateTokenURI(token) {
const period = token.digits === 7 ? 10 : 30;
const name = encodeURIComponent(token.name);
if (token.issuer === null) {
return `otpauth://totp/${name}?secret=${token.decrypted_seed}&digits=${token.digits}&period=${period}`;
}
const issuer = encodeURIComponent(token.issuer);
return `otpauth://totp/${issuer}%3A%20${name}?secret=${token.decrypted_seed}&issuer=${issuer}&digits=${token.digits}&period=${period}`;
}
exports.generateTokenURI = generateTokenURI;
function exportCSV(tokens, output) {
return __awaiter(this, void 0, void 0, function* () {
const outputFile = path_1.default.join(output, 'out.csv');
const headers = ['Account name', 'Issuer', 'Secret', 'URI'];
const rows = tokens
.map((token) => {
const { name, issuer, decrypted_seed } = token;
const uri = generateTokenURI(token);
// https://stackoverflow.com/a/4617967
const fields = [name, issuer, decrypted_seed, uri].map((field) => {
if (field === null)
return '""';
return `"${field.toString().replace(new RegExp('"', 'g'), '""')}"`;
});
return fields.join(',');
})
.join('\r\n');
const csv = `${headers}\r\n${rows}`;
yield fs_1.promises.writeFile(outputFile, csv);
});
}
exports.exportCSV = exportCSV;
function exportJSON(tokens, output) {
return __awaiter(this, void 0, void 0, function* () {
const outputFile = path_1.default.join(output, 'out.json');
const json = JSON.stringify(tokens.map((token) => ({
name: token.name,
issuer: token.issuer,
secret: token.decrypted_seed,
uri: generateTokenURI(token),
})), null, 2);
yield fs_1.promises.writeFile(outputFile, json);
});
}
exports.exportJSON = exportJSON;
function exportQR(tokens, output, correction) {
return __awaiter(this, void 0, void 0, function* () {
return Promise.all(tokens.map((token) => {
const outputFile = path_1.default.join(output, `${token.name}.png`);
return qrcode_1.default.toFile(outputFile, generateTokenURI(token), {
errorCorrectionLevel: correction,
});
}));
});
}
exports.exportQR = exportQR;