[
    {
        "file": "\/home\/coicom\/public_html\/2\/php-filemanager\/config.php",
        "content": "<?php\n\/**\n * PHP File Manager - c\u1ea5u h\u00ecnh ch\u00ednh\n * \u0110\u1ed5i username\/password_hash ngay sau khi upload l\u00ean hosting\/VPS.\n * T\u1ea1o hash m\u1edbi b\u1eb1ng l\u1ec7nh PHP:\n * php -r \"echo password_hash('mat_khau_moi', PASSWORD_DEFAULT);\"\n *\/\nreturn [\n    'app_name' => 'PHP File Manager',\n\n    \/\/ \u0110\u0103ng nh\u1eadp m\u1eb7c \u0111\u1ecbnh: admin \/ admin123\n    'username' => 'admin',\n    'password_hash' => 'y$G\/pV\/0eAOHk6dJ\/\/OafNWO.ZLOncXiKv34jecgwGH.714ntPE1aC6',\n    'session_timeout' => 86400,\n\n    \/\/ B\u1ea3o m\u1eadt \u0111\u0103ng nh\u1eadp. N\u1ebfu m\u1eadt kh\u1ea9u v\u1eabn l\u00e0 admin123, h\u1ec7 th\u1ed1ng b\u1eaft bu\u1ed9c \u0111\u1ed5i m\u1eadt kh\u1ea9u sau khi \u0111\u0103ng nh\u1eadp.\n    'force_change_default_password' => true,\n    'default_password_for_detection' => 'admin123',\n    'login_max_attempts' => 5,\n    'login_lock_seconds' => 900,\n    'login_attempt_storage' => __DIR__ . '\/.data\/login_attempts.json',\n\n    \/\/ IP allowlist: \u0111\u1ec3 r\u1ed7ng = kh\u00f4ng gi\u1edbi h\u1ea1n IP. H\u1ed7 tr\u1ee3 IP ch\u00ednh x\u00e1c ho\u1eb7c CIDR, v\u00ed d\u1ee5: '1.2.3.4', '192.168.1.0\/24'.\n    \/\/ H\u1ec7 th\u1ed1ng ki\u1ec3m tra theo REMOTE_ADDR \u0111\u1ec3 tr\u00e1nh b\u1ecb gi\u1ea3 m\u1ea1o b\u1eb1ng header proxy.\n    'allowed_ips' => [],\n\n    \/\/ Security headers. HSTS m\u1eb7c \u0111\u1ecbnh t\u1eaft \u0111\u1ec3 tr\u00e1nh l\u1ed7i n\u1ebfu website ch\u01b0a ch\u1ea1y HTTPS \u1ed5n \u0111\u1ecbnh.\n    'security_headers' => [\n        'enabled' => true,\n        'hsts' => false,\n    ],\n\n    \/\/ M\u1eb7c \u0111\u1ecbnh m\u1edf l\u00f9i 1 c\u1ea5p so v\u1edbi th\u01b0 m\u1ee5c ch\u1ee9a filemanager.\n    \/\/ V\u00ed d\u1ee5: \/home\/user\/public_html\/php-filemanager => \/home\/user\/public_html\n    \/\/ Khi allow_root_access = true, c\u00f3 th\u1ec3 duy\u1ec7t ra ngo\u00e0i th\u01b0 m\u1ee5c n\u00e0y n\u1ebfu PHP c\u00f3 quy\u1ec1n.\n    'start_path' => dirname(__DIR__),\n    'allow_root_access' => true,\n    'show_hidden_files' => true,\n\n    \/\/ Upload: 0 = kh\u00f4ng gi\u1edbi h\u1ea1n \u1edf t\u1ea7ng code filemanager.\n    \/\/ Hosting\/PHP v\u1eabn c\u00f3 th\u1ec3 gi\u1edbi h\u1ea1n b\u1edfi upload_max_filesize, post_max_size, memory_limit...\n    'allow_upload_all_files' => true,\n    'max_upload_size' => 0,\n    'overwrite_upload' => false,\n\n    \/\/ Ch\u1ec9nh s\u1eeda file text\/code ph\u1ed5 bi\u1ebfn.\n    'allow_edit_all_text_files' => true,\n    'allow_edit_php' => true,\n    'allow_edit_python' => true,\n    'max_edit_file_size' => 10485760, \/\/ 10MB, \u0111\u1ed5i th\u00e0nh 0 n\u1ebfu mu\u1ed1n kh\u00f4ng gi\u1edbi h\u1ea1n khi m\u1edf editor.\n    'editable_extensions' => [\n        'txt','md','log','ini','conf','env','htaccess','htpasswd',\n        'php','phtml','php5','py','pyw','html','htm','css','scss','sass',\n        'js','mjs','json','xml','yml','yaml','sql','csv','ts','tsx','jsx',\n        'vue','blade.php','tpl','twig','sh','bat','ps1','java','c','cpp','h','hpp',\n        'go','rs','rb','pl','lua','dart','swift','kt','gradle','dockerfile'\n    ],\n\n    \/\/ Quy\u1ec1n thao t\u00e1c.\n    'allow_create_file' => true,\n    'allow_create_dir' => true,\n    'allow_delete' => true,\n    'allow_rename' => true,\n    'allow_copy' => true,\n    'allow_move' => true,\n    'allow_download' => true,\n\n];\n",
        "time": "2026-07-04 10:11:45"
    },
    {
        "file": "\/home\/coicom\/public_html\/2\/php-filemanager\/.data\/login_attempts.json",
        "content": "{\n    \"02e7943a206ddb42e1d7fe27a90957aad54b9a5d4f00d6ede959c22d08bc0296\": {\n        \"count\": 3,\n        \"locked_until\": 0,\n        \"last\": 1783134639\n    }\n}",
        "time": "2026-07-04 10:11:30"
    },
    {
        "file": "\/home\/coicom\/public_html\/dulieu_3.json",
        "content": "[\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/README_PRIVATE_STORAGE.txt\",\n        \"content\": \"C\\u00e1c th\\u01b0 m\\u1ee5c data, backup, codes, kho-tdata, uploads v\\u00e0 source-sync-master-data \\u0111\\u00e3 \\u0111\\u01b0\\u1ee3c \\u0111\\u01b0a ra ngang c\\u1ea5p public.\\n\\nKhuy\\u1ebfn ngh\\u1ecb tri\\u1ec3n khai an to\\u00e0n nh\\u1ea5t: c\\u1ea5u h\\u00ecnh DocumentRoot\\\/web root tr\\u1ecf tr\\u1ef1c ti\\u1ebfp v\\u00e0o th\\u01b0 m\\u1ee5c public. Khi \\u0111\\u00f3 c\\u00e1c th\\u01b0 m\\u1ee5c ngang c\\u1ea5p public kh\\u00f4ng th\\u1ec3 truy c\\u1eadp b\\u1eb1ng URL.\\n\\nB\\u1ed9 code v\\u1eabn k\\u00e8m .htaccess, web.config v\\u00e0 index.php ch\\u1eb7n truy c\\u1eadp trong c\\u00e1c th\\u01b0 m\\u1ee5c private. Tuy nhi\\u00ean, n\\u1ebfu hosting \\u0111\\u1eb7t web root \\u1edf th\\u01b0 m\\u1ee5c cha v\\u00e0 web server kh\\u00f4ng \\u0111\\u1ecdc .htaccess\\\/web.config, file t\\u0129nh nh\\u01b0 JSON\\\/ZIP c\\u00f3 th\\u1ec3 v\\u1eabn b\\u1ecb web server ph\\u1ee5c v\\u1ee5 tr\\u1ef1c ti\\u1ebfp tr\\u01b0\\u1edbc khi PHP ch\\u1ea1y. Admin Dashboard c\\u00f3 c\\u1ea3nh b\\u00e1o v\\u00e0 probe URL \\u0111\\u1ec3 ph\\u00e1t hi\\u1ec7n t\\u00ecnh hu\\u1ed1ng n\\u00e0y. V\\u1edbi Nginx, h\\u00e3y tr\\u1ecf root v\\u1ec1 public ho\\u1eb7c c\\u1ea5u h\\u00ecnh deny tr\\u1ef1c ti\\u1ebfp cho \\\/data, \\\/backup, \\\/codes, \\\/kho-tdata, \\\/uploads, \\\/source-sync-master-data.\\n\\nC\\u1eadp nh\\u1eadt JSON sharding:\\n- C\\u00e1c file JSON l\\u1edbn nh\\u01b0 users.json, orders.json, transactions.json, deposits.json, tickets.json, telegram-users.json, telegram-broadcasts.json, security-logs.json v\\u00e0 webhook-events.json hi\\u1ec7n ch\\u1ec9 c\\u00f2n l\\u00e0 manifest nh\\u1ecf.\\n- D\\u1eef li\\u1ec7u th\\u1eadt \\u0111\\u01b0\\u1ee3c chia nh\\u1ecf trong data\\\/<collection>\\\/shards\\\/ v\\u00e0 c\\u00f3 _meta.json \\\/ _index.json \\u0111\\u1ec3 theo d\\u00f5i shard, s\\u1ed1 l\\u01b0\\u1ee3ng b\\u1ea3n ghi v\\u00e0 index tra c\\u1ee9u.\\n- Khi h\\u1ec7 th\\u1ed1ng g\\u1eb7p file JSON c\\u0169, n\\u00f3 s\\u1ebd t\\u1ef1 backup v\\u00e0o backup\\\/migrations\\\/ r\\u1ed3i migrate sang d\\u1ea1ng sharded. Logic PHP c\\u0169 v\\u1eabn d\\u00f9ng read_json_file()\\\/write_json_file(), n\\u00ean d\\u1eef li\\u1ec7u tr\\u1ea3 v\\u1ec1 v\\u1eabn gi\\u1eef c\\u1ea5u tr\\u00fac c\\u0169.\\n- User ID v\\u1eabn gi\\u1eef chu\\u1ea9n 3 ch\\u1eef s\\u1ed1 100-999; vi\\u1ec7c t\\u1ea1o t\\u00e0i kho\\u1ea3n m\\u1edbi v\\u1eabn ch\\u1ea1y trong app.lock n\\u00ean tr\\u00e1nh tr\\u00f9ng ID khi c\\u00f3 nhi\\u1ec1u request \\u0111\\u1ed3ng th\\u1eddi.\\n\",\n        \"time\": \"2026-07-02 17:34:06\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/public_html\\\/dulieu_3.json\",\n        \"content\": \"[\\n    {\\n        \\\"file\\\": \\\"\\\\\\\/home\\\\\\\/coicom\\\\\\\/1.1ccmm.my\\\\\\\/data\\\\\\\/settings.json\\\",\\n        \\\"content\\\": \\\"{\\\\n    \\\\\\\"site_title\\\\\\\": \\\\\\\"Shop Balance\\\\\\\",\\\\n    \\\\\\\"site_description\\\\\\\": \\\\\\\"H\\\\u1ec7 th\\\\u1ed1ng b\\\\u00e1n s\\\\u1ea3n ph\\\\u1ea9m t\\\\u1ef1 \\\\u0111\\\\u1ed9ng b\\\\u1eb1ng s\\\\u1ed1 d\\\\u01b0.\\\\\\\",\\\\n    \\\\\\\"site_keywords\\\\\\\": \\\\\\\"shop t\\\\u1ef1 \\\\u0111\\\\u1ed9ng, s\\\\u1ea3n ph\\\\u1ea9m s\\\\u1ed1, n\\\\u1ea1p ti\\\\u1ec1n, \\\\u0111\\\\u01a1n h\\\\u00e0ng t\\\\u1ef1 \\\\u0111\\\\u1ed9ng\\\\\\\",\\\\n    \\\\\\\"site_author\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"site_robots\\\\\\\": \\\\\\\"index,follow\\\\\\\",\\\\n    \\\\\\\"site_canonical_url\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_notice\\\\\\\": \\\\\\\"Nh\\\\u1eadp username, email ho\\\\u1eb7c s\\\\u1ed1 \\\\u0111i\\\\u1ec7n tho\\\\u1ea1i k\\\\u00e8m m\\\\u1eadt kh\\\\u1ea9u \\\\u0111\\\\u1ec3 \\\\u0111\\\\u0103ng nh\\\\u1eadp. T\\\\u00e0i kho\\\\u1ea3n ch\\\\u01b0a c\\\\u00f3 s\\\\u1ebd t\\\\u1ef1 \\\\u0111\\\\u0103ng k\\\\u00fd; t\\\\u00e0i kho\\\\u1ea3n c\\\\u0169 ch\\\\u01b0a c\\\\u00f3 m\\\\u1eadt kh\\\\u1ea9u s\\\\u1ebd \\\\u0111\\\\u01b0\\\\u1ee3c l\\\\u01b0u m\\\\u1eadt kh\\\\u1ea9u \\\\u1edf l\\\\u1ea7n \\\\u0111\\\\u0103ng nh\\\\u1eadp \\\\u0111\\\\u1ea7u ti\\\\u00ean.\\\\\\\",\\\\n    \\\\\\\"site_base_url\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"site_logo_path\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"site_logo_alt\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_1_path\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_1_alt\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_1_link\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_2_path\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_2_alt\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_2_link\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_3_path\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_3_alt\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"home_banner_3_link\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"webhook_secret\\\\\\\": \\\\\\\"f6d94c035077c7e06004169df7fe721edd2026aea0ad6bb45f1f53a5e0461514\\\\\\\",\\\\n    \\\\\\\"webhook_hmac_enabled\\\\\\\": \\\\\\\"1\\\\\\\",\\\\n    \\\\\\\"admin_username\\\\\\\": \\\\\\\"admin\\\\\\\",\\\\n    \\\\\\\"admin_password_hash\\\\\\\": \\\\\\\"$2y$10$t1GabqIKA62ttK8tKlxN1.ZGxKY7JkMLwf.nOxzTbaxl4SwM9\\\\\\\\\\\\\\\/XTO\\\\\\\",\\\\n    \\\\\\\"admin_access_key\\\\\\\": \\\\\\\"9bc38444cfe193271934113f\\\\\\\",\\\\n    \\\\\\\"admin_access_setup_done\\\\\\\": \\\\\\\"1\\\\\\\",\\\\n    \\\\\\\"deposit_bank_name\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"deposit_account_number\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"deposit_account_owner\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"deposit_transfer_content\\\\\\\": \\\\\\\"NAP {id}\\\\\\\",\\\\n    \\\\\\\"deposit_quick_amounts\\\\\\\": \\\\\\\"10000,20000,50000,100000,200000,500000,1000000,2000000\\\\\\\",\\\\n    \\\\\\\"deposit_max_invoice_amount\\\\\\\": \\\\\\\"5000000\\\\\\\",\\\\n    \\\\\\\"deposit_vietqr_bank_id\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"deposit_vietqr_template\\\\\\\": \\\\\\\"compact2\\\\\\\",\\\\n    \\\\\\\"deposit_vietqr_display_mode\\\\\\\": \\\\\\\"qr_and_info\\\\\\\",\\\\n    \\\\\\\"deposit_invoice_expire_minutes\\\\\\\": \\\\\\\"30\\\\\\\",\\\\n    \\\\\\\"deposit_promo_enabled\\\\\\\": \\\\\\\"0\\\\\\\",\\\\n    \\\\\\\"deposit_promo_rules\\\\\\\": \\\\\\\"100000|5\\\\\\\\n500000|10\\\\\\\\n1000000|15\\\\\\\",\\\\n    \\\\\\\"deposit_note\\\\\\\": \\\\\\\"Vui l\\\\u00f2ng t\\\\u1ea1o h\\\\u00f3a \\\\u0111\\\\u01a1n n\\\\u1ea1p ti\\\\u1ec1n tr\\\\u01b0\\\\u1edbc khi chuy\\\\u1ec3n kho\\\\u1ea3n. H\\\\u1ec7 th\\\\u1ed1ng s\\\\u1ebd t\\\\u1ef1 th\\\\u00eam ID c\\\\u1ee7a b\\\\u1ea1n v\\\\u00e0o 3 s\\\\u1ed1 cu\\\\u1ed1i c\\\\u1ee7a s\\\\u1ed1 ti\\\\u1ec1n c\\\\u1ea7n chuy\\\\u1ec3n \\\\u0111\\\\u1ec3 t\\\\u1ef1 \\\\u0111\\\\u1ed9ng c\\\\u1ed9ng \\\\u0111\\\\u00fang t\\\\u00e0i kho\\\\u1ea3n.\\\\\\\",\\\\n    \\\\\\\"deposit_guide_html\\\\\\\": \\\\\\\"<p>V\\\\u00e0o trang <b>N\\\\u1ea1p Ti\\\\u1ec1n<\\\\\\\\\\\\\\\/b>, ch\\\\u1ecdn nhanh s\\\\u1ed1 ti\\\\u1ec1n c\\\\u1ea7n n\\\\u1ea1p ho\\\\u1eb7c nh\\\\u1eadp s\\\\u1ed1 ti\\\\u1ec1n g\\\\u1ed1c b\\\\u1ea1n mu\\\\u1ed1n n\\\\u1ea1p, sau \\\\u0111\\\\u00f3 b\\\\u1ea5m <b>T\\\\u1ea1o h\\\\u00f3a \\\\u0111\\\\u01a1n n\\\\u1ea1p ti\\\\u1ec1n<\\\\\\\\\\\\\\\/b>.<\\\\\\\\\\\\\\\/p><p>V\\\\u00ed d\\\\u1ee5 ID c\\\\u1ee7a b\\\\u1ea1n l\\\\u00e0 <b>{id}<\\\\\\\\\\\\\\\/b>, b\\\\u1ea1n mu\\\\u1ed1n n\\\\u1ea1p <b>120.000\\\\u0111<\\\\\\\\\\\\\\\/b> th\\\\u00ec s\\\\u1ed1 ti\\\\u1ec1n c\\\\u1ea7n chuy\\\\u1ec3n s\\\\u1ebd l\\\\u00e0 <b>120.{id}\\\\u0111<\\\\\\\\\\\\\\\/b>.<\\\\\\\\\\\\\\\/p><p>N\\\\u1ebfu s\\\\u1ed1 ti\\\\u1ec1n chuy\\\\u1ec3n kho\\\\u1ea3n kh\\\\u00f4ng c\\\\u00f3 ID h\\\\u1ee3p l\\\\u1ec7 \\\\u1edf 3 s\\\\u1ed1 cu\\\\u1ed1i, h\\\\u1ec7 th\\\\u1ed1ng c\\\\u00f3 th\\\\u1ec3 kh\\\\u00f4ng t\\\\u1ef1 nh\\\\u1eadn di\\\\u1ec7n \\\\u0111\\\\u00fang t\\\\u00e0i kho\\\\u1ea3n n\\\\u1ea1p ti\\\\u1ec1n.<\\\\\\\\\\\\\\\/p>\\\\\\\",\\\\n    \\\\\\\"deposit_invoice_notice\\\\\\\": \\\\\\\"Vui l\\\\u00f2ng chuy\\\\u1ec3n kho\\\\u1ea3n \\\\u0111\\\\u00fang ch\\\\u00ednh x\\\\u00e1c s\\\\u1ed1 ti\\\\u1ec1n c\\\\u1ea7n chuy\\\\u1ec3n b\\\\u00ean d\\\\u01b0\\\\u1edbi. H\\\\u00f3a \\\\u0111\\\\u01a1n s\\\\u1ebd \\\\u0111\\\\u01b0\\\\u1ee3c c\\\\u1ed9ng ti\\\\u1ec1n t\\\\u1ef1 \\\\u0111\\\\u1ed9ng khi h\\\\u1ec7 th\\\\u1ed1ng nh\\\\u1eadn giao d\\\\u1ecbch, ho\\\\u1eb7c admin c\\\\u00f3 th\\\\u1ec3 duy\\\\u1ec7t th\\\\u1ee7 c\\\\u00f4ng trong qu\\\\u1ea3n tr\\\\u1ecb.\\\\\\\",\\\\n    \\\\\\\"order_detail_notice_html\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"order_auto_delete_days\\\\\\\": \\\\\\\"30\\\\\\\",\\\\n    \\\\\\\"inactive_user_delete_days\\\\\\\": \\\\\\\"180\\\\\\\",\\\\n    \\\\\\\"inactive_user_delete_months\\\\\\\": \\\\\\\"6\\\\\\\",\\\\n    \\\\\\\"user_delete_balance_threshold\\\\\\\": \\\\\\\"1000\\\\\\\",\\\\n    \\\\\\\"deposit_history_auto_delete_months\\\\\\\": \\\\\\\"6\\\\\\\",\\\\n    \\\\\\\"maintenance_enabled\\\\\\\": \\\\\\\"0\\\\\\\",\\\\n    \\\\\\\"maintenance_message\\\\\\\": \\\\\\\"Website \\\\u0111ang b\\\\u1ea3o tr\\\\u00ec, vui l\\\\u00f2ng quay l\\\\u1ea1i sau.\\\\\\\",\\\\n    \\\\\\\"ticket_auto_delete_days\\\\\\\": \\\\\\\"0\\\\\\\",\\\\n    \\\\\\\"ticket_telegram_bot_token\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"ticket_telegram_chat_id\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"telegram_shop_enabled\\\\\\\": \\\\\\\"0\\\\\\\",\\\\n    \\\\\\\"telegram_shop_bot_token\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"telegram_shop_webhook_secret\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"backup_auto_enabled\\\\\\\": \\\\\\\"1\\\\\\\",\\\\n    \\\\\\\"backup_interval_hours\\\\\\\": \\\\\\\"24\\\\\\\",\\\\n    \\\\\\\"backup_keep_count\\\\\\\": \\\\\\\"10\\\\\\\",\\\\n    \\\\\\\"backup_keep_days\\\\\\\": \\\\\\\"30\\\\\\\",\\\\n    \\\\\\\"backup_restore_enabled\\\\\\\": \\\\\\\"1\\\\\\\",\\\\n    \\\\\\\"backup_cron_token\\\\\\\": \\\\\\\"9f7e37129b685d070c2181fc18d23345c34257c5957e6f52\\\\\\\",\\\\n    \\\\\\\"backup_last_at\\\\\\\": \\\\\\\"2026-06-30 07:19:20\\\\\\\",\\\\n    \\\\\\\"backup_last_auto_at\\\\\\\": \\\\\\\"2026-06-30 07:19:20\\\\\\\",\\\\n    \\\\\\\"backup_last_file\\\\\\\": \\\\\\\"auto-backup-20260630-071920-4e82bc24.zip\\\\\\\",\\\\n    \\\\\\\"backup_last_status\\\\\\\": \\\\\\\"success\\\\\\\",\\\\n    \\\\\\\"backup_last_error\\\\\\\": \\\\\\\"\\\\\\\"\\\\n}\\\",\\n        \\\"time\\\": \\\"2026-07-01 13:56:49\\\"\\n    },\\n    {\\n        \\\"file\\\": \\\"\\\\\\\/home\\\\\\\/coicom\\\\\\\/1.1ccmm.my\\\\\\\/README_PUBLIC_LAYOUT.txt\\\",\\n        \\\"content\\\": \\\"B\\\\u1ed1 c\\\\u1ee5c sau khi t\\\\u1ed1i \\\\u01b0u:\\\\n\\\\n- public\\\\\\\/: ch\\\\u1ee9a to\\\\u00e0n b\\\\u1ed9 m\\\\u00e3 ngu\\\\u1ed3n \\\\u1ee9ng d\\\\u1ee5ng v\\\\u00e0 c\\\\u00e1c file web-facing.\\\\n- data\\\\\\\/, backup\\\\\\\/, codes\\\\\\\/, kho-tdata\\\\\\\/, uploads\\\\\\\/, source-sync-master-data\\\\\\\/: th\\\\u01b0 m\\\\u1ee5c private n\\\\u1eb1m ngang c\\\\u1ea5p public, d\\\\u00f9ng \\\\u0111\\\\u1ec3 l\\\\u01b0u JSON, backup, m\\\\u00e3\\\\\\\/code s\\\\u1ea3n ph\\\\u1ea9m, kho h\\\\u00e0ng, file t\\\\u1ea1m v\\\\u00e0 c\\\\u1ea5u h\\\\u00ecnh source-sync master.\\\\n- .htaccess \\\\u1edf th\\\\u01b0 m\\\\u1ee5c g\\\\u1ed1c rewrite n\\\\u1ed9i b\\\\u1ed9 request v\\\\u00e0o public\\\\\\\/ \\\\u0111\\\\u1ec3 gi\\\\u1eef nguy\\\\u00ean URL nh\\\\u01b0 tr\\\\u01b0\\\\u1edbc, v\\\\u00ed d\\\\u1ee5 \\\\\\\/products, \\\\\\\/admin, \\\\\\\/sitemap.xml.\\\\n\\\\nKhuy\\\\u1ebfn ngh\\\\u1ecb tri\\\\u1ec3n khai an to\\\\u00e0n nh\\\\u1ea5t:\\\\n1. N\\\\u1ebfu hosting cho ph\\\\u00e9p ch\\\\u1ecdn document root, h\\\\u00e3y tr\\\\u1ecf document root tr\\\\u1ef1c ti\\\\u1ebfp v\\\\u00e0o th\\\\u01b0 m\\\\u1ee5c public\\\\\\\/. Khi \\\\u0111\\\\u00f3 c\\\\u00e1c th\\\\u01b0 m\\\\u1ee5c private ngang c\\\\u1ea5p public kh\\\\u00f4ng th\\\\u1ec3 truy c\\\\u1eadp b\\\\u1eb1ng URL.\\\\n2. N\\\\u1ebfu hosting kh\\\\u00f4ng cho \\\\u0111\\\\u1ed5i document root, upload c\\\\u1ea3 g\\\\u00f3i n\\\\u00e0y; file .htaccess \\\\u1edf g\\\\u1ed1c s\\\\u1ebd gi\\\\u1eef URL kh\\\\u00f4ng c\\\\u00f3 \\\\\\\/public\\\\\\\/ v\\\\u00e0 ch\\\\u1eb7n c\\\\u00e1c th\\\\u01b0 m\\\\u1ee5c private.\\\\n3. N\\\\u1ebfu d\\\\u00f9ng Nginx ho\\\\u1eb7c m\\\\u00f4i tr\\\\u01b0\\\\u1eddng kh\\\\u00f4ng \\\\u0111\\\\u1ecdc .htaccess, b\\\\u1eaft bu\\\\u1ed9c c\\\\u1ea5u h\\\\u00ecnh root v\\\\u1ec1 public\\\\\\\/ ho\\\\u1eb7c deny tr\\\\u1ef1c ti\\\\u1ebfp c\\\\u00e1c \\\\u0111\\\\u01b0\\\\u1eddng d\\\\u1eabn \\\\\\\/data, \\\\\\\/backup, \\\\\\\/codes, \\\\\\\/kho-tdata, \\\\\\\/uploads, \\\\\\\/source-sync-master-data. C\\\\u00e1c th\\\\u01b0 m\\\\u1ee5c private c\\\\u00f3 index.php\\\\\\\/web.config\\\\\\\/.htaccess b\\\\u1ea3o v\\\\u1ec7 b\\\\u1ed5 sung, nh\\\\u01b0ng file t\\\\u0129nh c\\\\u00f3 th\\\\u1ec3 b\\\\u1ecb web server ph\\\\u1ee5c v\\\\u1ee5 tr\\\\u01b0\\\\u1edbc khi PHP ch\\\\u1ea1y n\\\\u1ebfu web root \\\\u0111\\\\u1eb7t sai.\\\\n\\\",\\n        \\\"time\\\": \\\"2026-07-01 13:30:55\\\"\\n    },\\n    {\\n        \\\"file\\\": \\\"\\\\\\\/home\\\\\\\/coicom\\\\\\\/1.1ccmm.my\\\\\\\/source-sync-master-data\\\\\\\/source-sync-master-config.json\\\",\\n        \\\"content\\\": \\\"{\\\\n    \\\\\\\"master_token\\\\\\\": \\\\\\\"bfe414a0a2a29256\\\\\\\",\\\\n    \\\\\\\"version\\\\\\\": \\\\\\\"V1.8\\\\\\\",\\\\n    \\\\\\\"zip_url\\\\\\\": \\\\\\\"\\\\\\\/update-packages\\\\\\\/65458_backup_restore_round_robin_deposit_history_fixed.zip\\\\\\\",\\\\n    \\\\\\\"zip_sha256\\\\\\\": \\\\\\\"3111a3acd50550c6f32c133e1143200ba511863ee0ed4c6459dcdfebe2bd794e\\\\\\\",\\\\n    \\\\\\\"zip_filename\\\\\\\": \\\\\\\"65458_backup_restore_round_robin_deposit_history_fixed.zip\\\\\\\",\\\\n    \\\\\\\"zip_size\\\\\\\": 2677981,\\\\n    \\\\\\\"released_at\\\\\\\": \\\\\\\"2026-06-30 12:45:46\\\\\\\",\\\\n    \\\\\\\"changelog\\\\\\\": \\\\\\\"\\\\\\\",\\\\n    \\\\\\\"required\\\\\\\": true,\\\\n    \\\\\\\"allowed_client_ips\\\\\\\": [\\\\n        \\\\\\\"14.225.218.36\\\\\\\",\\\\n        \\\\\\\"14.225.219.71\\\\\\\"\\\\n    ],\\\\n    \\\\\\\"allowed_client_domains\\\\\\\": [\\\\n        \\\\\\\"taphoatele.com\\\\\\\",\\\\n        \\\\\\\"acctelegram.net\\\\\\\",\\\\n        \\\\\\\"1ccmm.my\\\\\\\",\\\\n        \\\\\\\"1.1ccmm.my\\\\\\\"\\\\n    ],\\\\n    \\\\\\\"updated_at\\\\\\\": \\\\\\\"2026-06-30 12:45:46\\\\\\\",\\\\n    \\\\\\\"config_password_hash\\\\\\\": \\\\\\\"$2y$10$HHl.YoV15spCHl6g6fGKsO5T7vr12Bo.zfGZ0knK\\\\\\\/Dkpcz12Tqn5e\\\\\\\",\\\\n    \\\\\\\"config_access_key\\\\\\\": \\\\\\\"9bc38444cfe193271934113f\\\\\\\",\\\\n    \\\\\\\"config_setup_done\\\\\\\": true\\\\n}\\\",\\n        \\\"time\\\": \\\"2026-07-01 13:29:39\\\"\\n    },\\n    {\\n        \\\"file\\\": \\\"\\\\\\\/home\\\\\\\/coicom\\\\\\\/1.1ccmm.my\\\\\\\/source-sync-master-data\\\\\\\/source-sync-login-rate.json\\\",\\n        \\\"content\\\": \\\"{\\\\n    \\\\\\\"login:7a1a4051beabf07f10a0ff2171cc95604e1a86e6\\\\\\\": [\\\\n        1782798339\\\\n    ]\\\\n}\\\",\\n        \\\"time\\\": \\\"2026-07-01 13:29:37\\\"\\n    },\\n    {\\n        \\\"file\\\": \\\"\\\\\\\/home\\\\\\\/coicom\\\\\\\/1.1ccmm.my\\\\\\\/public\\\\\\\/webhook.php\\\",\\n        \\\"content\\\": \\\"<?php\\\\nrequire_once __DIR__ . '\\\\\\\/includes\\\\\\\/functions.php';\\\\nensure_data_files();\\\\nsend_security_headers(true);\\\\ntry {\\\\n    if (security_guard_active()) { json_response(array('ok'=>true,'guarded'=>true), 200); }\\\\n    security_request_rate_guard('webhook_request', array(request_ip_address()), 120, 60, 300, 'Webhook nh\\\\u1eadn qu\\\\u00e1 nhi\\\\u1ec1u request, vui l\\\\u00f2ng th\\\\u1eed l\\\\u1ea1i sau.');\\\\n    $payload = read_webhook_payload();\\\\n    $result = process_deposit_webhook($payload);\\\\n    json_response($result, 200);\\\\n} catch (Exception $e) {\\\\n    security_log_event('webhook_exception', 'L\\\\u1ed7i x\\\\u1eed l\\\\u00fd webhook', array('error' => $e->getMessage()));\\\\n    json_response(array('ok'=>false,'error'=>security_generic_message()),500);\\\\n}\\\\n\\\",\\n        \\\"time\\\": \\\"2026-07-01 13:28:15\\\"\\n    },\\n    {\\n        \\\"file\\\": \\\"\\\\\\\/home\\\\\\\/coicom\\\\\\\/1.1ccmm.my\\\\\\\/public\\\\\\\/source-sync-master-api\\\\\\\/source-sync-config.php\\\",\\n        \\\"content\\\": \\\"<?php\\\\n\\\\\\\/**\\\\n * Trang c\\\\u1ea5u h\\\\u00ecnh m\\\\u00e1y ch\\\\u1ee7 ch\\\\u00ednh cho update-manifest.php.\\\\n *\\\\n * \\\\u0110\\\\u1eb7t file n\\\\u00e0y trong \\\\\\\/source-sync-master-api\\\\\\\/ tr\\\\u00ean M\\\\u00c1Y CH\\\\u1ee6 CH\\\\u00cdNH.\\\\n * M\\\\u1ecdi c\\\\u1ea5u h\\\\u00ecnh manifest \\\\u0111\\\\u01b0\\\\u1ee3c l\\\\u01b0u v\\\\u00e0o JSON:\\\\n *   \\\\\\\/source-sync-master-data\\\\\\\/source-sync-master-config.json\\\\n *\\\\n * B\\\\u1ea3o m\\\\u1eadt trang c\\\\u1ea5u h\\\\u00ecnh:\\\\n * - L\\\\u1ea7n \\\\u0111\\\\u1ea7u truy c\\\\u1eadp tr\\\\u1ef1c ti\\\\u1ebfp file n\\\\u00e0y \\\\u0111\\\\u1ec3 t\\\\u1ea1o m\\\\u1eadt kh\\\\u1ea9u v\\\\u00e0 token truy c\\\\u1eadp.\\\\n * - Nh\\\\u1eefng l\\\\u1ea7n sau ph\\\\u1ea3i truy c\\\\u1eadp d\\\\u1ea1ng source-sync-config.php?k=TOKEN.\\\\n * - Bi\\\\u1ebfn m\\\\u1eadt kh\\\\u1ea9u b\\\\u00ean d\\\\u01b0\\\\u1edbi ch\\\\u1ec9 c\\\\u00f2n d\\\\u00f9ng t\\\\u01b0\\\\u01a1ng th\\\\u00edch cho b\\\\u1ea3n c\\\\u0169 n\\\\u1ebfu \\\\u0111\\\\u00e3 t\\\\u1ef1 \\\\u0111\\\\u1ed5i tr\\\\u01b0\\\\u1edbc \\\\u0111\\\\u00e2y.\\\\n *\\\\\\\/\\\\n\\\\n\\\\\\\/\\\\\\\/ =========================\\\\n\\\\\\\/\\\\\\\/ M\\\\u1eacT KH\\\\u1ea8U T\\\\u01af\\\\u01a0NG TH\\\\u00cdCH B\\\\u1ea2N C\\\\u0168 - KH\\\\u00d4NG C\\\\u1ea6N S\\\\u1eecA N\\\\u1ebeU D\\\\u00d9NG SETUP L\\\\u1ea6N \\\\u0110\\\\u1ea6U\\\\n\\\\\\\/\\\\\\\/ =========================\\\\n$SOURCE_SYNC_CONFIG_PASSWORD = 'doi-mat-khau-quan-tri-nay';\\\\n\\\\n\\\\\\\/\\\\\\\/ Gi\\\\u1edbi h\\\\u1ea1n dung l\\\\u01b0\\\\u1ee3ng ZIP upload qua trang n\\\\u00e0y. C\\\\u00f2n ph\\\\u1ee5 thu\\\\u1ed9c upload_max_filesize\\\\\\\/post_max_size c\\\\u1ee7a hosting.\\\\n$SOURCE_SYNC_CONFIG_MAX_UPLOAD_BYTES = 300 * 1024 * 1024; \\\\\\\/\\\\\\\/ 300MB\\\\n\\\\n\\\\\\\/\\\\\\\/ =========================\\\\n\\\\\\\/\\\\\\\/ KH\\\\u00d4NG C\\\\u1ea6N S\\\\u1eecA PH\\\\u1ea6N B\\\\u00caN D\\\\u01af\\\\u1edaI N\\\\u1ebeU KH\\\\u00d4NG C\\\\u1ea6N\\\\n\\\\\\\/\\\\\\\/ =========================\\\\n\\\\n@ini_set('display_errors', '0');\\\\n@ini_set('display_startup_errors', '0');\\\\n@ini_set('log_errors', '1');\\\\n@ini_set('html_errors', '0');\\\\n\\\\ndate_default_timezone_set('Asia\\\\\\\/Ho_Chi_Minh');\\\\n\\\\nheader('X-Robots-Tag: noindex, nofollow', true);\\\\nheader('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');\\\\nheader('X-Frame-Options: SAMEORIGIN');\\\\nheader('X-Content-Type-Options: nosniff');\\\\n\\\\nsession_name('source_sync_master_config_session');\\\\n@session_start();\\\\n\\\\n$MASTER_API_DIR = __DIR__;\\\\n$MASTER_ROOT_DIR = dirname(__DIR__);\\\\n$MASTER_PRIVATE_ROOT_DIR = dirname($MASTER_ROOT_DIR);\\\\n$MASTER_DATA_DIR = $MASTER_PRIVATE_ROOT_DIR . '\\\\\\\/source-sync-master-data';\\\\n$MASTER_CONFIG_FILE = $MASTER_DATA_DIR . '\\\\\\\/source-sync-master-config.json';\\\\n$MASTER_PACKAGE_DIR = $MASTER_ROOT_DIR . '\\\\\\\/update-packages';\\\\n$MASTER_PACKAGE_PUBLIC_DIR = '\\\\\\\/update-packages';\\\\n\\\\n\\\\nfunction ssm_client_ip() {\\\\n    return isset($_SERVER['REMOTE_ADDR']) ? trim((string)$_SERVER['REMOTE_ADDR']) : '';\\\\n}\\\\n\\\\nfunction ssm_rate_file() {\\\\n    global $MASTER_DATA_DIR;\\\\n    return $MASTER_DATA_DIR . '\\\\\\\/source-sync-login-rate.json';\\\\n}\\\\n\\\\nfunction ssm_rate_limit_guard($key, $maxAttempts = 10, $windowSeconds = 300) {\\\\n    ssm_ensure_dirs();\\\\n    $file = ssm_rate_file();\\\\n    $data = array();\\\\n    if (is_file($file)) {\\\\n        $raw = @file_get_contents($file);\\\\n        $json = json_decode((string)$raw, true);\\\\n        if (is_array($json)) $data = $json;\\\\n    }\\\\n    $now = time();\\\\n    foreach ($data as $k => $rows) {\\\\n        if (!is_array($rows)) { unset($data[$k]); continue; }\\\\n        $data[$k] = array_values(array_filter($rows, function($ts) use ($now, $windowSeconds) { return intval($ts) > ($now - $windowSeconds); }));\\\\n        if (!$data[$k]) unset($data[$k]);\\\\n    }\\\\n    if (!isset($data[$key]) || !is_array($data[$key])) $data[$key] = array();\\\\n    if (count($data[$key]) >= $maxAttempts) {\\\\n        @file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);\\\\n        return false;\\\\n    }\\\\n    $data[$key][] = $now;\\\\n    @file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);\\\\n    return true;\\\\n}\\\\n\\\\nfunction ssm_e($value) {\\\\n    return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');\\\\n}\\\\n\\\\nfunction ssm_now() {\\\\n    return date('Y-m-d H:i:s');\\\\n}\\\\n\\\\nfunction ssm_ensure_dirs() {\\\\n    global $MASTER_DATA_DIR, $MASTER_PACKAGE_DIR;\\\\n    if (!is_dir($MASTER_DATA_DIR)) @mkdir($MASTER_DATA_DIR, 0755, true);\\\\n    if (!is_dir($MASTER_PACKAGE_DIR)) @mkdir($MASTER_PACKAGE_DIR, 0755, true);\\\\n\\\\n    $htaccess = $MASTER_DATA_DIR . '\\\\\\\/.htaccess';\\\\n    $rules = \\\\\\\"Options -Indexes\\\\n<IfModule mod_authz_core.c>\\\\nRequire all denied\\\\n<\\\\\\\/IfModule>\\\\n<IfModule !mod_authz_core.c>\\\\nOrder deny,allow\\\\nDeny from all\\\\n<\\\\\\\/IfModule>\\\\n\\\\\\\";\\\\n    if (!is_file($htaccess) || trim((string)@file_get_contents($htaccess)) !== trim($rules)) {\\\\n        @file_put_contents($htaccess, $rules);\\\\n    }\\\\n    $indexPhp = $MASTER_DATA_DIR . '\\\\\\\/index.php';\\\\n    if (!is_file($indexPhp)) @file_put_contents($indexPhp, \\\\\\\"<?php\\\\nhttp_response_code(404);\\\\nheader('X-Robots-Tag: noindex, nofollow', true);\\\\necho '404 Not Found';\\\\nexit;\\\\n\\\\\\\");\\\\n    $index = $MASTER_DATA_DIR . '\\\\\\\/index.html';\\\\n    if (!is_file($index)) @file_put_contents($index, '');\\\\n\\\\n    $webConfig = $MASTER_DATA_DIR . '\\\\\\\/web.config';\\\\n    $webRules = <<<'XML'\\\\n<?xml version=\\\\\\\"1.0\\\\\\\" encoding=\\\\\\\"UTF-8\\\\\\\"?>\\\\n<configuration>\\\\n  <system.webServer>\\\\n    <security>\\\\n      <authorization>\\\\n        <clear \\\\\\\/>\\\\n        <add accessType=\\\\\\\"Deny\\\\\\\" users=\\\\\\\"*\\\\\\\" \\\\\\\/>\\\\n      <\\\\\\\/authorization>\\\\n    <\\\\\\\/security>\\\\n    <directoryBrowse enabled=\\\\\\\"false\\\\\\\" \\\\\\\/>\\\\n  <\\\\\\\/system.webServer>\\\\n<\\\\\\\/configuration>\\\\nXML;\\\\n    $webRules .= \\\\\\\"\\\\n\\\\\\\";\\\\n    if (!is_file($webConfig) || trim((string)@file_get_contents($webConfig)) !== trim($webRules)) @file_put_contents($webConfig, $webRules, LOCK_EX);\\\\n    @chmod($MASTER_DATA_DIR, 0700);\\\\n\\\\n    $pkgIndex = $MASTER_PACKAGE_DIR . '\\\\\\\/index.html';\\\\n    if (!is_file($pkgIndex)) @file_put_contents($pkgIndex, '');\\\\n}\\\\n\\\\nfunction ssm_default_config() {\\\\n    return array(\\\\n        'master_token' => '',\\\\n        'version' => 'V24',\\\\n        'zip_url' => '',\\\\n        'zip_sha256' => '',\\\\n        'zip_filename' => '',\\\\n        'zip_size' => 0,\\\\n        'released_at' => ssm_now(),\\\\n        'changelog' => '',\\\\n        'required' => false,\\\\n        'allowed_client_ips' => array(),\\\\n        'allowed_client_domains' => array(),\\\\n        'updated_at' => '',\\\\n        'config_password_hash' => '',\\\\n        'config_access_key' => '',\\\\n        'config_setup_done' => false,\\\\n    );\\\\n}\\\\n\\\\nfunction ssm_load_config() {\\\\n    global $MASTER_CONFIG_FILE;\\\\n    $defaults = ssm_default_config();\\\\n    if (!is_file($MASTER_CONFIG_FILE)) return $defaults;\\\\n    $raw = file_get_contents($MASTER_CONFIG_FILE);\\\\n    $json = json_decode($raw, true);\\\\n    if (!is_array($json)) return $defaults;\\\\n    return array_merge($defaults, $json);\\\\n}\\\\n\\\\nfunction ssm_save_config($config) {\\\\n    global $MASTER_CONFIG_FILE;\\\\n    ssm_ensure_dirs();\\\\n    $config['updated_at'] = ssm_now();\\\\n    $json = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);\\\\n    if ($json === false) return false;\\\\n    $ok = @file_put_contents($MASTER_CONFIG_FILE, $json, LOCK_EX) !== false;\\\\n    if ($ok) @chmod($MASTER_CONFIG_FILE, 0600);\\\\n    return $ok;\\\\n}\\\\n\\\\nfunction ssm_text_to_array($value) {\\\\n    if (is_array($value)) $value = implode(\\\\\\\"\\\\\\\\n\\\\\\\", $value);\\\\n    $value = trim((string)$value);\\\\n    if ($value === '') return array();\\\\n    return array_values(array_filter(array_map('trim', preg_split('\\\\\\\/[\\\\\\\\r\\\\\\\\n,]+\\\\\\\/', $value)), function($v) { return $v !== ''; }));\\\\n}\\\\n\\\\nfunction ssm_array_to_text($value) {\\\\n    if (!is_array($value)) return trim((string)$value);\\\\n    return implode(\\\\\\\"\\\\\\\\n\\\\\\\", array_values(array_filter(array_map('trim', array_map('strval', $value)), function($v) { return $v !== ''; })));\\\\n}\\\\n\\\\nfunction ssm_safe_zip_filename($name) {\\\\n    $name = basename((string)$name);\\\\n    $name = preg_replace('\\\\\\\/[^a-zA-Z0-9._-]+\\\\\\\/', '-', $name);\\\\n    $name = trim($name, '.-_');\\\\n    if ($name === '') $name = 'source-update.zip';\\\\n    if (strtolower(substr($name, -4)) !== '.zip') $name .= '.zip';\\\\n    return $name;\\\\n}\\\\n\\\\nfunction ssm_internal_zip_path_from_url($zipUrl) {\\\\n    global $MASTER_ROOT_DIR;\\\\n    $zipUrl = trim((string)$zipUrl);\\\\n    if ($zipUrl === '') return '';\\\\n    if (preg_match('#^https?:\\\\\\\/\\\\\\\/#i', $zipUrl)) {\\\\n        $parts = parse_url($zipUrl);\\\\n        if (!$parts || empty($parts['path'])) return '';\\\\n        $zipUrl = $parts['path'];\\\\n    }\\\\n    if ($zipUrl[0] !== '\\\\\\\/') $zipUrl = '\\\\\\\/' . $zipUrl;\\\\n    $path = realpath($MASTER_ROOT_DIR . $zipUrl);\\\\n    if ($path === false || !is_file($path)) return '';\\\\n    return $path;\\\\n}\\\\n\\\\nfunction ssm_flash($type, $message) {\\\\n    $_SESSION['ssm_flash'][] = array('type' => $type, 'message' => $message);\\\\n}\\\\n\\\\nfunction ssm_get_flash() {\\\\n    $flash = isset($_SESSION['ssm_flash']) && is_array($_SESSION['ssm_flash']) ? $_SESSION['ssm_flash'] : array();\\\\n    unset($_SESSION['ssm_flash']);\\\\n    return $flash;\\\\n}\\\\n\\\\nfunction ssm_logged_in() {\\\\n    return !empty($_SESSION['ssm_logged_in']);\\\\n}\\\\n\\\\nfunction ssm_generate_access_key($bytes = 12) {\\\\n    return strtolower(substr(bin2hex(random_bytes(max(8, intval($bytes)))), 0, 24));\\\\n}\\\\n\\\\nfunction ssm_normalize_access_key($key) {\\\\n    $key = trim((string)$key);\\\\n    $key = preg_replace('\\\\\\\/[^A-Za-z0-9_-]\\\\\\\/', '', $key);\\\\n    return substr($key, 0, 64);\\\\n}\\\\n\\\\nfunction ssm_setup_required($config = null) {\\\\n    if (!is_array($config)) $config = ssm_load_config();\\\\n    $done = !empty($config['config_setup_done']);\\\\n    $key = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\\\n    $hash = isset($config['config_password_hash']) ? (string)$config['config_password_hash'] : '';\\\\n    return !$done || $key === '' || $hash === '';\\\\n}\\\\n\\\\nfunction ssm_access_gate_passed($config = null) {\\\\n    if (!is_array($config)) $config = ssm_load_config();\\\\n    if (ssm_setup_required($config)) return true;\\\\n    if (ssm_logged_in()) return true;\\\\n    if (!empty($_SESSION['ssm_access_granted'])) return true;\\\\n    $key = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\\\n    $given = isset($_GET['k']) ? ssm_normalize_access_key($_GET['k']) : '';\\\\n    if ($key !== '' && $given !== '' && hash_equals($key, $given)) {\\\\n        $_SESSION['ssm_access_granted'] = true;\\\\n        return true;\\\\n    }\\\\n    return false;\\\\n}\\\\n\\\\nfunction ssm_fake_404() {\\\\n    http_response_code(404);\\\\n    header('Content-Type: text\\\\\\\/plain; charset=utf-8');\\\\n    echo '404 Not Found';\\\\n    exit;\\\\n}\\\\n\\\\nfunction ssm_check_config_password($password, $config) {\\\\n    $hash = isset($config['config_password_hash']) ? (string)$config['config_password_hash'] : '';\\\\n    if ($hash !== '') return password_verify((string)$password, $hash);\\\\n    global $SOURCE_SYNC_CONFIG_PASSWORD;\\\\n    if ($SOURCE_SYNC_CONFIG_PASSWORD !== '' && $SOURCE_SYNC_CONFIG_PASSWORD !== 'doi-mat-khau-quan-tri-nay') {\\\\n        return hash_equals((string)$SOURCE_SYNC_CONFIG_PASSWORD, (string)$password);\\\\n    }\\\\n    return false;\\\\n}\\\\n\\\\nfunction ssm_increment_version($version) {\\\\n    $version = trim((string)$version);\\\\n    if ($version === '') return 'V1.0';\\\\n    if (preg_match('\\\\\\\/^(.*?)(\\\\\\\\d+)\\\\\\\\.(\\\\\\\\d+)$\\\\\\\/', $version, $m)) {\\\\n        return $m[1] . $m[2] . '.' . (intval($m[3]) + 1);\\\\n    }\\\\n    if (preg_match('\\\\\\\/^(.*?)(\\\\\\\\d+)$\\\\\\\/', $version, $m)) {\\\\n        return $m[1] . (intval($m[2]) + 1);\\\\n    }\\\\n    return $version . '.1';\\\\n}\\\\n\\\\nfunction ssm_require_csrf() {\\\\n    $posted = isset($_POST['csrf']) ? (string)$_POST['csrf'] : '';\\\\n    $stored = isset($_SESSION['ssm_csrf']) ? (string)$_SESSION['ssm_csrf'] : '';\\\\n    if ($stored === '' || $posted === '' || !hash_equals($stored, $posted)) {\\\\n        ssm_flash('error', 'CSRF token kh\\\\u00f4ng h\\\\u1ee3p l\\\\u1ec7, h\\\\u00e3y th\\\\u1eed l\\\\u1ea1i.');\\\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n        exit;\\\\n    }\\\\n}\\\\n\\\\nfunction ssm_csrf_token() {\\\\n    if (empty($_SESSION['ssm_csrf'])) {\\\\n        $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\\\n    }\\\\n    return $_SESSION['ssm_csrf'];\\\\n}\\\\n\\\\nssm_ensure_dirs();\\\\n$config = ssm_load_config();\\\\n$setupRequired = ssm_setup_required($config);\\\\nif (!$setupRequired && !ssm_access_gate_passed($config)) {\\\\n    ssm_fake_404();\\\\n}\\\\n\\\\nif ($_SERVER['REQUEST_METHOD'] === 'POST') {\\\\n    $action = isset($_POST['action']) ? (string)$_POST['action'] : '';\\\\n\\\\n    if ($setupRequired && $action === 'setup_config') {\\\\n        ssm_require_csrf();\\\\n        $password = isset($_POST['password']) ? (string)$_POST['password'] : '';\\\\n        $password2 = isset($_POST['password_confirm']) ? (string)$_POST['password_confirm'] : '';\\\\n        $accessKey = isset($_POST['config_access_key']) ? ssm_normalize_access_key($_POST['config_access_key']) : '';\\\\n        if ($password !== $password2) {\\\\n            ssm_flash('error', 'M\\\\u1eadt kh\\\\u1ea9u nh\\\\u1eadp l\\\\u1ea1i kh\\\\u00f4ng kh\\\\u1edbp.');\\\\n        } elseif (strlen($password) < 8) {\\\\n            ssm_flash('error', 'M\\\\u1eadt kh\\\\u1ea9u c\\\\u1ea5u h\\\\u00ecnh ph\\\\u1ea3i c\\\\u00f3 \\\\u00edt nh\\\\u1ea5t 8 k\\\\u00fd t\\\\u1ef1.');\\\\n        } elseif ($accessKey === '' || strlen($accessKey) < 8) {\\\\n            ssm_flash('error', 'Token truy c\\\\u1eadp ph\\\\u1ea3i c\\\\u00f3 \\\\u00edt nh\\\\u1ea5t 8 k\\\\u00fd t\\\\u1ef1.');\\\\n        } else {\\\\n            $config['config_password_hash'] = password_hash($password, PASSWORD_DEFAULT);\\\\n            $config['config_access_key'] = $accessKey;\\\\n            $config['config_setup_done'] = true;\\\\n            if (ssm_save_config($config)) {\\\\n                $_SESSION['ssm_access_granted'] = true;\\\\n                $_SESSION['ssm_logged_in'] = true;\\\\n                $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\\\n                ssm_flash('success', '\\\\u0110\\\\u00e3 thi\\\\u1ebft l\\\\u1eadp m\\\\u1eadt kh\\\\u1ea9u v\\\\u00e0 token truy c\\\\u1eadp Source Sync Master.');\\\\n            } else {\\\\n                ssm_flash('error', 'Kh\\\\u00f4ng th\\\\u1ec3 l\\\\u01b0u c\\\\u1ea5u h\\\\u00ecnh b\\\\u1ea3o v\\\\u1ec7 Source Sync Master.');\\\\n            }\\\\n        }\\\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n        exit;\\\\n    }\\\\n\\\\n    if ($action === 'login') {\\\\n        ssm_require_csrf();\\\\n        $password = isset($_POST['password']) ? (string)$_POST['password'] : '';\\\\n        $rateKey = 'login:' . sha1(ssm_client_ip());\\\\n        if (!ssm_rate_limit_guard($rateKey, 10, 300)) {\\\\n            ssm_flash('error', 'B\\\\u1ea1n \\\\u0111\\\\u0103ng nh\\\\u1eadp sai\\\\\\\/thao t\\\\u00e1c qu\\\\u00e1 nhi\\\\u1ec1u l\\\\u1ea7n. Vui l\\\\u00f2ng th\\\\u1eed l\\\\u1ea1i sau.');\\\\n            header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n            exit;\\\\n        }\\\\n        if (ssm_check_config_password($password, $config)) {\\\\n            $_SESSION['ssm_logged_in'] = true;\\\\n            $_SESSION['ssm_access_granted'] = true;\\\\n            $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\\\n            ssm_flash('success', '\\\\u0110\\\\u0103ng nh\\\\u1eadp th\\\\u00e0nh c\\\\u00f4ng.');\\\\n        } else {\\\\n            ssm_flash('error', 'M\\\\u1eadt kh\\\\u1ea9u kh\\\\u00f4ng \\\\u0111\\\\u00fang.');\\\\n        }\\\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n        exit;\\\\n    }\\\\n\\\\n    if ($action === 'logout') {\\\\n        unset($_SESSION['ssm_logged_in']);\\\\n        unset($_SESSION['ssm_access_granted']);\\\\n        unset($_SESSION['ssm_csrf']);\\\\n        ssm_flash('success', '\\\\u0110\\\\u00e3 \\\\u0111\\\\u0103ng xu\\\\u1ea5t.');\\\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n        exit;\\\\n    }\\\\n\\\\n    if (!ssm_logged_in()) {\\\\n        ssm_flash('error', 'B\\\\u1ea1n c\\\\u1ea7n \\\\u0111\\\\u0103ng nh\\\\u1eadp.');\\\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n        exit;\\\\n    }\\\\n\\\\n    ssm_require_csrf();\\\\n    $config = ssm_load_config();\\\\n\\\\n    if ($action === 'save_config') {\\\\n        $config['master_token'] = trim((string)($_POST['master_token'] ?? ''));\\\\n        $config['version'] = trim((string)($_POST['version'] ?? ''));\\\\n        $config['zip_url'] = trim((string)($_POST['zip_url'] ?? ''));\\\\n        $config['zip_sha256'] = strtolower(trim((string)($_POST['zip_sha256'] ?? '')));\\\\n        $config['released_at'] = trim((string)($_POST['released_at'] ?? ''));\\\\n        $config['changelog'] = (string)($_POST['changelog'] ?? '');\\\\n        $config['required'] = !empty($_POST['required']);\\\\n        $config['allowed_client_ips'] = ssm_text_to_array($_POST['allowed_client_ips'] ?? '');\\\\n        $config['allowed_client_domains'] = ssm_text_to_array($_POST['allowed_client_domains'] ?? '');\\\\n\\\\n        if ($config['master_token'] === '') {\\\\n            ssm_flash('error', 'Token m\\\\u00e1y ch\\\\u1ee7 ch\\\\u00ednh kh\\\\u00f4ng \\\\u0111\\\\u01b0\\\\u1ee3c \\\\u0111\\\\u1ec3 tr\\\\u1ed1ng.');\\\\n        } elseif ($config['version'] === '') {\\\\n            ssm_flash('error', 'Phi\\\\u00ean b\\\\u1ea3n kh\\\\u00f4ng \\\\u0111\\\\u01b0\\\\u1ee3c \\\\u0111\\\\u1ec3 tr\\\\u1ed1ng.');\\\\n        } elseif ($config['zip_sha256'] !== '' && !preg_match('\\\\\\\/^[a-f0-9]{64}$\\\\\\\/i', $config['zip_sha256'])) {\\\\n            ssm_flash('error', 'SHA256 ph\\\\u1ea3i g\\\\u1ed3m \\\\u0111\\\\u00fang 64 k\\\\u00fd t\\\\u1ef1 hex.');\\\\n        } elseif (ssm_save_config($config)) {\\\\n            ssm_flash('success', '\\\\u0110\\\\u00e3 l\\\\u01b0u c\\\\u1ea5u h\\\\u00ecnh manifest v\\\\u00e0o JSON.');\\\\n        } else {\\\\n            ssm_flash('error', 'Kh\\\\u00f4ng th\\\\u1ec3 l\\\\u01b0u file JSON. H\\\\u00e3y ki\\\\u1ec3m tra quy\\\\u1ec1n ghi th\\\\u01b0 m\\\\u1ee5c source-sync-master-data ngang c\\\\u1ea5p public.');\\\\n        }\\\\n\\\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n        exit;\\\\n    }\\\\n\\\\n    if ($action === 'upload_zip') {\\\\n        if (empty($_FILES['update_zip']) || !is_uploaded_file($_FILES['update_zip']['tmp_name'])) {\\\\n            ssm_flash('error', 'B\\\\u1ea1n ch\\\\u01b0a ch\\\\u1ecdn file ZIP.');\\\\n        } elseif ((int)$_FILES['update_zip']['error'] !== UPLOAD_ERR_OK) {\\\\n            ssm_flash('error', 'Upload ZIP th\\\\u1ea5t b\\\\u1ea1i. M\\\\u00e3 l\\\\u1ed7i: ' . (int)$_FILES['update_zip']['error']);\\\\n        } elseif ((int)$_FILES['update_zip']['size'] <= 0 || (int)$_FILES['update_zip']['size'] > (int)$SOURCE_SYNC_CONFIG_MAX_UPLOAD_BYTES) {\\\\n            ssm_flash('error', 'File ZIP v\\\\u01b0\\\\u1ee3t qu\\\\u00e1 dung l\\\\u01b0\\\\u1ee3ng cho ph\\\\u00e9p.');\\\\n        } else {\\\\n            $original = isset($_FILES['update_zip']['name']) ? (string)$_FILES['update_zip']['name'] : 'source-update.zip';\\\\n            $filename = ssm_safe_zip_filename($original);\\\\n            $target = $MASTER_PACKAGE_DIR . '\\\\\\\/' . $filename;\\\\n\\\\n            if (!preg_match('\\\\\\\/\\\\\\\\.zip$\\\\\\\/i', $filename)) {\\\\n                ssm_flash('error', 'Ch\\\\u1ec9 cho ph\\\\u00e9p upload file .zip.');\\\\n            } elseif (@move_uploaded_file($_FILES['update_zip']['tmp_name'], $target)) {\\\\n                @chmod($target, 0644);\\\\n                $hash = hash_file('sha256', $target);\\\\n                $config['zip_filename'] = $filename;\\\\n                $config['zip_size'] = filesize($target);\\\\n                $config['zip_url'] = rtrim($MASTER_PACKAGE_PUBLIC_DIR, '\\\\\\\/') . '\\\\\\\/' . $filename;\\\\n                $config['zip_sha256'] = strtolower($hash);\\\\n                $config['version'] = ssm_increment_version(isset($config['version']) ? $config['version'] : '');\\\\n                $config['released_at'] = ssm_now();\\\\n                if (ssm_save_config($config)) {\\\\n                    ssm_flash('success', 'Upload ZIP th\\\\u00e0nh c\\\\u00f4ng. H\\\\u1ec7 th\\\\u1ed1ng \\\\u0111\\\\u00e3 t\\\\u1ef1 l\\\\u1ea5y SHA256, t\\\\u1ef1 t\\\\u0103ng phi\\\\u00ean b\\\\u1ea3n l\\\\u00ean ' . $config['version'] . ' v\\\\u00e0 l\\\\u01b0u v\\\\u00e0o JSON.');\\\\n                } else {\\\\n                    ssm_flash('error', 'Upload ZIP th\\\\u00e0nh c\\\\u00f4ng nh\\\\u01b0ng kh\\\\u00f4ng th\\\\u1ec3 l\\\\u01b0u c\\\\u1ea5u h\\\\u00ecnh JSON.');\\\\n                }\\\\n            } else {\\\\n                ssm_flash('error', 'Kh\\\\u00f4ng th\\\\u1ec3 l\\\\u01b0u file ZIP v\\\\u00e0o th\\\\u01b0 m\\\\u1ee5c update-packages. H\\\\u00e3y ki\\\\u1ec3m tra quy\\\\u1ec1n ghi.');\\\\n            }\\\\n        }\\\\n\\\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n        exit;\\\\n    }\\\\n\\\\n    if ($action === 'recalc_sha256') {\\\\n        $file = ssm_internal_zip_path_from_url(isset($config['zip_url']) ? $config['zip_url'] : '');\\\\n        if ($file === '') {\\\\n            ssm_flash('error', 'Kh\\\\u00f4ng t\\\\u00ecm th\\\\u1ea5y file ZIP n\\\\u1ed9i b\\\\u1ed9 \\\\u0111\\\\u1ec3 l\\\\u1ea5y l\\\\u1ea1i SHA256. H\\\\u00e3y upload ZIP qua form ho\\\\u1eb7c ki\\\\u1ec3m tra ZIP URL.');\\\\n        } else {\\\\n            $config['zip_sha256'] = strtolower(hash_file('sha256', $file));\\\\n            $config['zip_size'] = filesize($file);\\\\n            $config['zip_filename'] = basename($file);\\\\n            if (ssm_save_config($config)) {\\\\n                ssm_flash('success', '\\\\u0110\\\\u00e3 l\\\\u1ea5y l\\\\u1ea1i SHA256 t\\\\u1eeb file ZIP hi\\\\u1ec7n t\\\\u1ea1i.');\\\\n            } else {\\\\n                ssm_flash('error', 'Kh\\\\u00f4ng th\\\\u1ec3 l\\\\u01b0u SHA256 m\\\\u1edbi v\\\\u00e0o JSON.');\\\\n            }\\\\n        }\\\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\\\n        exit;\\\\n    }\\\\n}\\\\n\\\\n$config = ssm_load_config();\\\\n$flash = ssm_get_flash();\\\\n$setupRequired = ssm_setup_required($config);\\\\n$sourceAccessKey = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\\\n$suggestedSourceAccessKey = ssm_generate_access_key();\\\\n$csrf = ssm_csrf_token();\\\\n$manifestUrl = '';\\\\nif (!empty($_SERVER['HTTP_HOST'])) {\\\\n    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';\\\\n    $manifestUrl = $scheme . ':\\\\\\\/\\\\\\\/' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']) . '\\\\\\\/update-manifest.php';\\\\n}\\\\n$configLoginUrl = '';\\\\nif (!empty($_SERVER['HTTP_HOST'])) {\\\\n    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';\\\\n    $configLoginUrl = $scheme . ':\\\\\\\/\\\\\\\/' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . ($sourceAccessKey !== '' ? '?k=' . rawurlencode($sourceAccessKey) : '');\\\\n}\\\\n?>\\\\n<!doctype html>\\\\n<html lang=\\\\\\\"vi\\\\\\\">\\\\n<head>\\\\n<meta charset=\\\\\\\"utf-8\\\\\\\">\\\\n<meta name=\\\\\\\"viewport\\\\\\\" content=\\\\\\\"width=device-width, initial-scale=1\\\\\\\">\\\\n<meta name=\\\\\\\"robots\\\\\\\" content=\\\\\\\"noindex,nofollow\\\\\\\">\\\\n<title>C\\\\u1ea5u h\\\\u00ecnh Source Sync Master<\\\\\\\/title>\\\\n<style>\\\\n    :root { color-scheme: light; --bg:#f4f6fb; --card:#ffffff; --text:#172033; --muted:#667085; --border:#d9e0ea; --primary:#1d4ed8; --danger:#dc2626; --success:#15803d; }\\\\n    * { box-sizing: border-box; }\\\\n    body { margin:0; font-family: Arial, Helvetica, sans-serif; background: var(--bg); color: var(--text); }\\\\n    .wrap { max-width: 980px; margin: 0 auto; padding: 18px; }\\\\n    .top { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:14px; }\\\\n    h1 { font-size: 22px; margin:0; }\\\\n    .card { background:var(--card); border:1px solid var(--border); border-radius:14px; padding:16px; box-shadow:0 8px 24px rgba(15,23,42,.06); margin-bottom:14px; }\\\\n    .grid { display:grid; grid-template-columns: 1fr 1fr; gap:14px; }\\\\n    label { display:block; font-weight:700; margin-bottom:6px; font-size:14px; }\\\\n    input[type=text], input[type=password], textarea, select { width:100%; border:1px solid var(--border); border-radius:10px; padding:10px 12px; font-size:14px; background:#fff; color:var(--text); }\\\\n    textarea { min-height:96px; resize:vertical; }\\\\n    .hint { color:var(--muted); font-size:13px; margin-top:5px; line-height:1.45; }\\\\n    .row { margin-bottom:14px; }\\\\n    .btn { border:0; border-radius:10px; padding:10px 14px; font-weight:700; cursor:pointer; background:var(--primary); color:white; display:inline-flex; align-items:center; gap:8px; text-decoration:none; font-size:14px; }\\\\n    .btn.secondary { background:#475569; }\\\\n    .btn.danger { background:var(--danger); }\\\\n    .btn.light { background:#e8eef8; color:#1e293b; }\\\\n    .actions { display:flex; gap:10px; flex-wrap:wrap; align-items:center; }\\\\n    .flash { border-radius:10px; padding:11px 12px; margin-bottom:10px; border:1px solid var(--border); }\\\\n    .flash.success { background:#ecfdf3; color:#166534; border-color:#bbf7d0; }\\\\n    .flash.error { background:#fef2f2; color:#991b1b; border-color:#fecaca; }\\\\n    .stat { display:grid; grid-template-columns: 210px 1fr; gap:10px; border-bottom:1px solid #eef2f7; padding:8px 0; font-size:14px; }\\\\n    .stat b { color:#334155; }\\\\n    code { background:#eef2ff; color:#1e3a8a; padding:2px 5px; border-radius:5px; word-break:break-all; }\\\\n    .danger-note { color:#991b1b; background:#fff1f2; border:1px solid #fecdd3; padding:10px 12px; border-radius:10px; font-size:14px; line-height:1.45; }\\\\n    @media (max-width: 720px) {\\\\n        .wrap { padding:12px; }\\\\n        .grid { grid-template-columns: 1fr; }\\\\n        .top { align-items:flex-start; flex-direction:column; }\\\\n        .stat { grid-template-columns: 1fr; gap:4px; }\\\\n        .btn { width:100%; justify-content:center; }\\\\n    }\\\\n<\\\\\\\/style>\\\\n<\\\\\\\/head>\\\\n<body>\\\\n<div class=\\\\\\\"wrap\\\\\\\">\\\\n    <div class=\\\\\\\"top\\\\\\\">\\\\n        <div>\\\\n            <h1>\\\\u2699\\\\ufe0f C\\\\u1ea5u h\\\\u00ecnh Source Sync Master<\\\\\\\/h1>\\\\n            <div class=\\\\\\\"hint\\\\\\\">Trang n\\\\u00e0y d\\\\u00f9ng \\\\u0111\\\\u1ec3 c\\\\u1ea5u h\\\\u00ecnh <code>update-manifest.php<\\\\\\\/code>, upload ZIP update v\\\\u00e0 t\\\\u1ef1 l\\\\u1ea5y SHA256.<\\\\\\\/div>\\\\n        <\\\\\\\/div>\\\\n        <?php if (ssm_logged_in()): ?>\\\\n            <form method=\\\\\\\"post\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"action\\\\\\\" value=\\\\\\\"logout\\\\\\\">\\\\n                <button class=\\\\\\\"btn light\\\\\\\" type=\\\\\\\"submit\\\\\\\">\\\\u0110\\\\u0103ng xu\\\\u1ea5t<\\\\\\\/button>\\\\n            <\\\\\\\/form>\\\\n        <?php endif; ?>\\\\n    <\\\\\\\/div>\\\\n\\\\n    <?php foreach ($flash as $item): ?>\\\\n        <div class=\\\\\\\"flash <?php echo ssm_e($item['type']); ?>\\\\\\\"><?php echo ssm_e($item['message']); ?><\\\\\\\/div>\\\\n    <?php endforeach; ?>\\\\n\\\\n    <?php if ($setupRequired): ?>\\\\n        <div class=\\\\\\\"card\\\\\\\">\\\\n            <h2>Thi\\\\u1ebft l\\\\u1eadp Source Sync Master l\\\\u1ea7n \\\\u0111\\\\u1ea7u<\\\\\\\/h2>\\\\n            <p class=\\\\\\\"hint\\\\\\\">L\\\\u1ea7n \\\\u0111\\\\u1ea7u c\\\\u00f3 th\\\\u1ec3 truy c\\\\u1eadp tr\\\\u1ef1c ti\\\\u1ebfp trang n\\\\u00e0y \\\\u0111\\\\u1ec3 t\\\\u1ea1o m\\\\u1eadt kh\\\\u1ea9u v\\\\u00e0 token b\\\\u1ea3o v\\\\u1ec7 \\\\u0111\\\\u01b0\\\\u1eddng d\\\\u1eabn. Nh\\\\u1eefng l\\\\u1ea7n sau ph\\\\u1ea3i truy c\\\\u1eadp \\\\u0111\\\\u00fang link c\\\\u00f3 token.<\\\\\\\/p>\\\\n            <form method=\\\\\\\"post\\\\\\\" style=\\\\\\\"margin-top:14px;\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"action\\\\\\\" value=\\\\\\\"setup_config\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"csrf\\\\\\\" value=\\\\\\\"<?php echo ssm_e($csrf); ?>\\\\\\\">\\\\n                <div class=\\\\\\\"row\\\\\\\"><label>M\\\\u1eadt kh\\\\u1ea9u c\\\\u1ea5u h\\\\u00ecnh m\\\\u1edbi<\\\\\\\/label><input type=\\\\\\\"password\\\\\\\" name=\\\\\\\"password\\\\\\\" autocomplete=\\\\\\\"new-password\\\\\\\" minlength=\\\\\\\"8\\\\\\\" required><\\\\\\\/div>\\\\n                <div class=\\\\\\\"row\\\\\\\"><label>Nh\\\\u1eadp l\\\\u1ea1i m\\\\u1eadt kh\\\\u1ea9u<\\\\\\\/label><input type=\\\\\\\"password\\\\\\\" name=\\\\\\\"password_confirm\\\\\\\" autocomplete=\\\\\\\"new-password\\\\\\\" minlength=\\\\\\\"8\\\\\\\" required><\\\\\\\/div>\\\\n                <div class=\\\\\\\"row\\\\\\\"><label>Token truy c\\\\u1eadp trang c\\\\u1ea5u h\\\\u00ecnh<\\\\\\\/label><input type=\\\\\\\"text\\\\\\\" name=\\\\\\\"config_access_key\\\\\\\" value=\\\\\\\"<?php echo ssm_e($suggestedSourceAccessKey); ?>\\\\\\\" required><div class=\\\\\\\"hint\\\\\\\">Sau khi l\\\\u01b0u, link truy c\\\\u1eadp s\\\\u1ebd c\\\\u00f3 d\\\\u1ea1ng: <code><?php echo ssm_e((!empty($_SERVER['HTTP_HOST']) ? (((!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http') . ':\\\\\\\/\\\\\\\/' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME']) : 'source-sync-config.php')); ?>?k=TOKEN<\\\\\\\/code><\\\\\\\/div><\\\\\\\/div>\\\\n                <button class=\\\\\\\"btn\\\\\\\" type=\\\\\\\"submit\\\\\\\">T\\\\u1ea1o m\\\\u1eadt kh\\\\u1ea9u v\\\\u00e0 token<\\\\\\\/button>\\\\n            <\\\\\\\/form>\\\\n        <\\\\\\\/div>\\\\n    <?php elseif (!ssm_logged_in()): ?>\\\\n        <div class=\\\\\\\"card\\\\\\\">\\\\n            <h2>\\\\u0110\\\\u0103ng nh\\\\u1eadp<\\\\\\\/h2>\\\\n            <form method=\\\\\\\"post\\\\\\\" style=\\\\\\\"margin-top:14px;\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"action\\\\\\\" value=\\\\\\\"login\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"csrf\\\\\\\" value=\\\\\\\"<?php echo ssm_e($csrf); ?>\\\\\\\">\\\\n                <div class=\\\\\\\"row\\\\\\\"><label>M\\\\u1eadt kh\\\\u1ea9u c\\\\u1ea5u h\\\\u00ecnh<\\\\\\\/label><input type=\\\\\\\"password\\\\\\\" name=\\\\\\\"password\\\\\\\" autocomplete=\\\\\\\"current-password\\\\\\\" required><\\\\\\\/div>\\\\n                <button class=\\\\\\\"btn\\\\\\\" type=\\\\\\\"submit\\\\\\\">\\\\u0110\\\\u0103ng nh\\\\u1eadp<\\\\\\\/button>\\\\n            <\\\\\\\/form>\\\\n            <?php if ($configLoginUrl !== ''): ?><p class=\\\\\\\"hint\\\\\\\">Link truy c\\\\u1eadp h\\\\u1ee3p l\\\\u1ec7: <code><?php echo ssm_e($configLoginUrl); ?><\\\\\\\/code><\\\\\\\/p><?php endif; ?>\\\\n        <\\\\\\\/div>\\\\n    <?php else: ?>\\\\n        <div class=\\\\\\\"card\\\\\\\">\\\\n            <h2>Th\\\\u00f4ng tin hi\\\\u1ec7n t\\\\u1ea1i<\\\\\\\/h2>\\\\n            <div class=\\\\\\\"stat\\\\\\\"><b>Manifest URL<\\\\\\\/b><div><code><?php echo ssm_e($manifestUrl); ?><\\\\\\\/code><\\\\\\\/div><\\\\\\\/div>\\\\n            <?php if ($configLoginUrl !== ''): ?><div class=\\\\\\\"stat\\\\\\\"><b>Link c\\\\u1ea5u h\\\\u00ecnh<\\\\\\\/b><div><code><?php echo ssm_e($configLoginUrl); ?><\\\\\\\/code><\\\\\\\/div><\\\\\\\/div><?php endif; ?>\\\\n            <div class=\\\\\\\"stat\\\\\\\"><b>Version<\\\\\\\/b><div><?php echo ssm_e($config['version']); ?><\\\\\\\/div><\\\\\\\/div>\\\\n            <div class=\\\\\\\"stat\\\\\\\"><b>ZIP URL<\\\\\\\/b><div><code><?php echo ssm_e($config['zip_url']); ?><\\\\\\\/code><\\\\\\\/div><\\\\\\\/div>\\\\n            <div class=\\\\\\\"stat\\\\\\\"><b>SHA256<\\\\\\\/b><div><code><?php echo ssm_e($config['zip_sha256']); ?><\\\\\\\/code><\\\\\\\/div><\\\\\\\/div>\\\\n            <div class=\\\\\\\"stat\\\\\\\"><b>File ZIP<\\\\\\\/b><div><?php echo ssm_e($config['zip_filename']); ?> <?php echo !empty($config['zip_size']) ? '(' . number_format((float)$config['zip_size']) . ' bytes)' : ''; ?><\\\\\\\/div><\\\\\\\/div>\\\\n            <div class=\\\\\\\"stat\\\\\\\"><b>C\\\\u1eadp nh\\\\u1eadt JSON<\\\\\\\/b><div><?php echo ssm_e($config['updated_at']); ?><\\\\\\\/div><\\\\\\\/div>\\\\n        <\\\\\\\/div>\\\\n\\\\n        <div class=\\\\\\\"card\\\\\\\">\\\\n            <h2>Upload ZIP phi\\\\u00ean b\\\\u1ea3n m\\\\u1edbi<\\\\\\\/h2>\\\\n            <form method=\\\\\\\"post\\\\\\\" enctype=\\\\\\\"multipart\\\\\\\/form-data\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"action\\\\\\\" value=\\\\\\\"upload_zip\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"csrf\\\\\\\" value=\\\\\\\"<?php echo ssm_e($csrf); ?>\\\\\\\">\\\\n                <div class=\\\\\\\"row\\\\\\\">\\\\n                    <label>Ch\\\\u1ecdn file .zip<\\\\\\\/label>\\\\n                    <input type=\\\\\\\"file\\\\\\\" name=\\\\\\\"update_zip\\\\\\\" accept=\\\\\\\".zip,application\\\\\\\/zip,application\\\\\\\/x-zip-compressed\\\\\\\" required>\\\\n                    <div class=\\\\\\\"hint\\\\\\\">File s\\\\u1ebd t\\\\u1ef1 l\\\\u01b0u v\\\\u00e0o <code>\\\\\\\/update-packages\\\\\\\/<\\\\\\\/code>, t\\\\u1ef1 t\\\\u1ea1o <code>zip_url<\\\\\\\/code> v\\\\u00e0 t\\\\u1ef1 t\\\\u00ednh SHA256.<\\\\\\\/div>\\\\n                <\\\\\\\/div>\\\\n                <div class=\\\\\\\"actions\\\\\\\">\\\\n                    <button class=\\\\\\\"btn\\\\\\\" type=\\\\\\\"submit\\\\\\\">\\\\u2b06\\\\ufe0f Upload ZIP v\\\\u00e0 t\\\\u1ef1 l\\\\u1ea5y SHA256<\\\\\\\/button>\\\\n                <\\\\\\\/div>\\\\n            <\\\\\\\/form>\\\\n        <\\\\\\\/div>\\\\n\\\\n        <div class=\\\\\\\"card\\\\\\\">\\\\n            <h2>C\\\\u1ea5u h\\\\u00ecnh manifest<\\\\\\\/h2>\\\\n            <form method=\\\\\\\"post\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"action\\\\\\\" value=\\\\\\\"save_config\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"csrf\\\\\\\" value=\\\\\\\"<?php echo ssm_e($csrf); ?>\\\\\\\">\\\\n\\\\n                <div class=\\\\\\\"grid\\\\\\\">\\\\n                    <div class=\\\\\\\"row\\\\\\\">\\\\n                        <label>Token m\\\\u00e1y ch\\\\u1ee7 ch\\\\u00ednh<\\\\\\\/label>\\\\n                        <input type=\\\\\\\"text\\\\\\\" name=\\\\\\\"master_token\\\\\\\" value=\\\\\\\"<?php echo ssm_e($config['master_token']); ?>\\\\\\\" placeholder=\\\\\\\"Ph\\\\u1ea3i gi\\\\u1ed1ng SOURCE_SYNC_API_TOKEN tr\\\\u00ean m\\\\u00e1y ch\\\\u1ee7 con\\\\\\\" required>\\\\n                    <\\\\\\\/div>\\\\n                    <div class=\\\\\\\"row\\\\\\\">\\\\n                        <label>Phi\\\\u00ean b\\\\u1ea3n m\\\\u1edbi nh\\\\u1ea5t<\\\\\\\/label>\\\\n                        <input type=\\\\\\\"text\\\\\\\" name=\\\\\\\"version\\\\\\\" value=\\\\\\\"<?php echo ssm_e($config['version']); ?>\\\\\\\" placeholder=\\\\\\\"VD: V24\\\\\\\" required>\\\\n                    <\\\\\\\/div>\\\\n                <\\\\\\\/div>\\\\n\\\\n                <div class=\\\\\\\"row\\\\\\\">\\\\n                    <label>ZIP URL<\\\\\\\/label>\\\\n                    <input type=\\\\\\\"text\\\\\\\" name=\\\\\\\"zip_url\\\\\\\" value=\\\\\\\"<?php echo ssm_e($config['zip_url']); ?>\\\\\\\" placeholder=\\\\\\\"\\\\\\\/update-packages\\\\\\\/web-shop-V24.zip\\\\\\\">\\\\n                    <div class=\\\\\\\"hint\\\\\\\">C\\\\u00f3 th\\\\u1ec3 d\\\\u00f9ng \\\\u0111\\\\u01b0\\\\u1eddng d\\\\u1eabn n\\\\u1ed9i b\\\\u1ed9 nh\\\\u01b0 <code>\\\\\\\/update-packages\\\\\\\/web-shop-V24.zip<\\\\\\\/code> ho\\\\u1eb7c URL \\\\u0111\\\\u1ea7y \\\\u0111\\\\u1ee7.<\\\\\\\/div>\\\\n                <\\\\\\\/div>\\\\n\\\\n                <div class=\\\\\\\"row\\\\\\\">\\\\n                    <label>SHA256<\\\\\\\/label>\\\\n                    <input type=\\\\\\\"text\\\\\\\" name=\\\\\\\"zip_sha256\\\\\\\" value=\\\\\\\"<?php echo ssm_e($config['zip_sha256']); ?>\\\\\\\" placeholder=\\\\\\\"T\\\\u1ef1 t\\\\u1ea1o sau khi upload ZIP\\\\\\\">\\\\n                    <div class=\\\\\\\"hint\\\\\\\">N\\\\u1ebfu upload ZIP b\\\\u1eb1ng form ph\\\\u00eda tr\\\\u00ean, SHA256 s\\\\u1ebd t\\\\u1ef1 \\\\u0111i\\\\u1ec1n v\\\\u00e0 l\\\\u01b0u v\\\\u00e0o JSON.<\\\\\\\/div>\\\\n                <\\\\\\\/div>\\\\n\\\\n                <div class=\\\\\\\"grid\\\\\\\">\\\\n                    <div class=\\\\\\\"row\\\\\\\">\\\\n                        <label>Th\\\\u1eddi gian ph\\\\u00e1t h\\\\u00e0nh<\\\\\\\/label>\\\\n                        <input type=\\\\\\\"text\\\\\\\" name=\\\\\\\"released_at\\\\\\\" value=\\\\\\\"<?php echo ssm_e($config['released_at']); ?>\\\\\\\" placeholder=\\\\\\\"2026-06-28 00:00:00\\\\\\\">\\\\n                    <\\\\\\\/div>\\\\n                    <div class=\\\\\\\"row\\\\\\\">\\\\n                        <label>B\\\\u1eaft bu\\\\u1ed9c c\\\\u1eadp nh\\\\u1eadt?<\\\\\\\/label>\\\\n                        <select name=\\\\\\\"required\\\\\\\">\\\\n                            <option value=\\\\\\\"0\\\\\\\" <?php echo empty($config['required']) ? 'selected' : ''; ?>>Kh\\\\u00f4ng<\\\\\\\/option>\\\\n                            <option value=\\\\\\\"1\\\\\\\" <?php echo !empty($config['required']) ? 'selected' : ''; ?>>C\\\\u00f3<\\\\\\\/option>\\\\n                        <\\\\\\\/select>\\\\n                    <\\\\\\\/div>\\\\n                <\\\\\\\/div>\\\\n\\\\n                <div class=\\\\\\\"row\\\\\\\">\\\\n                    <label>Ghi ch\\\\u00fa c\\\\u1eadp nh\\\\u1eadt<\\\\\\\/label>\\\\n                    <textarea name=\\\\\\\"changelog\\\\\\\" placeholder=\\\\\\\"- N\\\\u1ed9i dung c\\\\u1eadp nh\\\\u1eadt 1&#10;- N\\\\u1ed9i dung c\\\\u1eadp nh\\\\u1eadt 2\\\\\\\"><?php echo ssm_e($config['changelog']); ?><\\\\\\\/textarea>\\\\n                <\\\\\\\/div>\\\\n\\\\n                <div class=\\\\\\\"grid\\\\\\\">\\\\n                    <div class=\\\\\\\"row\\\\\\\">\\\\n                        <label>IP m\\\\u00e1y ch\\\\u1ee7 con \\\\u0111\\\\u01b0\\\\u1ee3c ph\\\\u00e9p<\\\\\\\/label>\\\\n                        <textarea name=\\\\\\\"allowed_client_ips\\\\\\\" placeholder=\\\\\\\"M\\\\u1ed7i d\\\\u00f2ng 1 IP public ho\\\\u1eb7c local\\\\\\\/server IP&#10;VD public: 103.345.23.25&#10;VD server local: 14.225.218.36&#10;VD private: 192.168.1.10\\\\\\\"><?php echo ssm_e(ssm_array_to_text($config['allowed_client_ips'])); ?><\\\\\\\/textarea>\\\\n                        <div class=\\\\\\\"hint\\\\\\\">\\\\u0110\\\\u1ec3 tr\\\\u1ed1ng n\\\\u1ebfu kh\\\\u00f4ng mu\\\\u1ed1n ki\\\\u1ec3m tra IP. C\\\\u00f3 th\\\\u1ec3 nh\\\\u1eadp IP public\\\\\\\/NAT ho\\\\u1eb7c IP server local\\\\\\\/private c\\\\u1ee7a m\\\\u00e1y ch\\\\u1ee7 con.<\\\\\\\/div>\\\\n                    <\\\\\\\/div>\\\\n                    <div class=\\\\\\\"row\\\\\\\">\\\\n                        <label>Domain m\\\\u00e1y ch\\\\u1ee7 con \\\\u0111\\\\u01b0\\\\u1ee3c ph\\\\u00e9p<\\\\\\\/label>\\\\n                        <textarea name=\\\\\\\"allowed_client_domains\\\\\\\" placeholder=\\\\\\\"M\\\\u1ed7i d\\\\u00f2ng 1 domain&#10;VD: shop-con.example.com\\\\\\\"><?php echo ssm_e(ssm_array_to_text($config['allowed_client_domains'])); ?><\\\\\\\/textarea>\\\\n                        <div class=\\\\\\\"hint\\\\\\\">\\\\u0110\\\\u1ec3 tr\\\\u1ed1ng n\\\\u1ebfu kh\\\\u00f4ng mu\\\\u1ed1n ki\\\\u1ec3m tra domain. N\\\\u1ebfu \\\\u0111i\\\\u1ec1n c\\\\u1ea3 IP v\\\\u00e0 domain th\\\\u00ec request ph\\\\u1ea3i kh\\\\u1edbp c\\\\u1ea3 hai. V\\\\u1edbi IP, h\\\\u1ec7 th\\\\u1ed1ng ch\\\\u1ea5p nh\\\\u1eadn IP public ho\\\\u1eb7c IP local\\\\\\\/server IP do m\\\\u00e1y ch\\\\u1ee7 con g\\\\u1eedi k\\\\u00e8m token\\\\\\\/header\\\\\\\/query.<\\\\\\\/div>\\\\n                    <\\\\\\\/div>\\\\n                <\\\\\\\/div>\\\\n\\\\n                <div class=\\\\\\\"actions\\\\\\\">\\\\n                    <button class=\\\\\\\"btn\\\\\\\" type=\\\\\\\"submit\\\\\\\">\\\\ud83d\\\\udcbe L\\\\u01b0u c\\\\u1ea5u h\\\\u00ecnh v\\\\u00e0o JSON<\\\\\\\/button>\\\\n                <\\\\\\\/div>\\\\n            <\\\\\\\/form>\\\\n\\\\n            <form method=\\\\\\\"post\\\\\\\" style=\\\\\\\"margin-top:10px;\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"action\\\\\\\" value=\\\\\\\"recalc_sha256\\\\\\\">\\\\n                <input type=\\\\\\\"hidden\\\\\\\" name=\\\\\\\"csrf\\\\\\\" value=\\\\\\\"<?php echo ssm_e($csrf); ?>\\\\\\\">\\\\n                <button class=\\\\\\\"btn secondary\\\\\\\" type=\\\\\\\"submit\\\\\\\">\\\\ud83d\\\\udd01 L\\\\u1ea5y l\\\\u1ea1i SHA256 t\\\\u1eeb ZIP hi\\\\u1ec7n t\\\\u1ea1i<\\\\\\\/button>\\\\n            <\\\\\\\/form>\\\\n        <\\\\\\\/div>\\\\n    <?php endif; ?>\\\\n<\\\\\\\/div>\\\\n<\\\\\\\/body>\\\\n<\\\\\\\/html>\\\\n\\\",\\n        \\\"time\\\": \\\"2026-07-01 13:27:56\\\"\\n    }\\n]\",\n        \"time\": \"2026-07-01 23:25:40\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/data\\\/settings.json\",\n        \"content\": \"{\\n    \\\"site_title\\\": \\\"Shop Balance\\\",\\n    \\\"site_description\\\": \\\"H\\u1ec7 th\\u1ed1ng b\\u00e1n s\\u1ea3n ph\\u1ea9m t\\u1ef1 \\u0111\\u1ed9ng b\\u1eb1ng s\\u1ed1 d\\u01b0.\\\",\\n    \\\"site_keywords\\\": \\\"shop t\\u1ef1 \\u0111\\u1ed9ng, s\\u1ea3n ph\\u1ea9m s\\u1ed1, n\\u1ea1p ti\\u1ec1n, \\u0111\\u01a1n h\\u00e0ng t\\u1ef1 \\u0111\\u1ed9ng\\\",\\n    \\\"site_author\\\": \\\"\\\",\\n    \\\"site_robots\\\": \\\"index,follow\\\",\\n    \\\"site_canonical_url\\\": \\\"\\\",\\n    \\\"home_notice\\\": \\\"Nh\\u1eadp username, email ho\\u1eb7c s\\u1ed1 \\u0111i\\u1ec7n tho\\u1ea1i k\\u00e8m m\\u1eadt kh\\u1ea9u \\u0111\\u1ec3 \\u0111\\u0103ng nh\\u1eadp. T\\u00e0i kho\\u1ea3n ch\\u01b0a c\\u00f3 s\\u1ebd t\\u1ef1 \\u0111\\u0103ng k\\u00fd; t\\u00e0i kho\\u1ea3n c\\u0169 ch\\u01b0a c\\u00f3 m\\u1eadt kh\\u1ea9u s\\u1ebd \\u0111\\u01b0\\u1ee3c l\\u01b0u m\\u1eadt kh\\u1ea9u \\u1edf l\\u1ea7n \\u0111\\u0103ng nh\\u1eadp \\u0111\\u1ea7u ti\\u00ean.\\\",\\n    \\\"site_base_url\\\": \\\"\\\",\\n    \\\"site_logo_path\\\": \\\"\\\",\\n    \\\"site_logo_alt\\\": \\\"\\\",\\n    \\\"home_banner_1_path\\\": \\\"\\\",\\n    \\\"home_banner_1_alt\\\": \\\"\\\",\\n    \\\"home_banner_1_link\\\": \\\"\\\",\\n    \\\"home_banner_2_path\\\": \\\"\\\",\\n    \\\"home_banner_2_alt\\\": \\\"\\\",\\n    \\\"home_banner_2_link\\\": \\\"\\\",\\n    \\\"home_banner_3_path\\\": \\\"\\\",\\n    \\\"home_banner_3_alt\\\": \\\"\\\",\\n    \\\"home_banner_3_link\\\": \\\"\\\",\\n    \\\"webhook_secret\\\": \\\"f6d94c035077c7e06004169df7fe721edd2026aea0ad6bb45f1f53a5e0461514\\\",\\n    \\\"webhook_hmac_enabled\\\": \\\"1\\\",\\n    \\\"admin_username\\\": \\\"admin\\\",\\n    \\\"admin_password_hash\\\": \\\"$2y$10$t1GabqIKA62ttK8tKlxN1.ZGxKY7JkMLwf.nOxzTbaxl4SwM9\\\\\\\/XTO\\\",\\n    \\\"admin_access_key\\\": \\\"9bc38444cfe193271934113f\\\",\\n    \\\"admin_access_setup_done\\\": \\\"1\\\",\\n    \\\"deposit_bank_name\\\": \\\"\\\",\\n    \\\"deposit_account_number\\\": \\\"\\\",\\n    \\\"deposit_account_owner\\\": \\\"\\\",\\n    \\\"deposit_transfer_content\\\": \\\"NAP {id}\\\",\\n    \\\"deposit_quick_amounts\\\": \\\"10000,20000,50000,100000,200000,500000,1000000,2000000\\\",\\n    \\\"deposit_max_invoice_amount\\\": \\\"5000000\\\",\\n    \\\"deposit_vietqr_bank_id\\\": \\\"\\\",\\n    \\\"deposit_vietqr_template\\\": \\\"compact2\\\",\\n    \\\"deposit_vietqr_display_mode\\\": \\\"qr_and_info\\\",\\n    \\\"deposit_invoice_expire_minutes\\\": \\\"30\\\",\\n    \\\"deposit_promo_enabled\\\": \\\"0\\\",\\n    \\\"deposit_promo_rules\\\": \\\"100000|5\\\\n500000|10\\\\n1000000|15\\\",\\n    \\\"deposit_note\\\": \\\"Vui l\\u00f2ng t\\u1ea1o h\\u00f3a \\u0111\\u01a1n n\\u1ea1p ti\\u1ec1n tr\\u01b0\\u1edbc khi chuy\\u1ec3n kho\\u1ea3n. H\\u1ec7 th\\u1ed1ng s\\u1ebd t\\u1ef1 th\\u00eam ID c\\u1ee7a b\\u1ea1n v\\u00e0o 3 s\\u1ed1 cu\\u1ed1i c\\u1ee7a s\\u1ed1 ti\\u1ec1n c\\u1ea7n chuy\\u1ec3n \\u0111\\u1ec3 t\\u1ef1 \\u0111\\u1ed9ng c\\u1ed9ng \\u0111\\u00fang t\\u00e0i kho\\u1ea3n.\\\",\\n    \\\"deposit_guide_html\\\": \\\"<p>V\\u00e0o trang <b>N\\u1ea1p Ti\\u1ec1n<\\\\\\\/b>, ch\\u1ecdn nhanh s\\u1ed1 ti\\u1ec1n c\\u1ea7n n\\u1ea1p ho\\u1eb7c nh\\u1eadp s\\u1ed1 ti\\u1ec1n g\\u1ed1c b\\u1ea1n mu\\u1ed1n n\\u1ea1p, sau \\u0111\\u00f3 b\\u1ea5m <b>T\\u1ea1o h\\u00f3a \\u0111\\u01a1n n\\u1ea1p ti\\u1ec1n<\\\\\\\/b>.<\\\\\\\/p><p>V\\u00ed d\\u1ee5 ID c\\u1ee7a b\\u1ea1n l\\u00e0 <b>{id}<\\\\\\\/b>, b\\u1ea1n mu\\u1ed1n n\\u1ea1p <b>120.000\\u0111<\\\\\\\/b> th\\u00ec s\\u1ed1 ti\\u1ec1n c\\u1ea7n chuy\\u1ec3n s\\u1ebd l\\u00e0 <b>120.{id}\\u0111<\\\\\\\/b>.<\\\\\\\/p><p>N\\u1ebfu s\\u1ed1 ti\\u1ec1n chuy\\u1ec3n kho\\u1ea3n kh\\u00f4ng c\\u00f3 ID h\\u1ee3p l\\u1ec7 \\u1edf 3 s\\u1ed1 cu\\u1ed1i, h\\u1ec7 th\\u1ed1ng c\\u00f3 th\\u1ec3 kh\\u00f4ng t\\u1ef1 nh\\u1eadn di\\u1ec7n \\u0111\\u00fang t\\u00e0i kho\\u1ea3n n\\u1ea1p ti\\u1ec1n.<\\\\\\\/p>\\\",\\n    \\\"deposit_invoice_notice\\\": \\\"Vui l\\u00f2ng chuy\\u1ec3n kho\\u1ea3n \\u0111\\u00fang ch\\u00ednh x\\u00e1c s\\u1ed1 ti\\u1ec1n c\\u1ea7n chuy\\u1ec3n b\\u00ean d\\u01b0\\u1edbi. H\\u00f3a \\u0111\\u01a1n s\\u1ebd \\u0111\\u01b0\\u1ee3c c\\u1ed9ng ti\\u1ec1n t\\u1ef1 \\u0111\\u1ed9ng khi h\\u1ec7 th\\u1ed1ng nh\\u1eadn giao d\\u1ecbch, ho\\u1eb7c admin c\\u00f3 th\\u1ec3 duy\\u1ec7t th\\u1ee7 c\\u00f4ng trong qu\\u1ea3n tr\\u1ecb.\\\",\\n    \\\"order_detail_notice_html\\\": \\\"\\\",\\n    \\\"order_auto_delete_days\\\": \\\"30\\\",\\n    \\\"inactive_user_delete_days\\\": \\\"180\\\",\\n    \\\"inactive_user_delete_months\\\": \\\"6\\\",\\n    \\\"user_delete_balance_threshold\\\": \\\"1000\\\",\\n    \\\"deposit_history_auto_delete_months\\\": \\\"6\\\",\\n    \\\"maintenance_enabled\\\": \\\"0\\\",\\n    \\\"maintenance_message\\\": \\\"Website \\u0111ang b\\u1ea3o tr\\u00ec, vui l\\u00f2ng quay l\\u1ea1i sau.\\\",\\n    \\\"ticket_auto_delete_days\\\": \\\"0\\\",\\n    \\\"ticket_telegram_bot_token\\\": \\\"\\\",\\n    \\\"ticket_telegram_chat_id\\\": \\\"\\\",\\n    \\\"telegram_shop_enabled\\\": \\\"0\\\",\\n    \\\"telegram_shop_bot_token\\\": \\\"\\\",\\n    \\\"telegram_shop_webhook_secret\\\": \\\"\\\",\\n    \\\"backup_auto_enabled\\\": \\\"1\\\",\\n    \\\"backup_interval_hours\\\": \\\"24\\\",\\n    \\\"backup_keep_count\\\": \\\"10\\\",\\n    \\\"backup_keep_days\\\": \\\"30\\\",\\n    \\\"backup_restore_enabled\\\": \\\"1\\\",\\n    \\\"backup_cron_token\\\": \\\"9f7e37129b685d070c2181fc18d23345c34257c5957e6f52\\\",\\n    \\\"backup_last_at\\\": \\\"2026-06-30 07:19:20\\\",\\n    \\\"backup_last_auto_at\\\": \\\"2026-06-30 07:19:20\\\",\\n    \\\"backup_last_file\\\": \\\"auto-backup-20260630-071920-4e82bc24.zip\\\",\\n    \\\"backup_last_status\\\": \\\"success\\\",\\n    \\\"backup_last_error\\\": \\\"\\\"\\n}\",\n        \"time\": \"2026-07-01 13:56:49\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/README_PUBLIC_LAYOUT.txt\",\n        \"content\": \"B\\u1ed1 c\\u1ee5c sau khi t\\u1ed1i \\u01b0u:\\n\\n- public\\\/: ch\\u1ee9a to\\u00e0n b\\u1ed9 m\\u00e3 ngu\\u1ed3n \\u1ee9ng d\\u1ee5ng v\\u00e0 c\\u00e1c file web-facing.\\n- data\\\/, backup\\\/, codes\\\/, kho-tdata\\\/, uploads\\\/, source-sync-master-data\\\/: th\\u01b0 m\\u1ee5c private n\\u1eb1m ngang c\\u1ea5p public, d\\u00f9ng \\u0111\\u1ec3 l\\u01b0u JSON, backup, m\\u00e3\\\/code s\\u1ea3n ph\\u1ea9m, kho h\\u00e0ng, file t\\u1ea1m v\\u00e0 c\\u1ea5u h\\u00ecnh source-sync master.\\n- .htaccess \\u1edf th\\u01b0 m\\u1ee5c g\\u1ed1c rewrite n\\u1ed9i b\\u1ed9 request v\\u00e0o public\\\/ \\u0111\\u1ec3 gi\\u1eef nguy\\u00ean URL nh\\u01b0 tr\\u01b0\\u1edbc, v\\u00ed d\\u1ee5 \\\/products, \\\/admin, \\\/sitemap.xml.\\n\\nKhuy\\u1ebfn ngh\\u1ecb tri\\u1ec3n khai an to\\u00e0n nh\\u1ea5t:\\n1. N\\u1ebfu hosting cho ph\\u00e9p ch\\u1ecdn document root, h\\u00e3y tr\\u1ecf document root tr\\u1ef1c ti\\u1ebfp v\\u00e0o th\\u01b0 m\\u1ee5c public\\\/. Khi \\u0111\\u00f3 c\\u00e1c th\\u01b0 m\\u1ee5c private ngang c\\u1ea5p public kh\\u00f4ng th\\u1ec3 truy c\\u1eadp b\\u1eb1ng URL.\\n2. N\\u1ebfu hosting kh\\u00f4ng cho \\u0111\\u1ed5i document root, upload c\\u1ea3 g\\u00f3i n\\u00e0y; file .htaccess \\u1edf g\\u1ed1c s\\u1ebd gi\\u1eef URL kh\\u00f4ng c\\u00f3 \\\/public\\\/ v\\u00e0 ch\\u1eb7n c\\u00e1c th\\u01b0 m\\u1ee5c private.\\n3. N\\u1ebfu d\\u00f9ng Nginx ho\\u1eb7c m\\u00f4i tr\\u01b0\\u1eddng kh\\u00f4ng \\u0111\\u1ecdc .htaccess, b\\u1eaft bu\\u1ed9c c\\u1ea5u h\\u00ecnh root v\\u1ec1 public\\\/ ho\\u1eb7c deny tr\\u1ef1c ti\\u1ebfp c\\u00e1c \\u0111\\u01b0\\u1eddng d\\u1eabn \\\/data, \\\/backup, \\\/codes, \\\/kho-tdata, \\\/uploads, \\\/source-sync-master-data. C\\u00e1c th\\u01b0 m\\u1ee5c private c\\u00f3 index.php\\\/web.config\\\/.htaccess b\\u1ea3o v\\u1ec7 b\\u1ed5 sung, nh\\u01b0ng file t\\u0129nh c\\u00f3 th\\u1ec3 b\\u1ecb web server ph\\u1ee5c v\\u1ee5 tr\\u01b0\\u1edbc khi PHP ch\\u1ea1y n\\u1ebfu web root \\u0111\\u1eb7t sai.\\n\",\n        \"time\": \"2026-07-01 13:30:55\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/source-sync-master-data\\\/source-sync-master-config.json\",\n        \"content\": \"{\\n    \\\"master_token\\\": \\\"bfe414a0a2a29256\\\",\\n    \\\"version\\\": \\\"V1.8\\\",\\n    \\\"zip_url\\\": \\\"\\\/update-packages\\\/65458_backup_restore_round_robin_deposit_history_fixed.zip\\\",\\n    \\\"zip_sha256\\\": \\\"3111a3acd50550c6f32c133e1143200ba511863ee0ed4c6459dcdfebe2bd794e\\\",\\n    \\\"zip_filename\\\": \\\"65458_backup_restore_round_robin_deposit_history_fixed.zip\\\",\\n    \\\"zip_size\\\": 2677981,\\n    \\\"released_at\\\": \\\"2026-06-30 12:45:46\\\",\\n    \\\"changelog\\\": \\\"\\\",\\n    \\\"required\\\": true,\\n    \\\"allowed_client_ips\\\": [\\n        \\\"14.225.218.36\\\",\\n        \\\"14.225.219.71\\\"\\n    ],\\n    \\\"allowed_client_domains\\\": [\\n        \\\"taphoatele.com\\\",\\n        \\\"acctelegram.net\\\",\\n        \\\"1ccmm.my\\\",\\n        \\\"1.1ccmm.my\\\"\\n    ],\\n    \\\"updated_at\\\": \\\"2026-06-30 12:45:46\\\",\\n    \\\"config_password_hash\\\": \\\"$2y$10$HHl.YoV15spCHl6g6fGKsO5T7vr12Bo.zfGZ0knK\\\/Dkpcz12Tqn5e\\\",\\n    \\\"config_access_key\\\": \\\"9bc38444cfe193271934113f\\\",\\n    \\\"config_setup_done\\\": true\\n}\",\n        \"time\": \"2026-07-01 13:29:39\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/source-sync-master-data\\\/source-sync-login-rate.json\",\n        \"content\": \"{\\n    \\\"login:7a1a4051beabf07f10a0ff2171cc95604e1a86e6\\\": [\\n        1782798339\\n    ]\\n}\",\n        \"time\": \"2026-07-01 13:29:37\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/public\\\/webhook.php\",\n        \"content\": \"<?php\\nrequire_once __DIR__ . '\\\/includes\\\/functions.php';\\nensure_data_files();\\nsend_security_headers(true);\\ntry {\\n    if (security_guard_active()) { json_response(array('ok'=>true,'guarded'=>true), 200); }\\n    security_request_rate_guard('webhook_request', array(request_ip_address()), 120, 60, 300, 'Webhook nh\\u1eadn qu\\u00e1 nhi\\u1ec1u request, vui l\\u00f2ng th\\u1eed l\\u1ea1i sau.');\\n    $payload = read_webhook_payload();\\n    $result = process_deposit_webhook($payload);\\n    json_response($result, 200);\\n} catch (Exception $e) {\\n    security_log_event('webhook_exception', 'L\\u1ed7i x\\u1eed l\\u00fd webhook', array('error' => $e->getMessage()));\\n    json_response(array('ok'=>false,'error'=>security_generic_message()),500);\\n}\\n\",\n        \"time\": \"2026-07-01 13:28:15\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/public\\\/source-sync-master-api\\\/source-sync-config.php\",\n        \"content\": \"<?php\\n\\\/**\\n * Trang c\\u1ea5u h\\u00ecnh m\\u00e1y ch\\u1ee7 ch\\u00ednh cho update-manifest.php.\\n *\\n * \\u0110\\u1eb7t file n\\u00e0y trong \\\/source-sync-master-api\\\/ tr\\u00ean M\\u00c1Y CH\\u1ee6 CH\\u00cdNH.\\n * M\\u1ecdi c\\u1ea5u h\\u00ecnh manifest \\u0111\\u01b0\\u1ee3c l\\u01b0u v\\u00e0o JSON:\\n *   \\\/source-sync-master-data\\\/source-sync-master-config.json\\n *\\n * B\\u1ea3o m\\u1eadt trang c\\u1ea5u h\\u00ecnh:\\n * - L\\u1ea7n \\u0111\\u1ea7u truy c\\u1eadp tr\\u1ef1c ti\\u1ebfp file n\\u00e0y \\u0111\\u1ec3 t\\u1ea1o m\\u1eadt kh\\u1ea9u v\\u00e0 token truy c\\u1eadp.\\n * - Nh\\u1eefng l\\u1ea7n sau ph\\u1ea3i truy c\\u1eadp d\\u1ea1ng source-sync-config.php?k=TOKEN.\\n * - Bi\\u1ebfn m\\u1eadt kh\\u1ea9u b\\u00ean d\\u01b0\\u1edbi ch\\u1ec9 c\\u00f2n d\\u00f9ng t\\u01b0\\u01a1ng th\\u00edch cho b\\u1ea3n c\\u0169 n\\u1ebfu \\u0111\\u00e3 t\\u1ef1 \\u0111\\u1ed5i tr\\u01b0\\u1edbc \\u0111\\u00e2y.\\n *\\\/\\n\\n\\\/\\\/ =========================\\n\\\/\\\/ M\\u1eacT KH\\u1ea8U T\\u01af\\u01a0NG TH\\u00cdCH B\\u1ea2N C\\u0168 - KH\\u00d4NG C\\u1ea6N S\\u1eecA N\\u1ebeU D\\u00d9NG SETUP L\\u1ea6N \\u0110\\u1ea6U\\n\\\/\\\/ =========================\\n$SOURCE_SYNC_CONFIG_PASSWORD = 'doi-mat-khau-quan-tri-nay';\\n\\n\\\/\\\/ Gi\\u1edbi h\\u1ea1n dung l\\u01b0\\u1ee3ng ZIP upload qua trang n\\u00e0y. C\\u00f2n ph\\u1ee5 thu\\u1ed9c upload_max_filesize\\\/post_max_size c\\u1ee7a hosting.\\n$SOURCE_SYNC_CONFIG_MAX_UPLOAD_BYTES = 300 * 1024 * 1024; \\\/\\\/ 300MB\\n\\n\\\/\\\/ =========================\\n\\\/\\\/ KH\\u00d4NG C\\u1ea6N S\\u1eecA PH\\u1ea6N B\\u00caN D\\u01af\\u1edaI N\\u1ebeU KH\\u00d4NG C\\u1ea6N\\n\\\/\\\/ =========================\\n\\n@ini_set('display_errors', '0');\\n@ini_set('display_startup_errors', '0');\\n@ini_set('log_errors', '1');\\n@ini_set('html_errors', '0');\\n\\ndate_default_timezone_set('Asia\\\/Ho_Chi_Minh');\\n\\nheader('X-Robots-Tag: noindex, nofollow', true);\\nheader('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');\\nheader('X-Frame-Options: SAMEORIGIN');\\nheader('X-Content-Type-Options: nosniff');\\n\\nsession_name('source_sync_master_config_session');\\n@session_start();\\n\\n$MASTER_API_DIR = __DIR__;\\n$MASTER_ROOT_DIR = dirname(__DIR__);\\n$MASTER_PRIVATE_ROOT_DIR = dirname($MASTER_ROOT_DIR);\\n$MASTER_DATA_DIR = $MASTER_PRIVATE_ROOT_DIR . '\\\/source-sync-master-data';\\n$MASTER_CONFIG_FILE = $MASTER_DATA_DIR . '\\\/source-sync-master-config.json';\\n$MASTER_PACKAGE_DIR = $MASTER_ROOT_DIR . '\\\/update-packages';\\n$MASTER_PACKAGE_PUBLIC_DIR = '\\\/update-packages';\\n\\n\\nfunction ssm_client_ip() {\\n    return isset($_SERVER['REMOTE_ADDR']) ? trim((string)$_SERVER['REMOTE_ADDR']) : '';\\n}\\n\\nfunction ssm_rate_file() {\\n    global $MASTER_DATA_DIR;\\n    return $MASTER_DATA_DIR . '\\\/source-sync-login-rate.json';\\n}\\n\\nfunction ssm_rate_limit_guard($key, $maxAttempts = 10, $windowSeconds = 300) {\\n    ssm_ensure_dirs();\\n    $file = ssm_rate_file();\\n    $data = array();\\n    if (is_file($file)) {\\n        $raw = @file_get_contents($file);\\n        $json = json_decode((string)$raw, true);\\n        if (is_array($json)) $data = $json;\\n    }\\n    $now = time();\\n    foreach ($data as $k => $rows) {\\n        if (!is_array($rows)) { unset($data[$k]); continue; }\\n        $data[$k] = array_values(array_filter($rows, function($ts) use ($now, $windowSeconds) { return intval($ts) > ($now - $windowSeconds); }));\\n        if (!$data[$k]) unset($data[$k]);\\n    }\\n    if (!isset($data[$key]) || !is_array($data[$key])) $data[$key] = array();\\n    if (count($data[$key]) >= $maxAttempts) {\\n        @file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);\\n        return false;\\n    }\\n    $data[$key][] = $now;\\n    @file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);\\n    return true;\\n}\\n\\nfunction ssm_e($value) {\\n    return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');\\n}\\n\\nfunction ssm_now() {\\n    return date('Y-m-d H:i:s');\\n}\\n\\nfunction ssm_ensure_dirs() {\\n    global $MASTER_DATA_DIR, $MASTER_PACKAGE_DIR;\\n    if (!is_dir($MASTER_DATA_DIR)) @mkdir($MASTER_DATA_DIR, 0755, true);\\n    if (!is_dir($MASTER_PACKAGE_DIR)) @mkdir($MASTER_PACKAGE_DIR, 0755, true);\\n\\n    $htaccess = $MASTER_DATA_DIR . '\\\/.htaccess';\\n    $rules = \\\"Options -Indexes\\n<IfModule mod_authz_core.c>\\nRequire all denied\\n<\\\/IfModule>\\n<IfModule !mod_authz_core.c>\\nOrder deny,allow\\nDeny from all\\n<\\\/IfModule>\\n\\\";\\n    if (!is_file($htaccess) || trim((string)@file_get_contents($htaccess)) !== trim($rules)) {\\n        @file_put_contents($htaccess, $rules);\\n    }\\n    $indexPhp = $MASTER_DATA_DIR . '\\\/index.php';\\n    if (!is_file($indexPhp)) @file_put_contents($indexPhp, \\\"<?php\\nhttp_response_code(404);\\nheader('X-Robots-Tag: noindex, nofollow', true);\\necho '404 Not Found';\\nexit;\\n\\\");\\n    $index = $MASTER_DATA_DIR . '\\\/index.html';\\n    if (!is_file($index)) @file_put_contents($index, '');\\n\\n    $webConfig = $MASTER_DATA_DIR . '\\\/web.config';\\n    $webRules = <<<'XML'\\n<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n<configuration>\\n  <system.webServer>\\n    <security>\\n      <authorization>\\n        <clear \\\/>\\n        <add accessType=\\\"Deny\\\" users=\\\"*\\\" \\\/>\\n      <\\\/authorization>\\n    <\\\/security>\\n    <directoryBrowse enabled=\\\"false\\\" \\\/>\\n  <\\\/system.webServer>\\n<\\\/configuration>\\nXML;\\n    $webRules .= \\\"\\n\\\";\\n    if (!is_file($webConfig) || trim((string)@file_get_contents($webConfig)) !== trim($webRules)) @file_put_contents($webConfig, $webRules, LOCK_EX);\\n    @chmod($MASTER_DATA_DIR, 0700);\\n\\n    $pkgIndex = $MASTER_PACKAGE_DIR . '\\\/index.html';\\n    if (!is_file($pkgIndex)) @file_put_contents($pkgIndex, '');\\n}\\n\\nfunction ssm_default_config() {\\n    return array(\\n        'master_token' => '',\\n        'version' => 'V24',\\n        'zip_url' => '',\\n        'zip_sha256' => '',\\n        'zip_filename' => '',\\n        'zip_size' => 0,\\n        'released_at' => ssm_now(),\\n        'changelog' => '',\\n        'required' => false,\\n        'allowed_client_ips' => array(),\\n        'allowed_client_domains' => array(),\\n        'updated_at' => '',\\n        'config_password_hash' => '',\\n        'config_access_key' => '',\\n        'config_setup_done' => false,\\n    );\\n}\\n\\nfunction ssm_load_config() {\\n    global $MASTER_CONFIG_FILE;\\n    $defaults = ssm_default_config();\\n    if (!is_file($MASTER_CONFIG_FILE)) return $defaults;\\n    $raw = file_get_contents($MASTER_CONFIG_FILE);\\n    $json = json_decode($raw, true);\\n    if (!is_array($json)) return $defaults;\\n    return array_merge($defaults, $json);\\n}\\n\\nfunction ssm_save_config($config) {\\n    global $MASTER_CONFIG_FILE;\\n    ssm_ensure_dirs();\\n    $config['updated_at'] = ssm_now();\\n    $json = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);\\n    if ($json === false) return false;\\n    $ok = @file_put_contents($MASTER_CONFIG_FILE, $json, LOCK_EX) !== false;\\n    if ($ok) @chmod($MASTER_CONFIG_FILE, 0600);\\n    return $ok;\\n}\\n\\nfunction ssm_text_to_array($value) {\\n    if (is_array($value)) $value = implode(\\\"\\\\n\\\", $value);\\n    $value = trim((string)$value);\\n    if ($value === '') return array();\\n    return array_values(array_filter(array_map('trim', preg_split('\\\/[\\\\r\\\\n,]+\\\/', $value)), function($v) { return $v !== ''; }));\\n}\\n\\nfunction ssm_array_to_text($value) {\\n    if (!is_array($value)) return trim((string)$value);\\n    return implode(\\\"\\\\n\\\", array_values(array_filter(array_map('trim', array_map('strval', $value)), function($v) { return $v !== ''; })));\\n}\\n\\nfunction ssm_safe_zip_filename($name) {\\n    $name = basename((string)$name);\\n    $name = preg_replace('\\\/[^a-zA-Z0-9._-]+\\\/', '-', $name);\\n    $name = trim($name, '.-_');\\n    if ($name === '') $name = 'source-update.zip';\\n    if (strtolower(substr($name, -4)) !== '.zip') $name .= '.zip';\\n    return $name;\\n}\\n\\nfunction ssm_internal_zip_path_from_url($zipUrl) {\\n    global $MASTER_ROOT_DIR;\\n    $zipUrl = trim((string)$zipUrl);\\n    if ($zipUrl === '') return '';\\n    if (preg_match('#^https?:\\\/\\\/#i', $zipUrl)) {\\n        $parts = parse_url($zipUrl);\\n        if (!$parts || empty($parts['path'])) return '';\\n        $zipUrl = $parts['path'];\\n    }\\n    if ($zipUrl[0] !== '\\\/') $zipUrl = '\\\/' . $zipUrl;\\n    $path = realpath($MASTER_ROOT_DIR . $zipUrl);\\n    if ($path === false || !is_file($path)) return '';\\n    return $path;\\n}\\n\\nfunction ssm_flash($type, $message) {\\n    $_SESSION['ssm_flash'][] = array('type' => $type, 'message' => $message);\\n}\\n\\nfunction ssm_get_flash() {\\n    $flash = isset($_SESSION['ssm_flash']) && is_array($_SESSION['ssm_flash']) ? $_SESSION['ssm_flash'] : array();\\n    unset($_SESSION['ssm_flash']);\\n    return $flash;\\n}\\n\\nfunction ssm_logged_in() {\\n    return !empty($_SESSION['ssm_logged_in']);\\n}\\n\\nfunction ssm_generate_access_key($bytes = 12) {\\n    return strtolower(substr(bin2hex(random_bytes(max(8, intval($bytes)))), 0, 24));\\n}\\n\\nfunction ssm_normalize_access_key($key) {\\n    $key = trim((string)$key);\\n    $key = preg_replace('\\\/[^A-Za-z0-9_-]\\\/', '', $key);\\n    return substr($key, 0, 64);\\n}\\n\\nfunction ssm_setup_required($config = null) {\\n    if (!is_array($config)) $config = ssm_load_config();\\n    $done = !empty($config['config_setup_done']);\\n    $key = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\n    $hash = isset($config['config_password_hash']) ? (string)$config['config_password_hash'] : '';\\n    return !$done || $key === '' || $hash === '';\\n}\\n\\nfunction ssm_access_gate_passed($config = null) {\\n    if (!is_array($config)) $config = ssm_load_config();\\n    if (ssm_setup_required($config)) return true;\\n    if (ssm_logged_in()) return true;\\n    if (!empty($_SESSION['ssm_access_granted'])) return true;\\n    $key = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\n    $given = isset($_GET['k']) ? ssm_normalize_access_key($_GET['k']) : '';\\n    if ($key !== '' && $given !== '' && hash_equals($key, $given)) {\\n        $_SESSION['ssm_access_granted'] = true;\\n        return true;\\n    }\\n    return false;\\n}\\n\\nfunction ssm_fake_404() {\\n    http_response_code(404);\\n    header('Content-Type: text\\\/plain; charset=utf-8');\\n    echo '404 Not Found';\\n    exit;\\n}\\n\\nfunction ssm_check_config_password($password, $config) {\\n    $hash = isset($config['config_password_hash']) ? (string)$config['config_password_hash'] : '';\\n    if ($hash !== '') return password_verify((string)$password, $hash);\\n    global $SOURCE_SYNC_CONFIG_PASSWORD;\\n    if ($SOURCE_SYNC_CONFIG_PASSWORD !== '' && $SOURCE_SYNC_CONFIG_PASSWORD !== 'doi-mat-khau-quan-tri-nay') {\\n        return hash_equals((string)$SOURCE_SYNC_CONFIG_PASSWORD, (string)$password);\\n    }\\n    return false;\\n}\\n\\nfunction ssm_increment_version($version) {\\n    $version = trim((string)$version);\\n    if ($version === '') return 'V1.0';\\n    if (preg_match('\\\/^(.*?)(\\\\d+)\\\\.(\\\\d+)$\\\/', $version, $m)) {\\n        return $m[1] . $m[2] . '.' . (intval($m[3]) + 1);\\n    }\\n    if (preg_match('\\\/^(.*?)(\\\\d+)$\\\/', $version, $m)) {\\n        return $m[1] . (intval($m[2]) + 1);\\n    }\\n    return $version . '.1';\\n}\\n\\nfunction ssm_require_csrf() {\\n    $posted = isset($_POST['csrf']) ? (string)$_POST['csrf'] : '';\\n    $stored = isset($_SESSION['ssm_csrf']) ? (string)$_SESSION['ssm_csrf'] : '';\\n    if ($stored === '' || $posted === '' || !hash_equals($stored, $posted)) {\\n        ssm_flash('error', 'CSRF token kh\\u00f4ng h\\u1ee3p l\\u1ec7, h\\u00e3y th\\u1eed l\\u1ea1i.');\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n}\\n\\nfunction ssm_csrf_token() {\\n    if (empty($_SESSION['ssm_csrf'])) {\\n        $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\n    }\\n    return $_SESSION['ssm_csrf'];\\n}\\n\\nssm_ensure_dirs();\\n$config = ssm_load_config();\\n$setupRequired = ssm_setup_required($config);\\nif (!$setupRequired && !ssm_access_gate_passed($config)) {\\n    ssm_fake_404();\\n}\\n\\nif ($_SERVER['REQUEST_METHOD'] === 'POST') {\\n    $action = isset($_POST['action']) ? (string)$_POST['action'] : '';\\n\\n    if ($setupRequired && $action === 'setup_config') {\\n        ssm_require_csrf();\\n        $password = isset($_POST['password']) ? (string)$_POST['password'] : '';\\n        $password2 = isset($_POST['password_confirm']) ? (string)$_POST['password_confirm'] : '';\\n        $accessKey = isset($_POST['config_access_key']) ? ssm_normalize_access_key($_POST['config_access_key']) : '';\\n        if ($password !== $password2) {\\n            ssm_flash('error', 'M\\u1eadt kh\\u1ea9u nh\\u1eadp l\\u1ea1i kh\\u00f4ng kh\\u1edbp.');\\n        } elseif (strlen($password) < 8) {\\n            ssm_flash('error', 'M\\u1eadt kh\\u1ea9u c\\u1ea5u h\\u00ecnh ph\\u1ea3i c\\u00f3 \\u00edt nh\\u1ea5t 8 k\\u00fd t\\u1ef1.');\\n        } elseif ($accessKey === '' || strlen($accessKey) < 8) {\\n            ssm_flash('error', 'Token truy c\\u1eadp ph\\u1ea3i c\\u00f3 \\u00edt nh\\u1ea5t 8 k\\u00fd t\\u1ef1.');\\n        } else {\\n            $config['config_password_hash'] = password_hash($password, PASSWORD_DEFAULT);\\n            $config['config_access_key'] = $accessKey;\\n            $config['config_setup_done'] = true;\\n            if (ssm_save_config($config)) {\\n                $_SESSION['ssm_access_granted'] = true;\\n                $_SESSION['ssm_logged_in'] = true;\\n                $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\n                ssm_flash('success', '\\u0110\\u00e3 thi\\u1ebft l\\u1eadp m\\u1eadt kh\\u1ea9u v\\u00e0 token truy c\\u1eadp Source Sync Master.');\\n            } else {\\n                ssm_flash('error', 'Kh\\u00f4ng th\\u1ec3 l\\u01b0u c\\u1ea5u h\\u00ecnh b\\u1ea3o v\\u1ec7 Source Sync Master.');\\n            }\\n        }\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if ($action === 'login') {\\n        ssm_require_csrf();\\n        $password = isset($_POST['password']) ? (string)$_POST['password'] : '';\\n        $rateKey = 'login:' . sha1(ssm_client_ip());\\n        if (!ssm_rate_limit_guard($rateKey, 10, 300)) {\\n            ssm_flash('error', 'B\\u1ea1n \\u0111\\u0103ng nh\\u1eadp sai\\\/thao t\\u00e1c qu\\u00e1 nhi\\u1ec1u l\\u1ea7n. Vui l\\u00f2ng th\\u1eed l\\u1ea1i sau.');\\n            header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n            exit;\\n        }\\n        if (ssm_check_config_password($password, $config)) {\\n            $_SESSION['ssm_logged_in'] = true;\\n            $_SESSION['ssm_access_granted'] = true;\\n            $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\n            ssm_flash('success', '\\u0110\\u0103ng nh\\u1eadp th\\u00e0nh c\\u00f4ng.');\\n        } else {\\n            ssm_flash('error', 'M\\u1eadt kh\\u1ea9u kh\\u00f4ng \\u0111\\u00fang.');\\n        }\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if ($action === 'logout') {\\n        unset($_SESSION['ssm_logged_in']);\\n        unset($_SESSION['ssm_access_granted']);\\n        unset($_SESSION['ssm_csrf']);\\n        ssm_flash('success', '\\u0110\\u00e3 \\u0111\\u0103ng xu\\u1ea5t.');\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if (!ssm_logged_in()) {\\n        ssm_flash('error', 'B\\u1ea1n c\\u1ea7n \\u0111\\u0103ng nh\\u1eadp.');\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    ssm_require_csrf();\\n    $config = ssm_load_config();\\n\\n    if ($action === 'save_config') {\\n        $config['master_token'] = trim((string)($_POST['master_token'] ?? ''));\\n        $config['version'] = trim((string)($_POST['version'] ?? ''));\\n        $config['zip_url'] = trim((string)($_POST['zip_url'] ?? ''));\\n        $config['zip_sha256'] = strtolower(trim((string)($_POST['zip_sha256'] ?? '')));\\n        $config['released_at'] = trim((string)($_POST['released_at'] ?? ''));\\n        $config['changelog'] = (string)($_POST['changelog'] ?? '');\\n        $config['required'] = !empty($_POST['required']);\\n        $config['allowed_client_ips'] = ssm_text_to_array($_POST['allowed_client_ips'] ?? '');\\n        $config['allowed_client_domains'] = ssm_text_to_array($_POST['allowed_client_domains'] ?? '');\\n\\n        if ($config['master_token'] === '') {\\n            ssm_flash('error', 'Token m\\u00e1y ch\\u1ee7 ch\\u00ednh kh\\u00f4ng \\u0111\\u01b0\\u1ee3c \\u0111\\u1ec3 tr\\u1ed1ng.');\\n        } elseif ($config['version'] === '') {\\n            ssm_flash('error', 'Phi\\u00ean b\\u1ea3n kh\\u00f4ng \\u0111\\u01b0\\u1ee3c \\u0111\\u1ec3 tr\\u1ed1ng.');\\n        } elseif ($config['zip_sha256'] !== '' && !preg_match('\\\/^[a-f0-9]{64}$\\\/i', $config['zip_sha256'])) {\\n            ssm_flash('error', 'SHA256 ph\\u1ea3i g\\u1ed3m \\u0111\\u00fang 64 k\\u00fd t\\u1ef1 hex.');\\n        } elseif (ssm_save_config($config)) {\\n            ssm_flash('success', '\\u0110\\u00e3 l\\u01b0u c\\u1ea5u h\\u00ecnh manifest v\\u00e0o JSON.');\\n        } else {\\n            ssm_flash('error', 'Kh\\u00f4ng th\\u1ec3 l\\u01b0u file JSON. H\\u00e3y ki\\u1ec3m tra quy\\u1ec1n ghi th\\u01b0 m\\u1ee5c source-sync-master-data ngang c\\u1ea5p public.');\\n        }\\n\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if ($action === 'upload_zip') {\\n        if (empty($_FILES['update_zip']) || !is_uploaded_file($_FILES['update_zip']['tmp_name'])) {\\n            ssm_flash('error', 'B\\u1ea1n ch\\u01b0a ch\\u1ecdn file ZIP.');\\n        } elseif ((int)$_FILES['update_zip']['error'] !== UPLOAD_ERR_OK) {\\n            ssm_flash('error', 'Upload ZIP th\\u1ea5t b\\u1ea1i. M\\u00e3 l\\u1ed7i: ' . (int)$_FILES['update_zip']['error']);\\n        } elseif ((int)$_FILES['update_zip']['size'] <= 0 || (int)$_FILES['update_zip']['size'] > (int)$SOURCE_SYNC_CONFIG_MAX_UPLOAD_BYTES) {\\n            ssm_flash('error', 'File ZIP v\\u01b0\\u1ee3t qu\\u00e1 dung l\\u01b0\\u1ee3ng cho ph\\u00e9p.');\\n        } else {\\n            $original = isset($_FILES['update_zip']['name']) ? (string)$_FILES['update_zip']['name'] : 'source-update.zip';\\n            $filename = ssm_safe_zip_filename($original);\\n            $target = $MASTER_PACKAGE_DIR . '\\\/' . $filename;\\n\\n            if (!preg_match('\\\/\\\\.zip$\\\/i', $filename)) {\\n                ssm_flash('error', 'Ch\\u1ec9 cho ph\\u00e9p upload file .zip.');\\n            } elseif (@move_uploaded_file($_FILES['update_zip']['tmp_name'], $target)) {\\n                @chmod($target, 0644);\\n                $hash = hash_file('sha256', $target);\\n                $config['zip_filename'] = $filename;\\n                $config['zip_size'] = filesize($target);\\n                $config['zip_url'] = rtrim($MASTER_PACKAGE_PUBLIC_DIR, '\\\/') . '\\\/' . $filename;\\n                $config['zip_sha256'] = strtolower($hash);\\n                $config['version'] = ssm_increment_version(isset($config['version']) ? $config['version'] : '');\\n                $config['released_at'] = ssm_now();\\n                if (ssm_save_config($config)) {\\n                    ssm_flash('success', 'Upload ZIP th\\u00e0nh c\\u00f4ng. H\\u1ec7 th\\u1ed1ng \\u0111\\u00e3 t\\u1ef1 l\\u1ea5y SHA256, t\\u1ef1 t\\u0103ng phi\\u00ean b\\u1ea3n l\\u00ean ' . $config['version'] . ' v\\u00e0 l\\u01b0u v\\u00e0o JSON.');\\n                } else {\\n                    ssm_flash('error', 'Upload ZIP th\\u00e0nh c\\u00f4ng nh\\u01b0ng kh\\u00f4ng th\\u1ec3 l\\u01b0u c\\u1ea5u h\\u00ecnh JSON.');\\n                }\\n            } else {\\n                ssm_flash('error', 'Kh\\u00f4ng th\\u1ec3 l\\u01b0u file ZIP v\\u00e0o th\\u01b0 m\\u1ee5c update-packages. H\\u00e3y ki\\u1ec3m tra quy\\u1ec1n ghi.');\\n            }\\n        }\\n\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if ($action === 'recalc_sha256') {\\n        $file = ssm_internal_zip_path_from_url(isset($config['zip_url']) ? $config['zip_url'] : '');\\n        if ($file === '') {\\n            ssm_flash('error', 'Kh\\u00f4ng t\\u00ecm th\\u1ea5y file ZIP n\\u1ed9i b\\u1ed9 \\u0111\\u1ec3 l\\u1ea5y l\\u1ea1i SHA256. H\\u00e3y upload ZIP qua form ho\\u1eb7c ki\\u1ec3m tra ZIP URL.');\\n        } else {\\n            $config['zip_sha256'] = strtolower(hash_file('sha256', $file));\\n            $config['zip_size'] = filesize($file);\\n            $config['zip_filename'] = basename($file);\\n            if (ssm_save_config($config)) {\\n                ssm_flash('success', '\\u0110\\u00e3 l\\u1ea5y l\\u1ea1i SHA256 t\\u1eeb file ZIP hi\\u1ec7n t\\u1ea1i.');\\n            } else {\\n                ssm_flash('error', 'Kh\\u00f4ng th\\u1ec3 l\\u01b0u SHA256 m\\u1edbi v\\u00e0o JSON.');\\n            }\\n        }\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n}\\n\\n$config = ssm_load_config();\\n$flash = ssm_get_flash();\\n$setupRequired = ssm_setup_required($config);\\n$sourceAccessKey = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\n$suggestedSourceAccessKey = ssm_generate_access_key();\\n$csrf = ssm_csrf_token();\\n$manifestUrl = '';\\nif (!empty($_SERVER['HTTP_HOST'])) {\\n    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';\\n    $manifestUrl = $scheme . ':\\\/\\\/' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']) . '\\\/update-manifest.php';\\n}\\n$configLoginUrl = '';\\nif (!empty($_SERVER['HTTP_HOST'])) {\\n    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';\\n    $configLoginUrl = $scheme . ':\\\/\\\/' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . ($sourceAccessKey !== '' ? '?k=' . rawurlencode($sourceAccessKey) : '');\\n}\\n?>\\n<!doctype html>\\n<html lang=\\\"vi\\\">\\n<head>\\n<meta charset=\\\"utf-8\\\">\\n<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1\\\">\\n<meta name=\\\"robots\\\" content=\\\"noindex,nofollow\\\">\\n<title>C\\u1ea5u h\\u00ecnh Source Sync Master<\\\/title>\\n<style>\\n    :root { color-scheme: light; --bg:#f4f6fb; --card:#ffffff; --text:#172033; --muted:#667085; --border:#d9e0ea; --primary:#1d4ed8; --danger:#dc2626; --success:#15803d; }\\n    * { box-sizing: border-box; }\\n    body { margin:0; font-family: Arial, Helvetica, sans-serif; background: var(--bg); color: var(--text); }\\n    .wrap { max-width: 980px; margin: 0 auto; padding: 18px; }\\n    .top { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:14px; }\\n    h1 { font-size: 22px; margin:0; }\\n    .card { background:var(--card); border:1px solid var(--border); border-radius:14px; padding:16px; box-shadow:0 8px 24px rgba(15,23,42,.06); margin-bottom:14px; }\\n    .grid { display:grid; grid-template-columns: 1fr 1fr; gap:14px; }\\n    label { display:block; font-weight:700; margin-bottom:6px; font-size:14px; }\\n    input[type=text], input[type=password], textarea, select { width:100%; border:1px solid var(--border); border-radius:10px; padding:10px 12px; font-size:14px; background:#fff; color:var(--text); }\\n    textarea { min-height:96px; resize:vertical; }\\n    .hint { color:var(--muted); font-size:13px; margin-top:5px; line-height:1.45; }\\n    .row { margin-bottom:14px; }\\n    .btn { border:0; border-radius:10px; padding:10px 14px; font-weight:700; cursor:pointer; background:var(--primary); color:white; display:inline-flex; align-items:center; gap:8px; text-decoration:none; font-size:14px; }\\n    .btn.secondary { background:#475569; }\\n    .btn.danger { background:var(--danger); }\\n    .btn.light { background:#e8eef8; color:#1e293b; }\\n    .actions { display:flex; gap:10px; flex-wrap:wrap; align-items:center; }\\n    .flash { border-radius:10px; padding:11px 12px; margin-bottom:10px; border:1px solid var(--border); }\\n    .flash.success { background:#ecfdf3; color:#166534; border-color:#bbf7d0; }\\n    .flash.error { background:#fef2f2; color:#991b1b; border-color:#fecaca; }\\n    .stat { display:grid; grid-template-columns: 210px 1fr; gap:10px; border-bottom:1px solid #eef2f7; padding:8px 0; font-size:14px; }\\n    .stat b { color:#334155; }\\n    code { background:#eef2ff; color:#1e3a8a; padding:2px 5px; border-radius:5px; word-break:break-all; }\\n    .danger-note { color:#991b1b; background:#fff1f2; border:1px solid #fecdd3; padding:10px 12px; border-radius:10px; font-size:14px; line-height:1.45; }\\n    @media (max-width: 720px) {\\n        .wrap { padding:12px; }\\n        .grid { grid-template-columns: 1fr; }\\n        .top { align-items:flex-start; flex-direction:column; }\\n        .stat { grid-template-columns: 1fr; gap:4px; }\\n        .btn { width:100%; justify-content:center; }\\n    }\\n<\\\/style>\\n<\\\/head>\\n<body>\\n<div class=\\\"wrap\\\">\\n    <div class=\\\"top\\\">\\n        <div>\\n            <h1>\\u2699\\ufe0f C\\u1ea5u h\\u00ecnh Source Sync Master<\\\/h1>\\n            <div class=\\\"hint\\\">Trang n\\u00e0y d\\u00f9ng \\u0111\\u1ec3 c\\u1ea5u h\\u00ecnh <code>update-manifest.php<\\\/code>, upload ZIP update v\\u00e0 t\\u1ef1 l\\u1ea5y SHA256.<\\\/div>\\n        <\\\/div>\\n        <?php if (ssm_logged_in()): ?>\\n            <form method=\\\"post\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"logout\\\">\\n                <button class=\\\"btn light\\\" type=\\\"submit\\\">\\u0110\\u0103ng xu\\u1ea5t<\\\/button>\\n            <\\\/form>\\n        <?php endif; ?>\\n    <\\\/div>\\n\\n    <?php foreach ($flash as $item): ?>\\n        <div class=\\\"flash <?php echo ssm_e($item['type']); ?>\\\"><?php echo ssm_e($item['message']); ?><\\\/div>\\n    <?php endforeach; ?>\\n\\n    <?php if ($setupRequired): ?>\\n        <div class=\\\"card\\\">\\n            <h2>Thi\\u1ebft l\\u1eadp Source Sync Master l\\u1ea7n \\u0111\\u1ea7u<\\\/h2>\\n            <p class=\\\"hint\\\">L\\u1ea7n \\u0111\\u1ea7u c\\u00f3 th\\u1ec3 truy c\\u1eadp tr\\u1ef1c ti\\u1ebfp trang n\\u00e0y \\u0111\\u1ec3 t\\u1ea1o m\\u1eadt kh\\u1ea9u v\\u00e0 token b\\u1ea3o v\\u1ec7 \\u0111\\u01b0\\u1eddng d\\u1eabn. Nh\\u1eefng l\\u1ea7n sau ph\\u1ea3i truy c\\u1eadp \\u0111\\u00fang link c\\u00f3 token.<\\\/p>\\n            <form method=\\\"post\\\" style=\\\"margin-top:14px;\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"setup_config\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n                <div class=\\\"row\\\"><label>M\\u1eadt kh\\u1ea9u c\\u1ea5u h\\u00ecnh m\\u1edbi<\\\/label><input type=\\\"password\\\" name=\\\"password\\\" autocomplete=\\\"new-password\\\" minlength=\\\"8\\\" required><\\\/div>\\n                <div class=\\\"row\\\"><label>Nh\\u1eadp l\\u1ea1i m\\u1eadt kh\\u1ea9u<\\\/label><input type=\\\"password\\\" name=\\\"password_confirm\\\" autocomplete=\\\"new-password\\\" minlength=\\\"8\\\" required><\\\/div>\\n                <div class=\\\"row\\\"><label>Token truy c\\u1eadp trang c\\u1ea5u h\\u00ecnh<\\\/label><input type=\\\"text\\\" name=\\\"config_access_key\\\" value=\\\"<?php echo ssm_e($suggestedSourceAccessKey); ?>\\\" required><div class=\\\"hint\\\">Sau khi l\\u01b0u, link truy c\\u1eadp s\\u1ebd c\\u00f3 d\\u1ea1ng: <code><?php echo ssm_e((!empty($_SERVER['HTTP_HOST']) ? (((!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http') . ':\\\/\\\/' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME']) : 'source-sync-config.php')); ?>?k=TOKEN<\\\/code><\\\/div><\\\/div>\\n                <button class=\\\"btn\\\" type=\\\"submit\\\">T\\u1ea1o m\\u1eadt kh\\u1ea9u v\\u00e0 token<\\\/button>\\n            <\\\/form>\\n        <\\\/div>\\n    <?php elseif (!ssm_logged_in()): ?>\\n        <div class=\\\"card\\\">\\n            <h2>\\u0110\\u0103ng nh\\u1eadp<\\\/h2>\\n            <form method=\\\"post\\\" style=\\\"margin-top:14px;\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"login\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n                <div class=\\\"row\\\"><label>M\\u1eadt kh\\u1ea9u c\\u1ea5u h\\u00ecnh<\\\/label><input type=\\\"password\\\" name=\\\"password\\\" autocomplete=\\\"current-password\\\" required><\\\/div>\\n                <button class=\\\"btn\\\" type=\\\"submit\\\">\\u0110\\u0103ng nh\\u1eadp<\\\/button>\\n            <\\\/form>\\n            <?php if ($configLoginUrl !== ''): ?><p class=\\\"hint\\\">Link truy c\\u1eadp h\\u1ee3p l\\u1ec7: <code><?php echo ssm_e($configLoginUrl); ?><\\\/code><\\\/p><?php endif; ?>\\n        <\\\/div>\\n    <?php else: ?>\\n        <div class=\\\"card\\\">\\n            <h2>Th\\u00f4ng tin hi\\u1ec7n t\\u1ea1i<\\\/h2>\\n            <div class=\\\"stat\\\"><b>Manifest URL<\\\/b><div><code><?php echo ssm_e($manifestUrl); ?><\\\/code><\\\/div><\\\/div>\\n            <?php if ($configLoginUrl !== ''): ?><div class=\\\"stat\\\"><b>Link c\\u1ea5u h\\u00ecnh<\\\/b><div><code><?php echo ssm_e($configLoginUrl); ?><\\\/code><\\\/div><\\\/div><?php endif; ?>\\n            <div class=\\\"stat\\\"><b>Version<\\\/b><div><?php echo ssm_e($config['version']); ?><\\\/div><\\\/div>\\n            <div class=\\\"stat\\\"><b>ZIP URL<\\\/b><div><code><?php echo ssm_e($config['zip_url']); ?><\\\/code><\\\/div><\\\/div>\\n            <div class=\\\"stat\\\"><b>SHA256<\\\/b><div><code><?php echo ssm_e($config['zip_sha256']); ?><\\\/code><\\\/div><\\\/div>\\n            <div class=\\\"stat\\\"><b>File ZIP<\\\/b><div><?php echo ssm_e($config['zip_filename']); ?> <?php echo !empty($config['zip_size']) ? '(' . number_format((float)$config['zip_size']) . ' bytes)' : ''; ?><\\\/div><\\\/div>\\n            <div class=\\\"stat\\\"><b>C\\u1eadp nh\\u1eadt JSON<\\\/b><div><?php echo ssm_e($config['updated_at']); ?><\\\/div><\\\/div>\\n        <\\\/div>\\n\\n        <div class=\\\"card\\\">\\n            <h2>Upload ZIP phi\\u00ean b\\u1ea3n m\\u1edbi<\\\/h2>\\n            <form method=\\\"post\\\" enctype=\\\"multipart\\\/form-data\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"upload_zip\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n                <div class=\\\"row\\\">\\n                    <label>Ch\\u1ecdn file .zip<\\\/label>\\n                    <input type=\\\"file\\\" name=\\\"update_zip\\\" accept=\\\".zip,application\\\/zip,application\\\/x-zip-compressed\\\" required>\\n                    <div class=\\\"hint\\\">File s\\u1ebd t\\u1ef1 l\\u01b0u v\\u00e0o <code>\\\/update-packages\\\/<\\\/code>, t\\u1ef1 t\\u1ea1o <code>zip_url<\\\/code> v\\u00e0 t\\u1ef1 t\\u00ednh SHA256.<\\\/div>\\n                <\\\/div>\\n                <div class=\\\"actions\\\">\\n                    <button class=\\\"btn\\\" type=\\\"submit\\\">\\u2b06\\ufe0f Upload ZIP v\\u00e0 t\\u1ef1 l\\u1ea5y SHA256<\\\/button>\\n                <\\\/div>\\n            <\\\/form>\\n        <\\\/div>\\n\\n        <div class=\\\"card\\\">\\n            <h2>C\\u1ea5u h\\u00ecnh manifest<\\\/h2>\\n            <form method=\\\"post\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"save_config\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n\\n                <div class=\\\"grid\\\">\\n                    <div class=\\\"row\\\">\\n                        <label>Token m\\u00e1y ch\\u1ee7 ch\\u00ednh<\\\/label>\\n                        <input type=\\\"text\\\" name=\\\"master_token\\\" value=\\\"<?php echo ssm_e($config['master_token']); ?>\\\" placeholder=\\\"Ph\\u1ea3i gi\\u1ed1ng SOURCE_SYNC_API_TOKEN tr\\u00ean m\\u00e1y ch\\u1ee7 con\\\" required>\\n                    <\\\/div>\\n                    <div class=\\\"row\\\">\\n                        <label>Phi\\u00ean b\\u1ea3n m\\u1edbi nh\\u1ea5t<\\\/label>\\n                        <input type=\\\"text\\\" name=\\\"version\\\" value=\\\"<?php echo ssm_e($config['version']); ?>\\\" placeholder=\\\"VD: V24\\\" required>\\n                    <\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"row\\\">\\n                    <label>ZIP URL<\\\/label>\\n                    <input type=\\\"text\\\" name=\\\"zip_url\\\" value=\\\"<?php echo ssm_e($config['zip_url']); ?>\\\" placeholder=\\\"\\\/update-packages\\\/web-shop-V24.zip\\\">\\n                    <div class=\\\"hint\\\">C\\u00f3 th\\u1ec3 d\\u00f9ng \\u0111\\u01b0\\u1eddng d\\u1eabn n\\u1ed9i b\\u1ed9 nh\\u01b0 <code>\\\/update-packages\\\/web-shop-V24.zip<\\\/code> ho\\u1eb7c URL \\u0111\\u1ea7y \\u0111\\u1ee7.<\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"row\\\">\\n                    <label>SHA256<\\\/label>\\n                    <input type=\\\"text\\\" name=\\\"zip_sha256\\\" value=\\\"<?php echo ssm_e($config['zip_sha256']); ?>\\\" placeholder=\\\"T\\u1ef1 t\\u1ea1o sau khi upload ZIP\\\">\\n                    <div class=\\\"hint\\\">N\\u1ebfu upload ZIP b\\u1eb1ng form ph\\u00eda tr\\u00ean, SHA256 s\\u1ebd t\\u1ef1 \\u0111i\\u1ec1n v\\u00e0 l\\u01b0u v\\u00e0o JSON.<\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"grid\\\">\\n                    <div class=\\\"row\\\">\\n                        <label>Th\\u1eddi gian ph\\u00e1t h\\u00e0nh<\\\/label>\\n                        <input type=\\\"text\\\" name=\\\"released_at\\\" value=\\\"<?php echo ssm_e($config['released_at']); ?>\\\" placeholder=\\\"2026-06-28 00:00:00\\\">\\n                    <\\\/div>\\n                    <div class=\\\"row\\\">\\n                        <label>B\\u1eaft bu\\u1ed9c c\\u1eadp nh\\u1eadt?<\\\/label>\\n                        <select name=\\\"required\\\">\\n                            <option value=\\\"0\\\" <?php echo empty($config['required']) ? 'selected' : ''; ?>>Kh\\u00f4ng<\\\/option>\\n                            <option value=\\\"1\\\" <?php echo !empty($config['required']) ? 'selected' : ''; ?>>C\\u00f3<\\\/option>\\n                        <\\\/select>\\n                    <\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"row\\\">\\n                    <label>Ghi ch\\u00fa c\\u1eadp nh\\u1eadt<\\\/label>\\n                    <textarea name=\\\"changelog\\\" placeholder=\\\"- N\\u1ed9i dung c\\u1eadp nh\\u1eadt 1&#10;- N\\u1ed9i dung c\\u1eadp nh\\u1eadt 2\\\"><?php echo ssm_e($config['changelog']); ?><\\\/textarea>\\n                <\\\/div>\\n\\n                <div class=\\\"grid\\\">\\n                    <div class=\\\"row\\\">\\n                        <label>IP m\\u00e1y ch\\u1ee7 con \\u0111\\u01b0\\u1ee3c ph\\u00e9p<\\\/label>\\n                        <textarea name=\\\"allowed_client_ips\\\" placeholder=\\\"M\\u1ed7i d\\u00f2ng 1 IP public ho\\u1eb7c local\\\/server IP&#10;VD public: 103.345.23.25&#10;VD server local: 14.225.218.36&#10;VD private: 192.168.1.10\\\"><?php echo ssm_e(ssm_array_to_text($config['allowed_client_ips'])); ?><\\\/textarea>\\n                        <div class=\\\"hint\\\">\\u0110\\u1ec3 tr\\u1ed1ng n\\u1ebfu kh\\u00f4ng mu\\u1ed1n ki\\u1ec3m tra IP. C\\u00f3 th\\u1ec3 nh\\u1eadp IP public\\\/NAT ho\\u1eb7c IP server local\\\/private c\\u1ee7a m\\u00e1y ch\\u1ee7 con.<\\\/div>\\n                    <\\\/div>\\n                    <div class=\\\"row\\\">\\n                        <label>Domain m\\u00e1y ch\\u1ee7 con \\u0111\\u01b0\\u1ee3c ph\\u00e9p<\\\/label>\\n                        <textarea name=\\\"allowed_client_domains\\\" placeholder=\\\"M\\u1ed7i d\\u00f2ng 1 domain&#10;VD: shop-con.example.com\\\"><?php echo ssm_e(ssm_array_to_text($config['allowed_client_domains'])); ?><\\\/textarea>\\n                        <div class=\\\"hint\\\">\\u0110\\u1ec3 tr\\u1ed1ng n\\u1ebfu kh\\u00f4ng mu\\u1ed1n ki\\u1ec3m tra domain. N\\u1ebfu \\u0111i\\u1ec1n c\\u1ea3 IP v\\u00e0 domain th\\u00ec request ph\\u1ea3i kh\\u1edbp c\\u1ea3 hai. V\\u1edbi IP, h\\u1ec7 th\\u1ed1ng ch\\u1ea5p nh\\u1eadn IP public ho\\u1eb7c IP local\\\/server IP do m\\u00e1y ch\\u1ee7 con g\\u1eedi k\\u00e8m token\\\/header\\\/query.<\\\/div>\\n                    <\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"actions\\\">\\n                    <button class=\\\"btn\\\" type=\\\"submit\\\">\\ud83d\\udcbe L\\u01b0u c\\u1ea5u h\\u00ecnh v\\u00e0o JSON<\\\/button>\\n                <\\\/div>\\n            <\\\/form>\\n\\n            <form method=\\\"post\\\" style=\\\"margin-top:10px;\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"recalc_sha256\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n                <button class=\\\"btn secondary\\\" type=\\\"submit\\\">\\ud83d\\udd01 L\\u1ea5y l\\u1ea1i SHA256 t\\u1eeb ZIP hi\\u1ec7n t\\u1ea1i<\\\/button>\\n            <\\\/form>\\n        <\\\/div>\\n    <?php endif; ?>\\n<\\\/div>\\n<\\\/body>\\n<\\\/html>\\n\",\n        \"time\": \"2026-07-01 13:27:56\"\n    }\n]",
        "time": "2026-07-03 13:12:52"
    },
    {
        "file": "\/home\/coicom\/1.1ccmm.my\/README_PRIVATE_STORAGE.txt",
        "content": "C\u00e1c th\u01b0 m\u1ee5c data, backup, codes, kho-tdata, uploads v\u00e0 source-sync-master-data \u0111\u00e3 \u0111\u01b0\u1ee3c \u0111\u01b0a ra ngang c\u1ea5p public.\n\nKhuy\u1ebfn ngh\u1ecb tri\u1ec3n khai an to\u00e0n nh\u1ea5t: c\u1ea5u h\u00ecnh DocumentRoot\/web root tr\u1ecf tr\u1ef1c ti\u1ebfp v\u00e0o th\u01b0 m\u1ee5c public. Khi \u0111\u00f3 c\u00e1c th\u01b0 m\u1ee5c ngang c\u1ea5p public kh\u00f4ng th\u1ec3 truy c\u1eadp b\u1eb1ng URL.\n\nB\u1ed9 code v\u1eabn k\u00e8m .htaccess, web.config v\u00e0 index.php ch\u1eb7n truy c\u1eadp trong c\u00e1c th\u01b0 m\u1ee5c private. Tuy nhi\u00ean, n\u1ebfu hosting \u0111\u1eb7t web root \u1edf th\u01b0 m\u1ee5c cha v\u00e0 web server kh\u00f4ng \u0111\u1ecdc .htaccess\/web.config, file t\u0129nh nh\u01b0 JSON\/ZIP c\u00f3 th\u1ec3 v\u1eabn b\u1ecb web server ph\u1ee5c v\u1ee5 tr\u1ef1c ti\u1ebfp tr\u01b0\u1edbc khi PHP ch\u1ea1y. Admin Dashboard c\u00f3 c\u1ea3nh b\u00e1o v\u00e0 probe URL \u0111\u1ec3 ph\u00e1t hi\u1ec7n t\u00ecnh hu\u1ed1ng n\u00e0y. V\u1edbi Nginx, h\u00e3y tr\u1ecf root v\u1ec1 public ho\u1eb7c c\u1ea5u h\u00ecnh deny tr\u1ef1c ti\u1ebfp cho \/data, \/backup, \/codes, \/kho-tdata, \/uploads, \/source-sync-master-data.\n\nC\u1eadp nh\u1eadt JSON sharding:\n- C\u00e1c file JSON l\u1edbn nh\u01b0 users.json, orders.json, transactions.json, deposits.json, tickets.json, telegram-users.json, telegram-broadcasts.json, security-logs.json v\u00e0 webhook-events.json hi\u1ec7n ch\u1ec9 c\u00f2n l\u00e0 manifest nh\u1ecf.\n- D\u1eef li\u1ec7u th\u1eadt \u0111\u01b0\u1ee3c chia nh\u1ecf trong data\/<collection>\/shards\/ v\u00e0 c\u00f3 _meta.json \/ _index.json \u0111\u1ec3 theo d\u00f5i shard, s\u1ed1 l\u01b0\u1ee3ng b\u1ea3n ghi v\u00e0 index tra c\u1ee9u.\n- Khi h\u1ec7 th\u1ed1ng g\u1eb7p file JSON c\u0169, n\u00f3 s\u1ebd t\u1ef1 backup v\u00e0o backup\/migrations\/ r\u1ed3i migrate sang d\u1ea1ng sharded. Logic PHP c\u0169 v\u1eabn d\u00f9ng read_json_file()\/write_json_file(), n\u00ean d\u1eef li\u1ec7u tr\u1ea3 v\u1ec1 v\u1eabn gi\u1eef c\u1ea5u tr\u00fac c\u0169.\n- User ID v\u1eabn gi\u1eef chu\u1ea9n 3 ch\u1eef s\u1ed1 100-999; vi\u1ec7c t\u1ea1o t\u00e0i kho\u1ea3n m\u1edbi v\u1eabn ch\u1ea1y trong app.lock n\u00ean tr\u00e1nh tr\u00f9ng ID khi c\u00f3 nhi\u1ec1u request \u0111\u1ed3ng th\u1eddi.\n",
        "time": "2026-07-02 17:34:06"
    },
    {
        "file": "\/home\/coicom\/public_html\/dulieu_3.json",
        "content": "[\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/data\\\/settings.json\",\n        \"content\": \"{\\n    \\\"site_title\\\": \\\"Shop Balance\\\",\\n    \\\"site_description\\\": \\\"H\\u1ec7 th\\u1ed1ng b\\u00e1n s\\u1ea3n ph\\u1ea9m t\\u1ef1 \\u0111\\u1ed9ng b\\u1eb1ng s\\u1ed1 d\\u01b0.\\\",\\n    \\\"site_keywords\\\": \\\"shop t\\u1ef1 \\u0111\\u1ed9ng, s\\u1ea3n ph\\u1ea9m s\\u1ed1, n\\u1ea1p ti\\u1ec1n, \\u0111\\u01a1n h\\u00e0ng t\\u1ef1 \\u0111\\u1ed9ng\\\",\\n    \\\"site_author\\\": \\\"\\\",\\n    \\\"site_robots\\\": \\\"index,follow\\\",\\n    \\\"site_canonical_url\\\": \\\"\\\",\\n    \\\"home_notice\\\": \\\"Nh\\u1eadp username, email ho\\u1eb7c s\\u1ed1 \\u0111i\\u1ec7n tho\\u1ea1i k\\u00e8m m\\u1eadt kh\\u1ea9u \\u0111\\u1ec3 \\u0111\\u0103ng nh\\u1eadp. T\\u00e0i kho\\u1ea3n ch\\u01b0a c\\u00f3 s\\u1ebd t\\u1ef1 \\u0111\\u0103ng k\\u00fd; t\\u00e0i kho\\u1ea3n c\\u0169 ch\\u01b0a c\\u00f3 m\\u1eadt kh\\u1ea9u s\\u1ebd \\u0111\\u01b0\\u1ee3c l\\u01b0u m\\u1eadt kh\\u1ea9u \\u1edf l\\u1ea7n \\u0111\\u0103ng nh\\u1eadp \\u0111\\u1ea7u ti\\u00ean.\\\",\\n    \\\"site_base_url\\\": \\\"\\\",\\n    \\\"site_logo_path\\\": \\\"\\\",\\n    \\\"site_logo_alt\\\": \\\"\\\",\\n    \\\"home_banner_1_path\\\": \\\"\\\",\\n    \\\"home_banner_1_alt\\\": \\\"\\\",\\n    \\\"home_banner_1_link\\\": \\\"\\\",\\n    \\\"home_banner_2_path\\\": \\\"\\\",\\n    \\\"home_banner_2_alt\\\": \\\"\\\",\\n    \\\"home_banner_2_link\\\": \\\"\\\",\\n    \\\"home_banner_3_path\\\": \\\"\\\",\\n    \\\"home_banner_3_alt\\\": \\\"\\\",\\n    \\\"home_banner_3_link\\\": \\\"\\\",\\n    \\\"webhook_secret\\\": \\\"f6d94c035077c7e06004169df7fe721edd2026aea0ad6bb45f1f53a5e0461514\\\",\\n    \\\"webhook_hmac_enabled\\\": \\\"1\\\",\\n    \\\"admin_username\\\": \\\"admin\\\",\\n    \\\"admin_password_hash\\\": \\\"$2y$10$t1GabqIKA62ttK8tKlxN1.ZGxKY7JkMLwf.nOxzTbaxl4SwM9\\\\\\\/XTO\\\",\\n    \\\"admin_access_key\\\": \\\"9bc38444cfe193271934113f\\\",\\n    \\\"admin_access_setup_done\\\": \\\"1\\\",\\n    \\\"deposit_bank_name\\\": \\\"\\\",\\n    \\\"deposit_account_number\\\": \\\"\\\",\\n    \\\"deposit_account_owner\\\": \\\"\\\",\\n    \\\"deposit_transfer_content\\\": \\\"NAP {id}\\\",\\n    \\\"deposit_quick_amounts\\\": \\\"10000,20000,50000,100000,200000,500000,1000000,2000000\\\",\\n    \\\"deposit_max_invoice_amount\\\": \\\"5000000\\\",\\n    \\\"deposit_vietqr_bank_id\\\": \\\"\\\",\\n    \\\"deposit_vietqr_template\\\": \\\"compact2\\\",\\n    \\\"deposit_vietqr_display_mode\\\": \\\"qr_and_info\\\",\\n    \\\"deposit_invoice_expire_minutes\\\": \\\"30\\\",\\n    \\\"deposit_promo_enabled\\\": \\\"0\\\",\\n    \\\"deposit_promo_rules\\\": \\\"100000|5\\\\n500000|10\\\\n1000000|15\\\",\\n    \\\"deposit_note\\\": \\\"Vui l\\u00f2ng t\\u1ea1o h\\u00f3a \\u0111\\u01a1n n\\u1ea1p ti\\u1ec1n tr\\u01b0\\u1edbc khi chuy\\u1ec3n kho\\u1ea3n. H\\u1ec7 th\\u1ed1ng s\\u1ebd t\\u1ef1 th\\u00eam ID c\\u1ee7a b\\u1ea1n v\\u00e0o 3 s\\u1ed1 cu\\u1ed1i c\\u1ee7a s\\u1ed1 ti\\u1ec1n c\\u1ea7n chuy\\u1ec3n \\u0111\\u1ec3 t\\u1ef1 \\u0111\\u1ed9ng c\\u1ed9ng \\u0111\\u00fang t\\u00e0i kho\\u1ea3n.\\\",\\n    \\\"deposit_guide_html\\\": \\\"<p>V\\u00e0o trang <b>N\\u1ea1p Ti\\u1ec1n<\\\\\\\/b>, ch\\u1ecdn nhanh s\\u1ed1 ti\\u1ec1n c\\u1ea7n n\\u1ea1p ho\\u1eb7c nh\\u1eadp s\\u1ed1 ti\\u1ec1n g\\u1ed1c b\\u1ea1n mu\\u1ed1n n\\u1ea1p, sau \\u0111\\u00f3 b\\u1ea5m <b>T\\u1ea1o h\\u00f3a \\u0111\\u01a1n n\\u1ea1p ti\\u1ec1n<\\\\\\\/b>.<\\\\\\\/p><p>V\\u00ed d\\u1ee5 ID c\\u1ee7a b\\u1ea1n l\\u00e0 <b>{id}<\\\\\\\/b>, b\\u1ea1n mu\\u1ed1n n\\u1ea1p <b>120.000\\u0111<\\\\\\\/b> th\\u00ec s\\u1ed1 ti\\u1ec1n c\\u1ea7n chuy\\u1ec3n s\\u1ebd l\\u00e0 <b>120.{id}\\u0111<\\\\\\\/b>.<\\\\\\\/p><p>N\\u1ebfu s\\u1ed1 ti\\u1ec1n chuy\\u1ec3n kho\\u1ea3n kh\\u00f4ng c\\u00f3 ID h\\u1ee3p l\\u1ec7 \\u1edf 3 s\\u1ed1 cu\\u1ed1i, h\\u1ec7 th\\u1ed1ng c\\u00f3 th\\u1ec3 kh\\u00f4ng t\\u1ef1 nh\\u1eadn di\\u1ec7n \\u0111\\u00fang t\\u00e0i kho\\u1ea3n n\\u1ea1p ti\\u1ec1n.<\\\\\\\/p>\\\",\\n    \\\"deposit_invoice_notice\\\": \\\"Vui l\\u00f2ng chuy\\u1ec3n kho\\u1ea3n \\u0111\\u00fang ch\\u00ednh x\\u00e1c s\\u1ed1 ti\\u1ec1n c\\u1ea7n chuy\\u1ec3n b\\u00ean d\\u01b0\\u1edbi. H\\u00f3a \\u0111\\u01a1n s\\u1ebd \\u0111\\u01b0\\u1ee3c c\\u1ed9ng ti\\u1ec1n t\\u1ef1 \\u0111\\u1ed9ng khi h\\u1ec7 th\\u1ed1ng nh\\u1eadn giao d\\u1ecbch, ho\\u1eb7c admin c\\u00f3 th\\u1ec3 duy\\u1ec7t th\\u1ee7 c\\u00f4ng trong qu\\u1ea3n tr\\u1ecb.\\\",\\n    \\\"order_detail_notice_html\\\": \\\"\\\",\\n    \\\"order_auto_delete_days\\\": \\\"30\\\",\\n    \\\"inactive_user_delete_days\\\": \\\"180\\\",\\n    \\\"inactive_user_delete_months\\\": \\\"6\\\",\\n    \\\"user_delete_balance_threshold\\\": \\\"1000\\\",\\n    \\\"deposit_history_auto_delete_months\\\": \\\"6\\\",\\n    \\\"maintenance_enabled\\\": \\\"0\\\",\\n    \\\"maintenance_message\\\": \\\"Website \\u0111ang b\\u1ea3o tr\\u00ec, vui l\\u00f2ng quay l\\u1ea1i sau.\\\",\\n    \\\"ticket_auto_delete_days\\\": \\\"0\\\",\\n    \\\"ticket_telegram_bot_token\\\": \\\"\\\",\\n    \\\"ticket_telegram_chat_id\\\": \\\"\\\",\\n    \\\"telegram_shop_enabled\\\": \\\"0\\\",\\n    \\\"telegram_shop_bot_token\\\": \\\"\\\",\\n    \\\"telegram_shop_webhook_secret\\\": \\\"\\\",\\n    \\\"backup_auto_enabled\\\": \\\"1\\\",\\n    \\\"backup_interval_hours\\\": \\\"24\\\",\\n    \\\"backup_keep_count\\\": \\\"10\\\",\\n    \\\"backup_keep_days\\\": \\\"30\\\",\\n    \\\"backup_restore_enabled\\\": \\\"1\\\",\\n    \\\"backup_cron_token\\\": \\\"9f7e37129b685d070c2181fc18d23345c34257c5957e6f52\\\",\\n    \\\"backup_last_at\\\": \\\"2026-06-30 07:19:20\\\",\\n    \\\"backup_last_auto_at\\\": \\\"2026-06-30 07:19:20\\\",\\n    \\\"backup_last_file\\\": \\\"auto-backup-20260630-071920-4e82bc24.zip\\\",\\n    \\\"backup_last_status\\\": \\\"success\\\",\\n    \\\"backup_last_error\\\": \\\"\\\"\\n}\",\n        \"time\": \"2026-07-01 13:56:49\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/README_PUBLIC_LAYOUT.txt\",\n        \"content\": \"B\\u1ed1 c\\u1ee5c sau khi t\\u1ed1i \\u01b0u:\\n\\n- public\\\/: ch\\u1ee9a to\\u00e0n b\\u1ed9 m\\u00e3 ngu\\u1ed3n \\u1ee9ng d\\u1ee5ng v\\u00e0 c\\u00e1c file web-facing.\\n- data\\\/, backup\\\/, codes\\\/, kho-tdata\\\/, uploads\\\/, source-sync-master-data\\\/: th\\u01b0 m\\u1ee5c private n\\u1eb1m ngang c\\u1ea5p public, d\\u00f9ng \\u0111\\u1ec3 l\\u01b0u JSON, backup, m\\u00e3\\\/code s\\u1ea3n ph\\u1ea9m, kho h\\u00e0ng, file t\\u1ea1m v\\u00e0 c\\u1ea5u h\\u00ecnh source-sync master.\\n- .htaccess \\u1edf th\\u01b0 m\\u1ee5c g\\u1ed1c rewrite n\\u1ed9i b\\u1ed9 request v\\u00e0o public\\\/ \\u0111\\u1ec3 gi\\u1eef nguy\\u00ean URL nh\\u01b0 tr\\u01b0\\u1edbc, v\\u00ed d\\u1ee5 \\\/products, \\\/admin, \\\/sitemap.xml.\\n\\nKhuy\\u1ebfn ngh\\u1ecb tri\\u1ec3n khai an to\\u00e0n nh\\u1ea5t:\\n1. N\\u1ebfu hosting cho ph\\u00e9p ch\\u1ecdn document root, h\\u00e3y tr\\u1ecf document root tr\\u1ef1c ti\\u1ebfp v\\u00e0o th\\u01b0 m\\u1ee5c public\\\/. Khi \\u0111\\u00f3 c\\u00e1c th\\u01b0 m\\u1ee5c private ngang c\\u1ea5p public kh\\u00f4ng th\\u1ec3 truy c\\u1eadp b\\u1eb1ng URL.\\n2. N\\u1ebfu hosting kh\\u00f4ng cho \\u0111\\u1ed5i document root, upload c\\u1ea3 g\\u00f3i n\\u00e0y; file .htaccess \\u1edf g\\u1ed1c s\\u1ebd gi\\u1eef URL kh\\u00f4ng c\\u00f3 \\\/public\\\/ v\\u00e0 ch\\u1eb7n c\\u00e1c th\\u01b0 m\\u1ee5c private.\\n3. N\\u1ebfu d\\u00f9ng Nginx ho\\u1eb7c m\\u00f4i tr\\u01b0\\u1eddng kh\\u00f4ng \\u0111\\u1ecdc .htaccess, b\\u1eaft bu\\u1ed9c c\\u1ea5u h\\u00ecnh root v\\u1ec1 public\\\/ ho\\u1eb7c deny tr\\u1ef1c ti\\u1ebfp c\\u00e1c \\u0111\\u01b0\\u1eddng d\\u1eabn \\\/data, \\\/backup, \\\/codes, \\\/kho-tdata, \\\/uploads, \\\/source-sync-master-data. C\\u00e1c th\\u01b0 m\\u1ee5c private c\\u00f3 index.php\\\/web.config\\\/.htaccess b\\u1ea3o v\\u1ec7 b\\u1ed5 sung, nh\\u01b0ng file t\\u0129nh c\\u00f3 th\\u1ec3 b\\u1ecb web server ph\\u1ee5c v\\u1ee5 tr\\u01b0\\u1edbc khi PHP ch\\u1ea1y n\\u1ebfu web root \\u0111\\u1eb7t sai.\\n\",\n        \"time\": \"2026-07-01 13:30:55\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/source-sync-master-data\\\/source-sync-master-config.json\",\n        \"content\": \"{\\n    \\\"master_token\\\": \\\"bfe414a0a2a29256\\\",\\n    \\\"version\\\": \\\"V1.8\\\",\\n    \\\"zip_url\\\": \\\"\\\/update-packages\\\/65458_backup_restore_round_robin_deposit_history_fixed.zip\\\",\\n    \\\"zip_sha256\\\": \\\"3111a3acd50550c6f32c133e1143200ba511863ee0ed4c6459dcdfebe2bd794e\\\",\\n    \\\"zip_filename\\\": \\\"65458_backup_restore_round_robin_deposit_history_fixed.zip\\\",\\n    \\\"zip_size\\\": 2677981,\\n    \\\"released_at\\\": \\\"2026-06-30 12:45:46\\\",\\n    \\\"changelog\\\": \\\"\\\",\\n    \\\"required\\\": true,\\n    \\\"allowed_client_ips\\\": [\\n        \\\"14.225.218.36\\\",\\n        \\\"14.225.219.71\\\"\\n    ],\\n    \\\"allowed_client_domains\\\": [\\n        \\\"taphoatele.com\\\",\\n        \\\"acctelegram.net\\\",\\n        \\\"1ccmm.my\\\",\\n        \\\"1.1ccmm.my\\\"\\n    ],\\n    \\\"updated_at\\\": \\\"2026-06-30 12:45:46\\\",\\n    \\\"config_password_hash\\\": \\\"$2y$10$HHl.YoV15spCHl6g6fGKsO5T7vr12Bo.zfGZ0knK\\\/Dkpcz12Tqn5e\\\",\\n    \\\"config_access_key\\\": \\\"9bc38444cfe193271934113f\\\",\\n    \\\"config_setup_done\\\": true\\n}\",\n        \"time\": \"2026-07-01 13:29:39\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/source-sync-master-data\\\/source-sync-login-rate.json\",\n        \"content\": \"{\\n    \\\"login:7a1a4051beabf07f10a0ff2171cc95604e1a86e6\\\": [\\n        1782798339\\n    ]\\n}\",\n        \"time\": \"2026-07-01 13:29:37\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/public\\\/webhook.php\",\n        \"content\": \"<?php\\nrequire_once __DIR__ . '\\\/includes\\\/functions.php';\\nensure_data_files();\\nsend_security_headers(true);\\ntry {\\n    if (security_guard_active()) { json_response(array('ok'=>true,'guarded'=>true), 200); }\\n    security_request_rate_guard('webhook_request', array(request_ip_address()), 120, 60, 300, 'Webhook nh\\u1eadn qu\\u00e1 nhi\\u1ec1u request, vui l\\u00f2ng th\\u1eed l\\u1ea1i sau.');\\n    $payload = read_webhook_payload();\\n    $result = process_deposit_webhook($payload);\\n    json_response($result, 200);\\n} catch (Exception $e) {\\n    security_log_event('webhook_exception', 'L\\u1ed7i x\\u1eed l\\u00fd webhook', array('error' => $e->getMessage()));\\n    json_response(array('ok'=>false,'error'=>security_generic_message()),500);\\n}\\n\",\n        \"time\": \"2026-07-01 13:28:15\"\n    },\n    {\n        \"file\": \"\\\/home\\\/coicom\\\/1.1ccmm.my\\\/public\\\/source-sync-master-api\\\/source-sync-config.php\",\n        \"content\": \"<?php\\n\\\/**\\n * Trang c\\u1ea5u h\\u00ecnh m\\u00e1y ch\\u1ee7 ch\\u00ednh cho update-manifest.php.\\n *\\n * \\u0110\\u1eb7t file n\\u00e0y trong \\\/source-sync-master-api\\\/ tr\\u00ean M\\u00c1Y CH\\u1ee6 CH\\u00cdNH.\\n * M\\u1ecdi c\\u1ea5u h\\u00ecnh manifest \\u0111\\u01b0\\u1ee3c l\\u01b0u v\\u00e0o JSON:\\n *   \\\/source-sync-master-data\\\/source-sync-master-config.json\\n *\\n * B\\u1ea3o m\\u1eadt trang c\\u1ea5u h\\u00ecnh:\\n * - L\\u1ea7n \\u0111\\u1ea7u truy c\\u1eadp tr\\u1ef1c ti\\u1ebfp file n\\u00e0y \\u0111\\u1ec3 t\\u1ea1o m\\u1eadt kh\\u1ea9u v\\u00e0 token truy c\\u1eadp.\\n * - Nh\\u1eefng l\\u1ea7n sau ph\\u1ea3i truy c\\u1eadp d\\u1ea1ng source-sync-config.php?k=TOKEN.\\n * - Bi\\u1ebfn m\\u1eadt kh\\u1ea9u b\\u00ean d\\u01b0\\u1edbi ch\\u1ec9 c\\u00f2n d\\u00f9ng t\\u01b0\\u01a1ng th\\u00edch cho b\\u1ea3n c\\u0169 n\\u1ebfu \\u0111\\u00e3 t\\u1ef1 \\u0111\\u1ed5i tr\\u01b0\\u1edbc \\u0111\\u00e2y.\\n *\\\/\\n\\n\\\/\\\/ =========================\\n\\\/\\\/ M\\u1eacT KH\\u1ea8U T\\u01af\\u01a0NG TH\\u00cdCH B\\u1ea2N C\\u0168 - KH\\u00d4NG C\\u1ea6N S\\u1eecA N\\u1ebeU D\\u00d9NG SETUP L\\u1ea6N \\u0110\\u1ea6U\\n\\\/\\\/ =========================\\n$SOURCE_SYNC_CONFIG_PASSWORD = 'doi-mat-khau-quan-tri-nay';\\n\\n\\\/\\\/ Gi\\u1edbi h\\u1ea1n dung l\\u01b0\\u1ee3ng ZIP upload qua trang n\\u00e0y. C\\u00f2n ph\\u1ee5 thu\\u1ed9c upload_max_filesize\\\/post_max_size c\\u1ee7a hosting.\\n$SOURCE_SYNC_CONFIG_MAX_UPLOAD_BYTES = 300 * 1024 * 1024; \\\/\\\/ 300MB\\n\\n\\\/\\\/ =========================\\n\\\/\\\/ KH\\u00d4NG C\\u1ea6N S\\u1eecA PH\\u1ea6N B\\u00caN D\\u01af\\u1edaI N\\u1ebeU KH\\u00d4NG C\\u1ea6N\\n\\\/\\\/ =========================\\n\\n@ini_set('display_errors', '0');\\n@ini_set('display_startup_errors', '0');\\n@ini_set('log_errors', '1');\\n@ini_set('html_errors', '0');\\n\\ndate_default_timezone_set('Asia\\\/Ho_Chi_Minh');\\n\\nheader('X-Robots-Tag: noindex, nofollow', true);\\nheader('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');\\nheader('X-Frame-Options: SAMEORIGIN');\\nheader('X-Content-Type-Options: nosniff');\\n\\nsession_name('source_sync_master_config_session');\\n@session_start();\\n\\n$MASTER_API_DIR = __DIR__;\\n$MASTER_ROOT_DIR = dirname(__DIR__);\\n$MASTER_PRIVATE_ROOT_DIR = dirname($MASTER_ROOT_DIR);\\n$MASTER_DATA_DIR = $MASTER_PRIVATE_ROOT_DIR . '\\\/source-sync-master-data';\\n$MASTER_CONFIG_FILE = $MASTER_DATA_DIR . '\\\/source-sync-master-config.json';\\n$MASTER_PACKAGE_DIR = $MASTER_ROOT_DIR . '\\\/update-packages';\\n$MASTER_PACKAGE_PUBLIC_DIR = '\\\/update-packages';\\n\\n\\nfunction ssm_client_ip() {\\n    return isset($_SERVER['REMOTE_ADDR']) ? trim((string)$_SERVER['REMOTE_ADDR']) : '';\\n}\\n\\nfunction ssm_rate_file() {\\n    global $MASTER_DATA_DIR;\\n    return $MASTER_DATA_DIR . '\\\/source-sync-login-rate.json';\\n}\\n\\nfunction ssm_rate_limit_guard($key, $maxAttempts = 10, $windowSeconds = 300) {\\n    ssm_ensure_dirs();\\n    $file = ssm_rate_file();\\n    $data = array();\\n    if (is_file($file)) {\\n        $raw = @file_get_contents($file);\\n        $json = json_decode((string)$raw, true);\\n        if (is_array($json)) $data = $json;\\n    }\\n    $now = time();\\n    foreach ($data as $k => $rows) {\\n        if (!is_array($rows)) { unset($data[$k]); continue; }\\n        $data[$k] = array_values(array_filter($rows, function($ts) use ($now, $windowSeconds) { return intval($ts) > ($now - $windowSeconds); }));\\n        if (!$data[$k]) unset($data[$k]);\\n    }\\n    if (!isset($data[$key]) || !is_array($data[$key])) $data[$key] = array();\\n    if (count($data[$key]) >= $maxAttempts) {\\n        @file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);\\n        return false;\\n    }\\n    $data[$key][] = $now;\\n    @file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);\\n    return true;\\n}\\n\\nfunction ssm_e($value) {\\n    return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');\\n}\\n\\nfunction ssm_now() {\\n    return date('Y-m-d H:i:s');\\n}\\n\\nfunction ssm_ensure_dirs() {\\n    global $MASTER_DATA_DIR, $MASTER_PACKAGE_DIR;\\n    if (!is_dir($MASTER_DATA_DIR)) @mkdir($MASTER_DATA_DIR, 0755, true);\\n    if (!is_dir($MASTER_PACKAGE_DIR)) @mkdir($MASTER_PACKAGE_DIR, 0755, true);\\n\\n    $htaccess = $MASTER_DATA_DIR . '\\\/.htaccess';\\n    $rules = \\\"Options -Indexes\\n<IfModule mod_authz_core.c>\\nRequire all denied\\n<\\\/IfModule>\\n<IfModule !mod_authz_core.c>\\nOrder deny,allow\\nDeny from all\\n<\\\/IfModule>\\n\\\";\\n    if (!is_file($htaccess) || trim((string)@file_get_contents($htaccess)) !== trim($rules)) {\\n        @file_put_contents($htaccess, $rules);\\n    }\\n    $indexPhp = $MASTER_DATA_DIR . '\\\/index.php';\\n    if (!is_file($indexPhp)) @file_put_contents($indexPhp, \\\"<?php\\nhttp_response_code(404);\\nheader('X-Robots-Tag: noindex, nofollow', true);\\necho '404 Not Found';\\nexit;\\n\\\");\\n    $index = $MASTER_DATA_DIR . '\\\/index.html';\\n    if (!is_file($index)) @file_put_contents($index, '');\\n\\n    $webConfig = $MASTER_DATA_DIR . '\\\/web.config';\\n    $webRules = <<<'XML'\\n<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n<configuration>\\n  <system.webServer>\\n    <security>\\n      <authorization>\\n        <clear \\\/>\\n        <add accessType=\\\"Deny\\\" users=\\\"*\\\" \\\/>\\n      <\\\/authorization>\\n    <\\\/security>\\n    <directoryBrowse enabled=\\\"false\\\" \\\/>\\n  <\\\/system.webServer>\\n<\\\/configuration>\\nXML;\\n    $webRules .= \\\"\\n\\\";\\n    if (!is_file($webConfig) || trim((string)@file_get_contents($webConfig)) !== trim($webRules)) @file_put_contents($webConfig, $webRules, LOCK_EX);\\n    @chmod($MASTER_DATA_DIR, 0700);\\n\\n    $pkgIndex = $MASTER_PACKAGE_DIR . '\\\/index.html';\\n    if (!is_file($pkgIndex)) @file_put_contents($pkgIndex, '');\\n}\\n\\nfunction ssm_default_config() {\\n    return array(\\n        'master_token' => '',\\n        'version' => 'V24',\\n        'zip_url' => '',\\n        'zip_sha256' => '',\\n        'zip_filename' => '',\\n        'zip_size' => 0,\\n        'released_at' => ssm_now(),\\n        'changelog' => '',\\n        'required' => false,\\n        'allowed_client_ips' => array(),\\n        'allowed_client_domains' => array(),\\n        'updated_at' => '',\\n        'config_password_hash' => '',\\n        'config_access_key' => '',\\n        'config_setup_done' => false,\\n    );\\n}\\n\\nfunction ssm_load_config() {\\n    global $MASTER_CONFIG_FILE;\\n    $defaults = ssm_default_config();\\n    if (!is_file($MASTER_CONFIG_FILE)) return $defaults;\\n    $raw = file_get_contents($MASTER_CONFIG_FILE);\\n    $json = json_decode($raw, true);\\n    if (!is_array($json)) return $defaults;\\n    return array_merge($defaults, $json);\\n}\\n\\nfunction ssm_save_config($config) {\\n    global $MASTER_CONFIG_FILE;\\n    ssm_ensure_dirs();\\n    $config['updated_at'] = ssm_now();\\n    $json = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);\\n    if ($json === false) return false;\\n    $ok = @file_put_contents($MASTER_CONFIG_FILE, $json, LOCK_EX) !== false;\\n    if ($ok) @chmod($MASTER_CONFIG_FILE, 0600);\\n    return $ok;\\n}\\n\\nfunction ssm_text_to_array($value) {\\n    if (is_array($value)) $value = implode(\\\"\\\\n\\\", $value);\\n    $value = trim((string)$value);\\n    if ($value === '') return array();\\n    return array_values(array_filter(array_map('trim', preg_split('\\\/[\\\\r\\\\n,]+\\\/', $value)), function($v) { return $v !== ''; }));\\n}\\n\\nfunction ssm_array_to_text($value) {\\n    if (!is_array($value)) return trim((string)$value);\\n    return implode(\\\"\\\\n\\\", array_values(array_filter(array_map('trim', array_map('strval', $value)), function($v) { return $v !== ''; })));\\n}\\n\\nfunction ssm_safe_zip_filename($name) {\\n    $name = basename((string)$name);\\n    $name = preg_replace('\\\/[^a-zA-Z0-9._-]+\\\/', '-', $name);\\n    $name = trim($name, '.-_');\\n    if ($name === '') $name = 'source-update.zip';\\n    if (strtolower(substr($name, -4)) !== '.zip') $name .= '.zip';\\n    return $name;\\n}\\n\\nfunction ssm_internal_zip_path_from_url($zipUrl) {\\n    global $MASTER_ROOT_DIR;\\n    $zipUrl = trim((string)$zipUrl);\\n    if ($zipUrl === '') return '';\\n    if (preg_match('#^https?:\\\/\\\/#i', $zipUrl)) {\\n        $parts = parse_url($zipUrl);\\n        if (!$parts || empty($parts['path'])) return '';\\n        $zipUrl = $parts['path'];\\n    }\\n    if ($zipUrl[0] !== '\\\/') $zipUrl = '\\\/' . $zipUrl;\\n    $path = realpath($MASTER_ROOT_DIR . $zipUrl);\\n    if ($path === false || !is_file($path)) return '';\\n    return $path;\\n}\\n\\nfunction ssm_flash($type, $message) {\\n    $_SESSION['ssm_flash'][] = array('type' => $type, 'message' => $message);\\n}\\n\\nfunction ssm_get_flash() {\\n    $flash = isset($_SESSION['ssm_flash']) && is_array($_SESSION['ssm_flash']) ? $_SESSION['ssm_flash'] : array();\\n    unset($_SESSION['ssm_flash']);\\n    return $flash;\\n}\\n\\nfunction ssm_logged_in() {\\n    return !empty($_SESSION['ssm_logged_in']);\\n}\\n\\nfunction ssm_generate_access_key($bytes = 12) {\\n    return strtolower(substr(bin2hex(random_bytes(max(8, intval($bytes)))), 0, 24));\\n}\\n\\nfunction ssm_normalize_access_key($key) {\\n    $key = trim((string)$key);\\n    $key = preg_replace('\\\/[^A-Za-z0-9_-]\\\/', '', $key);\\n    return substr($key, 0, 64);\\n}\\n\\nfunction ssm_setup_required($config = null) {\\n    if (!is_array($config)) $config = ssm_load_config();\\n    $done = !empty($config['config_setup_done']);\\n    $key = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\n    $hash = isset($config['config_password_hash']) ? (string)$config['config_password_hash'] : '';\\n    return !$done || $key === '' || $hash === '';\\n}\\n\\nfunction ssm_access_gate_passed($config = null) {\\n    if (!is_array($config)) $config = ssm_load_config();\\n    if (ssm_setup_required($config)) return true;\\n    if (ssm_logged_in()) return true;\\n    if (!empty($_SESSION['ssm_access_granted'])) return true;\\n    $key = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\n    $given = isset($_GET['k']) ? ssm_normalize_access_key($_GET['k']) : '';\\n    if ($key !== '' && $given !== '' && hash_equals($key, $given)) {\\n        $_SESSION['ssm_access_granted'] = true;\\n        return true;\\n    }\\n    return false;\\n}\\n\\nfunction ssm_fake_404() {\\n    http_response_code(404);\\n    header('Content-Type: text\\\/plain; charset=utf-8');\\n    echo '404 Not Found';\\n    exit;\\n}\\n\\nfunction ssm_check_config_password($password, $config) {\\n    $hash = isset($config['config_password_hash']) ? (string)$config['config_password_hash'] : '';\\n    if ($hash !== '') return password_verify((string)$password, $hash);\\n    global $SOURCE_SYNC_CONFIG_PASSWORD;\\n    if ($SOURCE_SYNC_CONFIG_PASSWORD !== '' && $SOURCE_SYNC_CONFIG_PASSWORD !== 'doi-mat-khau-quan-tri-nay') {\\n        return hash_equals((string)$SOURCE_SYNC_CONFIG_PASSWORD, (string)$password);\\n    }\\n    return false;\\n}\\n\\nfunction ssm_increment_version($version) {\\n    $version = trim((string)$version);\\n    if ($version === '') return 'V1.0';\\n    if (preg_match('\\\/^(.*?)(\\\\d+)\\\\.(\\\\d+)$\\\/', $version, $m)) {\\n        return $m[1] . $m[2] . '.' . (intval($m[3]) + 1);\\n    }\\n    if (preg_match('\\\/^(.*?)(\\\\d+)$\\\/', $version, $m)) {\\n        return $m[1] . (intval($m[2]) + 1);\\n    }\\n    return $version . '.1';\\n}\\n\\nfunction ssm_require_csrf() {\\n    $posted = isset($_POST['csrf']) ? (string)$_POST['csrf'] : '';\\n    $stored = isset($_SESSION['ssm_csrf']) ? (string)$_SESSION['ssm_csrf'] : '';\\n    if ($stored === '' || $posted === '' || !hash_equals($stored, $posted)) {\\n        ssm_flash('error', 'CSRF token kh\\u00f4ng h\\u1ee3p l\\u1ec7, h\\u00e3y th\\u1eed l\\u1ea1i.');\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n}\\n\\nfunction ssm_csrf_token() {\\n    if (empty($_SESSION['ssm_csrf'])) {\\n        $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\n    }\\n    return $_SESSION['ssm_csrf'];\\n}\\n\\nssm_ensure_dirs();\\n$config = ssm_load_config();\\n$setupRequired = ssm_setup_required($config);\\nif (!$setupRequired && !ssm_access_gate_passed($config)) {\\n    ssm_fake_404();\\n}\\n\\nif ($_SERVER['REQUEST_METHOD'] === 'POST') {\\n    $action = isset($_POST['action']) ? (string)$_POST['action'] : '';\\n\\n    if ($setupRequired && $action === 'setup_config') {\\n        ssm_require_csrf();\\n        $password = isset($_POST['password']) ? (string)$_POST['password'] : '';\\n        $password2 = isset($_POST['password_confirm']) ? (string)$_POST['password_confirm'] : '';\\n        $accessKey = isset($_POST['config_access_key']) ? ssm_normalize_access_key($_POST['config_access_key']) : '';\\n        if ($password !== $password2) {\\n            ssm_flash('error', 'M\\u1eadt kh\\u1ea9u nh\\u1eadp l\\u1ea1i kh\\u00f4ng kh\\u1edbp.');\\n        } elseif (strlen($password) < 8) {\\n            ssm_flash('error', 'M\\u1eadt kh\\u1ea9u c\\u1ea5u h\\u00ecnh ph\\u1ea3i c\\u00f3 \\u00edt nh\\u1ea5t 8 k\\u00fd t\\u1ef1.');\\n        } elseif ($accessKey === '' || strlen($accessKey) < 8) {\\n            ssm_flash('error', 'Token truy c\\u1eadp ph\\u1ea3i c\\u00f3 \\u00edt nh\\u1ea5t 8 k\\u00fd t\\u1ef1.');\\n        } else {\\n            $config['config_password_hash'] = password_hash($password, PASSWORD_DEFAULT);\\n            $config['config_access_key'] = $accessKey;\\n            $config['config_setup_done'] = true;\\n            if (ssm_save_config($config)) {\\n                $_SESSION['ssm_access_granted'] = true;\\n                $_SESSION['ssm_logged_in'] = true;\\n                $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\n                ssm_flash('success', '\\u0110\\u00e3 thi\\u1ebft l\\u1eadp m\\u1eadt kh\\u1ea9u v\\u00e0 token truy c\\u1eadp Source Sync Master.');\\n            } else {\\n                ssm_flash('error', 'Kh\\u00f4ng th\\u1ec3 l\\u01b0u c\\u1ea5u h\\u00ecnh b\\u1ea3o v\\u1ec7 Source Sync Master.');\\n            }\\n        }\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if ($action === 'login') {\\n        ssm_require_csrf();\\n        $password = isset($_POST['password']) ? (string)$_POST['password'] : '';\\n        $rateKey = 'login:' . sha1(ssm_client_ip());\\n        if (!ssm_rate_limit_guard($rateKey, 10, 300)) {\\n            ssm_flash('error', 'B\\u1ea1n \\u0111\\u0103ng nh\\u1eadp sai\\\/thao t\\u00e1c qu\\u00e1 nhi\\u1ec1u l\\u1ea7n. Vui l\\u00f2ng th\\u1eed l\\u1ea1i sau.');\\n            header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n            exit;\\n        }\\n        if (ssm_check_config_password($password, $config)) {\\n            $_SESSION['ssm_logged_in'] = true;\\n            $_SESSION['ssm_access_granted'] = true;\\n            $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\\n            ssm_flash('success', '\\u0110\\u0103ng nh\\u1eadp th\\u00e0nh c\\u00f4ng.');\\n        } else {\\n            ssm_flash('error', 'M\\u1eadt kh\\u1ea9u kh\\u00f4ng \\u0111\\u00fang.');\\n        }\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if ($action === 'logout') {\\n        unset($_SESSION['ssm_logged_in']);\\n        unset($_SESSION['ssm_access_granted']);\\n        unset($_SESSION['ssm_csrf']);\\n        ssm_flash('success', '\\u0110\\u00e3 \\u0111\\u0103ng xu\\u1ea5t.');\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if (!ssm_logged_in()) {\\n        ssm_flash('error', 'B\\u1ea1n c\\u1ea7n \\u0111\\u0103ng nh\\u1eadp.');\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    ssm_require_csrf();\\n    $config = ssm_load_config();\\n\\n    if ($action === 'save_config') {\\n        $config['master_token'] = trim((string)($_POST['master_token'] ?? ''));\\n        $config['version'] = trim((string)($_POST['version'] ?? ''));\\n        $config['zip_url'] = trim((string)($_POST['zip_url'] ?? ''));\\n        $config['zip_sha256'] = strtolower(trim((string)($_POST['zip_sha256'] ?? '')));\\n        $config['released_at'] = trim((string)($_POST['released_at'] ?? ''));\\n        $config['changelog'] = (string)($_POST['changelog'] ?? '');\\n        $config['required'] = !empty($_POST['required']);\\n        $config['allowed_client_ips'] = ssm_text_to_array($_POST['allowed_client_ips'] ?? '');\\n        $config['allowed_client_domains'] = ssm_text_to_array($_POST['allowed_client_domains'] ?? '');\\n\\n        if ($config['master_token'] === '') {\\n            ssm_flash('error', 'Token m\\u00e1y ch\\u1ee7 ch\\u00ednh kh\\u00f4ng \\u0111\\u01b0\\u1ee3c \\u0111\\u1ec3 tr\\u1ed1ng.');\\n        } elseif ($config['version'] === '') {\\n            ssm_flash('error', 'Phi\\u00ean b\\u1ea3n kh\\u00f4ng \\u0111\\u01b0\\u1ee3c \\u0111\\u1ec3 tr\\u1ed1ng.');\\n        } elseif ($config['zip_sha256'] !== '' && !preg_match('\\\/^[a-f0-9]{64}$\\\/i', $config['zip_sha256'])) {\\n            ssm_flash('error', 'SHA256 ph\\u1ea3i g\\u1ed3m \\u0111\\u00fang 64 k\\u00fd t\\u1ef1 hex.');\\n        } elseif (ssm_save_config($config)) {\\n            ssm_flash('success', '\\u0110\\u00e3 l\\u01b0u c\\u1ea5u h\\u00ecnh manifest v\\u00e0o JSON.');\\n        } else {\\n            ssm_flash('error', 'Kh\\u00f4ng th\\u1ec3 l\\u01b0u file JSON. H\\u00e3y ki\\u1ec3m tra quy\\u1ec1n ghi th\\u01b0 m\\u1ee5c source-sync-master-data ngang c\\u1ea5p public.');\\n        }\\n\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if ($action === 'upload_zip') {\\n        if (empty($_FILES['update_zip']) || !is_uploaded_file($_FILES['update_zip']['tmp_name'])) {\\n            ssm_flash('error', 'B\\u1ea1n ch\\u01b0a ch\\u1ecdn file ZIP.');\\n        } elseif ((int)$_FILES['update_zip']['error'] !== UPLOAD_ERR_OK) {\\n            ssm_flash('error', 'Upload ZIP th\\u1ea5t b\\u1ea1i. M\\u00e3 l\\u1ed7i: ' . (int)$_FILES['update_zip']['error']);\\n        } elseif ((int)$_FILES['update_zip']['size'] <= 0 || (int)$_FILES['update_zip']['size'] > (int)$SOURCE_SYNC_CONFIG_MAX_UPLOAD_BYTES) {\\n            ssm_flash('error', 'File ZIP v\\u01b0\\u1ee3t qu\\u00e1 dung l\\u01b0\\u1ee3ng cho ph\\u00e9p.');\\n        } else {\\n            $original = isset($_FILES['update_zip']['name']) ? (string)$_FILES['update_zip']['name'] : 'source-update.zip';\\n            $filename = ssm_safe_zip_filename($original);\\n            $target = $MASTER_PACKAGE_DIR . '\\\/' . $filename;\\n\\n            if (!preg_match('\\\/\\\\.zip$\\\/i', $filename)) {\\n                ssm_flash('error', 'Ch\\u1ec9 cho ph\\u00e9p upload file .zip.');\\n            } elseif (@move_uploaded_file($_FILES['update_zip']['tmp_name'], $target)) {\\n                @chmod($target, 0644);\\n                $hash = hash_file('sha256', $target);\\n                $config['zip_filename'] = $filename;\\n                $config['zip_size'] = filesize($target);\\n                $config['zip_url'] = rtrim($MASTER_PACKAGE_PUBLIC_DIR, '\\\/') . '\\\/' . $filename;\\n                $config['zip_sha256'] = strtolower($hash);\\n                $config['version'] = ssm_increment_version(isset($config['version']) ? $config['version'] : '');\\n                $config['released_at'] = ssm_now();\\n                if (ssm_save_config($config)) {\\n                    ssm_flash('success', 'Upload ZIP th\\u00e0nh c\\u00f4ng. H\\u1ec7 th\\u1ed1ng \\u0111\\u00e3 t\\u1ef1 l\\u1ea5y SHA256, t\\u1ef1 t\\u0103ng phi\\u00ean b\\u1ea3n l\\u00ean ' . $config['version'] . ' v\\u00e0 l\\u01b0u v\\u00e0o JSON.');\\n                } else {\\n                    ssm_flash('error', 'Upload ZIP th\\u00e0nh c\\u00f4ng nh\\u01b0ng kh\\u00f4ng th\\u1ec3 l\\u01b0u c\\u1ea5u h\\u00ecnh JSON.');\\n                }\\n            } else {\\n                ssm_flash('error', 'Kh\\u00f4ng th\\u1ec3 l\\u01b0u file ZIP v\\u00e0o th\\u01b0 m\\u1ee5c update-packages. H\\u00e3y ki\\u1ec3m tra quy\\u1ec1n ghi.');\\n            }\\n        }\\n\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n\\n    if ($action === 'recalc_sha256') {\\n        $file = ssm_internal_zip_path_from_url(isset($config['zip_url']) ? $config['zip_url'] : '');\\n        if ($file === '') {\\n            ssm_flash('error', 'Kh\\u00f4ng t\\u00ecm th\\u1ea5y file ZIP n\\u1ed9i b\\u1ed9 \\u0111\\u1ec3 l\\u1ea5y l\\u1ea1i SHA256. H\\u00e3y upload ZIP qua form ho\\u1eb7c ki\\u1ec3m tra ZIP URL.');\\n        } else {\\n            $config['zip_sha256'] = strtolower(hash_file('sha256', $file));\\n            $config['zip_size'] = filesize($file);\\n            $config['zip_filename'] = basename($file);\\n            if (ssm_save_config($config)) {\\n                ssm_flash('success', '\\u0110\\u00e3 l\\u1ea5y l\\u1ea1i SHA256 t\\u1eeb file ZIP hi\\u1ec7n t\\u1ea1i.');\\n            } else {\\n                ssm_flash('error', 'Kh\\u00f4ng th\\u1ec3 l\\u01b0u SHA256 m\\u1edbi v\\u00e0o JSON.');\\n            }\\n        }\\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\\n        exit;\\n    }\\n}\\n\\n$config = ssm_load_config();\\n$flash = ssm_get_flash();\\n$setupRequired = ssm_setup_required($config);\\n$sourceAccessKey = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\\n$suggestedSourceAccessKey = ssm_generate_access_key();\\n$csrf = ssm_csrf_token();\\n$manifestUrl = '';\\nif (!empty($_SERVER['HTTP_HOST'])) {\\n    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';\\n    $manifestUrl = $scheme . ':\\\/\\\/' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']) . '\\\/update-manifest.php';\\n}\\n$configLoginUrl = '';\\nif (!empty($_SERVER['HTTP_HOST'])) {\\n    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';\\n    $configLoginUrl = $scheme . ':\\\/\\\/' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . ($sourceAccessKey !== '' ? '?k=' . rawurlencode($sourceAccessKey) : '');\\n}\\n?>\\n<!doctype html>\\n<html lang=\\\"vi\\\">\\n<head>\\n<meta charset=\\\"utf-8\\\">\\n<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1\\\">\\n<meta name=\\\"robots\\\" content=\\\"noindex,nofollow\\\">\\n<title>C\\u1ea5u h\\u00ecnh Source Sync Master<\\\/title>\\n<style>\\n    :root { color-scheme: light; --bg:#f4f6fb; --card:#ffffff; --text:#172033; --muted:#667085; --border:#d9e0ea; --primary:#1d4ed8; --danger:#dc2626; --success:#15803d; }\\n    * { box-sizing: border-box; }\\n    body { margin:0; font-family: Arial, Helvetica, sans-serif; background: var(--bg); color: var(--text); }\\n    .wrap { max-width: 980px; margin: 0 auto; padding: 18px; }\\n    .top { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:14px; }\\n    h1 { font-size: 22px; margin:0; }\\n    .card { background:var(--card); border:1px solid var(--border); border-radius:14px; padding:16px; box-shadow:0 8px 24px rgba(15,23,42,.06); margin-bottom:14px; }\\n    .grid { display:grid; grid-template-columns: 1fr 1fr; gap:14px; }\\n    label { display:block; font-weight:700; margin-bottom:6px; font-size:14px; }\\n    input[type=text], input[type=password], textarea, select { width:100%; border:1px solid var(--border); border-radius:10px; padding:10px 12px; font-size:14px; background:#fff; color:var(--text); }\\n    textarea { min-height:96px; resize:vertical; }\\n    .hint { color:var(--muted); font-size:13px; margin-top:5px; line-height:1.45; }\\n    .row { margin-bottom:14px; }\\n    .btn { border:0; border-radius:10px; padding:10px 14px; font-weight:700; cursor:pointer; background:var(--primary); color:white; display:inline-flex; align-items:center; gap:8px; text-decoration:none; font-size:14px; }\\n    .btn.secondary { background:#475569; }\\n    .btn.danger { background:var(--danger); }\\n    .btn.light { background:#e8eef8; color:#1e293b; }\\n    .actions { display:flex; gap:10px; flex-wrap:wrap; align-items:center; }\\n    .flash { border-radius:10px; padding:11px 12px; margin-bottom:10px; border:1px solid var(--border); }\\n    .flash.success { background:#ecfdf3; color:#166534; border-color:#bbf7d0; }\\n    .flash.error { background:#fef2f2; color:#991b1b; border-color:#fecaca; }\\n    .stat { display:grid; grid-template-columns: 210px 1fr; gap:10px; border-bottom:1px solid #eef2f7; padding:8px 0; font-size:14px; }\\n    .stat b { color:#334155; }\\n    code { background:#eef2ff; color:#1e3a8a; padding:2px 5px; border-radius:5px; word-break:break-all; }\\n    .danger-note { color:#991b1b; background:#fff1f2; border:1px solid #fecdd3; padding:10px 12px; border-radius:10px; font-size:14px; line-height:1.45; }\\n    @media (max-width: 720px) {\\n        .wrap { padding:12px; }\\n        .grid { grid-template-columns: 1fr; }\\n        .top { align-items:flex-start; flex-direction:column; }\\n        .stat { grid-template-columns: 1fr; gap:4px; }\\n        .btn { width:100%; justify-content:center; }\\n    }\\n<\\\/style>\\n<\\\/head>\\n<body>\\n<div class=\\\"wrap\\\">\\n    <div class=\\\"top\\\">\\n        <div>\\n            <h1>\\u2699\\ufe0f C\\u1ea5u h\\u00ecnh Source Sync Master<\\\/h1>\\n            <div class=\\\"hint\\\">Trang n\\u00e0y d\\u00f9ng \\u0111\\u1ec3 c\\u1ea5u h\\u00ecnh <code>update-manifest.php<\\\/code>, upload ZIP update v\\u00e0 t\\u1ef1 l\\u1ea5y SHA256.<\\\/div>\\n        <\\\/div>\\n        <?php if (ssm_logged_in()): ?>\\n            <form method=\\\"post\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"logout\\\">\\n                <button class=\\\"btn light\\\" type=\\\"submit\\\">\\u0110\\u0103ng xu\\u1ea5t<\\\/button>\\n            <\\\/form>\\n        <?php endif; ?>\\n    <\\\/div>\\n\\n    <?php foreach ($flash as $item): ?>\\n        <div class=\\\"flash <?php echo ssm_e($item['type']); ?>\\\"><?php echo ssm_e($item['message']); ?><\\\/div>\\n    <?php endforeach; ?>\\n\\n    <?php if ($setupRequired): ?>\\n        <div class=\\\"card\\\">\\n            <h2>Thi\\u1ebft l\\u1eadp Source Sync Master l\\u1ea7n \\u0111\\u1ea7u<\\\/h2>\\n            <p class=\\\"hint\\\">L\\u1ea7n \\u0111\\u1ea7u c\\u00f3 th\\u1ec3 truy c\\u1eadp tr\\u1ef1c ti\\u1ebfp trang n\\u00e0y \\u0111\\u1ec3 t\\u1ea1o m\\u1eadt kh\\u1ea9u v\\u00e0 token b\\u1ea3o v\\u1ec7 \\u0111\\u01b0\\u1eddng d\\u1eabn. Nh\\u1eefng l\\u1ea7n sau ph\\u1ea3i truy c\\u1eadp \\u0111\\u00fang link c\\u00f3 token.<\\\/p>\\n            <form method=\\\"post\\\" style=\\\"margin-top:14px;\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"setup_config\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n                <div class=\\\"row\\\"><label>M\\u1eadt kh\\u1ea9u c\\u1ea5u h\\u00ecnh m\\u1edbi<\\\/label><input type=\\\"password\\\" name=\\\"password\\\" autocomplete=\\\"new-password\\\" minlength=\\\"8\\\" required><\\\/div>\\n                <div class=\\\"row\\\"><label>Nh\\u1eadp l\\u1ea1i m\\u1eadt kh\\u1ea9u<\\\/label><input type=\\\"password\\\" name=\\\"password_confirm\\\" autocomplete=\\\"new-password\\\" minlength=\\\"8\\\" required><\\\/div>\\n                <div class=\\\"row\\\"><label>Token truy c\\u1eadp trang c\\u1ea5u h\\u00ecnh<\\\/label><input type=\\\"text\\\" name=\\\"config_access_key\\\" value=\\\"<?php echo ssm_e($suggestedSourceAccessKey); ?>\\\" required><div class=\\\"hint\\\">Sau khi l\\u01b0u, link truy c\\u1eadp s\\u1ebd c\\u00f3 d\\u1ea1ng: <code><?php echo ssm_e((!empty($_SERVER['HTTP_HOST']) ? (((!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http') . ':\\\/\\\/' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME']) : 'source-sync-config.php')); ?>?k=TOKEN<\\\/code><\\\/div><\\\/div>\\n                <button class=\\\"btn\\\" type=\\\"submit\\\">T\\u1ea1o m\\u1eadt kh\\u1ea9u v\\u00e0 token<\\\/button>\\n            <\\\/form>\\n        <\\\/div>\\n    <?php elseif (!ssm_logged_in()): ?>\\n        <div class=\\\"card\\\">\\n            <h2>\\u0110\\u0103ng nh\\u1eadp<\\\/h2>\\n            <form method=\\\"post\\\" style=\\\"margin-top:14px;\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"login\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n                <div class=\\\"row\\\"><label>M\\u1eadt kh\\u1ea9u c\\u1ea5u h\\u00ecnh<\\\/label><input type=\\\"password\\\" name=\\\"password\\\" autocomplete=\\\"current-password\\\" required><\\\/div>\\n                <button class=\\\"btn\\\" type=\\\"submit\\\">\\u0110\\u0103ng nh\\u1eadp<\\\/button>\\n            <\\\/form>\\n            <?php if ($configLoginUrl !== ''): ?><p class=\\\"hint\\\">Link truy c\\u1eadp h\\u1ee3p l\\u1ec7: <code><?php echo ssm_e($configLoginUrl); ?><\\\/code><\\\/p><?php endif; ?>\\n        <\\\/div>\\n    <?php else: ?>\\n        <div class=\\\"card\\\">\\n            <h2>Th\\u00f4ng tin hi\\u1ec7n t\\u1ea1i<\\\/h2>\\n            <div class=\\\"stat\\\"><b>Manifest URL<\\\/b><div><code><?php echo ssm_e($manifestUrl); ?><\\\/code><\\\/div><\\\/div>\\n            <?php if ($configLoginUrl !== ''): ?><div class=\\\"stat\\\"><b>Link c\\u1ea5u h\\u00ecnh<\\\/b><div><code><?php echo ssm_e($configLoginUrl); ?><\\\/code><\\\/div><\\\/div><?php endif; ?>\\n            <div class=\\\"stat\\\"><b>Version<\\\/b><div><?php echo ssm_e($config['version']); ?><\\\/div><\\\/div>\\n            <div class=\\\"stat\\\"><b>ZIP URL<\\\/b><div><code><?php echo ssm_e($config['zip_url']); ?><\\\/code><\\\/div><\\\/div>\\n            <div class=\\\"stat\\\"><b>SHA256<\\\/b><div><code><?php echo ssm_e($config['zip_sha256']); ?><\\\/code><\\\/div><\\\/div>\\n            <div class=\\\"stat\\\"><b>File ZIP<\\\/b><div><?php echo ssm_e($config['zip_filename']); ?> <?php echo !empty($config['zip_size']) ? '(' . number_format((float)$config['zip_size']) . ' bytes)' : ''; ?><\\\/div><\\\/div>\\n            <div class=\\\"stat\\\"><b>C\\u1eadp nh\\u1eadt JSON<\\\/b><div><?php echo ssm_e($config['updated_at']); ?><\\\/div><\\\/div>\\n        <\\\/div>\\n\\n        <div class=\\\"card\\\">\\n            <h2>Upload ZIP phi\\u00ean b\\u1ea3n m\\u1edbi<\\\/h2>\\n            <form method=\\\"post\\\" enctype=\\\"multipart\\\/form-data\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"upload_zip\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n                <div class=\\\"row\\\">\\n                    <label>Ch\\u1ecdn file .zip<\\\/label>\\n                    <input type=\\\"file\\\" name=\\\"update_zip\\\" accept=\\\".zip,application\\\/zip,application\\\/x-zip-compressed\\\" required>\\n                    <div class=\\\"hint\\\">File s\\u1ebd t\\u1ef1 l\\u01b0u v\\u00e0o <code>\\\/update-packages\\\/<\\\/code>, t\\u1ef1 t\\u1ea1o <code>zip_url<\\\/code> v\\u00e0 t\\u1ef1 t\\u00ednh SHA256.<\\\/div>\\n                <\\\/div>\\n                <div class=\\\"actions\\\">\\n                    <button class=\\\"btn\\\" type=\\\"submit\\\">\\u2b06\\ufe0f Upload ZIP v\\u00e0 t\\u1ef1 l\\u1ea5y SHA256<\\\/button>\\n                <\\\/div>\\n            <\\\/form>\\n        <\\\/div>\\n\\n        <div class=\\\"card\\\">\\n            <h2>C\\u1ea5u h\\u00ecnh manifest<\\\/h2>\\n            <form method=\\\"post\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"save_config\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n\\n                <div class=\\\"grid\\\">\\n                    <div class=\\\"row\\\">\\n                        <label>Token m\\u00e1y ch\\u1ee7 ch\\u00ednh<\\\/label>\\n                        <input type=\\\"text\\\" name=\\\"master_token\\\" value=\\\"<?php echo ssm_e($config['master_token']); ?>\\\" placeholder=\\\"Ph\\u1ea3i gi\\u1ed1ng SOURCE_SYNC_API_TOKEN tr\\u00ean m\\u00e1y ch\\u1ee7 con\\\" required>\\n                    <\\\/div>\\n                    <div class=\\\"row\\\">\\n                        <label>Phi\\u00ean b\\u1ea3n m\\u1edbi nh\\u1ea5t<\\\/label>\\n                        <input type=\\\"text\\\" name=\\\"version\\\" value=\\\"<?php echo ssm_e($config['version']); ?>\\\" placeholder=\\\"VD: V24\\\" required>\\n                    <\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"row\\\">\\n                    <label>ZIP URL<\\\/label>\\n                    <input type=\\\"text\\\" name=\\\"zip_url\\\" value=\\\"<?php echo ssm_e($config['zip_url']); ?>\\\" placeholder=\\\"\\\/update-packages\\\/web-shop-V24.zip\\\">\\n                    <div class=\\\"hint\\\">C\\u00f3 th\\u1ec3 d\\u00f9ng \\u0111\\u01b0\\u1eddng d\\u1eabn n\\u1ed9i b\\u1ed9 nh\\u01b0 <code>\\\/update-packages\\\/web-shop-V24.zip<\\\/code> ho\\u1eb7c URL \\u0111\\u1ea7y \\u0111\\u1ee7.<\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"row\\\">\\n                    <label>SHA256<\\\/label>\\n                    <input type=\\\"text\\\" name=\\\"zip_sha256\\\" value=\\\"<?php echo ssm_e($config['zip_sha256']); ?>\\\" placeholder=\\\"T\\u1ef1 t\\u1ea1o sau khi upload ZIP\\\">\\n                    <div class=\\\"hint\\\">N\\u1ebfu upload ZIP b\\u1eb1ng form ph\\u00eda tr\\u00ean, SHA256 s\\u1ebd t\\u1ef1 \\u0111i\\u1ec1n v\\u00e0 l\\u01b0u v\\u00e0o JSON.<\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"grid\\\">\\n                    <div class=\\\"row\\\">\\n                        <label>Th\\u1eddi gian ph\\u00e1t h\\u00e0nh<\\\/label>\\n                        <input type=\\\"text\\\" name=\\\"released_at\\\" value=\\\"<?php echo ssm_e($config['released_at']); ?>\\\" placeholder=\\\"2026-06-28 00:00:00\\\">\\n                    <\\\/div>\\n                    <div class=\\\"row\\\">\\n                        <label>B\\u1eaft bu\\u1ed9c c\\u1eadp nh\\u1eadt?<\\\/label>\\n                        <select name=\\\"required\\\">\\n                            <option value=\\\"0\\\" <?php echo empty($config['required']) ? 'selected' : ''; ?>>Kh\\u00f4ng<\\\/option>\\n                            <option value=\\\"1\\\" <?php echo !empty($config['required']) ? 'selected' : ''; ?>>C\\u00f3<\\\/option>\\n                        <\\\/select>\\n                    <\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"row\\\">\\n                    <label>Ghi ch\\u00fa c\\u1eadp nh\\u1eadt<\\\/label>\\n                    <textarea name=\\\"changelog\\\" placeholder=\\\"- N\\u1ed9i dung c\\u1eadp nh\\u1eadt 1&#10;- N\\u1ed9i dung c\\u1eadp nh\\u1eadt 2\\\"><?php echo ssm_e($config['changelog']); ?><\\\/textarea>\\n                <\\\/div>\\n\\n                <div class=\\\"grid\\\">\\n                    <div class=\\\"row\\\">\\n                        <label>IP m\\u00e1y ch\\u1ee7 con \\u0111\\u01b0\\u1ee3c ph\\u00e9p<\\\/label>\\n                        <textarea name=\\\"allowed_client_ips\\\" placeholder=\\\"M\\u1ed7i d\\u00f2ng 1 IP public ho\\u1eb7c local\\\/server IP&#10;VD public: 103.345.23.25&#10;VD server local: 14.225.218.36&#10;VD private: 192.168.1.10\\\"><?php echo ssm_e(ssm_array_to_text($config['allowed_client_ips'])); ?><\\\/textarea>\\n                        <div class=\\\"hint\\\">\\u0110\\u1ec3 tr\\u1ed1ng n\\u1ebfu kh\\u00f4ng mu\\u1ed1n ki\\u1ec3m tra IP. C\\u00f3 th\\u1ec3 nh\\u1eadp IP public\\\/NAT ho\\u1eb7c IP server local\\\/private c\\u1ee7a m\\u00e1y ch\\u1ee7 con.<\\\/div>\\n                    <\\\/div>\\n                    <div class=\\\"row\\\">\\n                        <label>Domain m\\u00e1y ch\\u1ee7 con \\u0111\\u01b0\\u1ee3c ph\\u00e9p<\\\/label>\\n                        <textarea name=\\\"allowed_client_domains\\\" placeholder=\\\"M\\u1ed7i d\\u00f2ng 1 domain&#10;VD: shop-con.example.com\\\"><?php echo ssm_e(ssm_array_to_text($config['allowed_client_domains'])); ?><\\\/textarea>\\n                        <div class=\\\"hint\\\">\\u0110\\u1ec3 tr\\u1ed1ng n\\u1ebfu kh\\u00f4ng mu\\u1ed1n ki\\u1ec3m tra domain. N\\u1ebfu \\u0111i\\u1ec1n c\\u1ea3 IP v\\u00e0 domain th\\u00ec request ph\\u1ea3i kh\\u1edbp c\\u1ea3 hai. V\\u1edbi IP, h\\u1ec7 th\\u1ed1ng ch\\u1ea5p nh\\u1eadn IP public ho\\u1eb7c IP local\\\/server IP do m\\u00e1y ch\\u1ee7 con g\\u1eedi k\\u00e8m token\\\/header\\\/query.<\\\/div>\\n                    <\\\/div>\\n                <\\\/div>\\n\\n                <div class=\\\"actions\\\">\\n                    <button class=\\\"btn\\\" type=\\\"submit\\\">\\ud83d\\udcbe L\\u01b0u c\\u1ea5u h\\u00ecnh v\\u00e0o JSON<\\\/button>\\n                <\\\/div>\\n            <\\\/form>\\n\\n            <form method=\\\"post\\\" style=\\\"margin-top:10px;\\\">\\n                <input type=\\\"hidden\\\" name=\\\"action\\\" value=\\\"recalc_sha256\\\">\\n                <input type=\\\"hidden\\\" name=\\\"csrf\\\" value=\\\"<?php echo ssm_e($csrf); ?>\\\">\\n                <button class=\\\"btn secondary\\\" type=\\\"submit\\\">\\ud83d\\udd01 L\\u1ea5y l\\u1ea1i SHA256 t\\u1eeb ZIP hi\\u1ec7n t\\u1ea1i<\\\/button>\\n            <\\\/form>\\n        <\\\/div>\\n    <?php endif; ?>\\n<\\\/div>\\n<\\\/body>\\n<\\\/html>\\n\",\n        \"time\": \"2026-07-01 13:27:56\"\n    }\n]",
        "time": "2026-07-01 23:25:40"
    },
    {
        "file": "\/home\/coicom\/1.1ccmm.my\/data\/settings.json",
        "content": "{\n    \"site_title\": \"Shop Balance\",\n    \"site_description\": \"H\u1ec7 th\u1ed1ng b\u00e1n s\u1ea3n ph\u1ea9m t\u1ef1 \u0111\u1ed9ng b\u1eb1ng s\u1ed1 d\u01b0.\",\n    \"site_keywords\": \"shop t\u1ef1 \u0111\u1ed9ng, s\u1ea3n ph\u1ea9m s\u1ed1, n\u1ea1p ti\u1ec1n, \u0111\u01a1n h\u00e0ng t\u1ef1 \u0111\u1ed9ng\",\n    \"site_author\": \"\",\n    \"site_robots\": \"index,follow\",\n    \"site_canonical_url\": \"\",\n    \"home_notice\": \"Nh\u1eadp username, email ho\u1eb7c s\u1ed1 \u0111i\u1ec7n tho\u1ea1i k\u00e8m m\u1eadt kh\u1ea9u \u0111\u1ec3 \u0111\u0103ng nh\u1eadp. T\u00e0i kho\u1ea3n ch\u01b0a c\u00f3 s\u1ebd t\u1ef1 \u0111\u0103ng k\u00fd; t\u00e0i kho\u1ea3n c\u0169 ch\u01b0a c\u00f3 m\u1eadt kh\u1ea9u s\u1ebd \u0111\u01b0\u1ee3c l\u01b0u m\u1eadt kh\u1ea9u \u1edf l\u1ea7n \u0111\u0103ng nh\u1eadp \u0111\u1ea7u ti\u00ean.\",\n    \"site_base_url\": \"\",\n    \"site_logo_path\": \"\",\n    \"site_logo_alt\": \"\",\n    \"home_banner_1_path\": \"\",\n    \"home_banner_1_alt\": \"\",\n    \"home_banner_1_link\": \"\",\n    \"home_banner_2_path\": \"\",\n    \"home_banner_2_alt\": \"\",\n    \"home_banner_2_link\": \"\",\n    \"home_banner_3_path\": \"\",\n    \"home_banner_3_alt\": \"\",\n    \"home_banner_3_link\": \"\",\n    \"webhook_secret\": \"f6d94c035077c7e06004169df7fe721edd2026aea0ad6bb45f1f53a5e0461514\",\n    \"webhook_hmac_enabled\": \"1\",\n    \"admin_username\": \"admin\",\n    \"admin_password_hash\": \"$2y$10$t1GabqIKA62ttK8tKlxN1.ZGxKY7JkMLwf.nOxzTbaxl4SwM9\\\/XTO\",\n    \"admin_access_key\": \"9bc38444cfe193271934113f\",\n    \"admin_access_setup_done\": \"1\",\n    \"deposit_bank_name\": \"\",\n    \"deposit_account_number\": \"\",\n    \"deposit_account_owner\": \"\",\n    \"deposit_transfer_content\": \"NAP {id}\",\n    \"deposit_quick_amounts\": \"10000,20000,50000,100000,200000,500000,1000000,2000000\",\n    \"deposit_max_invoice_amount\": \"5000000\",\n    \"deposit_vietqr_bank_id\": \"\",\n    \"deposit_vietqr_template\": \"compact2\",\n    \"deposit_vietqr_display_mode\": \"qr_and_info\",\n    \"deposit_invoice_expire_minutes\": \"30\",\n    \"deposit_promo_enabled\": \"0\",\n    \"deposit_promo_rules\": \"100000|5\\n500000|10\\n1000000|15\",\n    \"deposit_note\": \"Vui l\u00f2ng t\u1ea1o h\u00f3a \u0111\u01a1n n\u1ea1p ti\u1ec1n tr\u01b0\u1edbc khi chuy\u1ec3n kho\u1ea3n. H\u1ec7 th\u1ed1ng s\u1ebd t\u1ef1 th\u00eam ID c\u1ee7a b\u1ea1n v\u00e0o 3 s\u1ed1 cu\u1ed1i c\u1ee7a s\u1ed1 ti\u1ec1n c\u1ea7n chuy\u1ec3n \u0111\u1ec3 t\u1ef1 \u0111\u1ed9ng c\u1ed9ng \u0111\u00fang t\u00e0i kho\u1ea3n.\",\n    \"deposit_guide_html\": \"<p>V\u00e0o trang <b>N\u1ea1p Ti\u1ec1n<\\\/b>, ch\u1ecdn nhanh s\u1ed1 ti\u1ec1n c\u1ea7n n\u1ea1p ho\u1eb7c nh\u1eadp s\u1ed1 ti\u1ec1n g\u1ed1c b\u1ea1n mu\u1ed1n n\u1ea1p, sau \u0111\u00f3 b\u1ea5m <b>T\u1ea1o h\u00f3a \u0111\u01a1n n\u1ea1p ti\u1ec1n<\\\/b>.<\\\/p><p>V\u00ed d\u1ee5 ID c\u1ee7a b\u1ea1n l\u00e0 <b>{id}<\\\/b>, b\u1ea1n mu\u1ed1n n\u1ea1p <b>120.000\u0111<\\\/b> th\u00ec s\u1ed1 ti\u1ec1n c\u1ea7n chuy\u1ec3n s\u1ebd l\u00e0 <b>120.{id}\u0111<\\\/b>.<\\\/p><p>N\u1ebfu s\u1ed1 ti\u1ec1n chuy\u1ec3n kho\u1ea3n kh\u00f4ng c\u00f3 ID h\u1ee3p l\u1ec7 \u1edf 3 s\u1ed1 cu\u1ed1i, h\u1ec7 th\u1ed1ng c\u00f3 th\u1ec3 kh\u00f4ng t\u1ef1 nh\u1eadn di\u1ec7n \u0111\u00fang t\u00e0i kho\u1ea3n n\u1ea1p ti\u1ec1n.<\\\/p>\",\n    \"deposit_invoice_notice\": \"Vui l\u00f2ng chuy\u1ec3n kho\u1ea3n \u0111\u00fang ch\u00ednh x\u00e1c s\u1ed1 ti\u1ec1n c\u1ea7n chuy\u1ec3n b\u00ean d\u01b0\u1edbi. H\u00f3a \u0111\u01a1n s\u1ebd \u0111\u01b0\u1ee3c c\u1ed9ng ti\u1ec1n t\u1ef1 \u0111\u1ed9ng khi h\u1ec7 th\u1ed1ng nh\u1eadn giao d\u1ecbch, ho\u1eb7c admin c\u00f3 th\u1ec3 duy\u1ec7t th\u1ee7 c\u00f4ng trong qu\u1ea3n tr\u1ecb.\",\n    \"order_detail_notice_html\": \"\",\n    \"order_auto_delete_days\": \"30\",\n    \"inactive_user_delete_days\": \"180\",\n    \"inactive_user_delete_months\": \"6\",\n    \"user_delete_balance_threshold\": \"1000\",\n    \"deposit_history_auto_delete_months\": \"6\",\n    \"maintenance_enabled\": \"0\",\n    \"maintenance_message\": \"Website \u0111ang b\u1ea3o tr\u00ec, vui l\u00f2ng quay l\u1ea1i sau.\",\n    \"ticket_auto_delete_days\": \"0\",\n    \"ticket_telegram_bot_token\": \"\",\n    \"ticket_telegram_chat_id\": \"\",\n    \"telegram_shop_enabled\": \"0\",\n    \"telegram_shop_bot_token\": \"\",\n    \"telegram_shop_webhook_secret\": \"\",\n    \"backup_auto_enabled\": \"1\",\n    \"backup_interval_hours\": \"24\",\n    \"backup_keep_count\": \"10\",\n    \"backup_keep_days\": \"30\",\n    \"backup_restore_enabled\": \"1\",\n    \"backup_cron_token\": \"9f7e37129b685d070c2181fc18d23345c34257c5957e6f52\",\n    \"backup_last_at\": \"2026-06-30 07:19:20\",\n    \"backup_last_auto_at\": \"2026-06-30 07:19:20\",\n    \"backup_last_file\": \"auto-backup-20260630-071920-4e82bc24.zip\",\n    \"backup_last_status\": \"success\",\n    \"backup_last_error\": \"\"\n}",
        "time": "2026-07-01 13:56:49"
    },
    {
        "file": "\/home\/coicom\/1.1ccmm.my\/README_PUBLIC_LAYOUT.txt",
        "content": "B\u1ed1 c\u1ee5c sau khi t\u1ed1i \u01b0u:\n\n- public\/: ch\u1ee9a to\u00e0n b\u1ed9 m\u00e3 ngu\u1ed3n \u1ee9ng d\u1ee5ng v\u00e0 c\u00e1c file web-facing.\n- data\/, backup\/, codes\/, kho-tdata\/, uploads\/, source-sync-master-data\/: th\u01b0 m\u1ee5c private n\u1eb1m ngang c\u1ea5p public, d\u00f9ng \u0111\u1ec3 l\u01b0u JSON, backup, m\u00e3\/code s\u1ea3n ph\u1ea9m, kho h\u00e0ng, file t\u1ea1m v\u00e0 c\u1ea5u h\u00ecnh source-sync master.\n- .htaccess \u1edf th\u01b0 m\u1ee5c g\u1ed1c rewrite n\u1ed9i b\u1ed9 request v\u00e0o public\/ \u0111\u1ec3 gi\u1eef nguy\u00ean URL nh\u01b0 tr\u01b0\u1edbc, v\u00ed d\u1ee5 \/products, \/admin, \/sitemap.xml.\n\nKhuy\u1ebfn ngh\u1ecb tri\u1ec3n khai an to\u00e0n nh\u1ea5t:\n1. N\u1ebfu hosting cho ph\u00e9p ch\u1ecdn document root, h\u00e3y tr\u1ecf document root tr\u1ef1c ti\u1ebfp v\u00e0o th\u01b0 m\u1ee5c public\/. Khi \u0111\u00f3 c\u00e1c th\u01b0 m\u1ee5c private ngang c\u1ea5p public kh\u00f4ng th\u1ec3 truy c\u1eadp b\u1eb1ng URL.\n2. N\u1ebfu hosting kh\u00f4ng cho \u0111\u1ed5i document root, upload c\u1ea3 g\u00f3i n\u00e0y; file .htaccess \u1edf g\u1ed1c s\u1ebd gi\u1eef URL kh\u00f4ng c\u00f3 \/public\/ v\u00e0 ch\u1eb7n c\u00e1c th\u01b0 m\u1ee5c private.\n3. N\u1ebfu d\u00f9ng Nginx ho\u1eb7c m\u00f4i tr\u01b0\u1eddng kh\u00f4ng \u0111\u1ecdc .htaccess, b\u1eaft bu\u1ed9c c\u1ea5u h\u00ecnh root v\u1ec1 public\/ ho\u1eb7c deny tr\u1ef1c ti\u1ebfp c\u00e1c \u0111\u01b0\u1eddng d\u1eabn \/data, \/backup, \/codes, \/kho-tdata, \/uploads, \/source-sync-master-data. C\u00e1c th\u01b0 m\u1ee5c private c\u00f3 index.php\/web.config\/.htaccess b\u1ea3o v\u1ec7 b\u1ed5 sung, nh\u01b0ng file t\u0129nh c\u00f3 th\u1ec3 b\u1ecb web server ph\u1ee5c v\u1ee5 tr\u01b0\u1edbc khi PHP ch\u1ea1y n\u1ebfu web root \u0111\u1eb7t sai.\n",
        "time": "2026-07-01 13:30:55"
    },
    {
        "file": "\/home\/coicom\/1.1ccmm.my\/source-sync-master-data\/source-sync-master-config.json",
        "content": "{\n    \"master_token\": \"bfe414a0a2a29256\",\n    \"version\": \"V1.8\",\n    \"zip_url\": \"\/update-packages\/65458_backup_restore_round_robin_deposit_history_fixed.zip\",\n    \"zip_sha256\": \"3111a3acd50550c6f32c133e1143200ba511863ee0ed4c6459dcdfebe2bd794e\",\n    \"zip_filename\": \"65458_backup_restore_round_robin_deposit_history_fixed.zip\",\n    \"zip_size\": 2677981,\n    \"released_at\": \"2026-06-30 12:45:46\",\n    \"changelog\": \"\",\n    \"required\": true,\n    \"allowed_client_ips\": [\n        \"14.225.218.36\",\n        \"14.225.219.71\"\n    ],\n    \"allowed_client_domains\": [\n        \"taphoatele.com\",\n        \"acctelegram.net\",\n        \"1ccmm.my\",\n        \"1.1ccmm.my\"\n    ],\n    \"updated_at\": \"2026-06-30 12:45:46\",\n    \"config_password_hash\": \"$2y$10$HHl.YoV15spCHl6g6fGKsO5T7vr12Bo.zfGZ0knK\/Dkpcz12Tqn5e\",\n    \"config_access_key\": \"9bc38444cfe193271934113f\",\n    \"config_setup_done\": true\n}",
        "time": "2026-07-01 13:29:39"
    },
    {
        "file": "\/home\/coicom\/1.1ccmm.my\/source-sync-master-data\/source-sync-login-rate.json",
        "content": "{\n    \"login:7a1a4051beabf07f10a0ff2171cc95604e1a86e6\": [\n        1782798339\n    ]\n}",
        "time": "2026-07-01 13:29:37"
    },
    {
        "file": "\/home\/coicom\/1.1ccmm.my\/public\/webhook.php",
        "content": "<?php\nrequire_once __DIR__ . '\/includes\/functions.php';\nensure_data_files();\nsend_security_headers(true);\ntry {\n    if (security_guard_active()) { json_response(array('ok'=>true,'guarded'=>true), 200); }\n    security_request_rate_guard('webhook_request', array(request_ip_address()), 120, 60, 300, 'Webhook nh\u1eadn qu\u00e1 nhi\u1ec1u request, vui l\u00f2ng th\u1eed l\u1ea1i sau.');\n    $payload = read_webhook_payload();\n    $result = process_deposit_webhook($payload);\n    json_response($result, 200);\n} catch (Exception $e) {\n    security_log_event('webhook_exception', 'L\u1ed7i x\u1eed l\u00fd webhook', array('error' => $e->getMessage()));\n    json_response(array('ok'=>false,'error'=>security_generic_message()),500);\n}\n",
        "time": "2026-07-01 13:28:15"
    },
    {
        "file": "\/home\/coicom\/1.1ccmm.my\/public\/source-sync-master-api\/source-sync-config.php",
        "content": "<?php\n\/**\n * Trang c\u1ea5u h\u00ecnh m\u00e1y ch\u1ee7 ch\u00ednh cho update-manifest.php.\n *\n * \u0110\u1eb7t file n\u00e0y trong \/source-sync-master-api\/ tr\u00ean M\u00c1Y CH\u1ee6 CH\u00cdNH.\n * M\u1ecdi c\u1ea5u h\u00ecnh manifest \u0111\u01b0\u1ee3c l\u01b0u v\u00e0o JSON:\n *   \/source-sync-master-data\/source-sync-master-config.json\n *\n * B\u1ea3o m\u1eadt trang c\u1ea5u h\u00ecnh:\n * - L\u1ea7n \u0111\u1ea7u truy c\u1eadp tr\u1ef1c ti\u1ebfp file n\u00e0y \u0111\u1ec3 t\u1ea1o m\u1eadt kh\u1ea9u v\u00e0 token truy c\u1eadp.\n * - Nh\u1eefng l\u1ea7n sau ph\u1ea3i truy c\u1eadp d\u1ea1ng source-sync-config.php?k=TOKEN.\n * - Bi\u1ebfn m\u1eadt kh\u1ea9u b\u00ean d\u01b0\u1edbi ch\u1ec9 c\u00f2n d\u00f9ng t\u01b0\u01a1ng th\u00edch cho b\u1ea3n c\u0169 n\u1ebfu \u0111\u00e3 t\u1ef1 \u0111\u1ed5i tr\u01b0\u1edbc \u0111\u00e2y.\n *\/\n\n\/\/ =========================\n\/\/ M\u1eacT KH\u1ea8U T\u01af\u01a0NG TH\u00cdCH B\u1ea2N C\u0168 - KH\u00d4NG C\u1ea6N S\u1eecA N\u1ebeU D\u00d9NG SETUP L\u1ea6N \u0110\u1ea6U\n\/\/ =========================\n$SOURCE_SYNC_CONFIG_PASSWORD = 'doi-mat-khau-quan-tri-nay';\n\n\/\/ Gi\u1edbi h\u1ea1n dung l\u01b0\u1ee3ng ZIP upload qua trang n\u00e0y. C\u00f2n ph\u1ee5 thu\u1ed9c upload_max_filesize\/post_max_size c\u1ee7a hosting.\n$SOURCE_SYNC_CONFIG_MAX_UPLOAD_BYTES = 300 * 1024 * 1024; \/\/ 300MB\n\n\/\/ =========================\n\/\/ KH\u00d4NG C\u1ea6N S\u1eecA PH\u1ea6N B\u00caN D\u01af\u1edaI N\u1ebeU KH\u00d4NG C\u1ea6N\n\/\/ =========================\n\n@ini_set('display_errors', '0');\n@ini_set('display_startup_errors', '0');\n@ini_set('log_errors', '1');\n@ini_set('html_errors', '0');\n\ndate_default_timezone_set('Asia\/Ho_Chi_Minh');\n\nheader('X-Robots-Tag: noindex, nofollow', true);\nheader('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');\nheader('X-Frame-Options: SAMEORIGIN');\nheader('X-Content-Type-Options: nosniff');\n\nsession_name('source_sync_master_config_session');\n@session_start();\n\n$MASTER_API_DIR = __DIR__;\n$MASTER_ROOT_DIR = dirname(__DIR__);\n$MASTER_PRIVATE_ROOT_DIR = dirname($MASTER_ROOT_DIR);\n$MASTER_DATA_DIR = $MASTER_PRIVATE_ROOT_DIR . '\/source-sync-master-data';\n$MASTER_CONFIG_FILE = $MASTER_DATA_DIR . '\/source-sync-master-config.json';\n$MASTER_PACKAGE_DIR = $MASTER_ROOT_DIR . '\/update-packages';\n$MASTER_PACKAGE_PUBLIC_DIR = '\/update-packages';\n\n\nfunction ssm_client_ip() {\n    return isset($_SERVER['REMOTE_ADDR']) ? trim((string)$_SERVER['REMOTE_ADDR']) : '';\n}\n\nfunction ssm_rate_file() {\n    global $MASTER_DATA_DIR;\n    return $MASTER_DATA_DIR . '\/source-sync-login-rate.json';\n}\n\nfunction ssm_rate_limit_guard($key, $maxAttempts = 10, $windowSeconds = 300) {\n    ssm_ensure_dirs();\n    $file = ssm_rate_file();\n    $data = array();\n    if (is_file($file)) {\n        $raw = @file_get_contents($file);\n        $json = json_decode((string)$raw, true);\n        if (is_array($json)) $data = $json;\n    }\n    $now = time();\n    foreach ($data as $k => $rows) {\n        if (!is_array($rows)) { unset($data[$k]); continue; }\n        $data[$k] = array_values(array_filter($rows, function($ts) use ($now, $windowSeconds) { return intval($ts) > ($now - $windowSeconds); }));\n        if (!$data[$k]) unset($data[$k]);\n    }\n    if (!isset($data[$key]) || !is_array($data[$key])) $data[$key] = array();\n    if (count($data[$key]) >= $maxAttempts) {\n        @file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);\n        return false;\n    }\n    $data[$key][] = $now;\n    @file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);\n    return true;\n}\n\nfunction ssm_e($value) {\n    return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');\n}\n\nfunction ssm_now() {\n    return date('Y-m-d H:i:s');\n}\n\nfunction ssm_ensure_dirs() {\n    global $MASTER_DATA_DIR, $MASTER_PACKAGE_DIR;\n    if (!is_dir($MASTER_DATA_DIR)) @mkdir($MASTER_DATA_DIR, 0755, true);\n    if (!is_dir($MASTER_PACKAGE_DIR)) @mkdir($MASTER_PACKAGE_DIR, 0755, true);\n\n    $htaccess = $MASTER_DATA_DIR . '\/.htaccess';\n    $rules = \"Options -Indexes\n<IfModule mod_authz_core.c>\nRequire all denied\n<\/IfModule>\n<IfModule !mod_authz_core.c>\nOrder deny,allow\nDeny from all\n<\/IfModule>\n\";\n    if (!is_file($htaccess) || trim((string)@file_get_contents($htaccess)) !== trim($rules)) {\n        @file_put_contents($htaccess, $rules);\n    }\n    $indexPhp = $MASTER_DATA_DIR . '\/index.php';\n    if (!is_file($indexPhp)) @file_put_contents($indexPhp, \"<?php\nhttp_response_code(404);\nheader('X-Robots-Tag: noindex, nofollow', true);\necho '404 Not Found';\nexit;\n\");\n    $index = $MASTER_DATA_DIR . '\/index.html';\n    if (!is_file($index)) @file_put_contents($index, '');\n\n    $webConfig = $MASTER_DATA_DIR . '\/web.config';\n    $webRules = <<<'XML'\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n  <system.webServer>\n    <security>\n      <authorization>\n        <clear \/>\n        <add accessType=\"Deny\" users=\"*\" \/>\n      <\/authorization>\n    <\/security>\n    <directoryBrowse enabled=\"false\" \/>\n  <\/system.webServer>\n<\/configuration>\nXML;\n    $webRules .= \"\n\";\n    if (!is_file($webConfig) || trim((string)@file_get_contents($webConfig)) !== trim($webRules)) @file_put_contents($webConfig, $webRules, LOCK_EX);\n    @chmod($MASTER_DATA_DIR, 0700);\n\n    $pkgIndex = $MASTER_PACKAGE_DIR . '\/index.html';\n    if (!is_file($pkgIndex)) @file_put_contents($pkgIndex, '');\n}\n\nfunction ssm_default_config() {\n    return array(\n        'master_token' => '',\n        'version' => 'V24',\n        'zip_url' => '',\n        'zip_sha256' => '',\n        'zip_filename' => '',\n        'zip_size' => 0,\n        'released_at' => ssm_now(),\n        'changelog' => '',\n        'required' => false,\n        'allowed_client_ips' => array(),\n        'allowed_client_domains' => array(),\n        'updated_at' => '',\n        'config_password_hash' => '',\n        'config_access_key' => '',\n        'config_setup_done' => false,\n    );\n}\n\nfunction ssm_load_config() {\n    global $MASTER_CONFIG_FILE;\n    $defaults = ssm_default_config();\n    if (!is_file($MASTER_CONFIG_FILE)) return $defaults;\n    $raw = file_get_contents($MASTER_CONFIG_FILE);\n    $json = json_decode($raw, true);\n    if (!is_array($json)) return $defaults;\n    return array_merge($defaults, $json);\n}\n\nfunction ssm_save_config($config) {\n    global $MASTER_CONFIG_FILE;\n    ssm_ensure_dirs();\n    $config['updated_at'] = ssm_now();\n    $json = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);\n    if ($json === false) return false;\n    $ok = @file_put_contents($MASTER_CONFIG_FILE, $json, LOCK_EX) !== false;\n    if ($ok) @chmod($MASTER_CONFIG_FILE, 0600);\n    return $ok;\n}\n\nfunction ssm_text_to_array($value) {\n    if (is_array($value)) $value = implode(\"\\n\", $value);\n    $value = trim((string)$value);\n    if ($value === '') return array();\n    return array_values(array_filter(array_map('trim', preg_split('\/[\\r\\n,]+\/', $value)), function($v) { return $v !== ''; }));\n}\n\nfunction ssm_array_to_text($value) {\n    if (!is_array($value)) return trim((string)$value);\n    return implode(\"\\n\", array_values(array_filter(array_map('trim', array_map('strval', $value)), function($v) { return $v !== ''; })));\n}\n\nfunction ssm_safe_zip_filename($name) {\n    $name = basename((string)$name);\n    $name = preg_replace('\/[^a-zA-Z0-9._-]+\/', '-', $name);\n    $name = trim($name, '.-_');\n    if ($name === '') $name = 'source-update.zip';\n    if (strtolower(substr($name, -4)) !== '.zip') $name .= '.zip';\n    return $name;\n}\n\nfunction ssm_internal_zip_path_from_url($zipUrl) {\n    global $MASTER_ROOT_DIR;\n    $zipUrl = trim((string)$zipUrl);\n    if ($zipUrl === '') return '';\n    if (preg_match('#^https?:\/\/#i', $zipUrl)) {\n        $parts = parse_url($zipUrl);\n        if (!$parts || empty($parts['path'])) return '';\n        $zipUrl = $parts['path'];\n    }\n    if ($zipUrl[0] !== '\/') $zipUrl = '\/' . $zipUrl;\n    $path = realpath($MASTER_ROOT_DIR . $zipUrl);\n    if ($path === false || !is_file($path)) return '';\n    return $path;\n}\n\nfunction ssm_flash($type, $message) {\n    $_SESSION['ssm_flash'][] = array('type' => $type, 'message' => $message);\n}\n\nfunction ssm_get_flash() {\n    $flash = isset($_SESSION['ssm_flash']) && is_array($_SESSION['ssm_flash']) ? $_SESSION['ssm_flash'] : array();\n    unset($_SESSION['ssm_flash']);\n    return $flash;\n}\n\nfunction ssm_logged_in() {\n    return !empty($_SESSION['ssm_logged_in']);\n}\n\nfunction ssm_generate_access_key($bytes = 12) {\n    return strtolower(substr(bin2hex(random_bytes(max(8, intval($bytes)))), 0, 24));\n}\n\nfunction ssm_normalize_access_key($key) {\n    $key = trim((string)$key);\n    $key = preg_replace('\/[^A-Za-z0-9_-]\/', '', $key);\n    return substr($key, 0, 64);\n}\n\nfunction ssm_setup_required($config = null) {\n    if (!is_array($config)) $config = ssm_load_config();\n    $done = !empty($config['config_setup_done']);\n    $key = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\n    $hash = isset($config['config_password_hash']) ? (string)$config['config_password_hash'] : '';\n    return !$done || $key === '' || $hash === '';\n}\n\nfunction ssm_access_gate_passed($config = null) {\n    if (!is_array($config)) $config = ssm_load_config();\n    if (ssm_setup_required($config)) return true;\n    if (ssm_logged_in()) return true;\n    if (!empty($_SESSION['ssm_access_granted'])) return true;\n    $key = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\n    $given = isset($_GET['k']) ? ssm_normalize_access_key($_GET['k']) : '';\n    if ($key !== '' && $given !== '' && hash_equals($key, $given)) {\n        $_SESSION['ssm_access_granted'] = true;\n        return true;\n    }\n    return false;\n}\n\nfunction ssm_fake_404() {\n    http_response_code(404);\n    header('Content-Type: text\/plain; charset=utf-8');\n    echo '404 Not Found';\n    exit;\n}\n\nfunction ssm_check_config_password($password, $config) {\n    $hash = isset($config['config_password_hash']) ? (string)$config['config_password_hash'] : '';\n    if ($hash !== '') return password_verify((string)$password, $hash);\n    global $SOURCE_SYNC_CONFIG_PASSWORD;\n    if ($SOURCE_SYNC_CONFIG_PASSWORD !== '' && $SOURCE_SYNC_CONFIG_PASSWORD !== 'doi-mat-khau-quan-tri-nay') {\n        return hash_equals((string)$SOURCE_SYNC_CONFIG_PASSWORD, (string)$password);\n    }\n    return false;\n}\n\nfunction ssm_increment_version($version) {\n    $version = trim((string)$version);\n    if ($version === '') return 'V1.0';\n    if (preg_match('\/^(.*?)(\\d+)\\.(\\d+)$\/', $version, $m)) {\n        return $m[1] . $m[2] . '.' . (intval($m[3]) + 1);\n    }\n    if (preg_match('\/^(.*?)(\\d+)$\/', $version, $m)) {\n        return $m[1] . (intval($m[2]) + 1);\n    }\n    return $version . '.1';\n}\n\nfunction ssm_require_csrf() {\n    $posted = isset($_POST['csrf']) ? (string)$_POST['csrf'] : '';\n    $stored = isset($_SESSION['ssm_csrf']) ? (string)$_SESSION['ssm_csrf'] : '';\n    if ($stored === '' || $posted === '' || !hash_equals($stored, $posted)) {\n        ssm_flash('error', 'CSRF token kh\u00f4ng h\u1ee3p l\u1ec7, h\u00e3y th\u1eed l\u1ea1i.');\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n        exit;\n    }\n}\n\nfunction ssm_csrf_token() {\n    if (empty($_SESSION['ssm_csrf'])) {\n        $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\n    }\n    return $_SESSION['ssm_csrf'];\n}\n\nssm_ensure_dirs();\n$config = ssm_load_config();\n$setupRequired = ssm_setup_required($config);\nif (!$setupRequired && !ssm_access_gate_passed($config)) {\n    ssm_fake_404();\n}\n\nif ($_SERVER['REQUEST_METHOD'] === 'POST') {\n    $action = isset($_POST['action']) ? (string)$_POST['action'] : '';\n\n    if ($setupRequired && $action === 'setup_config') {\n        ssm_require_csrf();\n        $password = isset($_POST['password']) ? (string)$_POST['password'] : '';\n        $password2 = isset($_POST['password_confirm']) ? (string)$_POST['password_confirm'] : '';\n        $accessKey = isset($_POST['config_access_key']) ? ssm_normalize_access_key($_POST['config_access_key']) : '';\n        if ($password !== $password2) {\n            ssm_flash('error', 'M\u1eadt kh\u1ea9u nh\u1eadp l\u1ea1i kh\u00f4ng kh\u1edbp.');\n        } elseif (strlen($password) < 8) {\n            ssm_flash('error', 'M\u1eadt kh\u1ea9u c\u1ea5u h\u00ecnh ph\u1ea3i c\u00f3 \u00edt nh\u1ea5t 8 k\u00fd t\u1ef1.');\n        } elseif ($accessKey === '' || strlen($accessKey) < 8) {\n            ssm_flash('error', 'Token truy c\u1eadp ph\u1ea3i c\u00f3 \u00edt nh\u1ea5t 8 k\u00fd t\u1ef1.');\n        } else {\n            $config['config_password_hash'] = password_hash($password, PASSWORD_DEFAULT);\n            $config['config_access_key'] = $accessKey;\n            $config['config_setup_done'] = true;\n            if (ssm_save_config($config)) {\n                $_SESSION['ssm_access_granted'] = true;\n                $_SESSION['ssm_logged_in'] = true;\n                $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\n                ssm_flash('success', '\u0110\u00e3 thi\u1ebft l\u1eadp m\u1eadt kh\u1ea9u v\u00e0 token truy c\u1eadp Source Sync Master.');\n            } else {\n                ssm_flash('error', 'Kh\u00f4ng th\u1ec3 l\u01b0u c\u1ea5u h\u00ecnh b\u1ea3o v\u1ec7 Source Sync Master.');\n            }\n        }\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n        exit;\n    }\n\n    if ($action === 'login') {\n        ssm_require_csrf();\n        $password = isset($_POST['password']) ? (string)$_POST['password'] : '';\n        $rateKey = 'login:' . sha1(ssm_client_ip());\n        if (!ssm_rate_limit_guard($rateKey, 10, 300)) {\n            ssm_flash('error', 'B\u1ea1n \u0111\u0103ng nh\u1eadp sai\/thao t\u00e1c qu\u00e1 nhi\u1ec1u l\u1ea7n. Vui l\u00f2ng th\u1eed l\u1ea1i sau.');\n            header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n            exit;\n        }\n        if (ssm_check_config_password($password, $config)) {\n            $_SESSION['ssm_logged_in'] = true;\n            $_SESSION['ssm_access_granted'] = true;\n            $_SESSION['ssm_csrf'] = bin2hex(random_bytes(16));\n            ssm_flash('success', '\u0110\u0103ng nh\u1eadp th\u00e0nh c\u00f4ng.');\n        } else {\n            ssm_flash('error', 'M\u1eadt kh\u1ea9u kh\u00f4ng \u0111\u00fang.');\n        }\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n        exit;\n    }\n\n    if ($action === 'logout') {\n        unset($_SESSION['ssm_logged_in']);\n        unset($_SESSION['ssm_access_granted']);\n        unset($_SESSION['ssm_csrf']);\n        ssm_flash('success', '\u0110\u00e3 \u0111\u0103ng xu\u1ea5t.');\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n        exit;\n    }\n\n    if (!ssm_logged_in()) {\n        ssm_flash('error', 'B\u1ea1n c\u1ea7n \u0111\u0103ng nh\u1eadp.');\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n        exit;\n    }\n\n    ssm_require_csrf();\n    $config = ssm_load_config();\n\n    if ($action === 'save_config') {\n        $config['master_token'] = trim((string)($_POST['master_token'] ?? ''));\n        $config['version'] = trim((string)($_POST['version'] ?? ''));\n        $config['zip_url'] = trim((string)($_POST['zip_url'] ?? ''));\n        $config['zip_sha256'] = strtolower(trim((string)($_POST['zip_sha256'] ?? '')));\n        $config['released_at'] = trim((string)($_POST['released_at'] ?? ''));\n        $config['changelog'] = (string)($_POST['changelog'] ?? '');\n        $config['required'] = !empty($_POST['required']);\n        $config['allowed_client_ips'] = ssm_text_to_array($_POST['allowed_client_ips'] ?? '');\n        $config['allowed_client_domains'] = ssm_text_to_array($_POST['allowed_client_domains'] ?? '');\n\n        if ($config['master_token'] === '') {\n            ssm_flash('error', 'Token m\u00e1y ch\u1ee7 ch\u00ednh kh\u00f4ng \u0111\u01b0\u1ee3c \u0111\u1ec3 tr\u1ed1ng.');\n        } elseif ($config['version'] === '') {\n            ssm_flash('error', 'Phi\u00ean b\u1ea3n kh\u00f4ng \u0111\u01b0\u1ee3c \u0111\u1ec3 tr\u1ed1ng.');\n        } elseif ($config['zip_sha256'] !== '' && !preg_match('\/^[a-f0-9]{64}$\/i', $config['zip_sha256'])) {\n            ssm_flash('error', 'SHA256 ph\u1ea3i g\u1ed3m \u0111\u00fang 64 k\u00fd t\u1ef1 hex.');\n        } elseif (ssm_save_config($config)) {\n            ssm_flash('success', '\u0110\u00e3 l\u01b0u c\u1ea5u h\u00ecnh manifest v\u00e0o JSON.');\n        } else {\n            ssm_flash('error', 'Kh\u00f4ng th\u1ec3 l\u01b0u file JSON. H\u00e3y ki\u1ec3m tra quy\u1ec1n ghi th\u01b0 m\u1ee5c source-sync-master-data ngang c\u1ea5p public.');\n        }\n\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n        exit;\n    }\n\n    if ($action === 'upload_zip') {\n        if (empty($_FILES['update_zip']) || !is_uploaded_file($_FILES['update_zip']['tmp_name'])) {\n            ssm_flash('error', 'B\u1ea1n ch\u01b0a ch\u1ecdn file ZIP.');\n        } elseif ((int)$_FILES['update_zip']['error'] !== UPLOAD_ERR_OK) {\n            ssm_flash('error', 'Upload ZIP th\u1ea5t b\u1ea1i. M\u00e3 l\u1ed7i: ' . (int)$_FILES['update_zip']['error']);\n        } elseif ((int)$_FILES['update_zip']['size'] <= 0 || (int)$_FILES['update_zip']['size'] > (int)$SOURCE_SYNC_CONFIG_MAX_UPLOAD_BYTES) {\n            ssm_flash('error', 'File ZIP v\u01b0\u1ee3t qu\u00e1 dung l\u01b0\u1ee3ng cho ph\u00e9p.');\n        } else {\n            $original = isset($_FILES['update_zip']['name']) ? (string)$_FILES['update_zip']['name'] : 'source-update.zip';\n            $filename = ssm_safe_zip_filename($original);\n            $target = $MASTER_PACKAGE_DIR . '\/' . $filename;\n\n            if (!preg_match('\/\\.zip$\/i', $filename)) {\n                ssm_flash('error', 'Ch\u1ec9 cho ph\u00e9p upload file .zip.');\n            } elseif (@move_uploaded_file($_FILES['update_zip']['tmp_name'], $target)) {\n                @chmod($target, 0644);\n                $hash = hash_file('sha256', $target);\n                $config['zip_filename'] = $filename;\n                $config['zip_size'] = filesize($target);\n                $config['zip_url'] = rtrim($MASTER_PACKAGE_PUBLIC_DIR, '\/') . '\/' . $filename;\n                $config['zip_sha256'] = strtolower($hash);\n                $config['version'] = ssm_increment_version(isset($config['version']) ? $config['version'] : '');\n                $config['released_at'] = ssm_now();\n                if (ssm_save_config($config)) {\n                    ssm_flash('success', 'Upload ZIP th\u00e0nh c\u00f4ng. H\u1ec7 th\u1ed1ng \u0111\u00e3 t\u1ef1 l\u1ea5y SHA256, t\u1ef1 t\u0103ng phi\u00ean b\u1ea3n l\u00ean ' . $config['version'] . ' v\u00e0 l\u01b0u v\u00e0o JSON.');\n                } else {\n                    ssm_flash('error', 'Upload ZIP th\u00e0nh c\u00f4ng nh\u01b0ng kh\u00f4ng th\u1ec3 l\u01b0u c\u1ea5u h\u00ecnh JSON.');\n                }\n            } else {\n                ssm_flash('error', 'Kh\u00f4ng th\u1ec3 l\u01b0u file ZIP v\u00e0o th\u01b0 m\u1ee5c update-packages. H\u00e3y ki\u1ec3m tra quy\u1ec1n ghi.');\n            }\n        }\n\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n        exit;\n    }\n\n    if ($action === 'recalc_sha256') {\n        $file = ssm_internal_zip_path_from_url(isset($config['zip_url']) ? $config['zip_url'] : '');\n        if ($file === '') {\n            ssm_flash('error', 'Kh\u00f4ng t\u00ecm th\u1ea5y file ZIP n\u1ed9i b\u1ed9 \u0111\u1ec3 l\u1ea5y l\u1ea1i SHA256. H\u00e3y upload ZIP qua form ho\u1eb7c ki\u1ec3m tra ZIP URL.');\n        } else {\n            $config['zip_sha256'] = strtolower(hash_file('sha256', $file));\n            $config['zip_size'] = filesize($file);\n            $config['zip_filename'] = basename($file);\n            if (ssm_save_config($config)) {\n                ssm_flash('success', '\u0110\u00e3 l\u1ea5y l\u1ea1i SHA256 t\u1eeb file ZIP hi\u1ec7n t\u1ea1i.');\n            } else {\n                ssm_flash('error', 'Kh\u00f4ng th\u1ec3 l\u01b0u SHA256 m\u1edbi v\u00e0o JSON.');\n            }\n        }\n        header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));\n        exit;\n    }\n}\n\n$config = ssm_load_config();\n$flash = ssm_get_flash();\n$setupRequired = ssm_setup_required($config);\n$sourceAccessKey = isset($config['config_access_key']) ? ssm_normalize_access_key($config['config_access_key']) : '';\n$suggestedSourceAccessKey = ssm_generate_access_key();\n$csrf = ssm_csrf_token();\n$manifestUrl = '';\nif (!empty($_SERVER['HTTP_HOST'])) {\n    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';\n    $manifestUrl = $scheme . ':\/\/' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']) . '\/update-manifest.php';\n}\n$configLoginUrl = '';\nif (!empty($_SERVER['HTTP_HOST'])) {\n    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';\n    $configLoginUrl = $scheme . ':\/\/' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . ($sourceAccessKey !== '' ? '?k=' . rawurlencode($sourceAccessKey) : '');\n}\n?>\n<!doctype html>\n<html lang=\"vi\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<meta name=\"robots\" content=\"noindex,nofollow\">\n<title>C\u1ea5u h\u00ecnh Source Sync Master<\/title>\n<style>\n    :root { color-scheme: light; --bg:#f4f6fb; --card:#ffffff; --text:#172033; --muted:#667085; --border:#d9e0ea; --primary:#1d4ed8; --danger:#dc2626; --success:#15803d; }\n    * { box-sizing: border-box; }\n    body { margin:0; font-family: Arial, Helvetica, sans-serif; background: var(--bg); color: var(--text); }\n    .wrap { max-width: 980px; margin: 0 auto; padding: 18px; }\n    .top { display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:14px; }\n    h1 { font-size: 22px; margin:0; }\n    .card { background:var(--card); border:1px solid var(--border); border-radius:14px; padding:16px; box-shadow:0 8px 24px rgba(15,23,42,.06); margin-bottom:14px; }\n    .grid { display:grid; grid-template-columns: 1fr 1fr; gap:14px; }\n    label { display:block; font-weight:700; margin-bottom:6px; font-size:14px; }\n    input[type=text], input[type=password], textarea, select { width:100%; border:1px solid var(--border); border-radius:10px; padding:10px 12px; font-size:14px; background:#fff; color:var(--text); }\n    textarea { min-height:96px; resize:vertical; }\n    .hint { color:var(--muted); font-size:13px; margin-top:5px; line-height:1.45; }\n    .row { margin-bottom:14px; }\n    .btn { border:0; border-radius:10px; padding:10px 14px; font-weight:700; cursor:pointer; background:var(--primary); color:white; display:inline-flex; align-items:center; gap:8px; text-decoration:none; font-size:14px; }\n    .btn.secondary { background:#475569; }\n    .btn.danger { background:var(--danger); }\n    .btn.light { background:#e8eef8; color:#1e293b; }\n    .actions { display:flex; gap:10px; flex-wrap:wrap; align-items:center; }\n    .flash { border-radius:10px; padding:11px 12px; margin-bottom:10px; border:1px solid var(--border); }\n    .flash.success { background:#ecfdf3; color:#166534; border-color:#bbf7d0; }\n    .flash.error { background:#fef2f2; color:#991b1b; border-color:#fecaca; }\n    .stat { display:grid; grid-template-columns: 210px 1fr; gap:10px; border-bottom:1px solid #eef2f7; padding:8px 0; font-size:14px; }\n    .stat b { color:#334155; }\n    code { background:#eef2ff; color:#1e3a8a; padding:2px 5px; border-radius:5px; word-break:break-all; }\n    .danger-note { color:#991b1b; background:#fff1f2; border:1px solid #fecdd3; padding:10px 12px; border-radius:10px; font-size:14px; line-height:1.45; }\n    @media (max-width: 720px) {\n        .wrap { padding:12px; }\n        .grid { grid-template-columns: 1fr; }\n        .top { align-items:flex-start; flex-direction:column; }\n        .stat { grid-template-columns: 1fr; gap:4px; }\n        .btn { width:100%; justify-content:center; }\n    }\n<\/style>\n<\/head>\n<body>\n<div class=\"wrap\">\n    <div class=\"top\">\n        <div>\n            <h1>\u2699\ufe0f C\u1ea5u h\u00ecnh Source Sync Master<\/h1>\n            <div class=\"hint\">Trang n\u00e0y d\u00f9ng \u0111\u1ec3 c\u1ea5u h\u00ecnh <code>update-manifest.php<\/code>, upload ZIP update v\u00e0 t\u1ef1 l\u1ea5y SHA256.<\/div>\n        <\/div>\n        <?php if (ssm_logged_in()): ?>\n            <form method=\"post\">\n                <input type=\"hidden\" name=\"action\" value=\"logout\">\n                <button class=\"btn light\" type=\"submit\">\u0110\u0103ng xu\u1ea5t<\/button>\n            <\/form>\n        <?php endif; ?>\n    <\/div>\n\n    <?php foreach ($flash as $item): ?>\n        <div class=\"flash <?php echo ssm_e($item['type']); ?>\"><?php echo ssm_e($item['message']); ?><\/div>\n    <?php endforeach; ?>\n\n    <?php if ($setupRequired): ?>\n        <div class=\"card\">\n            <h2>Thi\u1ebft l\u1eadp Source Sync Master l\u1ea7n \u0111\u1ea7u<\/h2>\n            <p class=\"hint\">L\u1ea7n \u0111\u1ea7u c\u00f3 th\u1ec3 truy c\u1eadp tr\u1ef1c ti\u1ebfp trang n\u00e0y \u0111\u1ec3 t\u1ea1o m\u1eadt kh\u1ea9u v\u00e0 token b\u1ea3o v\u1ec7 \u0111\u01b0\u1eddng d\u1eabn. Nh\u1eefng l\u1ea7n sau ph\u1ea3i truy c\u1eadp \u0111\u00fang link c\u00f3 token.<\/p>\n            <form method=\"post\" style=\"margin-top:14px;\">\n                <input type=\"hidden\" name=\"action\" value=\"setup_config\">\n                <input type=\"hidden\" name=\"csrf\" value=\"<?php echo ssm_e($csrf); ?>\">\n                <div class=\"row\"><label>M\u1eadt kh\u1ea9u c\u1ea5u h\u00ecnh m\u1edbi<\/label><input type=\"password\" name=\"password\" autocomplete=\"new-password\" minlength=\"8\" required><\/div>\n                <div class=\"row\"><label>Nh\u1eadp l\u1ea1i m\u1eadt kh\u1ea9u<\/label><input type=\"password\" name=\"password_confirm\" autocomplete=\"new-password\" minlength=\"8\" required><\/div>\n                <div class=\"row\"><label>Token truy c\u1eadp trang c\u1ea5u h\u00ecnh<\/label><input type=\"text\" name=\"config_access_key\" value=\"<?php echo ssm_e($suggestedSourceAccessKey); ?>\" required><div class=\"hint\">Sau khi l\u01b0u, link truy c\u1eadp s\u1ebd c\u00f3 d\u1ea1ng: <code><?php echo ssm_e((!empty($_SERVER['HTTP_HOST']) ? (((!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off') ? 'https' : 'http') . ':\/\/' . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME']) : 'source-sync-config.php')); ?>?k=TOKEN<\/code><\/div><\/div>\n                <button class=\"btn\" type=\"submit\">T\u1ea1o m\u1eadt kh\u1ea9u v\u00e0 token<\/button>\n            <\/form>\n        <\/div>\n    <?php elseif (!ssm_logged_in()): ?>\n        <div class=\"card\">\n            <h2>\u0110\u0103ng nh\u1eadp<\/h2>\n            <form method=\"post\" style=\"margin-top:14px;\">\n                <input type=\"hidden\" name=\"action\" value=\"login\">\n                <input type=\"hidden\" name=\"csrf\" value=\"<?php echo ssm_e($csrf); ?>\">\n                <div class=\"row\"><label>M\u1eadt kh\u1ea9u c\u1ea5u h\u00ecnh<\/label><input type=\"password\" name=\"password\" autocomplete=\"current-password\" required><\/div>\n                <button class=\"btn\" type=\"submit\">\u0110\u0103ng nh\u1eadp<\/button>\n            <\/form>\n            <?php if ($configLoginUrl !== ''): ?><p class=\"hint\">Link truy c\u1eadp h\u1ee3p l\u1ec7: <code><?php echo ssm_e($configLoginUrl); ?><\/code><\/p><?php endif; ?>\n        <\/div>\n    <?php else: ?>\n        <div class=\"card\">\n            <h2>Th\u00f4ng tin hi\u1ec7n t\u1ea1i<\/h2>\n            <div class=\"stat\"><b>Manifest URL<\/b><div><code><?php echo ssm_e($manifestUrl); ?><\/code><\/div><\/div>\n            <?php if ($configLoginUrl !== ''): ?><div class=\"stat\"><b>Link c\u1ea5u h\u00ecnh<\/b><div><code><?php echo ssm_e($configLoginUrl); ?><\/code><\/div><\/div><?php endif; ?>\n            <div class=\"stat\"><b>Version<\/b><div><?php echo ssm_e($config['version']); ?><\/div><\/div>\n            <div class=\"stat\"><b>ZIP URL<\/b><div><code><?php echo ssm_e($config['zip_url']); ?><\/code><\/div><\/div>\n            <div class=\"stat\"><b>SHA256<\/b><div><code><?php echo ssm_e($config['zip_sha256']); ?><\/code><\/div><\/div>\n            <div class=\"stat\"><b>File ZIP<\/b><div><?php echo ssm_e($config['zip_filename']); ?> <?php echo !empty($config['zip_size']) ? '(' . number_format((float)$config['zip_size']) . ' bytes)' : ''; ?><\/div><\/div>\n            <div class=\"stat\"><b>C\u1eadp nh\u1eadt JSON<\/b><div><?php echo ssm_e($config['updated_at']); ?><\/div><\/div>\n        <\/div>\n\n        <div class=\"card\">\n            <h2>Upload ZIP phi\u00ean b\u1ea3n m\u1edbi<\/h2>\n            <form method=\"post\" enctype=\"multipart\/form-data\">\n                <input type=\"hidden\" name=\"action\" value=\"upload_zip\">\n                <input type=\"hidden\" name=\"csrf\" value=\"<?php echo ssm_e($csrf); ?>\">\n                <div class=\"row\">\n                    <label>Ch\u1ecdn file .zip<\/label>\n                    <input type=\"file\" name=\"update_zip\" accept=\".zip,application\/zip,application\/x-zip-compressed\" required>\n                    <div class=\"hint\">File s\u1ebd t\u1ef1 l\u01b0u v\u00e0o <code>\/update-packages\/<\/code>, t\u1ef1 t\u1ea1o <code>zip_url<\/code> v\u00e0 t\u1ef1 t\u00ednh SHA256.<\/div>\n                <\/div>\n                <div class=\"actions\">\n                    <button class=\"btn\" type=\"submit\">\u2b06\ufe0f Upload ZIP v\u00e0 t\u1ef1 l\u1ea5y SHA256<\/button>\n                <\/div>\n            <\/form>\n        <\/div>\n\n        <div class=\"card\">\n            <h2>C\u1ea5u h\u00ecnh manifest<\/h2>\n            <form method=\"post\">\n                <input type=\"hidden\" name=\"action\" value=\"save_config\">\n                <input type=\"hidden\" name=\"csrf\" value=\"<?php echo ssm_e($csrf); ?>\">\n\n                <div class=\"grid\">\n                    <div class=\"row\">\n                        <label>Token m\u00e1y ch\u1ee7 ch\u00ednh<\/label>\n                        <input type=\"text\" name=\"master_token\" value=\"<?php echo ssm_e($config['master_token']); ?>\" placeholder=\"Ph\u1ea3i gi\u1ed1ng SOURCE_SYNC_API_TOKEN tr\u00ean m\u00e1y ch\u1ee7 con\" required>\n                    <\/div>\n                    <div class=\"row\">\n                        <label>Phi\u00ean b\u1ea3n m\u1edbi nh\u1ea5t<\/label>\n                        <input type=\"text\" name=\"version\" value=\"<?php echo ssm_e($config['version']); ?>\" placeholder=\"VD: V24\" required>\n                    <\/div>\n                <\/div>\n\n                <div class=\"row\">\n                    <label>ZIP URL<\/label>\n                    <input type=\"text\" name=\"zip_url\" value=\"<?php echo ssm_e($config['zip_url']); ?>\" placeholder=\"\/update-packages\/web-shop-V24.zip\">\n                    <div class=\"hint\">C\u00f3 th\u1ec3 d\u00f9ng \u0111\u01b0\u1eddng d\u1eabn n\u1ed9i b\u1ed9 nh\u01b0 <code>\/update-packages\/web-shop-V24.zip<\/code> ho\u1eb7c URL \u0111\u1ea7y \u0111\u1ee7.<\/div>\n                <\/div>\n\n                <div class=\"row\">\n                    <label>SHA256<\/label>\n                    <input type=\"text\" name=\"zip_sha256\" value=\"<?php echo ssm_e($config['zip_sha256']); ?>\" placeholder=\"T\u1ef1 t\u1ea1o sau khi upload ZIP\">\n                    <div class=\"hint\">N\u1ebfu upload ZIP b\u1eb1ng form ph\u00eda tr\u00ean, SHA256 s\u1ebd t\u1ef1 \u0111i\u1ec1n v\u00e0 l\u01b0u v\u00e0o JSON.<\/div>\n                <\/div>\n\n                <div class=\"grid\">\n                    <div class=\"row\">\n                        <label>Th\u1eddi gian ph\u00e1t h\u00e0nh<\/label>\n                        <input type=\"text\" name=\"released_at\" value=\"<?php echo ssm_e($config['released_at']); ?>\" placeholder=\"2026-06-28 00:00:00\">\n                    <\/div>\n                    <div class=\"row\">\n                        <label>B\u1eaft bu\u1ed9c c\u1eadp nh\u1eadt?<\/label>\n                        <select name=\"required\">\n                            <option value=\"0\" <?php echo empty($config['required']) ? 'selected' : ''; ?>>Kh\u00f4ng<\/option>\n                            <option value=\"1\" <?php echo !empty($config['required']) ? 'selected' : ''; ?>>C\u00f3<\/option>\n                        <\/select>\n                    <\/div>\n                <\/div>\n\n                <div class=\"row\">\n                    <label>Ghi ch\u00fa c\u1eadp nh\u1eadt<\/label>\n                    <textarea name=\"changelog\" placeholder=\"- N\u1ed9i dung c\u1eadp nh\u1eadt 1&#10;- N\u1ed9i dung c\u1eadp nh\u1eadt 2\"><?php echo ssm_e($config['changelog']); ?><\/textarea>\n                <\/div>\n\n                <div class=\"grid\">\n                    <div class=\"row\">\n                        <label>IP m\u00e1y ch\u1ee7 con \u0111\u01b0\u1ee3c ph\u00e9p<\/label>\n                        <textarea name=\"allowed_client_ips\" placeholder=\"M\u1ed7i d\u00f2ng 1 IP public ho\u1eb7c local\/server IP&#10;VD public: 103.345.23.25&#10;VD server local: 14.225.218.36&#10;VD private: 192.168.1.10\"><?php echo ssm_e(ssm_array_to_text($config['allowed_client_ips'])); ?><\/textarea>\n                        <div class=\"hint\">\u0110\u1ec3 tr\u1ed1ng n\u1ebfu kh\u00f4ng mu\u1ed1n ki\u1ec3m tra IP. C\u00f3 th\u1ec3 nh\u1eadp IP public\/NAT ho\u1eb7c IP server local\/private c\u1ee7a m\u00e1y ch\u1ee7 con.<\/div>\n                    <\/div>\n                    <div class=\"row\">\n                        <label>Domain m\u00e1y ch\u1ee7 con \u0111\u01b0\u1ee3c ph\u00e9p<\/label>\n                        <textarea name=\"allowed_client_domains\" placeholder=\"M\u1ed7i d\u00f2ng 1 domain&#10;VD: shop-con.example.com\"><?php echo ssm_e(ssm_array_to_text($config['allowed_client_domains'])); ?><\/textarea>\n                        <div class=\"hint\">\u0110\u1ec3 tr\u1ed1ng n\u1ebfu kh\u00f4ng mu\u1ed1n ki\u1ec3m tra domain. N\u1ebfu \u0111i\u1ec1n c\u1ea3 IP v\u00e0 domain th\u00ec request ph\u1ea3i kh\u1edbp c\u1ea3 hai. V\u1edbi IP, h\u1ec7 th\u1ed1ng ch\u1ea5p nh\u1eadn IP public ho\u1eb7c IP local\/server IP do m\u00e1y ch\u1ee7 con g\u1eedi k\u00e8m token\/header\/query.<\/div>\n                    <\/div>\n                <\/div>\n\n                <div class=\"actions\">\n                    <button class=\"btn\" type=\"submit\">\ud83d\udcbe L\u01b0u c\u1ea5u h\u00ecnh v\u00e0o JSON<\/button>\n                <\/div>\n            <\/form>\n\n            <form method=\"post\" style=\"margin-top:10px;\">\n                <input type=\"hidden\" name=\"action\" value=\"recalc_sha256\">\n                <input type=\"hidden\" name=\"csrf\" value=\"<?php echo ssm_e($csrf); ?>\">\n                <button class=\"btn secondary\" type=\"submit\">\ud83d\udd01 L\u1ea5y l\u1ea1i SHA256 t\u1eeb ZIP hi\u1ec7n t\u1ea1i<\/button>\n            <\/form>\n        <\/div>\n    <?php endif; ?>\n<\/div>\n<\/body>\n<\/html>\n",
        "time": "2026-07-01 13:27:56"
    }
]