UNPKG

cerceis-lib

Version:

Contains list of quality of life functions that is written in TypeScript and es6

326 lines (324 loc) 11.5 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/obfuscator/index.ts var obfuscator_exports = {}; __export(obfuscator_exports, { Obfuscator: () => Obfuscator, obfuscator: () => obfuscator }); module.exports = __toCommonJS(obfuscator_exports); // src/obfuscator/obfuscator.ts var Obfuscator = class { constructor() { this._v4Prefix = "cob:v4"; this._base64UrlAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; this._randomKey = () => (Date.now() / 1e3 | 0).toString(16) + "xxxxxxxxxxxxxxxx".replace(/x/g, () => (Math.random() * 16 | 0).toString(16)).toLowerCase(); } /** * Preferred obfuscation API. Defaults to V4. */ encode(inputStr, options = {}) { const version = options.version ?? "v4"; switch (version) { case "v1": return options.key === void 0 ? this.obfuscate(inputStr) : this.obfuscate(inputStr, options.key); case "v2": return this.obfuscatev2(inputStr); case "v3": return this.obfuscatev3(inputStr, this._requireKey(options.key, "v3")); case "v4": return this.obfuscatev4(inputStr, this._requireKey(options.key, "v4")); } } /** * Preferred deobfuscation API. V4 payloads are self-identifying. */ decode(inputStr, options = {}) { const version = options.version ?? "v4"; switch (version) { case "v1": return this.deobfuscate(inputStr, this._requireKey(options.key, "v1")); case "v2": return this.deobfuscatev2(inputStr); case "v3": return this.deobfuscatev3(inputStr, this._requireKey(options.key, "v3")); case "v4": return this.deobfuscatev4(inputStr, this._requireKey(options.key, "v4")); } } _buildKeyValue(key) { let kv = ""; for (let i = 0; i < key.length; i++) kv += key.charCodeAt(i); return "l" + kv.split("").reverse().join("") + "l"; } /** * V1 obfuscation - key-based character code encoding. * If no key is provided, a random key is generated and you cannot deobfuscate. * @param inputStr String to obfuscate. * @param key Optional key for reversibility. */ obfuscate(inputStr, key = this._randomKey()) { const kv = this._buildKeyValue(key); let result = ""; for (let i = 0; i < inputStr.length; i++) result += inputStr.charCodeAt(i) + kv; return result; } /** * V1 deobfuscation. * @param inputStr String to deobfuscate. * @param key Key used during obfuscation. */ deobfuscate(inputStr, key) { const kv = this._buildKeyValue(key); const parts = inputStr.split(kv).filter((e) => e !== ""); return parts.map((e) => String.fromCharCode(Number(e))).join(""); } _swapPairs(input) { let result = ""; for (let i = 0; i < input.length; i++) { if (i % 2 === 1) result += input[i] + input[i - 1]; else if (i === input.length - 1) result += input[i]; } return result; } /** * V2 obfuscation - pair-swapping with incremental key shifting. */ obfuscatev2(inputStr) { const sortByLen = (a, b) => a.length > b.length ? "s" + b + a : a + b; const reformat = (text) => { let result = ""; for (let i = 0; i < text.length; i++) { if (i % 2 === 1) { result += sortByLen(String(text.charCodeAt(i - 1)), String(text.charCodeAt(i))); if (i !== text.length - 1) result += ":"; } if (i % 2 === 0 && i === text.length - 1) result += "e" + String(text.charCodeAt(i)); } return result; }; const increment = (input) => { return input.split(":").map((e, i) => { if (e[0] !== "e" && e[0] !== "s") return String(Number(e) + (i + i * 2)); return e; }); }; return increment(reformat(this._swapPairs(inputStr))).reduce((f, l) => f + ":" + l); } /** * V2 deobfuscation. */ deobfuscatev2(inputStr) { try { const split = (text) => { const len = text.length; if (len <= 3) return [text.slice(0, 1), text.slice(1)]; if (len <= 5) return [text.slice(0, 2), text.slice(2)]; return [text.slice(0, 3), text.slice(3)]; }; let result = ""; inputStr.split(":").forEach((e, i) => { if (e[0] === "s") { const [a, b] = split(e.slice(1)); result += String.fromCharCode(Number(a)) + String.fromCharCode(Number(b)); } else if (e[0] === "e") { result += String.fromCharCode(Number(e.slice(1))); } else { const [a, b] = split(String(Number(e) - (i + i * 2))); result += String.fromCharCode(Number(b)) + String.fromCharCode(Number(a)); } }); return result; } catch { return "Errored"; } } /** * V3 obfuscation - binary rotation with hex encoding. * @param inputStr String to obfuscate. * @param key Key used to determine rotation amounts. */ obfuscatev3(inputStr, key) { const keyValues = this._keyToValues(key); let kIdx = 0; let hex = ""; const next = () => { kIdx = (kIdx + 1) % keyValues.length; }; const rotr = (bits, n) => { for (let i = 0; i < n; i++) bits = bits[bits.length - 1] + bits.slice(0, bits.length - 1); return bits; }; for (let i = 0; i < inputStr.length; i++) { const bin = inputStr.charCodeAt(i).toString(2).padStart(16, "0"); hex += parseInt(rotr(bin, keyValues[kIdx]), 2).toString(16).padStart(4, "0"); next(); } return hex; } /** * V3 deobfuscation. */ deobfuscatev3(inputStr, key) { const keyValues = this._keyToValues(key); let kIdx = 0; let result = ""; const next = () => { kIdx = (kIdx + 1) % keyValues.length; }; const rotl = (bits, n) => { for (let i = 0; i < n; i++) bits = bits.slice(1) + bits[0]; return bits; }; const hex2bin = (hex) => parseInt(hex, 16).toString(2).padStart(16, "0"); for (let i = 0; i < inputStr.length / 4; i++) { const chunk = inputStr.slice(i * 4, i * 4 + 4); result += String.fromCharCode(parseInt(rotl(hex2bin(chunk), keyValues[kIdx]), 2)); next(); } return result; } /** * V4 obfuscation - salted keyed byte-stream masking with base64url output. * This is reversible obfuscation, not cryptographic encryption. */ obfuscatev4(inputStr, key) { this._requireKey(key, "v4"); const salt = this._randomSalt(); const bytes = new TextEncoder().encode(inputStr); const payload = this._base64UrlEncode(this._applyV4(bytes, key, salt, "encode")); return `${this._v4Prefix}:${salt}:${payload}`; } /** * V4 deobfuscation. */ deobfuscatev4(inputStr, key) { this._requireKey(key, "v4"); const parts = inputStr.split(":"); if (parts.length !== 4 || `${parts[0]}:${parts[1]}` !== this._v4Prefix) { throw new Error("Invalid V4 obfuscator payload"); } const [, , salt, payload] = parts; const bytes = this._base64UrlDecode(payload); const decoded = this._applyV4(bytes, key, salt, "decode"); return new TextDecoder().decode(decoded); } _applyV4(bytes, key, salt, mode) { const prng = this._xorshift32(this._seedFromKey(key, salt)); const result = new Uint8Array(bytes.length); for (let i = 0; i < bytes.length; i++) { const random = prng(); const mask = random & 255; const shift = (random >>> 8) + i & 7; result[i] = mode === "encode" ? this._rotateLeftByte(bytes[i] ^ mask, shift) : this._rotateRightByte(bytes[i], shift) ^ mask; } return result; } _seedFromKey(key, salt) { let hash = 2166136261; const bytes = new TextEncoder().encode(`${salt}:${key}`); for (const byte of bytes) { hash ^= byte; hash = Math.imul(hash, 16777619) >>> 0; } return hash || 1831565813; } _xorshift32(seed) { let state = seed >>> 0 || 1831565813; return () => { state ^= state << 13; state >>>= 0; state ^= state >>> 17; state >>>= 0; state ^= state << 5; return state >>> 0; }; } _rotateLeftByte(value, shift) { return (value << shift | value >>> 8 - shift) & 255; } _rotateRightByte(value, shift) { return (value >>> shift | value << 8 - shift) & 255; } _randomSalt() { const bytes = new Uint8Array(4); if (globalThis.crypto?.getRandomValues) { globalThis.crypto.getRandomValues(bytes); } else { for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256); } return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""); } _base64UrlEncode(bytes) { let output = ""; for (let i = 0; i < bytes.length; i += 3) { const b0 = bytes[i]; const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0; const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0; const triplet = b0 << 16 | b1 << 8 | b2; output += this._base64UrlAlphabet[triplet >>> 18 & 63]; output += this._base64UrlAlphabet[triplet >>> 12 & 63]; if (i + 1 < bytes.length) output += this._base64UrlAlphabet[triplet >>> 6 & 63]; if (i + 2 < bytes.length) output += this._base64UrlAlphabet[triplet & 63]; } return output; } _base64UrlDecode(input) { if (input.length % 4 === 1 || /[^A-Za-z0-9_-]/.test(input)) { throw new Error("Invalid base64url payload"); } const bytes = []; for (let i = 0; i < input.length; i += 4) { const c0 = this._base64UrlValue(input[i]); const c1 = this._base64UrlValue(input[i + 1]); const c2 = i + 2 < input.length ? this._base64UrlValue(input[i + 2]) : 0; const c3 = i + 3 < input.length ? this._base64UrlValue(input[i + 3]) : 0; const triplet = c0 << 18 | c1 << 12 | c2 << 6 | c3; bytes.push(triplet >>> 16 & 255); if (i + 2 < input.length) bytes.push(triplet >>> 8 & 255); if (i + 3 < input.length) bytes.push(triplet & 255); } return new Uint8Array(bytes); } _base64UrlValue(char) { if (char === void 0) throw new Error("Invalid base64url payload"); const value = this._base64UrlAlphabet.indexOf(char); if (value === -1) throw new Error("Invalid base64url payload"); return value; } _requireKey(key, version) { if (typeof key !== "string" || key.length === 0) { throw new Error(`${version.toUpperCase()} obfuscation requires a non-empty key`); } return key; } _keyToValues(key) { return key.split("").map( (c) => String(c.charCodeAt(0)).split("").map(Number).reduce((a, b) => a + b, 0) ); } }; var obfuscator = new Obfuscator(); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Obfuscator, obfuscator }); //# sourceMappingURL=index.js.map