Cookie Manager

Powerful cookie management tool with blurred glassmorphism UI

当前为 2025-10-29 提交的版本,查看 最新版本

// ==UserScript==
// @name         Cookie Manager
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Powerful cookie management tool with blurred glassmorphism UI
// @author       Balta zar
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_xmlhttpRequest
// @run-at       document-end
// @license      temporary on hold 📢
// ==/UserScript==

(function() {
    'use strict';

    // Cookie Manager Class
    class CookieManager {
        constructor() {
            this.currentDomain = window.location.hostname;
            this.cookies = [];
            this.filteredCookies = [];
            this.init();
        }

        async init() {
            this.loadCookies();
            this.createUI();
            this.bindEvents();
        }

        // Load cookies from current domain
        loadCookies() {
            this.cookies = [];
            const cookieString = document.cookie;
            
            if (!cookieString) return;

            const cookiePairs = cookieString.split(';');
            
            cookiePairs.forEach(pair => {
                const [name, ...valueParts] = pair.trim().split('=');
                const value = valueParts.join('=');
                
                if (name) {
                    this.cookies.push({
                        name: decodeURIComponent(name),
                        value: decodeURIComponent(value),
                        domain: this.currentDomain,
                        path: this.getCookiePath(name),
                        expires: this.getCookieExpiration(name),
                        secure: this.isCookieSecure(name),
                        httpOnly: false // Cannot detect via JavaScript
                    });
                }
            });

            this.filteredCookies = [...this.cookies];
        }

        // Helper methods to get cookie attributes
        getCookiePath(name) {
            // In a real implementation, this would need more complex logic
            return '/';
        }

        getCookieExpiration(name) {
            // Cannot reliably get expiration via JavaScript alone
            // This would require extension permissions
            return null;
        }

        isCookieSecure(name) {
            // Cannot reliably detect secure flag via JavaScript
            return false;
        }

        // Create the UI
        createUI() {
            const style = document.createElement('style');
            style.textContent = `
                .cookie-manager-container {
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    width: 90%;
                    max-width: 1000px;
                    max-height: 90vh;
                    background: rgba(255, 255, 255, 0.15);
                    backdrop-filter: blur(10px);
                    border-radius: 20px;
                    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
                    border: 1px solid rgba(255, 255, 255, 0.18);
                    overflow: hidden;
                    color: white;
                    z-index: 10000;
                    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                }

                .cookie-manager-container * {
                    margin: 0;
                    padding: 0;
                    box-sizing: border-box;
                }

                .cookie-header {
                    padding: 20px;
                    background: rgba(0, 0, 0, 0.2);
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
                }

                .cookie-header h1 {
                    font-size: 1.8rem;
                    font-weight: 600;
                }

                .cookie-controls {
                    display: flex;
                    gap: 10px;
                }

                .cookie-btn {
                    padding: 10px 20px;
                    border: none;
                    border-radius: 10px;
                    background: rgba(255, 255, 255, 0.2);
                    color: white;
                    font-weight: 500;
                    cursor: pointer;
                    transition: all 0.3s ease;
                    display: flex;
                    align-items: center;
                    gap: 8px;
                }

                .cookie-btn:hover {
                    background: rgba(255, 255, 255, 0.3);
                    transform: translateY(-2px);
                }

                .cookie-btn-primary {
                    background: rgba(103, 58, 183, 0.7);
                }

                .cookie-btn-primary:hover {
                    background: rgba(103, 58, 183, 0.9);
                }

                .cookie-btn-danger {
                    background: rgba(244, 67, 54, 0.7);
                }

                .cookie-btn-danger:hover {
                    background: rgba(244, 67, 54, 0.9);
                }

                .cookie-content {
                    padding: 20px;
                    max-height: 500px;
                    overflow-y: auto;
                }

                .cookie-filters {
                    display: flex;
                    gap: 15px;
                    margin-bottom: 20px;
                    flex-wrap: wrap;
                }

                .cookie-search {
                    flex: 1;
                    min-width: 200px;
                }

                .cookie-domain-filter {
                    min-width: 150px;
                }

                .cookie-input {
                    width: 100%;
                    padding: 10px 15px;
                    background: rgba(255, 255, 255, 0.1);
                    border: 1px solid rgba(255, 255, 255, 0.2);
                    border-radius: 8px;
                    color: white;
                    font-size: 1rem;
                }

                .cookie-input:focus {
                    outline: none;
                    border-color: rgba(103, 58, 183, 0.7);
                }

                .cookie-table {
                    width: 100%;
                    border-collapse: collapse;
                }

                .cookie-table th, .cookie-table td {
                    padding: 12px 15px;
                    text-align: left;
                    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
                }

                .cookie-table th {
                    background: rgba(0, 0, 0, 0.2);
                    font-weight: 600;
                }

                .cookie-table tr:hover {
                    background: rgba(255, 255, 255, 0.05);
                }

                .cookie-actions {
                    display: flex;
                    gap: 8px;
                }

                .cookie-action-btn {
                    background: none;
                    border: none;
                    color: white;
                    cursor: pointer;
                    padding: 5px;
                    border-radius: 5px;
                    transition: background 0.3s;
                }

                .cookie-action-btn:hover {
                    background: rgba(255, 255, 255, 0.1);
                }

                .cookie-empty-state {
                    text-align: center;
                    padding: 40px 20px;
                    color: rgba(255, 255, 255, 0.7);
                }

                .cookie-modal {
                    display: none;
                    position: fixed;
                    top: 0;
                    left: 0;
                    width: 100%;
                    height: 100%;
                    background: rgba(0, 0, 0, 0.5);
                    backdrop-filter: blur(5px);
                    z-index: 10001;
                    justify-content: center;
                    align-items: center;
                }

                .cookie-modal-content {
                    background: rgba(30, 30, 46, 0.9);
                    backdrop-filter: blur(10px);
                    border-radius: 15px;
                    padding: 25px;
                    width: 90%;
                    max-width: 500px;
                    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
                    border: 1px solid rgba(255, 255, 255, 0.1);
                }

                .cookie-modal-header {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    margin-bottom: 20px;
                }

                .cookie-modal-header h2 {
                    font-size: 1.5rem;
                    font-weight: 600;
                }

                .cookie-close-btn {
                    background: none;
                    border: none;
                    color: white;
                    font-size: 1.5rem;
                    cursor: pointer;
                }

                .cookie-form-group {
                    margin-bottom: 15px;
                }

                .cookie-form-group label {
                    display: block;
                    margin-bottom: 5px;
                    font-weight: 500;
                }

                .cookie-checkbox-group {
                    display: flex;
                    align-items: center;
                    gap: 10px;
                }

                .cookie-checkbox-group input {
                    width: 18px;
                    height: 18px;
                }

                .cookie-modal-footer {
                    display: flex;
                    justify-content: flex-end;
                    gap: 10px;
                    margin-top: 20px;
                }

                .cookie-toggle-btn {
                    position: fixed;
                    top: 20px;
                    right: 20px;
                    background: rgba(103, 58, 183, 0.7);
                    color: white;
                    border: none;
                    border-radius: 50%;
                    width: 60px;
                    height: 60px;
                    font-size: 24px;
                    cursor: pointer;
                    z-index: 9999;
                    backdrop-filter: blur(10px);
                    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
                    transition: all 0.3s ease;
                }

                .cookie-toggle-btn:hover {
                    background: rgba(103, 58, 183, 0.9);
                    transform: scale(1.1);
                }

                @keyframes cookieFadeIn {
                    from { opacity: 0; transform: translateY(10px); }
                    to { opacity: 1; transform: translateY(0); }
                }

                .cookie-manager-container {
                    animation: cookieFadeIn 0.5s ease;
                }

                @media (max-width: 768px) {
                    .cookie-table {
                        display: block;
                        overflow-x: auto;
                    }
                    
                    .cookie-header {
                        flex-direction: column;
                        gap: 15px;
                        align-items: flex-start;
                    }
                    
                    .cookie-controls {
                        width: 100%;
                        justify-content: space-between;
                    }
                }
            `;
            document.head.appendChild(style);

            // Create toggle button
            this.toggleBtn = document.createElement('button');
            this.toggleBtn.className = 'cookie-toggle-btn';
            this.toggleBtn.innerHTML = '🍪';
            this.toggleBtn.title = 'Cookie Manager';
            document.body.appendChild(this.toggleBtn);

            // Create main container
            this.container = document.createElement('div');
            this.container.className = 'cookie-manager-container';
            this.container.style.display = 'none';
            this.container.innerHTML = `
                <div class="cookie-header">
                    <h1>Cookie Manager</h1>
                    <div class="cookie-controls">
                        <button class="cookie-btn cookie-btn-primary" id="cookieAddBtn">
                            + Add Cookie
                        </button>
                        <button class="cookie-btn" id="cookieRefreshBtn">
                            ↻ Refresh
                        </button>
                        <button class="cookie-btn cookie-btn-danger" id="cookieDeleteAllBtn">
                            × Delete All
                        </button>
                    </div>
                </div>
                
                <div class="cookie-content">
                    <div class="cookie-filters">
                        <div class="cookie-search">
                            <input type="text" class="cookie-input" id="cookieSearchInput" placeholder="Search cookies...">
                        </div>
                        <div class="cookie-domain-filter">
                            <select class="cookie-input" id="cookieDomainFilter">
                                <option value="all">All Domains</option>
                                <option value="current">Current Domain</option>
                            </select>
                        </div>
                    </div>
                    
                    <table class="cookie-table">
                        <thead>
                            <tr>
                                <th>Name</th>
                                <th>Value</th>
                                <th>Domain</th>
                                <th>Path</th>
                                <th>Secure</th>
                                <th>Actions</th>
                            </tr>
                        </thead>
                        <tbody id="cookieListBody">
                        </tbody>
                    </table>
                    
                    <div class="cookie-empty-state" id="cookieEmptyState" style="display: none;">
                        <div style="font-size: 3rem; margin-bottom: 15px; opacity: 0.5;">🍪</div>
                        <h3>No Cookies Found</h3>
                        <p>There are no cookies to display. Add a new cookie to get started.</p>
                    </div>
                </div>
            `;
            document.body.appendChild(this.container);

            // Create modal
            this.modal = document.createElement('div');
            this.modal.className = 'cookie-modal';
            this.modal.innerHTML = `
                <div class="cookie-modal-content">
                    <div class="cookie-modal-header">
                        <h2 id="cookieModalTitle">Add New Cookie</h2>
                        <button class="cookie-close-btn" id="cookieCloseModalBtn">&times;</button>
                    </div>
                    <form id="cookieForm">
                        <div class="cookie-form-group">
                            <label for="cookieNameInput">Name</label>
                            <input type="text" class="cookie-input" id="cookieNameInput" required>
                        </div>
                        <div class="cookie-form-group">
                            <label for="cookieValueInput">Value</label>
                            <input type="text" class="cookie-input" id="cookieValueInput" required>
                        </div>
                        <div class="cookie-form-group">
                            <label for="cookieDomainInput">Domain</label>
                            <input type="text" class="cookie-input" id="cookieDomainInput" value="${this.currentDomain}" required>
                        </div>
                        <div class="cookie-form-group">
                            <label for="cookiePathInput">Path</label>
                            <input type="text" class="cookie-input" id="cookiePathInput" value="/">
                        </div>
                        <div class="cookie-form-group">
                            <label for="cookieExpiresInput">Expires (UTC)</label>
                            <input type="datetime-local" class="cookie-input" id="cookieExpiresInput">
                        </div>
                        <div class="cookie-form-group">
                            <div class="cookie-checkbox-group">
                                <input type="checkbox" id="cookieSecureInput">
                                <label for="cookieSecureInput">Secure</label>
                            </div>
                        </div>
                        <div class="cookie-modal-footer">
                            <button type="button" class="cookie-btn" id="cookieCancelBtn">Cancel</button>
                            <button type="submit" class="cookie-btn cookie-btn-primary" id="cookieSaveBtn">Save Cookie</button>
                        </div>
                    </form>
                </div>
            `;
            document.body.appendChild(this.modal);
        }

        // Bind event listeners
        bindEvents() {
            this.toggleBtn.addEventListener('click', () => this.toggleManager());
            document.getElementById('cookieAddBtn').addEventListener('click', () => this.openAddModal());
            document.getElementById('cookieRefreshBtn').addEventListener('click', () => this.refreshCookies());
            document.getElementById('cookieDeleteAllBtn').addEventListener('click', () => this.deleteAllCookies());
            document.getElementById('cookieCloseModalBtn').addEventListener('click', () => this.closeModal());
            document.getElementById('cookieCancelBtn').addEventListener('click', () => this.closeModal());
            document.getElementById('cookieForm').addEventListener('submit', (e) => this.saveCookie(e));
            document.getElementById('cookieSearchInput').addEventListener('input', () => this.filterCookies());
            document.getElementById('cookieDomainFilter').addEventListener('change', () => this.filterCookies());

            // Close modal when clicking outside
            this.modal.addEventListener('click', (e) => {
                if (e.target === this.modal) {
                    this.closeModal();
                }
            });
        }

        // Toggle manager visibility
        toggleManager() {
            if (this.container.style.display === 'none') {
                this.refreshCookies();
                this.container.style.display = 'block';
            } else {
                this.container.style.display = 'none';
            }
        }

        // Refresh cookies list
        refreshCookies() {
            this.loadCookies();
            this.renderCookies();
        }

        // Render cookies in table
        renderCookies() {
            const tbody = document.getElementById('cookieListBody');
            const emptyState = document.getElementById('cookieEmptyState');
            
            tbody.innerHTML = '';
            
            if (this.filteredCookies.length === 0) {
                emptyState.style.display = 'block';
                return;
            }
            
            emptyState.style.display = 'none';
            
            this.filteredCookies.forEach((cookie, index) => {
                const row = document.createElement('tr');
                
                row.innerHTML = `
                    <td>${this.escapeHtml(cookie.name)}</td>
                    <td title="${this.escapeHtml(cookie.value)}">${this.truncateValue(this.escapeHtml(cookie.value))}</td>
                    <td>${this.escapeHtml(cookie.domain)}</td>
                    <td>${this.escapeHtml(cookie.path)}</td>
                    <td>${cookie.secure ? 'Yes' : 'No'}</td>
                    <td>
                        <div class="cookie-actions">
                            <button class="cookie-action-btn cookie-edit-btn" data-index="${index}" title="Edit">
                                ✏️
                            </button>
                            <button class="cookie-action-btn cookie-delete-btn" data-index="${index}" title="Delete">
                                🗑️
                            </button>
                        </div>
                    </td>
                `;
                
                tbody.appendChild(row);
            });
            
            // Add event listeners to action buttons
            document.querySelectorAll('.cookie-edit-btn').forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const index = parseInt(e.target.closest('.cookie-edit-btn').getAttribute('data-index'));
                    this.openEditModal(index);
                });
            });
            
            document.querySelectorAll('.cookie-delete-btn').forEach(btn => {
                btn.addEventListener('click', (e) => {
                    const index = parseInt(e.target.closest('.cookie-delete-btn').getAttribute('data-index'));
                    this.deleteCookie(index);
                });
            });
        }

        // Filter cookies based on search and domain
        filterCookies() {
            const searchTerm = document.getElementById('cookieSearchInput').value.toLowerCase();
            const domainFilter = document.getElementById('cookieDomainFilter').value;
            
            this.filteredCookies = this.cookies.filter(cookie => {
                const matchesSearch = cookie.name.toLowerCase().includes(searchTerm) || 
                                     cookie.value.toLowerCase().includes(searchTerm);
                
                let matchesDomain = true;
                if (domainFilter === 'current') {
                    matchesDomain = cookie.domain === this.currentDomain;
                }
                
                return matchesSearch && matchesDomain;
            });
            
            this.renderCookies();
        }

        // Open modal for adding new cookie
        openAddModal() {
            document.getElementById('cookieModalTitle').textContent = 'Add New Cookie';
            document.getElementById('cookieForm').reset();
            document.getElementById('cookieDomainInput').value = this.currentDomain;
            this.modal.style.display = 'flex';
        }

        // Open modal for editing existing cookie
        openEditModal(index) {
            const cookie = this.filteredCookies[index];
            document.getElementById('cookieModalTitle').textContent = 'Edit Cookie';
            
            document.getElementById('cookieNameInput').value = cookie.name;
            document.getElementById('cookieValueInput').value = cookie.value;
            document.getElementById('cookieDomainInput').value = cookie.domain;
            document.getElementById('cookiePathInput').value = cookie.path;
            
            if (cookie.expires) {
                const expiresDate = new Date(cookie.expires);
                const localDateTime = expiresDate.toISOString().slice(0, 16);
                document.getElementById('cookieExpiresInput').value = localDateTime;
            } else {
                document.getElementById('cookieExpiresInput').value = '';
            }
            
            document.getElementById('cookieSecureInput').checked = cookie.secure;
            
            // Store the index of the cookie being edited
            document.getElementById('cookieForm').setAttribute('data-edit-index', index);
            
            this.modal.style.display = 'flex';
        }

        // Close modal
        closeModal() {
            this.modal.style.display = 'none';
            document.getElementById('cookieForm').removeAttribute('data-edit-index');
        }

        // Save cookie (add or update)
        saveCookie(e) {
            e.preventDefault();
            
            const cookieData = {
                name: document.getElementById('cookieNameInput').value,
                value: document.getElementById('cookieValueInput').value,
                domain: document.getElementById('cookieDomainInput').value,
                path: document.getElementById('cookiePathInput').value || '/',
                secure: document.getElementById('cookieSecureInput').checked
            };
            
            // Handle expiration
            const expiresInput = document.getElementById('cookieExpiresInput').value;
            if (expiresInput) {
                cookieData.expires = new Date(expiresInput).toUTCString();
            }
            
            const editIndex = document.getElementById('cookieForm').getAttribute('data-edit-index');
            
            if (editIndex !== null) {
                // Update existing cookie
                this.updateCookie(this.filteredCookies[editIndex].name, cookieData);
            } else {
                // Add new cookie
                this.setCookie(cookieData);
            }
            
            this.refreshCookies();
            this.closeModal();
        }

        // Set a cookie
        setCookie(cookie) {
            let cookieString = `${encodeURIComponent(cookie.name)}=${encodeURIComponent(cookie.value)}`;
            
            if (cookie.domain) cookieString += `; domain=${cookie.domain}`;
            if (cookie.path) cookieString += `; path=${cookie.path}`;
            if (cookie.expires) cookieString += `; expires=${cookie.expires}`;
            if (cookie.secure) cookieString += '; secure';
            
            document.cookie = cookieString;
        }

        // Update a cookie
        updateCookie(oldName, newCookie) {
            // Delete old cookie first
            this.deleteCookieByName(oldName);
            // Set new cookie
            this.setCookie(newCookie);
        }

        // Delete a cookie by index
        deleteCookie(index) {
            const cookie = this.filteredCookies[index];
            if (confirm(`Are you sure you want to delete the cookie "${cookie.name}"?`)) {
                this.deleteCookieByName(cookie.name);
                this.refreshCookies();
            }
        }

        // Delete a cookie by name
        deleteCookieByName(name) {
            document.cookie = `${encodeURIComponent(name)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
            // Also try to delete with domain
            document.cookie = `${encodeURIComponent(name)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=${this.currentDomain}; path=/`;
        }

        // Delete all cookies
        deleteAllCookies() {
            if (confirm('Are you sure you want to delete ALL cookies? This action cannot be undone.')) {
                this.cookies.forEach(cookie => {
                    this.deleteCookieByName(cookie.name);
                });
                this.refreshCookies();
            }
        }

        // Utility functions
        escapeHtml(text) {
            const div = document.createElement('div');
            div.textContent = text;
            return div.innerHTML;
        }

        truncateValue(value, maxLength = 30) {
            if (value.length > maxLength) {
                return value.substring(0, maxLength) + '...';
            }
            return value;
        }
    }

    // Initialize the Cookie Manager
    let cookieManager;
    
    function initCookieManager() {
        if (!cookieManager) {
            cookieManager = new CookieManager();
        }
    }

    // Add key shortcut (Ctrl+Shift+C) to open manager
    document.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.shiftKey && e.key === 'C') {
            e.preventDefault();
            initCookieManager();
            cookieManager.toggleManager();
        }
    });

    // Export for manual initialization if needed
    window.CookieManager = {
        init: initCookieManager
    };

    console.log('Cookie Manager userscript loaded. Use Ctrl+Shift+C to open, or click the cookie button.');
})();