diff --git a/CSSGuard.js b/CSSGuard.js new file mode 100644 index 0000000..bfb8d9b --- /dev/null +++ b/CSSGuard.js @@ -0,0 +1,519 @@ +(function(window) { + 'use strict'; + + // DYNAMIC OBFUSCATION SETTINGS BASED ON FILE SIZE + function getDynamicObfuscationSettings(codeLength) { + const randomSeed = Math.floor(Math.random() * 999999); + const sizeInKB = codeLength / 1024; + + // 0-100 KB: MAXIMUM security + if (sizeInKB <= 100) { + return { + compact: true, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1.0, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.4, + debugProtection: true, + debugProtectionInterval: 4000, + disableConsoleOutput: true, + identifierNamesGenerator: 'hexadecimal', + identifiersPrefix: '', + ignoreRequireImports: false, + log: false, + numbersToExpressions: true, + renameGlobals: false, + rotateStringArray: true, + seed: randomSeed, + selfDefending: true, + simplify: true, + splitStrings: true, + splitStringsChunkLength: 5, + stringArray: true, + stringArrayCallsTransform: true, + stringArrayCallsTransformThreshold: 0.9, + stringArrayEncoding: ['base64', 'rc4'], + stringArrayIndexShift: true, + stringArrayRotate: true, + stringArrayShuffle: true, + stringArrayWrappersCount: 1, + stringArrayWrappersChainedCalls: true, + stringArrayWrappersParametersMaxCount: 2, + stringArrayWrappersType: 'variable', + stringArrayThreshold: 1.0, + target: 'browser', + transformObjectKeys: true, + unicodeEscapeSequence: true + }; + } + + // 100-400 KB: HIGH security + if (sizeInKB > 100 && sizeInKB <= 400) { + return { + compact: true, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 0.85, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.3, + debugProtection: true, + debugProtectionInterval: false, + disableConsoleOutput: true, + identifierNamesGenerator: 'hexadecimal', + identifiersPrefix: '', + ignoreRequireImports: false, + log: false, + numbersToExpressions: false, + renameGlobals: false, + rotateStringArray: true, + seed: randomSeed, + selfDefending: true, + simplify: true, + splitStrings: true, + splitStringsChunkLength: 7, + stringArray: true, + stringArrayCallsTransform: true, + stringArrayCallsTransformThreshold: 0.8, + stringArrayEncoding: ['base64', 'rc4'], + stringArrayIndexShift: true, + stringArrayRotate: true, + stringArrayShuffle: true, + stringArrayWrappersCount: 1, + stringArrayWrappersChainedCalls: true, + stringArrayWrappersParametersMaxCount: 2, + stringArrayWrappersType: 'variable', + stringArrayThreshold: 0.9, + target: 'browser', + transformObjectKeys: true, + unicodeEscapeSequence: true + }; + } + + // 400-800 KB: STRONG security + if (sizeInKB > 400 && sizeInKB <= 800) { + return { + compact: true, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 0.7, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.25, + debugProtection: true, + debugProtectionInterval: false, + disableConsoleOutput: true, + identifierNamesGenerator: 'hexadecimal', + identifiersPrefix: '', + ignoreRequireImports: false, + log: false, + numbersToExpressions: false, + renameGlobals: false, + rotateStringArray: true, + seed: randomSeed, + selfDefending: true, + simplify: true, + splitStrings: true, + splitStringsChunkLength: 10, + stringArray: true, + stringArrayCallsTransform: true, + stringArrayCallsTransformThreshold: 0.7, + stringArrayEncoding: ['base64', 'rc4'], + stringArrayIndexShift: true, + stringArrayRotate: true, + stringArrayShuffle: true, + stringArrayWrappersCount: 1, + stringArrayWrappersChainedCalls: false, + stringArrayWrappersParametersMaxCount: 2, + stringArrayWrappersType: 'variable', + stringArrayThreshold: 0.8, + target: 'browser', + transformObjectKeys: true, + unicodeEscapeSequence: false + }; + } + + // 800KB-1.1MB: MODERATE security (optimized for large files) + if (sizeInKB > 800 && sizeInKB <= 1126) { + return { + compact: true, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 0.5, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.15, + debugProtection: false, + debugProtectionInterval: false, + disableConsoleOutput: true, + identifierNamesGenerator: 'hexadecimal', + identifiersPrefix: '', + ignoreRequireImports: false, + log: false, + numbersToExpressions: false, + renameGlobals: false, + rotateStringArray: true, + seed: randomSeed, + selfDefending: false, + simplify: true, + splitStrings: true, + splitStringsChunkLength: 12, + stringArray: true, + stringArrayCallsTransform: false, + stringArrayCallsTransformThreshold: 0.6, + stringArrayEncoding: ['base64', 'rc4'], + stringArrayIndexShift: true, + stringArrayRotate: true, + stringArrayShuffle: true, + stringArrayWrappersCount: 1, + stringArrayWrappersChainedCalls: false, + stringArrayWrappersParametersMaxCount: 2, + stringArrayWrappersType: 'variable', + stringArrayThreshold: 0.7, + target: 'browser', + transformObjectKeys: false, + unicodeEscapeSequence: false + }; + } + + // > 1.1MB: LIGHTWEIGHT security (minimal obfuscation) + return { + compact: true, + controlFlowFlattening: false, + deadCodeInjection: false, + debugProtection: false, + debugProtectionInterval: false, + disableConsoleOutput: true, + identifierNamesGenerator: 'hexadecimal', + identifiersPrefix: '', + ignoreRequireImports: false, + log: false, + numbersToExpressions: false, + renameGlobals: false, + rotateStringArray: true, + seed: randomSeed, + selfDefending: false, + simplify: true, + splitStrings: false, + stringArray: true, + stringArrayCallsTransform: false, + stringArrayEncoding: ['base64'], + stringArrayThreshold: 0.5, + target: 'browser', + transformObjectKeys: false, + unicodeEscapeSequence: false + }; + } + + // Track if obfuscator is loaded + let obfuscatorLoaded = false; + let obfuscatorLoading = false; + const loadQueue = []; + + // Extract clean domain from any URL format + function extractDomain(input) { + if (!input || typeof input !== 'string') return ''; + + let domain = input.trim().toLowerCase(); + domain = domain.replace(/^https?:\/\//, ''); + domain = domain.replace(/^www\./, ''); + domain = domain.split('/')[0]; + domain = domain.split(':')[0]; + domain = domain.split('?')[0]; + domain = domain.split('#')[0]; + + return domain; + } + + // Load JavaScriptObfuscator dynamically + function loadObfuscator() { + return new Promise(function(resolve, reject) { + if (typeof window.JavaScriptObfuscator !== 'undefined') { + obfuscatorLoaded = true; + return resolve(); + } + + if (obfuscatorLoading) { + loadQueue.push({ resolve: resolve, reject: reject }); + return; + } + + obfuscatorLoading = true; + + const script = document.createElement('script'); + script.src = 'https://cdn.jsdelivr.net/npm/javascript-obfuscator@4.1.0/dist/index.browser.js'; + script.async = true; + + script.onload = function() { + obfuscatorLoaded = true; + obfuscatorLoading = false; + + setTimeout(function() { + if (typeof window.JavaScriptObfuscator !== 'undefined') { + console.log('✔ JavaScriptObfuscator loaded and ready'); + resolve(); + + loadQueue.forEach(function(item) { + item.resolve(); + }); + loadQueue.length = 0; + } else { + console.error('✗ JavaScriptObfuscator script loaded but not available in window'); + const error = new Error('JavaScriptObfuscator loaded but not available'); + reject(error); + loadQueue.forEach(function(item) { + item.reject(error); + }); + loadQueue.length = 0; + } + }, 200); + }; + + script.onerror = function() { + obfuscatorLoading = false; + const error = new Error('Failed to load JavaScriptObfuscator library from CDN'); + reject(error); + + loadQueue.forEach(function(item) { + item.reject(error); + }); + loadQueue.length = 0; + }; + + (document.head || document.documentElement).appendChild(script); + }); + } + + // random string generation with crypto API + function randomStr(len) { + const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + const arr = new Uint8Array(len); + crypto.getRandomValues(arr); + let result = ''; + for (let i = 0; i < len; i++) { + result += chars[arr[i] % chars.length]; + } + return result + Date.now().toString(36).slice(-6); + } + + // ZERO-MODIFICATION CSS PARSER + function zeroModificationParser(css) { + const preserved = { + charset: [], + imports: [] + }; + + // Extract @charset (must be first line in CSS) + css = css.replace(/(@charset\s+[^;]+;)/gi, (match) => { + preserved.charset.push(match.trim()); + return ''; + }); + + // Extract @import (must be near top, before other rules) + css = css.replace(/(@import\s+(?:url\([^)]+\)|["'][^"']+["'])[^;]*;)/gi, (match) => { + preserved.imports.push(match.trim()); + return ''; + }); + + return { + css: css.trim(), + charset: preserved.charset, + imports: preserved.imports + }; + } + + // 2-layer XOR encryption + function fastEncrypt(text) { + const k1 = randomStr(24); + const k2 = randomStr(20); + + const tLen = text.length; + const k1Len = k1.length; + const k2Len = k2.length; + const result = new Array(tLen); + + for (let i = 0; i < tLen; i++) { + result[i] = String.fromCharCode(text.charCodeAt(i) ^ k1.charCodeAt(i % k1Len) ^ k2.charCodeAt(i % k2Len)); + } + + let enc = btoa(unescape(encodeURIComponent(result.join('')))).split('').reverse().join(''); + enc = btoa(enc); + + return enc + '§§' + btoa(k1) + '§' + btoa(k2); + } + + // MAIN PROTECTION SCRIPT GENERATOR + function createProtectionScript(cssText, options) { + const parsed = zeroModificationParser(cssText); + const encrypted = fastEncrypt(parsed.css); + + // Generate unique variable names + const v = { + d: '_' + randomStr(8), + f: '_' + randomStr(7), + x: '_' + randomStr(6), + i: '_' + randomStr(7), + n: '_' + randomStr(6), + l: '_' + randomStr(5), + ext: '_e' + randomStr(6), + dmc: '_c' + randomStr(6), + dml: '_l' + randomStr(6) + }; + + const code = []; + + code.push('!function(){'); + code.push('"use strict";'); + + // Charset handling + if (parsed.charset.length > 0) { + code.push(`const ${v.l}=${JSON.stringify(parsed.charset)};`); + code.push(`${v.l}.forEach(c=>{const s=document.createElement('style');s.textContent=c;document.head.insertBefore(s,document.head.firstChild)});`); + } + + // Imports handling + if (parsed.imports.length > 0) { + const impVar = '_' + randomStr(5); + code.push(`const ${impVar}=${JSON.stringify(parsed.imports)};`); + code.push(`${impVar}.forEach(imp=>{const s=document.createElement('style');s.textContent=imp;document.head.insertBefore(s,document.head.firstChild)});`); + } + + // Domain lock check + if (options && options.lockToDomain) { + const allowedDomains = Array.isArray(options.lockToDomain) ? options.lockToDomain : [options.lockToDomain]; + const encodedDomains = allowedDomains.map(function(d) { + return btoa(extractDomain(d)); + }); + + code.push(`function ${v.ext}(d){if(!d)return "";d=d.trim().toLowerCase();d=d.replace(/^https?:\\/\\//,"");d=d.replace(/^www\\./,"");d=d.split("/")[0];d=d.split(":")[0];d=d.split("?")[0];d=d.split("#")[0];return d;}`); + code.push(`const ${v.dml}=${JSON.stringify(encodedDomains)};`); + code.push(`function ${v.dmc}(){try{const c=${v.ext}(window.location.hostname);let m=false;for(let i=0;i<${v.dml}.length;i++){try{const a=atob(${v.dml}[i]);if(c===a||c.endsWith("."+a)){m=true;break;}}catch(e){}}if(!m){document.body.innerHTML="