Greasy Fork

Greasy Fork is available in English.

Deepseek Privacy

Hide and replace sensitive data on the chat interface with a user-friendly UI.

// ==UserScript==
// @name         Deepseek Privacy
// @namespace    https://github.com/landifrancesco/Deepseek-Privacy
// @version      1
// @description  Hide and replace sensitive data on the chat interface with a user-friendly UI.
// @author       Francesco Landi
// @match        https://chat.deepseek.com/a/chat/s/*
// @grant        GM_addStyle
// @license      GNU General Public License v3.0
// ==/UserScript==

(function () {
    'use strict';

    // Load saved sensitive data from localStorage
    let sensitiveData = JSON.parse(localStorage.getItem('sensitiveData')) || {};
    let caseSensitive = JSON.parse(localStorage.getItem('caseSensitive')) || false;

    // Function to replace sensitive data
    function replaceSensitiveData() {
        const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
        let node;

        while (node = walker.nextNode()) {
            // Skip if the node is within the popup
            if (node.parentElement.closest('#sensitiveDataPopup')) continue;

            let text = node.nodeValue;

            // Replace each sensitive word
            for (const [word, replacement] of Object.entries(sensitiveData)) {
                const regex = new RegExp(word, caseSensitive ? "g" : "gi"); // Use "g" or "gi" based on caseSensitive
                text = text.replace(regex, replacement);
            }

            node.nodeValue = text;
        }
    }

    // Function to detect the page theme
    function detectTheme() {
        const bgColor = window.getComputedStyle(document.body).backgroundColor;
        const rgb = bgColor.match(/\d+/g);
        if (rgb) {
            const brightness = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
            return brightness > 128 ? 'light' : 'dark';
        }
        return 'light'; // Default to light theme if detection fails
    }

    // Function to create the lock icon and popup UI
    function createUI() {
        const theme = detectTheme();
        const isDarkTheme = theme === 'dark';

        // Add styles for the lock icon and popup
        GM_addStyle(`
            #sensitiveDataLock {
                position: fixed;
                top: 10px;
                right: 10px;
                z-index: 1000;
                cursor: pointer;
                font-size: 24px;
                color: ${isDarkTheme ? '#fff' : '#555'};
            }
            #sensitiveDataPopup {
                display: none;
                position: fixed;
                top: 50px;
                right: 10px;
                z-index: 1000;
                background: ${isDarkTheme ? '#333' : '#fff'};
                border: 1px solid ${isDarkTheme ? '#555' : '#ccc'};
                padding: 10px;
                box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
                width: 300px;
                color: ${isDarkTheme ? '#fff' : '#000'};
            }
            #sensitiveDataPopup input {
                width: 100%;
                margin-bottom: 10px;
                padding: 5px;
                background: ${isDarkTheme ? '#444' : '#fff'};
                color: ${isDarkTheme ? '#fff' : '#000'};
                border: 1px solid ${isDarkTheme ? '#555' : '#ccc'};
            }
            #sensitiveDataPopup button {
                padding: 5px 10px;
                margin-right: 5px;
                background: ${isDarkTheme ? '#555' : '#eee'};
                color: ${isDarkTheme ? '#fff' : '#000'};
                border: 1px solid ${isDarkTheme ? '#666' : '#ccc'};
                cursor: pointer;
            }
            #sensitiveDataList {
                max-height: 200px;
                overflow-y: auto;
                margin-bottom: 10px;
            }
            .case-sensitive-container {
                display: flex;
                align-items: center;
                margin-bottom: 10px;
            }
            .case-sensitive-container label {
                margin-left: 5px;
            }
        `);

        // Create the lock icon
        const lockIcon = document.createElement('div');
        lockIcon.id = 'sensitiveDataLock';
        lockIcon.innerHTML = '🔒';
        document.body.appendChild(lockIcon);

        // Create the popup
        const popup = document.createElement('div');
        popup.id = 'sensitiveDataPopup';
        popup.innerHTML = `
            <h3>Sensitive Data Hider</h3>
            <input id="sensitiveWordInput" placeholder="Sensitive Word">
            <input id="replacementInput" placeholder="Replacement">
            <div class="case-sensitive-container">
                <input type="checkbox" id="caseSensitiveCheckbox">
                <label for="caseSensitiveCheckbox">Case Sensitive</label>
            </div>
            <button id="addSensitiveData">Add</button>
            <div id="sensitiveDataList"></div>
            <button id="closePopup">Close</button>
        `;
        document.body.appendChild(popup);

        // Toggle popup visibility
        lockIcon.addEventListener('click', () => {
            popup.style.display = popup.style.display === 'block' ? 'none' : 'block';
            updateSensitiveDataList();
            // Update the checkbox state when the popup is opened
            document.getElementById('caseSensitiveCheckbox').checked = caseSensitive;
        });

        // Close popup
        document.getElementById('closePopup').addEventListener('click', () => {
            popup.style.display = 'none';
        });

        // Add new sensitive word and replacement
        document.getElementById('addSensitiveData').addEventListener('click', () => {
            const word = document.getElementById('sensitiveWordInput').value.trim();
            const replacement = document.getElementById('replacementInput').value.trim();

            if (word && replacement) {
                sensitiveData[word] = replacement;
                localStorage.setItem('sensitiveData', JSON.stringify(sensitiveData));
                updateSensitiveDataList();
                replaceSensitiveData();
                document.getElementById('sensitiveWordInput').value = '';
                document.getElementById('replacementInput').value = '';
            }
        });

        // Update the list of sensitive words and replacements
        function updateSensitiveDataList() {
            const list = document.getElementById('sensitiveDataList');
            list.innerHTML = Object.entries(sensitiveData)
                .map(([word, replacement]) => `
                    <div>
                        <strong>${word}</strong> → ${replacement}
                        <button data-word="${word}" class="removeButton">Remove</button>
                    </div>
                `)
                .join('');

            // Add event listeners to the remove buttons
            document.querySelectorAll('.removeButton').forEach(button => {
                button.addEventListener('click', () => {
                    const word = button.getAttribute('data-word');
                    removeSensitiveData(word);
                });
            });
        }

        // Remove a sensitive word and replacement
        function removeSensitiveData(word) {
            delete sensitiveData[word];
            localStorage.setItem('sensitiveData', JSON.stringify(sensitiveData));
            updateSensitiveDataList();
            replaceSensitiveData();
        }

        // Toggle case sensitivity
        document.getElementById('caseSensitiveCheckbox').addEventListener('change', (event) => {
            caseSensitive = event.target.checked;
            localStorage.setItem('caseSensitive', JSON.stringify(caseSensitive));
            replaceSensitiveData(); // Reapply replacements with the new case sensitivity setting
        });

        // Initialize the checkbox state
        document.getElementById('caseSensitiveCheckbox').checked = caseSensitive;
    }

    // Initialize the UI and replace sensitive data
    createUI();
    replaceSensitiveData();

    // Observe DOM changes for dynamic content
    const observer = new MutationObserver(replaceSensitiveData);
    observer.observe(document.body, { childList: true, subtree: true });
})();