176 lines
5.0 KiB
JavaScript
176 lines
5.0 KiB
JavaScript
function TS_decrypt(input, secret, callback, table, id) {
|
|
// Accept objects or plaintext strings. Also support legacy RSA{...} AES-encrypted entries.
|
|
var __ts_sync = true;
|
|
if (typeof input !== "string") {
|
|
try {
|
|
callback(input, false);
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
return __ts_sync;
|
|
}
|
|
|
|
// Legacy encrypted format: RSA{...}
|
|
if (
|
|
input.startsWith("RSA{") &&
|
|
input.endsWith("}") &&
|
|
typeof CryptoJS !== "undefined"
|
|
) {
|
|
try {
|
|
var data = input.slice(4, -1);
|
|
var words = CryptoJS.AES.decrypt(data, secret);
|
|
var decryptedUtf8 = null;
|
|
try {
|
|
decryptedUtf8 = words.toString(CryptoJS.enc.Utf8);
|
|
} catch (utfErr) {
|
|
// Malformed UTF-8 — try Latin1 fallback
|
|
try {
|
|
decryptedUtf8 = words.toString(CryptoJS.enc.Latin1);
|
|
} catch (latinErr) {
|
|
console.warn(
|
|
"TS_decrypt: failed to decode decrypted bytes",
|
|
utfErr,
|
|
latinErr
|
|
);
|
|
try {
|
|
callback(input, false);
|
|
} catch (ee) {}
|
|
return;
|
|
}
|
|
}
|
|
var parsed = null;
|
|
try {
|
|
parsed = JSON.parse(decryptedUtf8);
|
|
} catch (pe) {
|
|
// If JSON parsing fails, the decrypted string may be raw Latin1 bytes.
|
|
// Try to convert Latin1 byte string -> UTF-8 and parse again.
|
|
try {
|
|
if (
|
|
typeof TextDecoder !== "undefined" &&
|
|
typeof decryptedUtf8 === "string"
|
|
) {
|
|
var bytes = new Uint8Array(decryptedUtf8.length);
|
|
for (var _i = 0; _i < decryptedUtf8.length; _i++)
|
|
bytes[_i] = decryptedUtf8.charCodeAt(_i) & 0xff;
|
|
var converted = new TextDecoder("utf-8").decode(bytes);
|
|
try {
|
|
parsed = JSON.parse(converted);
|
|
decryptedUtf8 = converted;
|
|
} catch (e2) {
|
|
parsed = decryptedUtf8;
|
|
}
|
|
} else {
|
|
parsed = decryptedUtf8;
|
|
}
|
|
} catch (convErr) {
|
|
parsed = decryptedUtf8;
|
|
}
|
|
}
|
|
try {
|
|
callback(parsed, true);
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
// Migrate to plaintext in DB if table/id provided
|
|
if (table && id && window.DB && DB.put && typeof parsed !== "string") {
|
|
DB.put(table, id, parsed).catch(() => {});
|
|
}
|
|
return;
|
|
} catch (e) {
|
|
console.error("TS_decrypt: invalid encrypted payload", e);
|
|
try {
|
|
callback(input, false);
|
|
} catch (ee) {}
|
|
return;
|
|
}
|
|
}
|
|
if (input.startsWith("SEA{") && input.endsWith("}")) {
|
|
__ts_sync = false;
|
|
SEA.decrypt(input, secret, (decrypted) => {
|
|
try {
|
|
callback(decrypted, true);
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
});
|
|
return __ts_sync;
|
|
}
|
|
|
|
// Try to parse JSON strings and migrate to object
|
|
try {
|
|
var parsed = JSON.parse(input);
|
|
try {
|
|
callback(parsed, false);
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
if (table && id && window.DB && DB.put) {
|
|
DB.put(table, id, parsed).catch(() => {});
|
|
}
|
|
} catch (e) {
|
|
// Not JSON, return raw string
|
|
try {
|
|
callback(input, false);
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
}
|
|
return __ts_sync;
|
|
}
|
|
|
|
function recursiveTSDecrypt(input, secret = "") {
|
|
// Skip null values (do not show on decrypted output)
|
|
if (input === null) return null;
|
|
if (typeof input === "string") {
|
|
let result = null;
|
|
let resolver = null;
|
|
const promise = new Promise((resolve) => {
|
|
resolver = resolve;
|
|
});
|
|
const sync = TS_decrypt(input, secret, (decrypted) => {
|
|
result = decrypted;
|
|
if (resolver) resolver(decrypted);
|
|
});
|
|
if (sync === false) return promise;
|
|
return result;
|
|
} else if (Array.isArray(input)) {
|
|
const mapped = input.map((item) => recursiveTSDecrypt(item, secret));
|
|
if (mapped.some((v) => v && typeof v.then === "function")) {
|
|
return Promise.all(mapped).then((values) => values.filter((v) => v !== null && typeof v !== 'undefined'));
|
|
}
|
|
return mapped.filter((v) => v !== null && typeof v !== 'undefined');
|
|
} else if (typeof input === "object" && input !== null) {
|
|
const keys = Object.keys(input);
|
|
const mapped = keys.map((k) => recursiveTSDecrypt(input[k], secret));
|
|
if (mapped.some((v) => v && typeof v.then === "function")) {
|
|
return Promise.all(mapped).then((values) => {
|
|
const out = {};
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const val = values[i];
|
|
if (val !== null && typeof val !== 'undefined') out[keys[i]] = val;
|
|
}
|
|
return out;
|
|
});
|
|
} else {
|
|
const out = {};
|
|
for (let i = 0; i < keys.length; i++) {
|
|
const val = mapped[i];
|
|
if (val !== null && typeof val !== 'undefined') out[keys[i]] = val;
|
|
}
|
|
return out;
|
|
}
|
|
} else {
|
|
return input;
|
|
}
|
|
}
|
|
|
|
gun.get(TABLE).load((DATA) => {
|
|
var plain2 = recursiveTSDecrypt(DATA, SECRET);
|
|
plain2.then(function (result) {
|
|
download(
|
|
`Export TeleSec ${GROUPID} Decrypted.json.txt`,
|
|
JSON.stringify(result)
|
|
);
|
|
});
|
|
});
|