2025-03-17 15:30:03 +03:00
|
|
|
import { decodeProto, TYPES } from "../../lib/protobuf-decoder/protobufDecoder";
|
2024-12-30 01:05:30 +03:00
|
|
|
import { TOTP } from "../../lib/totp-quickjs";
|
2025-03-17 15:30:03 +03:00
|
|
|
import { base64decode, encode } from "../../lib/totp-quickjs/base32decoder";
|
2024-12-30 01:05:30 +03:00
|
|
|
|
2025-02-28 23:32:54 +03:00
|
|
|
const otpauthScheme = "otpauth:/";
|
|
|
|
const googleMigrationScheme = "otpauth-migration:/";
|
2024-12-30 01:05:30 +03:00
|
|
|
|
2025-01-13 02:35:18 +03:00
|
|
|
export function getTOTPByLink(link) {
|
2025-02-28 23:32:54 +03:00
|
|
|
if(link.includes(otpauthScheme))
|
|
|
|
return getByOtpauthScheme(link)
|
|
|
|
if(link.includes(googleMigrationScheme))
|
|
|
|
return getByGoogleMigrationScheme(link)
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getHashType(algorithm) {
|
|
|
|
if (algorithm == "SHA1") return "SHA-1";
|
|
|
|
if (algorithm == "SHA256") return "SHA-256";
|
|
|
|
if (algorithm == "SHA512") return "SHA-512";
|
|
|
|
else return "SHA-1";
|
|
|
|
}
|
|
|
|
|
|
|
|
function getByOtpauthScheme(link){
|
2025-02-26 00:33:40 +03:00
|
|
|
try {
|
2025-02-28 23:32:54 +03:00
|
|
|
let args = link.split("/", otpauthScheme.length);
|
2025-02-26 00:33:40 +03:00
|
|
|
let type = args[2]; //Returns 'hotp' or 'totp'
|
|
|
|
let issuer = args[3].split(":")[0]?.split("?")[0]; //Returns issuer
|
|
|
|
let client =
|
|
|
|
args[3].split(":")[1]?.split("?")[0] ??
|
|
|
|
args[3].split(":")[0]?.split("?")[0]; //Returns client
|
|
|
|
let secret = args[3].split("secret=")[1]?.split("&")[0]; //Returns secret
|
|
|
|
let period = args[3].split("period=")[1]?.split("&")[0]; //Returns period
|
|
|
|
let digits = args[3].split("digits=")[1]?.split("&")[0]; //Returns digits
|
|
|
|
let algorithm = args[3].split("algorithm=")[1]?.split("&")[0]; //Returns algorithm
|
2024-12-30 01:05:30 +03:00
|
|
|
|
2025-02-26 00:33:40 +03:00
|
|
|
if (type.toLowerCase() != "totp")
|
|
|
|
throw new Error("Type is not valid, requires 'TOTP'");
|
2024-12-30 01:05:30 +03:00
|
|
|
|
2025-02-26 00:33:40 +03:00
|
|
|
if (secret === undefined) throw new Error("Secret not defined");
|
2024-12-30 01:05:30 +03:00
|
|
|
|
2025-02-26 02:28:30 +03:00
|
|
|
if(issuer == client){
|
2025-03-17 15:30:03 +03:00
|
|
|
issuer = args[3].split("issuer=")[1]?.split("&")[0];
|
2025-02-26 02:28:30 +03:00
|
|
|
}
|
|
|
|
|
2025-02-26 02:46:16 +03:00
|
|
|
issuer = decodeURIComponent(issuer);
|
|
|
|
client = decodeURIComponent(client);
|
2025-02-26 02:36:43 +03:00
|
|
|
|
2025-02-26 00:33:40 +03:00
|
|
|
return new TOTP(
|
|
|
|
secret,
|
|
|
|
issuer,
|
|
|
|
client,
|
|
|
|
digits,
|
|
|
|
period,
|
|
|
|
0,
|
|
|
|
getHashType(algorithm)
|
|
|
|
);
|
|
|
|
} catch (err) {
|
2025-02-26 02:46:16 +03:00
|
|
|
console.log(err)
|
2025-02-26 00:33:40 +03:00
|
|
|
return null;
|
|
|
|
}
|
2024-12-30 01:05:30 +03:00
|
|
|
}
|
|
|
|
|
2025-02-28 23:32:54 +03:00
|
|
|
function getByGoogleMigrationScheme(link){
|
2025-03-17 13:37:12 +03:00
|
|
|
|
|
|
|
let data = link.split("data=")[1]; //Returns base64 encoded data
|
2025-03-01 22:58:48 +03:00
|
|
|
data = decodeURIComponent(data);
|
|
|
|
let decode = base64decode(data);
|
2025-03-17 13:37:12 +03:00
|
|
|
let proto = decodeProto(decode);
|
2025-03-17 15:30:03 +03:00
|
|
|
|
|
|
|
let protoTotps = [];
|
|
|
|
|
|
|
|
proto.parts.forEach(part => {
|
|
|
|
if(part.type == TYPES.LENDELIM){
|
|
|
|
protoTotps.push(decodeProto(part.value));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let totps = [];
|
|
|
|
protoTotps.forEach(x => {
|
|
|
|
let type = x.parts.filter(x => x.index == 6)[0]; //find type of OTP
|
|
|
|
if(type.value !== '2'){
|
|
|
|
console.log("ERR: it's a not TOTP record")
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let secret = x.parts.filter(x => x.index == 1)[0].value;
|
|
|
|
secret = encode(secret);
|
|
|
|
|
|
|
|
let name = bytesToString(x.parts.filter(x => x.index == 2)[0].value);
|
|
|
|
let issuer = bytesToString(x.parts.filter(x => x.index == 3)[0].value);
|
|
|
|
|
|
|
|
totps.push(new TOTP(
|
|
|
|
secret,
|
|
|
|
issuer,
|
|
|
|
name,
|
|
|
|
6,
|
|
|
|
30,
|
|
|
|
0,
|
|
|
|
"SHA-1"
|
|
|
|
));
|
|
|
|
});
|
|
|
|
|
|
|
|
return totps;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
function bytesToString(bytes) {
|
|
|
|
let str = '';
|
|
|
|
for (let i = 0; i < bytes.length; i++) {
|
|
|
|
str += String.fromCharCode(bytes[i]);
|
|
|
|
}
|
|
|
|
return str;
|
2025-02-28 23:32:54 +03:00
|
|
|
}
|