Script Security Analyzer & Boilerplate Packager

Static security analysis and Tampermonkey boilerplate packager.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Advertisement:

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

Advertisement:

// ==UserScript==
// @name         Script Security Analyzer & Boilerplate Packager
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  Static security analysis and Tampermonkey boilerplate packager.
// @match        *://*/*
// @grant        none
// @icon         https://cdn-icons-png.flaticon.com/512/1006/1006771.png
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    let mainHost = null;

    // 4 Dil Desteği - Varsayılan İngilizce
    const translations = {
        en: {
            titleLeft: "Source Code Input",
            btnClose: "Close Panel",
            placeholderInput: "Paste your code here...",
            tabAudit: "Security Audit",
            tabPackage: "Script Packager",
            secTitleAudit: "Static Code Security Audit Report",
            infoNotice: "Paste your code on the left to trigger real-time analysis.",
            secTitleMeta: "Greasemonkey / Tampermonkey Meta Settings",
            lblScriptName: "Script Name:",
            lblVersion: "Version:",
            lblMatch: "Match Sites (@match):",
            lblDesc: "Description:",
            btnBuild: "Build Installation Package",
            placeholderOutput: "Your packaged meta code will appear here...",
            btnCopy: "Copy Package Code",
            btnClearInput: "Clear Input Code",
            cleanScript: "Clean Script",
            cleanScriptDesc: "No obvious static security risks (eval, unsafeWindow, etc.) detected."
        },
        tr: {
            titleLeft: "Kaynak Kod Girisi",
            btnClose: "Paneli Kapat",
            placeholderInput: "Kodunuzu buraya yapistirin...",
            tabAudit: "Guvenlik Taramasi",
            tabPackage: "Script Paketleyici",
            secTitleAudit: "Statik Kod Guvenlik Analiz Raporu",
            infoNotice: "Gercek zamanli analizi tetiklemek icin sol tarafa kod yapistirin.",
            secTitleMeta: "Greasemonkey / Tampermonkey Meta Ayarlari",
            lblScriptName: "Betik Adi:",
            lblVersion: "Versiyon:",
            lblMatch: "Calisacagi Siteler (@match):",
            lblDesc: "Aciklama:",
            btnBuild: "Kurulum Paketini Olustur",
            placeholderOutput: "Olusturulan meta paket kodu burada belirecektir...",
            btnCopy: "Paket Kodunu Kopyala",
            btnClearInput: "Giris Kodunu Temizle",
            cleanScript: "Temiz Script",
            cleanScriptDesc: "Belirgin bir statik guvenlik riski (eval, unsafeWindow vb.) tespit edilmedi."
        },
        de: {
            titleLeft: "Quellcode-Eingabe",
            btnClose: "Panel Schliessen",
            placeholderInput: "Fuegen Sie Ihren Code hier ein...",
            tabAudit: "Sicherheitsaudit",
            tabPackage: "Skript-Packer",
            secTitleAudit: "Sicherheitsbericht fuer statischen Code",
            infoNotice: "Fuegen Sie links Code ein, um die Echtzeitanalyse zu starten.",
            secTitleMeta: "Greasemonkey / Tampermonkey Meta-Einstellungen",
            lblScriptName: "Skriptname:",
            lblVersion: "Version:",
            lblMatch: "Passende Seiten (@match):",
            lblDesc: "Beschreibung:",
            btnBuild: "Installationspaket Packen",
            placeholderOutput: "Ihr gepackter Meta-Code wird hier angezeigt...",
            btnCopy: "Paketcode Kopieren",
            btnClearInput: "Eingabecode Loeschen",
            cleanScript: "Sauberes Skript",
            cleanScriptDesc: "Keine offensichtlichen statischen Sicherheitsrisiken (eval, unsafeWindow usw.) erkannt."
        },
        fr: {
            titleLeft: "Saisie du Code Source",
            btnClose: "Fermer le Panneau",
            placeholderInput: "Collez votre code ici...",
            tabAudit: "Audit de Securite",
            tabPackage: "Package de Script",
            secTitleAudit: "Rapport d'Audit de Securite du Code Statique",
            infoNotice: "Collez le code a gauche pour lancer l'analyse en temps reel.",
            secTitleMeta: "Parametres Meta Greasemonkey / Tampermonkey",
            lblScriptName: "Nom du Script:",
            lblVersion: "Version:",
            lblMatch: "Sites de Match (@match):",
            lblDesc: "Description:",
            btnBuild: "Creer le Package d'Installation",
            placeholderOutput: "Votre code meta package apparaitra ici...",
            btnCopy: "Copier le Code du Package",
            btnClearInput: "Effacer le Code Source",
            cleanScript: "Script Propre",
            cleanScriptDesc: "Aucun risque de securite statique evident (eval, unsafeWindow, etc.) detecte."
        }
    };

    let currentLang = 'en'; // Varsayılan İngilizce
    let t = translations[currentLang];

    function toggleAnalyzerPanel() {
        if (mainHost) { mainHost.remove(); mainHost = null; } 
        else { createAnalyzerPanel(); }
    }

    function runSecurityAudit(code) {
        const findings = [];
        if (!code.trim()) return [{ type: 'info', name: "Notice", desc: t.infoNotice }];

        const rules = [
            { rx: /\beval\s*\(/g, type: 'danger', name: 'Risk (eval)', desc: 'Dynamic code execution detected.' },
            { rx: /\bunsafeWindow\b/g, type: 'warning', name: 'Zafiyet (unsafeWindow)', desc: 'Direct page window access.' },
            { rx: /\b(fetch|XMLHttpRequest)\b/g, type: 'info', name: 'Network', desc: 'External data transfer detected.' },
            { rx: /document\.write\s*\(/g, type: 'danger', name: 'DOM (document.write)', desc: 'Direct DOM writing.' },
            { rx: /location\.href\s*=/g, type: 'warning', name: 'Redirect', desc: 'Script contains redirection commands.' },
            { rx: /GM_(xmlhttpRequest|setValue|getValue|download)/g, type: 'info', name: 'API Usage', desc: 'Extension privileged API functions triggered.' }
        ];

        rules.forEach(rule => {
            const matches = code.match(rule.rx);
            if (matches) {
                findings.push({
                    type: rule.type,
                    name: rule.name,
                    desc: rule.desc,
                    count: matches.length
                });
            }
        });

        if (findings.length === 0) {
            findings.push({ type: 'success', name: t.cleanScript, desc: t.cleanScriptDesc });
        }

        return findings;
    }

    function generateBoilerplate(code, meta) {
        return [
            `// ==UserScript==`,
            `// @name         ${meta.name || 'Production Script'}`,
            `// @namespace    http://tampermonkey.net/`,
            `// @version      ${meta.version || '1.0.0'}`,
            `// @description  ${meta.desc || 'Packaged using premium builder.'}`,
            `// @match        ${meta.match || '*://*/*'}`,
            `// @grant        ${meta.grant || 'none'}`,
            `// @run-at       ${meta.runAt || 'document-end'}`,
            `// ==/UserScript==\n`,
            `(function() {`,
            `    'use strict';\n`,
            code.split('\n').map(line => '    ' + line).join('\n'),
            `\n})();`
        ].join('\n');
    }

    function createAnalyzerPanel() {
        if (mainHost) return;

        mainHost = document.createElement('div');
        mainHost.id = "script-analyzer-host";
        mainHost.style.position = "fixed";
        mainHost.style.zIndex = "999999999";
        mainHost.style.top = "0";
        mainHost.style.left = "0";
        
        const shadow = mainHost.attachShadow({ mode: 'open' });
        document.body.appendChild(mainHost);

        const overlay = document.createElement('div');
        overlay.className = "sandbox-overlay";

        overlay.innerHTML = `
            <div class="sandbox-container">
                <div class="panel editor-panel">
                    <div class="panel-header">
                        <span id="txtTitleLeft">${t.titleLeft}</span>
                        <div style="display:flex; gap:8px; align-items:center;">
                            <select id="langSelect" class="crayon-select">
                                <option value="en" ${currentLang==='en'?'selected':''}>EN</option>
                                <option value="tr" ${currentLang==='tr'?'selected':''}>TR</option>
                                <option value="de" ${currentLang==='de'?'selected':''}>DE</option>
                                <option value="fr" ${currentLang==='fr'?'selected':''}>FR</option>
                            </select>
                            <button id="clearInputBtn" class="crayon-btn yellow-crayon" style="padding: 4px 10px; font-size: 0.75rem;">${t.btnClearInput}</button>
                            <button id="closeBtn" class="close-btn">${t.btnClose}</button>
                        </div>
                    </div>
                    <div class="code-area">
                        <pre class="line-numbers" id="leftLines">1</pre>
                        <textarea id="inputCode" spellcheck="false" wrap="off" placeholder="${t.placeholderInput}"></textarea>
                    </div>
                </div>

                <div class="panel tools-panel">
                    <div class="tabs-header">
                        <button id="tabAudit" class="tab-btn active">${t.tabAudit}</button>
                        <button id="tabPackage" class="tab-btn">${t.tabPackage}</button>
                    </div>

                    <div class="tab-content" id="contentArea">
                        <div id="auditView" class="view-block">
                            <div class="section-title" id="txtSecTitleAudit">${t.secTitleAudit}</div>
                            <div id="auditReportList" class="report-list">
                                <div class="info-notice">${t.infoNotice}</div>
                            </div>
                        </div>

                        <div id="packageView" class="view-block" style="display: none;">
                            <div class="section-title" id="txtSecTitleMeta">${t.secTitleMeta}</div>
                            <div class="meta-form">
                                <div class="form-group"><label id="lblScriptName">${t.lblScriptName}</label><input type="text" id="metaName" value="My New Script"></div>
                                <div class="form-group"><label id="lblVersion">${t.lblVersion}</label><input type="text" id="metaVersion" value="1.0.0"></div>
                                <div class="form-group"><label id="lblMatch">${t.lblMatch}</label><input type="text" id="metaMatch" value="*://*/*"></div>
                                <div class="form-group"><label id="lblDesc">${t.lblDesc}</label><input type="text" id="metaDesc" value="Packaged production script."></div>
                            </div>
                            <div style="display:flex; gap:10px;">
                                <button id="btnBuildPackage" class="crayon-btn green-crayon" style="flex:1;">${t.btnBuild}</button>
                                <button id="btnCopyPackage" class="crayon-btn yellow-crayon" style="padding:0 15px;">${t.btnCopy}</button>
                            </div>
                            <div class="code-area output-area" style="margin-top: 15px; height: 180px;">
                                <textarea id="outputPackageCode" readonly placeholder="${t.placeholderOutput}"></textarea>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        `;

        const style = document.createElement('style');
        style.textContent = `
            /* Çocuksu ve Pastel Boya Sanat Tarzı Tasarım Kuralları */
            @import url('https://fonts.googleapis.com/css2?family=Comic+Neue:wght@400;700&display=swap');

            .sandbox-overlay * { 
                box-sizing: border-box; margin: 0; padding: 0; 
                font-family: 'Comic Neue', 'Comic Sans MS', cursive, sans-serif;
                font-weight: 700;
            }
            .sandbox-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(20, 25, 35, 0.85); display: flex; align-items: center; justify-content: center; }
            
            /* Konteyner: Pastel Mavi çocuk boyaması arka planı */
            .sandbox-container {
                width: 96vw; max-width: 1550px; height: 88vh; max-height: 88vh;
                background: #E0F2FE; 
                border: 6px dashed #38BDF8; 
                border-radius: 30px; padding: 20px;
                display: grid; grid-template-columns: 1fr 1fr; gap: 20px; overflow: hidden;
                box-shadow: inset 0 0 40px rgba(56, 189, 248, 0.4);
            }
            
            /* Paneller: Sanki kağıda pastel tebeşirle çizilmiş gibi */
            .panel { 
                background: #FFFDFA; 
                border: 5px solid #F43F5E; /* Pastel Kırmızı tebeşir çizgisi */
                border-radius: 24px; padding: 16px; 
                display: flex; flex-direction: column; gap: 14px; height: 100%; overflow: hidden; 
                box-shadow: 5px 5px 0px #FB7185;
            }
            
            .panel-header { display: flex; justify-content: space-between; align-items: center; height: 35px; }
            .panel-header span { font-size: 1.1rem; color: #475569; letter-spacing: -0.5px; }
            
            /* Pastel Boya Buton Tipleri */
            .crayon-btn { 
                border: 4px solid #1E293B; border-radius: 14px; padding: 10px; font-size: 0.9rem; cursor: pointer; color: #1E293B;
                box-shadow: 3px 3px 0px #1E293B; transition: transform 0.1s;
            }
            .crayon-btn:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0px #1E293B; }
            
            .green-crayon { background: #4ADE80; border-color: #166534; box-shadow: 3px 3px 0px #166534; color: #166534; }
            .yellow-crayon { background: #FDE047; border-color: #854D0E; box-shadow: 3px 3px 0px #854D0E; color: #854D0E; }
            .close-btn { background: #FB7185; border: 4px solid #9F1239; color: #9F1239; padding: 6px 12px; border-radius: 12px; font-size: 0.8rem; cursor: pointer; box-shadow: 3px 3px 0px #9F1239; }
            
            .crayon-select { background: #F3F4F6; border: 3px solid #475569; border-radius: 10px; padding: 4px 8px; font-size: 0.8rem; cursor: pointer; outline: none; }

            /* Sekme Menü Alanı */
            .tabs-header { display: flex; background: #FED7AA; border: 4px solid #EA580C; border-radius: 16px; padding: 4px; gap: 4px; }
            .tab-btn { flex: 1; border: none; background: transparent; color: #C2410C; padding: 10px; border-radius: 12px; font-size: 0.9rem; cursor: pointer; }
            .tab-btn.active { background: #EA580C; color: white; }
            
            .tab-content { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
            .view-block { display: flex; flex-direction: column; height: 100%; overflow: hidden; }
            .section-title { font-size: 1.1rem; color: #1E293B; margin-bottom: 12px; border-left: 5px solid #FDE047; padding-left: 8px; }

            /* Kod Giriş Kağıdı */
            .code-area { flex: 1; display: flex; background: #1E293B; border-radius: 16px; border: 4px solid #475569; overflow: hidden; position: relative; }
            .line-numbers { background: #0F172A; padding: 16px 8px; text-align: right; font-family: monospace; font-size: 0.85rem; color: #64748B; min-width: 55px; max-width: 55px; line-height: 1.6; overflow: hidden; border-right: 2px solid #334155; white-space: pre; }
            textarea { flex: 1; padding: 16px; resize: none; border: none; background: transparent; outline: none; color: #F1F5F9; font-family: monospace; font-size: 0.85rem; line-height: 1.6; overflow: auto; }
            .output-area { background: #0F172A; }

            /* Rapor Kartları: Pastel Renk Paletleri */
            .report-list { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; padding-right: 4px; }
            .info-notice { color: #64748B; font-size: 0.9rem; text-align: center; margin-top: 40px; }
            
            .audit-card { border-radius: 14px; padding: 12px; font-size: 0.9rem; border: 3px solid #1E293B; box-shadow: 3px 3px 0px #1E293B; }
            .audit-card.danger { background: #FCA5A5; color: #7F1D1D; border-color: #7F1D1D; box-shadow: 3px 3px 0px #7F1D1D; }
            .audit-card.warning { background: #FDE047; color: #713F12; border-color: #713F12; box-shadow: 3px 3px 0px #713F12; }
            .audit-card.info { background: #93C5FD; color: #1E3A8A; border-color: #1E3A8A; box-shadow: 3px 3px 0px #1E3A8A; }
            .audit-card.success { background: #86EFAC; color: #14532D; border-color: #14532D; box-shadow: 3px 3px 0px #14532D; }
            
            .card-title { font-weight: bold; margin-bottom: 4px; display: flex; justify-content: space-between; }
            .card-desc { font-size: 0.8rem; opacity: 0.9; }

            /* Form Elemanları */
            .meta-form { display: flex; flex-direction: column; gap: 10px; background: #FEF3C7; border: 4px solid #D97706; padding: 14px; border-radius: 16px; margin-bottom: 12px; box-shadow: 3px 3px 0px #D97706; }
            .form-group { display: flex; flex-direction: column; gap: 4px; }
            .form-group label { font-size: 0.8rem; color: #92400E; }
            .form-group input { background: #FFF; border: 3px solid #D97706; border-radius: 10px; padding: 8px; color: #1E293B; font-size: 0.85rem; outline: none; }
        `;

        shadow.appendChild(style);
        shadow.appendChild(overlay);

        const inputCode = shadow.getElementById('inputCode');
        const leftLines = shadow.getElementById('leftLines');
        const closeBtn = shadow.getElementById('closeBtn');
        const clearInputBtn = shadow.getElementById('clearInputBtn');
        const langSelect = shadow.getElementById('langSelect');
        
        const tabAudit = shadow.getElementById('tabAudit');
        const tabPackage = shadow.getElementById('tabPackage');
        const auditView = shadow.getElementById('auditView');
        const packageView = shadow.getElementById('packageView');
        
        const auditReportList = shadow.getElementById('auditReportList');
        const btnBuildPackage = shadow.getElementById('btnBuildPackage');
        const btnCopyPackage = shadow.getElementById('btnCopyPackage');
        const outputPackageCode = shadow.getElementById('outputPackageCode');

        const metaName = shadow.getElementById('metaName');
        const metaVersion = shadow.getElementById('metaVersion');
        const metaMatch = shadow.getElementById('metaMatch');
        const metaDesc = shadow.getElementById('metaDesc');

        // Statik Dil Güncelleme Motoru
        const updateLanguageUI = (langKey) => {
            currentLang = langKey;
            t = translations[currentLang];
            
            shadow.getElementById('txtTitleLeft').textContent = t.titleLeft;
            closeBtn.textContent = t.btnClose;
            clearInputBtn.textContent = t.btnClearInput;
            inputCode.placeholder = t.placeholderInput;
            tabAudit.textContent = t.tabAudit;
            tabPackage.textContent = t.tabPackage;
            shadow.getElementById('txtSecTitleAudit').textContent = t.secTitleAudit;
            shadow.getElementById('txtSecTitleMeta').textContent = t.secTitleMeta;
            shadow.getElementById('lblScriptName').textContent = t.lblScriptName;
            shadow.getElementById('lblVersion').textContent = t.lblVersion;
            shadow.getElementById('lblMatch').textContent = t.lblMatch;
            shadow.getElementById('lblDesc').textContent = t.lblDesc;
            btnBuildPackage.textContent = t.btnBuild;
            btnCopyPackage.textContent = t.btnCopy;
            outputPackageCode.placeholder = t.placeholderOutput;
            
            triggerAuditRun();
        };

        const updateLineNumbers = () => {
            const lines = inputCode.value.split('\n');
            let nums = '';
            for (let i = 1; i <= lines.length; i++) nums += i + '\n';
            leftLines.textContent = nums;
        };

        const triggerAuditRun = () => {
            const reports = runSecurityAudit(inputCode.value);
            auditReportList.innerHTML = '';
            reports.forEach(item => {
                const card = document.createElement('div');
                card.className = `audit-card ${item.type}`;
                if (item.type === 'success' || (item.type === 'info' && !inputCode.value.trim())) {
                    card.innerHTML = `
                        <div class="card-title"><span>${item.name}</span></div>
                        <div class="card-desc">${item.desc}</div>
                    `;
                } else {
                    card.innerHTML = `
                        <div class="card-title"><span>${item.name}</span> <span style="background:rgba(0,0,0,0.1); padding:2px 6px; border-radius:8px;">${item.count}</span></div>
                        <div class="card-desc">${item.desc}</div>
                    `;
                }
                auditReportList.appendChild(card);
            });
        };

        // Dil Değişimi Dinleyicisi
        langSelect.addEventListener('change', (e) => {
            updateLanguageUI(e.target.value);
        });

        // Giriş Alanı Temizleme Kolaylığı
        clearInputBtn.addEventListener('click', () => {
            inputCode.value = '';
            updateLineNumbers();
            triggerAuditRun();
            inputCode.focus();
        });

        inputCode.addEventListener('input', () => {
            updateLineNumbers();
            triggerAuditRun();
        });
        
        inputCode.addEventListener('scroll', () => { leftLines.scrollTop = inputCode.scrollTop; });

        tabAudit.addEventListener('click', () => {
            tabAudit.className = "tab-btn active";
            tabPackage.className = "tab-btn";
            auditView.style.display = "flex";
            packageView.setAttribute('style', 'display:none;');
            triggerAuditRun();
        });

        tabPackage.addEventListener('click', () => {
            tabPackage.className = "tab-btn active";
            tabAudit.className = "tab-btn";
            auditView.style.display = "none";
            packageView.style.display = "flex";
        });

        btnBuildPackage.addEventListener('click', () => {
            const metaData = {
                name: metaName.value,
                version: metaVersion.value,
                match: metaMatch.value,
                desc: metaDesc.value
            };
            outputPackageCode.value = generateBoilerplate(inputCode.value, metaData);
        });

        // Tek Tıkla Kopyalama Kolaylığı
        btnCopyPackage.addEventListener('click', () => {
            if (outputPackageCode.value.trim()) {
                navigator.clipboard.writeText(outputPackageCode.value);
                const oldText = btnCopyPackage.textContent;
                btnCopyPackage.textContent = "Copied!";
                setTimeout(() => { btnCopyPackage.textContent = oldText; }, 1500);
            }
        });

        const closePanel = () => { if (mainHost) { mainHost.remove(); mainHost = null; } };
        closeBtn.addEventListener('click', closePanel);
        document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closePanel(); });

        updateLanguageUI(currentLang);
        updateLineNumbers();
    }

    document.addEventListener('keydown', (e) => {
        if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === 'a') {
            e.preventDefault(); toggleAnalyzerPanel();
        }
    });
})();