Nojima Cookie Sender

Gửi cookies về server local khi vào trang mypage hoặc cart

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Nojima Cookie Sender
// @namespace    http://tampermonkey.net/
// @version      1.5
// @description  Gửi cookies về server local khi vào trang mypage hoặc cart
// @author       You
// @match        https://online.nojima.co.jp/app/mypage/mypage/*
// @match        https://online.nojima.co.jp/app/mypage/mypage
// @match        https://online.nojima.co.jp/sp/app/mypage/mypage/*
// @match        https://online.nojima.co.jp/sp/app/mypage/mypage
// @match        https://online.nojima.co.jp/sp/app/cart/cart/*
// @match        https://online.nojima.co.jp/sp/app/cart/cart
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      localhost
// @connect      127.0.0.1
// @connect      192.168.1.13
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // ====== CẤU HÌNH ======
    const SERVER_URL = 'http://192.168.1.13:3000/receive-cookies';
    const CHECK_INTERVAL = 2000; // Kiểm tra mỗi 2 giây
    const MAX_WAIT_TIME = 30000; // Đợi tối đa 30 giây

    // ====== HÀM UTILITY ======

    // Lưu trữ Set-Cookie headers
    let capturedSetCookies = [];
    let lastResponseHeaders = null;

    // Intercept fetch để lấy Set-Cookie headers
    const originalFetch = window.fetch;
    window.fetch = async function(...args) {
        const response = await originalFetch(...args);
        
        // Clone response để đọc headers
        const clonedResponse = response.clone();
        
        // Lấy Set-Cookie từ headers (nếu có)
        const setCookie = clonedResponse.headers.get('set-cookie');
        if (setCookie) {
            console.log('[Nojima] Phát hiện Set-Cookie header:', setCookie);
            capturedSetCookies.push({
                url: args[0],
                timestamp: new Date().toISOString(),
                setCookie: setCookie
            });
        }
        
        // Lưu headers
        lastResponseHeaders = Array.from(clonedResponse.headers.entries());
        
        return response;
    };

    // Intercept XMLHttpRequest để lấy Set-Cookie
    const originalXHROpen = XMLHttpRequest.prototype.open;
    const originalXHRSend = XMLHttpRequest.prototype.send;
    
    XMLHttpRequest.prototype.open = function(...args) {
        this._url = args[1];
        return originalXHROpen.apply(this, args);
    };
    
    XMLHttpRequest.prototype.send = function(...args) {
        this.addEventListener('load', function() {
            const setCookie = this.getResponseHeader('set-cookie');
            if (setCookie) {
                console.log('[Nojima] XHR Set-Cookie:', setCookie);
                capturedSetCookies.push({
                    url: this._url,
                    timestamp: new Date().toISOString(),
                    setCookie: setCookie
                });
            }
        });
        return originalXHRSend.apply(this, args);
    };

    // Lấy tất cả cookies hiện tại
    function getAllCookies() {
        const cookies = document.cookie.split(';').map(cookie => {
            const [name, ...rest] = cookie.trim().split('=');
            return {
                name: name,
                value: rest.join('=')
            };
        });
        return cookies;
    }

    // Lấy cookie cụ thể
    function getCookie(name) {
        const value = `; ${document.cookie}`;
        const parts = value.split(`; ${name}=`);
        if (parts.length === 2) return parts.pop().split(';').shift();
        return null;
    }

    // Parse Set-Cookie header thành array
    function parseSetCookieHeader(setCookieString) {
        if (!setCookieString) return [];
        
        // Split by comma nhưng chú ý không split trong expires date
        const cookies = [];
        let current = '';
        let inExpires = false;
        
        for (let i = 0; i < setCookieString.length; i++) {
            const char = setCookieString[i];
            
            if (char === ',' && !inExpires) {
                if (current.trim()) {
                    cookies.push(current.trim());
                }
                current = '';
            } else {
                current += char;
                if (setCookieString.substr(i, 8).toLowerCase() === 'expires=') {
                    inExpires = true;
                }
                if (char === ';') {
                    inExpires = false;
                }
            }
        }
        
        if (current.trim()) {
            cookies.push(current.trim());
        }
        
        return cookies;
    }

    // Kiểm tra có phải trang hợp lệ không (không bị redirect)
    function isValidPage() {
        const currentUrl = window.location.href;
        const isMypage = currentUrl.includes('/mypage/mypage'); // Bỏ /app/ để match cả /sp/app/mypage
        const isCart = currentUrl.includes('/sp/app/cart/cart');

        // Kiểm tra xem có bị redirect về login không
        if (currentUrl.includes('/login')) {
            console.log('[Nojima] Bị redirect về login - cookies không hợp lệ');
            return false;
        }

        // Kiểm tra xem có bị redirect về error không
        if (currentUrl.includes('/error')) {
            console.log('[Nojima] Bị redirect về error');
            return false;
        }

        // Nếu là mypage (cả desktop /app/ và mobile /sp/app/)
        if (isMypage) {
            const pageType = currentUrl.includes('/sp/') ? 'mypage (mobile)' : 'mypage (desktop)';
            console.log(`[Nojima] Đang ở trang ${pageType}`);
            
            // Kiểm tra có element đặc trưng
            const mypageElements = document.querySelector('[class*="mypage"], [id*="mypage"], .member-info, .user-info, body');
            
            // Hoặc kiểm tra title
            const titleCheck = document.title.includes('マイページ') || 
                              document.title.includes('mypage') || 
                              document.title.toLowerCase().includes('my page');
            
            return mypageElements !== null || titleCheck;
        }

        // Nếu là cart
        if (isCart) {
            console.log('[Nojima] Đang ở trang cart');
            const cartElements = document.querySelector('.cart-list, .cart-item, [class*="cart"], body');
            return cartElements !== null;
        }

        return false;
    }

    // Gửi cookies về server
    function sendCookiesToServer() {
        const cookies = getAllCookies();

        // Lấy các cookies quan trọng
        const importantCookies = {
            '_abck': getCookie('_abck'),
            'JSESSIONID': getCookie('JSESSIONID'),
            'bm_sz': getCookie('bm_sz'),
            'bm_sv': getCookie('bm_sv'),
            'bm_mi': getCookie('bm_mi')
        };

        // Parse Set-Cookie headers đã capture
        const parsedSetCookies = [];
        capturedSetCookies.forEach(item => {
            const parsed = parseSetCookieHeader(item.setCookie);
            parsed.forEach(cookie => {
                parsedSetCookies.push({
                    url: item.url,
                    timestamp: item.timestamp,
                    rawCookie: cookie,
                    // Parse name=value
                    name: cookie.split('=')[0],
                    value: cookie.split('=').slice(1).join('=').split(';')[0]
                });
            });
        });

        const data = {
            timestamp: new Date().toISOString(),
            url: window.location.href,
            cookies: cookies,
            importantCookies: importantCookies,
            userAgent: navigator.userAgent,
            cookieString: document.cookie,
            // Thêm Set-Cookie headers
            setCookieHeaders: capturedSetCookies,
            parsedSetCookies: parsedSetCookies,
            lastResponseHeaders: lastResponseHeaders
        };

        console.log('[Nojima] Đang gửi cookies về server (có Set-Cookie headers)...', data);

        // Gửi bằng GM_xmlhttpRequest (bypass CORS)
        GM_xmlhttpRequest({
            method: 'POST',
            url: SERVER_URL,
            headers: {
                'Content-Type': 'application/json'
            },
            data: JSON.stringify(data),
            onload: function(response) {
                if (response.status === 200) {
                    console.log('[Nojima] ✅ Đã gửi cookies thành công!');
                    console.log('[Nojima] Response:', response.responseText);

                    // Hiển thị thông báo trên trang
                    showNotification('✅ Cookies đã được gửi về server!', 'success');

                    // Lưu timestamp để tránh gửi lại quá nhanh
                    GM_setValue('lastSentTime', Date.now());
                } else {
                    console.error('[Nojima] ❌ Lỗi khi gửi cookies:', response.status, response.statusText);
                    showNotification('❌ Lỗi khi gửi cookies: ' + response.status, 'error');
                }
            },
            onerror: function(error) {
                console.error('[Nojima] ❌ Không thể kết nối đến server:', error);
                showNotification('❌ Không thể kết nối đến server local!', 'error');
            }
        });
    }

    // Hiển thị thông báo trên trang
    function showNotification(message, type = 'info') {
        // Tạo element notification
        const notification = document.createElement('div');
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 15px 20px;
            background-color: ${type === 'success' ? '#4CAF50' : type === 'error' ? '#f44336' : '#2196F3'};
            color: white;
            border-radius: 5px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            z-index: 999999;
            font-family: Arial, sans-serif;
            font-size: 14px;
            max-width: 300px;
            animation: slideIn 0.3s ease-out;
        `;
        notification.textContent = message;

        // Thêm animation
        const style = document.createElement('style');
        style.textContent = `
            @keyframes slideIn {
                from {
                    transform: translateX(400px);
                    opacity: 0;
                }
                to {
                    transform: translateX(0);
                    opacity: 1;
                }
            }
        `;
        document.head.appendChild(style);

        document.body.appendChild(notification);

        // Tự động xóa sau 5 giây
        setTimeout(() => {
            notification.style.animation = 'slideOut 0.3s ease-out';
            setTimeout(() => notification.remove(), 300);
        }, 5000);
    }

    // ====== MAIN LOGIC ======

    function main() {
        console.log('[Nojima] Script đã load!');
        console.log('[Nojima] URL hiện tại:', window.location.href);

        // Kiểm tra xem đã gửi gần đây chưa (tránh spam)
        const lastSentTime = GM_getValue('lastSentTime', 0);
        const timeSinceLastSent = Date.now() - lastSentTime;

        if (timeSinceLastSent < 10000) { // 10 giây
            console.log('[Nojima] Vừa mới gửi cookies, bỏ qua lần này');
            showNotification('ℹ️ Vừa mới gửi cookies rồi', 'info');
            return;
        }

        let attempts = 0;
        const maxAttempts = MAX_WAIT_TIME / CHECK_INTERVAL;

        showNotification('⏳ Đang kiểm tra trang...', 'info');

        // Đợi và kiểm tra trang có load đầy đủ không
        const checkInterval = setInterval(() => {
            attempts++;

            console.log(`[Nojima] Kiểm tra lần ${attempts}/${maxAttempts}...`);

            if (isValidPage()) {
                console.log('[Nojima] ✅ Trang đã load thành công!');
                clearInterval(checkInterval);

                // Đợi thêm 2 giây để chắc chắn
                setTimeout(() => {
                    sendCookiesToServer();
                }, 2000);

            } else if (attempts >= maxAttempts) {
                console.log('[Nojima] ⏱️ Timeout - trang không hợp lệ hoặc bị redirect');
                clearInterval(checkInterval);
                showNotification('⚠️ Không thể xác nhận trang', 'error');
            }
        }, CHECK_INTERVAL);
    }

    // Chạy khi DOM ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', main);
    } else {
        main();
    }

})();