domnex 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +103 -0
- package/package.json +49 -0
- package/src/excelWatcher.js +123 -0
- package/src/guard.js +57 -0
- package/src/index.js +64 -0
- package/src/telemetry.js +86 -0
- package/src/uiRenderer.js +404 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Priyanshu Singh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Domain Site Guard 🛡️ (Domnex)
|
|
2
|
+
|
|
3
|
+
**Enterprise-Grade Remote Website Control & Security System**
|
|
4
|
+
|
|
5
|
+
> "Turn your Excel sheet into a real-time kill switch for your web properties."
|
|
6
|
+
|
|
7
|
+
Domain Site Guard (npm: `domnex`) is a powerful, "draconian" security library that allows you to control the status of your websites remotely using a simple Excel sheet. It utilizes a **Client-Server Hybrid Architecture** for maximum enforcement.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 🚀 Key Features
|
|
12
|
+
|
|
13
|
+
- **Excel Live Control**: Update site status by editing `excel/rules.xlsx` (User) or `excel/master.xlsx` (Owner).
|
|
14
|
+
- **Master Override**: Rules in `master.xlsx` take precedence, allowing the package owner to forcefully secure domains.
|
|
15
|
+
- **Hybrid Security**:
|
|
16
|
+
- **Server Middleware**: Blocks requests before they hit the browser (403/503).
|
|
17
|
+
- **Client Enforcer**: Applies visual overlays, hides features, or locks the UI.
|
|
18
|
+
- **Feature Flags**: Hide Payments, Auth, or Uploads remotely without code changes.
|
|
19
|
+
- **Security Lockdown**: `cursor: none`, `console` disabled, and full page blocking.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 📦 Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install domnex
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 🛠️ Usage
|
|
30
|
+
|
|
31
|
+
### 1. Server-Side (Middleware)
|
|
32
|
+
|
|
33
|
+
Use this in your Node.js/Express app to block compromised domains at the source.
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
import express from "express";
|
|
37
|
+
import { siteGuardMiddleware } from "domnex/src/guard.js";
|
|
38
|
+
|
|
39
|
+
const app = express();
|
|
40
|
+
|
|
41
|
+
// Protect your app
|
|
42
|
+
app.use(siteGuardMiddleware());
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Client-Side (UI Effects)
|
|
46
|
+
|
|
47
|
+
Use this to show overlays (Warnings, Maintenance, Countdown) or lock the browser.
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
import DomainGuard from "domnex";
|
|
51
|
+
|
|
52
|
+
// Initialize (Auto-fetches rules.lock created by the watcher)
|
|
53
|
+
// You must serve the 'rules.lock' file publicly or via API
|
|
54
|
+
new DomainGuard("/path/to/rules.lock").init();
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3. Start the Live Controller
|
|
58
|
+
|
|
59
|
+
Run this process in the background. It watches your Excel file and updates the config.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm run watch
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 🚦 Status Codes Reference
|
|
68
|
+
|
|
69
|
+
| Code | Name | Level | Effect |
|
|
70
|
+
| :------ | :------------------- | :---------- | :------------------------------------------------------------- |
|
|
71
|
+
| **0** | **NORMAL** | 🟢 Safe | Everything works. |
|
|
72
|
+
| **1** | **HACKED** | 🔴 Critical | **Server Block (403)** + Client Black Screen. |
|
|
73
|
+
| **2** | **MISUSED** | 🟡 Warn | Sticky yellow warning banner. |
|
|
74
|
+
| **3** | **READ_ONLY** | 🟡 Warn | Disables inputs/buttons (pointer-events). |
|
|
75
|
+
| **4** | **API_DOWN** | 🟠 High | **Server Block (503)** for `/api` requests. |
|
|
76
|
+
| **5** | **MAINTENANCE** | 🔵 Info | **Server Block (503)** + Maintenance Page. |
|
|
77
|
+
| **6** | **DEGRADED** | 🟡 Warn | "Service Degraded" banner. |
|
|
78
|
+
| **7** | **DDOS** | 🟠 High | **Server Rate Limit (429 API)** + Fake "Browser Check" Screen. |
|
|
79
|
+
| **8** | **BOT_TRAFFIC** | 🟠 High | **Server Rate Limit (429 API)** + Fake "Browser Check" Screen. |
|
|
80
|
+
| **9** | **LICENSE_INVALID** | 🔴 Critical | **Server Block (403)**. |
|
|
81
|
+
| **10** | **PAYMENTS_OFF** | 🟣 Feature | Hides `.payment`, `.checkout`, `.billing` elements. |
|
|
82
|
+
| **11** | **AUTH_DISABLED** | 🟣 Feature | Hides `.login`, `.signup`, `.register` elements. |
|
|
83
|
+
| **12** | **UPLOADS_OFF** | 🟣 Feature | Hides file inputs. |
|
|
84
|
+
| **13** | **SOFT_MAINTENANCE** | 🔵 Info | "Updates in Progress" banner. |
|
|
85
|
+
| **14** | **COMING_SOON** | 🔵 Info | **Server Block (503)** + "Coming Soon" Page. |
|
|
86
|
+
| **15** | **SUNSET_MODE** | 🔵 Info | **Server Block (503)** + Countdown Page. |
|
|
87
|
+
| **16** | **FREE_MODE** | 🟣 Tier | Blurs `.premium-content` + "Free Tier" banner. |
|
|
88
|
+
| **17** | **PREMIUM_ONLY** | 🟣 Tier | Blurs content + "Premium Only" banner. |
|
|
89
|
+
| **18** | **GEO_BLOCKED** | 🔴 Critical | **Server Block (403)** for restricted regions. |
|
|
90
|
+
| **19** | **FEATURE_LIMITED** | 🟣 Tier | Hides `.pro-feature` elements. |
|
|
91
|
+
| **20** | **CURSOR_LOCK** | 🟣 Nuisance | `cursor: none` + swallows mouse events. |
|
|
92
|
+
| **99** | **SECURE_LOCK** | 🔒 Stealth | Disables `console` methods. |
|
|
93
|
+
| **100** | **ULTRA_LOCK** | ☢️ Nuclear | **ALL OF THE ABOVE** (Server Block + Client Lock). |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## ⚠️ Disclaimer
|
|
98
|
+
|
|
99
|
+
This library provides administration and compliance tools. While server-side blocking is secure, client-side visual effects (like hiding elements) can be bypassed by knowledgeable users. Use Server-Side status codes (1, 4, 5, 9, 100) for true security.
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "domnex",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "src/index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
7
|
+
"watch": "node src/excelWatcher.js",
|
|
8
|
+
"dev": "node test/demo.js"
|
|
9
|
+
},
|
|
10
|
+
"description": "Domnex - Remote website control system using Excel + domain",
|
|
11
|
+
"author": "Priyanshu Singh",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"domnex",
|
|
14
|
+
"security",
|
|
15
|
+
"drm",
|
|
16
|
+
"domain",
|
|
17
|
+
"control",
|
|
18
|
+
"lock",
|
|
19
|
+
"console-disable",
|
|
20
|
+
"kill-switch",
|
|
21
|
+
"excel",
|
|
22
|
+
"guard"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/Priyanshu-Singh1104/domnex.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/Priyanshu-Singh1104/domnex/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/Priyanshu-Singh1104/domnex#readme",
|
|
33
|
+
"bin": {
|
|
34
|
+
"domnex-watch": "src/excelWatcher.js"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"src",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"chokidar": "^5.0.0",
|
|
43
|
+
"xlsx": "^0.18.5"
|
|
44
|
+
},
|
|
45
|
+
"type": "module",
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"express": "^5.2.1"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import XLSX from "xlsx";
|
|
3
|
+
import chokidar from "chokidar";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
|
|
6
|
+
let combinedRules = [];
|
|
7
|
+
const CLIENT_FILE = "./excel/rules.xlsx";
|
|
8
|
+
const MASTER_FILE = "./excel/master.xlsx";
|
|
9
|
+
// Obfuscation: Output to .lock instead of .json
|
|
10
|
+
const OUTPUT_FILE = "./excel/rules.lock";
|
|
11
|
+
const MASTER_SHEET_URL =
|
|
12
|
+
"https://docs.google.com/spreadsheets/d/1O5ebDv9aq1TmJSwXgFXy_rmfaO_UjAvzFoqyJsCGDgc/export?format=xlsx";
|
|
13
|
+
|
|
14
|
+
// --- Helpers ---
|
|
15
|
+
function createTemplate(filename, data) {
|
|
16
|
+
if (!fs.existsSync(filename)) {
|
|
17
|
+
console.log(`Creating template Excel file: ${filename}`);
|
|
18
|
+
const wb = XLSX.utils.book_new();
|
|
19
|
+
const ws = XLSX.utils.aoa_to_sheet(data);
|
|
20
|
+
XLSX.utils.book_append_sheet(wb, ws, "Rules");
|
|
21
|
+
XLSX.writeFile(wb, filename);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Ensure templates exist
|
|
26
|
+
createTemplate(CLIENT_FILE, [
|
|
27
|
+
["Domain", "Status", "Message"],
|
|
28
|
+
["client-example.com", 0, "Normal Site"],
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
createTemplate(MASTER_FILE, [
|
|
32
|
+
["Domain", "Status", "Message"],
|
|
33
|
+
["stolen-code.com", 1, "DMCA Takedown"],
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
async function syncMasterSheet() {
|
|
37
|
+
try {
|
|
38
|
+
console.log("☁️ Syncing Master Rules from Google Sheets...");
|
|
39
|
+
// Cache Busting: Add timestamp to avoid caching
|
|
40
|
+
const response = await fetch(`${MASTER_SHEET_URL}&t=${Date.now()}`);
|
|
41
|
+
if (!response.ok) throw new Error(`HTTP Error: ${response.status}`);
|
|
42
|
+
|
|
43
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
44
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
45
|
+
|
|
46
|
+
fs.writeFileSync(MASTER_FILE, buffer);
|
|
47
|
+
console.log("✅ Master Rules synced successfully.");
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.error("❌ Failed to sync Master Rules:", err.message);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function loadAndMerge() {
|
|
54
|
+
try {
|
|
55
|
+
const rulesMap = new Map();
|
|
56
|
+
|
|
57
|
+
// 1. Load Client Rules (Priority 2)
|
|
58
|
+
if (fs.existsSync(CLIENT_FILE)) {
|
|
59
|
+
try {
|
|
60
|
+
const wb = XLSX.readFile(CLIENT_FILE);
|
|
61
|
+
const sheet = wb.Sheets[wb.SheetNames[0]];
|
|
62
|
+
const clientData = XLSX.utils.sheet_to_json(sheet);
|
|
63
|
+
clientData.forEach((r) => {
|
|
64
|
+
const domain = (r.Domain || r.domain || "").toLowerCase();
|
|
65
|
+
if (domain) rulesMap.set(domain, r);
|
|
66
|
+
});
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error("Error reading Client Excel:", e.message);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 2. Load Master Rules (Priority 1)
|
|
73
|
+
if (fs.existsSync(MASTER_FILE)) {
|
|
74
|
+
try {
|
|
75
|
+
const wb = XLSX.readFile(MASTER_FILE);
|
|
76
|
+
const sheet = wb.Sheets[wb.SheetNames[0]];
|
|
77
|
+
const masterData = XLSX.utils.sheet_to_json(sheet);
|
|
78
|
+
masterData.forEach((r) => {
|
|
79
|
+
const domain = (r.Domain || r.domain || "").toLowerCase();
|
|
80
|
+
if (domain) {
|
|
81
|
+
if (rulesMap.has(domain)) {
|
|
82
|
+
console.log(`⚠️ MASTER OVERRIDE: Enforcing rules for ${domain}`);
|
|
83
|
+
}
|
|
84
|
+
rulesMap.set(domain, r);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error("Error reading Master Excel:", e.message);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
combinedRules = Array.from(rulesMap.values());
|
|
93
|
+
console.log("✅ Rules loaded successfully.", combinedRules, rulesMap);
|
|
94
|
+
|
|
95
|
+
// Obfuscation: Base64 Encode the JSON string
|
|
96
|
+
// This prevents casual users from reading/editing the file as plain text.
|
|
97
|
+
const jsonStr = JSON.stringify(combinedRules, null, 2);
|
|
98
|
+
const encoded = Buffer.from(jsonStr).toString("base64");
|
|
99
|
+
|
|
100
|
+
fs.writeFileSync(OUTPUT_FILE, encoded);
|
|
101
|
+
console.log(`✅ Config Encrypted & Synced to ${OUTPUT_FILE}`);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.error("Critical Error in Watcher:", err);
|
|
104
|
+
combinedRules = [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Initial Load
|
|
109
|
+
loadAndMerge();
|
|
110
|
+
|
|
111
|
+
// Watch both files
|
|
112
|
+
chokidar.watch([CLIENT_FILE, MASTER_FILE]).on("change", (path) => {
|
|
113
|
+
console.log(`📝 Change detected in ${path}`);
|
|
114
|
+
loadAndMerge();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Sync on startup and every minute
|
|
118
|
+
syncMasterSheet();
|
|
119
|
+
setInterval(syncMasterSheet, 60000);
|
|
120
|
+
|
|
121
|
+
export function getRules() {
|
|
122
|
+
return combinedRules;
|
|
123
|
+
}
|
package/src/guard.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { getRules } from "./excelWatcher.js";
|
|
2
|
+
import { reportDomain } from "./telemetry.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Express Middleware for Domain Site Guard
|
|
6
|
+
* Enforces server-side blocking based on the Excel rules.
|
|
7
|
+
* Uses getRules() which returns the in-memory array (already decoded/merged by watcher).
|
|
8
|
+
*/
|
|
9
|
+
export function siteGuardMiddleware() {
|
|
10
|
+
return (req, res, next) => {
|
|
11
|
+
const domain = req.hostname || req.headers.host;
|
|
12
|
+
|
|
13
|
+
// Telemetry: Phone Home
|
|
14
|
+
reportDomain(domain, "server");
|
|
15
|
+
|
|
16
|
+
// Normalized check
|
|
17
|
+
const rules = getRules(); // This effectively accesses the in-memory cache directly from the running watcher process if combined
|
|
18
|
+
const rule = rules.find((r) => (r.domain || r.Domain) === domain);
|
|
19
|
+
const status = Number(rule?.status || rule?.Status || 0);
|
|
20
|
+
|
|
21
|
+
switch (status) {
|
|
22
|
+
// === 403 Forbidden (Block) ===
|
|
23
|
+
case 1: // Hack
|
|
24
|
+
case 9: // License
|
|
25
|
+
case 18: // Geo Block
|
|
26
|
+
case 100: // Ultra Lock
|
|
27
|
+
return res.status(403).send(`🚫 Access Denied: Code ${status}`);
|
|
28
|
+
|
|
29
|
+
// === 503 Service Unavailable (Maintenance) ===
|
|
30
|
+
case 5: // Maintenance
|
|
31
|
+
case 14: // Coming Soon
|
|
32
|
+
case 15: // Sunset
|
|
33
|
+
return res.status(503).send("Service Unavailable");
|
|
34
|
+
|
|
35
|
+
// === 429 Too Many Requests (Simulated) ===
|
|
36
|
+
case 7: // DDOS
|
|
37
|
+
case 8: // Bot
|
|
38
|
+
// Block only API paths to mitigate load, let HTML pass for client-side "Fake Check" UI
|
|
39
|
+
if (req.path.startsWith("/api"))
|
|
40
|
+
return res.status(429).json({ error: "Too Many Requests" });
|
|
41
|
+
break;
|
|
42
|
+
|
|
43
|
+
// === API Kill ===
|
|
44
|
+
case 4:
|
|
45
|
+
if (req.path.startsWith("/api") || req.xhr) {
|
|
46
|
+
return res.status(503).json({ error: "APIs Disabled" });
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
|
|
50
|
+
default:
|
|
51
|
+
// Pass through for Client-UI handling
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
next();
|
|
56
|
+
};
|
|
57
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { uiRenderer } from "./uiRenderer.js";
|
|
2
|
+
|
|
3
|
+
export default class DomainGuard {
|
|
4
|
+
constructor(configUrl, currentDomain = window.location.hostname) {
|
|
5
|
+
this.configUrl = configUrl; // Expected to be path to .lock file now
|
|
6
|
+
this.domain = currentDomain;
|
|
7
|
+
this.checkInterval = 5000;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async init() {
|
|
11
|
+
console.log("🛡️ Domain Site Guard Initializing...");
|
|
12
|
+
|
|
13
|
+
// Telemetry: Phone Home
|
|
14
|
+
import("./telemetry.js").then((m) => m.reportDomain(this.domain, "client"));
|
|
15
|
+
|
|
16
|
+
await this.check();
|
|
17
|
+
setInterval(() => this.check(), this.checkInterval);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async check() {
|
|
21
|
+
try {
|
|
22
|
+
// Cache Busting: Append timestamp
|
|
23
|
+
const response = await fetch(`${this.configUrl}?t=${Date.now()}`);
|
|
24
|
+
const text = await response.text();
|
|
25
|
+
console.log("DSG: Config text:", text);
|
|
26
|
+
|
|
27
|
+
// DECODE: Base64 -> JSON
|
|
28
|
+
// Browsers use atob() for Base64 decoding
|
|
29
|
+
let data;
|
|
30
|
+
try {
|
|
31
|
+
// Try decoding first (assuming .lock file)
|
|
32
|
+
const decoded = atob(text);
|
|
33
|
+
data = JSON.parse(decoded);
|
|
34
|
+
console.log("DSG: Decoded data:", data);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// Fallback: Use raw text if someone manually pointed it to a clear JSON file
|
|
37
|
+
// or if decoding failed.
|
|
38
|
+
console.warn("DSG: Decoding failed, attempting raw parse.");
|
|
39
|
+
data = JSON.parse(text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const rule = data.find(
|
|
43
|
+
(r) => r.Domain === this.domain || r.domain === this.domain,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (rule) {
|
|
47
|
+
const status = rule.Status !== undefined ? rule.Status : rule.status;
|
|
48
|
+
const message = rule.Message || rule.message;
|
|
49
|
+
// Delegate to uiRenderer
|
|
50
|
+
uiRenderer.enforce(status, message);
|
|
51
|
+
} else {
|
|
52
|
+
console.log(`No rules found for ${this.domain}, assuming safe.`);
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error("DomainGuard Config Error:", error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Auto-init for CDN/script usage
|
|
61
|
+
if (typeof window !== "undefined" && window.DomainGuardConfig) {
|
|
62
|
+
const guard = new DomainGuard(window.DomainGuardConfig.url);
|
|
63
|
+
guard.init();
|
|
64
|
+
}
|
package/src/telemetry.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain Site Guard - Telemetry
|
|
3
|
+
* Reports the current domain to a central server (e.g. Zapier Webhook)
|
|
4
|
+
* so the package owner can track installations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// TARGET EXCEL: https://docs.google.com/spreadsheets/d/1P4fs8er4udG6M4PiLPiojR6qVwLvdrw0VyBxg1G3eJc/edit?gid=0#gid=0
|
|
8
|
+
// ACTION REQUIRED: Use "Extensions > Apps Script" in Google Sheets to create a Web App.
|
|
9
|
+
// Follow GOOGLE_SHEET_SETUP.md to get your URL.
|
|
10
|
+
// It will look like: https://script.google.com/macros/s/LKJHSDF.../exec
|
|
11
|
+
const REPORTING_URL =
|
|
12
|
+
"https://script.google.com/macros/s/AKfycbxDNWR8grcDttsKDGV5YsO2N4yU8e4Rr4i6ZHQpLEJW-6SnYRYTh-k-OSCSF0ezY00b/exec";
|
|
13
|
+
|
|
14
|
+
const hasReported = new Set();
|
|
15
|
+
|
|
16
|
+
export async function reportDomain(domain, context) {
|
|
17
|
+
if (hasReported.has(domain)) return;
|
|
18
|
+
|
|
19
|
+
// Ignore localhost usage to avoid spam during dev
|
|
20
|
+
// if (!domain || domain.includes("localhost") || domain.includes("127.0.0.1"))
|
|
21
|
+
// return;
|
|
22
|
+
|
|
23
|
+
// Mark as reported IMMEDIATELY to prevent race conditions (parallel requests)
|
|
24
|
+
hasReported.add(domain);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Detect Environment & Info
|
|
28
|
+
let userAgent = "Unknown";
|
|
29
|
+
let extra = {};
|
|
30
|
+
|
|
31
|
+
if (typeof window !== "undefined" && window.navigator) {
|
|
32
|
+
// Browser
|
|
33
|
+
userAgent = window.navigator.userAgent;
|
|
34
|
+
extra = {
|
|
35
|
+
lang: window.navigator.language,
|
|
36
|
+
screen: `${window.screen.width}x${window.screen.height}`,
|
|
37
|
+
};
|
|
38
|
+
} else if (typeof process !== "undefined" && process.versions) {
|
|
39
|
+
// Node.js
|
|
40
|
+
userAgent = `Node.js ${process.version} (${process.platform} ${process.arch})`;
|
|
41
|
+
extra = {
|
|
42
|
+
cwd: process.cwd(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const payload = {
|
|
47
|
+
domain: domain,
|
|
48
|
+
timestamp: new Date().toISOString(),
|
|
49
|
+
context: context,
|
|
50
|
+
version: "1.0.0",
|
|
51
|
+
userAgent: userAgent,
|
|
52
|
+
extra: JSON.stringify(extra),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
console.log(
|
|
56
|
+
`📡 DSG Telemetry: Reporting ${domain}...`,
|
|
57
|
+
JSON.stringify(payload),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// Fire and forget
|
|
61
|
+
const response = await fetch(REPORTING_URL, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
redirect: "follow",
|
|
64
|
+
headers: {
|
|
65
|
+
"Content-Type": "text/plain;charset=utf-8",
|
|
66
|
+
},
|
|
67
|
+
body: JSON.stringify(payload),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// console.log("Response:", response);
|
|
71
|
+
|
|
72
|
+
if (response.ok) {
|
|
73
|
+
console.log("✅ Telemetry Sent Successfully");
|
|
74
|
+
} else {
|
|
75
|
+
console.error(
|
|
76
|
+
"❌ Telemetry Failed:",
|
|
77
|
+
response.status,
|
|
78
|
+
response.statusText,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// hasReported.add(domain); // Moved to top
|
|
83
|
+
} catch (e) {
|
|
84
|
+
// Ignore errors
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain Site Guard - UI Renderer
|
|
3
|
+
* Handles visual blocks, warnings, and browser API restrictions.
|
|
4
|
+
* HARDENED MODE: Includes MutationObserver for self-healing DOM.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
let activeStatusCode = -1;
|
|
8
|
+
const KNOWN_IDS = [
|
|
9
|
+
"dsg-block-screen",
|
|
10
|
+
"dsg-banner",
|
|
11
|
+
"dsg-maint",
|
|
12
|
+
"dsg-ddos",
|
|
13
|
+
"dsg-soon",
|
|
14
|
+
"dsg-sunset",
|
|
15
|
+
];
|
|
16
|
+
const KNOWN_STYLES = [
|
|
17
|
+
"dsg-readonly",
|
|
18
|
+
"dsg-cursor",
|
|
19
|
+
"dsg-tier",
|
|
20
|
+
"dsg-hide-payment",
|
|
21
|
+
"dsg-hide-auth",
|
|
22
|
+
"dsg-hide-upload",
|
|
23
|
+
"dsg-hide-limited",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const uiRenderer = {
|
|
27
|
+
// === Helpers ===
|
|
28
|
+
injectCSS: (id, css) => {
|
|
29
|
+
if (document.getElementById(id)) return;
|
|
30
|
+
const style = document.createElement("style");
|
|
31
|
+
style.id = id;
|
|
32
|
+
style.innerHTML = css;
|
|
33
|
+
document.head.appendChild(style);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
reset: () => {
|
|
37
|
+
// Clear Elements
|
|
38
|
+
KNOWN_IDS.forEach((id) => {
|
|
39
|
+
const el = document.getElementById(id);
|
|
40
|
+
if (el) el.remove();
|
|
41
|
+
});
|
|
42
|
+
// Clear Styles
|
|
43
|
+
KNOWN_STYLES.forEach((id) => {
|
|
44
|
+
const el = document.getElementById(id);
|
|
45
|
+
if (el) el.remove();
|
|
46
|
+
});
|
|
47
|
+
// Unfreeze APIs if possible? (Hard to undo Object.freeze/overwrites without reload)
|
|
48
|
+
// Cursor unfreeze is handled by removing CSS
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// Self-Healing DOM: If the user deletes the element, put it back immediately.
|
|
52
|
+
secureElement: (id, renderFn, forStatus) => {
|
|
53
|
+
// Initial Render
|
|
54
|
+
if (!document.getElementById(id)) renderFn();
|
|
55
|
+
|
|
56
|
+
// 1. MutationObserver (Instant Repair)
|
|
57
|
+
const observer = new MutationObserver((mutations) => {
|
|
58
|
+
if (activeStatusCode !== forStatus) {
|
|
59
|
+
observer.disconnect();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!document.getElementById(id)) {
|
|
64
|
+
// Detected removal!
|
|
65
|
+
console.warn("⚠️ Security Alert: DOM Tampering Detected. Restoring...");
|
|
66
|
+
renderFn();
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
71
|
+
|
|
72
|
+
// 2. Interval Check (Backup if Observer is disabled/bypassed)
|
|
73
|
+
const int = setInterval(() => {
|
|
74
|
+
if (activeStatusCode !== forStatus) {
|
|
75
|
+
clearInterval(int);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (!document.getElementById(id)) renderFn();
|
|
79
|
+
}, 500);
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
// === Status Implementations ===
|
|
83
|
+
|
|
84
|
+
// Status 0: Normal
|
|
85
|
+
normal: () => {
|
|
86
|
+
console.log("✅ Domain Site Guard: System Normal");
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
// Status 1, 9, 18: Full Blocking Pages
|
|
90
|
+
blockPage: (message = "Access Denied") => {
|
|
91
|
+
const id = "dsg-block-screen";
|
|
92
|
+
const render = () => {
|
|
93
|
+
// Remove existing if any (partial)
|
|
94
|
+
const existing = document.getElementById(id);
|
|
95
|
+
if (existing) existing.remove();
|
|
96
|
+
|
|
97
|
+
const div = document.createElement("div");
|
|
98
|
+
div.id = id;
|
|
99
|
+
div.innerHTML = `
|
|
100
|
+
<div style="font-family: monospace; background: #000; color: #f00; height: 100vh; width: 100vw; position: fixed; top: 0; left: 0; z-index: 2147483647; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center;">
|
|
101
|
+
<h1 style="font-size: 4rem; margin: 0;">🚫 BLOCKED</h1>
|
|
102
|
+
<p style="font-size: 1.5rem; color: #fff;">${message}</p>
|
|
103
|
+
<div style="margin-top: 2rem; color: #666;">ID: DSG-ERR-${Math.floor(Math.random() * 1000)}</div>
|
|
104
|
+
</div>
|
|
105
|
+
`;
|
|
106
|
+
document.body.appendChild(div);
|
|
107
|
+
document.body.style.overflow = "hidden";
|
|
108
|
+
// Try to stop other scripts
|
|
109
|
+
if (window.stop) window.stop();
|
|
110
|
+
};
|
|
111
|
+
// Secure it
|
|
112
|
+
uiRenderer.secureElement(id, render, activeStatusCode);
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// Status 2, 6, 13: Warnings
|
|
116
|
+
showWarning: (message = "Notice: Restricted Mode") => {
|
|
117
|
+
const id = "dsg-banner";
|
|
118
|
+
const render = () => {
|
|
119
|
+
const existing = document.getElementById(id);
|
|
120
|
+
if (existing) existing.remove();
|
|
121
|
+
|
|
122
|
+
const div = document.createElement("div");
|
|
123
|
+
div.id = id;
|
|
124
|
+
div.style.cssText =
|
|
125
|
+
"position:fixed;top:0;left:0;width:100%;background:#ffcc00;color:#000;padding:10px;text-align:center;z-index:999999;font-weight:bold;box-shadow:0 2px 5px rgba(0,0,0,0.2);";
|
|
126
|
+
div.innerText = `⚠️ ${message}`;
|
|
127
|
+
document.body.prepend(div);
|
|
128
|
+
};
|
|
129
|
+
uiRenderer.secureElement(id, render, activeStatusCode);
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
// Status 3: Read Only
|
|
133
|
+
disableInputs: () => {
|
|
134
|
+
uiRenderer.injectCSS(
|
|
135
|
+
"dsg-readonly",
|
|
136
|
+
`
|
|
137
|
+
input, button, select, textarea, [contenteditable] {
|
|
138
|
+
pointer-events: none !important;
|
|
139
|
+
opacity: 0.6 !important;
|
|
140
|
+
background: #eee !important;
|
|
141
|
+
}
|
|
142
|
+
`,
|
|
143
|
+
);
|
|
144
|
+
uiRenderer.showWarning("Read-Only Mode: You cannot make changes.");
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
// Status 4: API Kill
|
|
148
|
+
disableAPIs: () => {
|
|
149
|
+
const noop = () => {
|
|
150
|
+
throw new Error("Blocked by DSG");
|
|
151
|
+
};
|
|
152
|
+
// Freeze these objects to prevent re-enabling
|
|
153
|
+
try {
|
|
154
|
+
window.fetch = noop;
|
|
155
|
+
window.XMLHttpRequest = function () {
|
|
156
|
+
this.open = noop;
|
|
157
|
+
this.send = noop;
|
|
158
|
+
};
|
|
159
|
+
Object.freeze(window.fetch);
|
|
160
|
+
} catch (e) {}
|
|
161
|
+
console.warn("☠️ APIs Disabled");
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
// Status 5: Maintenance
|
|
165
|
+
maintenanceMode: (message = "Maintenance in Progress") => {
|
|
166
|
+
const id = "dsg-maint";
|
|
167
|
+
const render = () => {
|
|
168
|
+
const div = document.createElement("div");
|
|
169
|
+
div.id = id;
|
|
170
|
+
div.innerHTML = `
|
|
171
|
+
<div style="font-family: sans-serif; background: #f8f9fa; color: #333; height: 100vh; width: 100vw; position: fixed; top: 0; left: 0; z-index: 2147483647; display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
|
172
|
+
<h1>System Maintenance</h1>
|
|
173
|
+
<p>${message}</p>
|
|
174
|
+
</div>
|
|
175
|
+
`;
|
|
176
|
+
if (!document.getElementById(id)) document.body.appendChild(div);
|
|
177
|
+
};
|
|
178
|
+
uiRenderer.secureElement(id, render, activeStatusCode);
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
// Status 7, 8: Fake Browser Check (DDOS/Bot)
|
|
182
|
+
fakeProtection: (message = "Checking your browser...") => {
|
|
183
|
+
const id = "dsg-ddos";
|
|
184
|
+
const render = () => {
|
|
185
|
+
const div = document.createElement("div");
|
|
186
|
+
div.id = id;
|
|
187
|
+
div.innerHTML = `
|
|
188
|
+
<div style="font-family: sans-serif; height: 100vh; width: 100vw; position: fixed; top: 0; left: 0; z-index: 2147483647; display: flex; flex-direction: column; justify-content: center; align-items: center; background: #fff;">
|
|
189
|
+
<div class="loader" style="border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite;"></div>
|
|
190
|
+
<h2 style="margin-top: 20px;">DDoS Protection</h2>
|
|
191
|
+
<p>${message}</p>
|
|
192
|
+
<style>@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>
|
|
193
|
+
</div>
|
|
194
|
+
`;
|
|
195
|
+
if (!document.getElementById(id)) document.body.appendChild(div);
|
|
196
|
+
};
|
|
197
|
+
uiRenderer.secureElement(id, render, activeStatusCode);
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// Status 10, 11, 12, 19: Feature Hiding
|
|
201
|
+
hideFeatures: (type) => {
|
|
202
|
+
let css = "";
|
|
203
|
+
let msg = "";
|
|
204
|
+
switch (type) {
|
|
205
|
+
case "payment":
|
|
206
|
+
css = `.payment, .checkout, .billing, [href*="checkout"], [href*="pay"] { display: none !important; }`;
|
|
207
|
+
msg = "Payments are currently disabled.";
|
|
208
|
+
break;
|
|
209
|
+
case "auth":
|
|
210
|
+
css = `.login, .signin, .signup, .register, [href*="login"], [href*="register"] { display: none !important; }`;
|
|
211
|
+
msg = "Authentication is disabled.";
|
|
212
|
+
break;
|
|
213
|
+
case "upload":
|
|
214
|
+
css = `input[type="file"], .upload-btn { display: none !important; }`;
|
|
215
|
+
msg = "File uploads are disabled.";
|
|
216
|
+
break;
|
|
217
|
+
case "limited": // 19
|
|
218
|
+
css = `.premium, .advanced, .pro-feature { display: none !important; }`;
|
|
219
|
+
msg = "Running in Limited Feature Mode.";
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
uiRenderer.injectCSS(`dsg-hide-${type}`, css);
|
|
223
|
+
uiRenderer.showWarning(msg);
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
// Status 14: Coming Soon
|
|
227
|
+
comingSoon: (message = "We are launching soon!") => {
|
|
228
|
+
const id = "dsg-soon";
|
|
229
|
+
const render = () => {
|
|
230
|
+
const div = document.createElement("div");
|
|
231
|
+
div.id = id;
|
|
232
|
+
div.innerHTML = `
|
|
233
|
+
<div style="font-family: sans-serif; background: #1a1a1a; color: #fff; height: 100vh; width: 100vw; position: fixed; top: 0; left: 0; z-index: 2147483647; display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
|
234
|
+
<h1>🚀 Coming Soon</h1>
|
|
235
|
+
<p>${message}</p>
|
|
236
|
+
</div>
|
|
237
|
+
`;
|
|
238
|
+
if (!document.getElementById(id)) document.body.appendChild(div);
|
|
239
|
+
};
|
|
240
|
+
uiRenderer.secureElement(id, render, activeStatusCode);
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
// Status 15: Sunset Countdown
|
|
244
|
+
sunsetMode: (message = "Service Shutting Down") => {
|
|
245
|
+
const id = "dsg-sunset";
|
|
246
|
+
const target = new Date();
|
|
247
|
+
target.setDate(target.getDate() + 30);
|
|
248
|
+
const render = () => {
|
|
249
|
+
const div = document.createElement("div");
|
|
250
|
+
div.id = id;
|
|
251
|
+
div.innerHTML = `
|
|
252
|
+
<div style="font-family: sans-serif; background: #000; color: #ff9900; height: 100vh; width: 100vw; position: fixed; top: 0; left: 0; z-index: 2147483647; display: flex; flex-direction: column; justify-content: center; align-items: center;">
|
|
253
|
+
<h1>🌅 service sunset</h1>
|
|
254
|
+
<p>${message}</p>
|
|
255
|
+
<div style="font-size: 4rem; margin: 20px;">${target.toISOString().split("T")[0]}</div>
|
|
256
|
+
<p>Please export your data immediately.</p>
|
|
257
|
+
</div>
|
|
258
|
+
`;
|
|
259
|
+
if (!document.getElementById(id)) document.body.appendChild(div);
|
|
260
|
+
};
|
|
261
|
+
uiRenderer.secureElement(id, render, activeStatusCode);
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
// Status 16, 17: Tier Lock
|
|
265
|
+
tierLock: (msg) => {
|
|
266
|
+
uiRenderer.showWarning(`🔒 ${msg}`);
|
|
267
|
+
uiRenderer.injectCSS(
|
|
268
|
+
"dsg-tier",
|
|
269
|
+
`.premium-content { filter: blur(5px); pointer-events: none; }`,
|
|
270
|
+
);
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
// Status 20: Cursor Lock
|
|
274
|
+
freezeCursor: () => {
|
|
275
|
+
uiRenderer.injectCSS("dsg-cursor", `* { cursor: none !important; }`);
|
|
276
|
+
window.addEventListener("mousemove", (e) => e.stopPropagation(), true);
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
// Status 99, 100: Ultra
|
|
280
|
+
disableConsole: () => {
|
|
281
|
+
["log", "warn", "error", "table"].forEach((m) => {
|
|
282
|
+
try {
|
|
283
|
+
console[m] = () => {};
|
|
284
|
+
// Object.defineProperty(console, m, { value: () => {}, writable: false });
|
|
285
|
+
} catch (e) {}
|
|
286
|
+
});
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
ultraLock: (msg) => {
|
|
290
|
+
uiRenderer.disableConsole();
|
|
291
|
+
uiRenderer.freezeCursor();
|
|
292
|
+
uiRenderer.blockPage(msg || "SYSTEM LOCKDOWN");
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
// === Main Switch ===
|
|
296
|
+
enforce: (statusCode, message) => {
|
|
297
|
+
const code = parseInt(statusCode, 10);
|
|
298
|
+
|
|
299
|
+
// State Transition Check: Only update if status CHANGED
|
|
300
|
+
if (activeStatusCode === code) return;
|
|
301
|
+
|
|
302
|
+
// Changing state: Reset previous blockers
|
|
303
|
+
uiRenderer.reset();
|
|
304
|
+
activeStatusCode = code;
|
|
305
|
+
|
|
306
|
+
switch (code) {
|
|
307
|
+
case 0:
|
|
308
|
+
uiRenderer.normal();
|
|
309
|
+
break;
|
|
310
|
+
|
|
311
|
+
case 1:
|
|
312
|
+
uiRenderer.blockPage(message || "Hack Detected: Access Denied");
|
|
313
|
+
break;
|
|
314
|
+
|
|
315
|
+
case 2:
|
|
316
|
+
uiRenderer.showWarning(message || "Misuse Detected");
|
|
317
|
+
break;
|
|
318
|
+
case 3:
|
|
319
|
+
uiRenderer.disableInputs();
|
|
320
|
+
break;
|
|
321
|
+
case 4:
|
|
322
|
+
uiRenderer.disableAPIs();
|
|
323
|
+
break;
|
|
324
|
+
case 5:
|
|
325
|
+
uiRenderer.maintenanceMode(message);
|
|
326
|
+
break;
|
|
327
|
+
case 6:
|
|
328
|
+
uiRenderer.showWarning(message || "Service Degraded: Expect Delays");
|
|
329
|
+
break;
|
|
330
|
+
|
|
331
|
+
case 7:
|
|
332
|
+
uiRenderer.fakeProtection(
|
|
333
|
+
message || "DDoS Protection: Verifying request...",
|
|
334
|
+
);
|
|
335
|
+
break;
|
|
336
|
+
case 8:
|
|
337
|
+
uiRenderer.fakeProtection(
|
|
338
|
+
message || "Bot Protection: Verifying human...",
|
|
339
|
+
);
|
|
340
|
+
break;
|
|
341
|
+
|
|
342
|
+
case 9:
|
|
343
|
+
uiRenderer.blockPage(message || "License Invalid or Expired");
|
|
344
|
+
break;
|
|
345
|
+
|
|
346
|
+
case 10:
|
|
347
|
+
uiRenderer.hideFeatures("payment");
|
|
348
|
+
break;
|
|
349
|
+
case 11:
|
|
350
|
+
uiRenderer.hideFeatures("auth");
|
|
351
|
+
break;
|
|
352
|
+
case 12:
|
|
353
|
+
uiRenderer.hideFeatures("upload");
|
|
354
|
+
break;
|
|
355
|
+
case 13:
|
|
356
|
+
uiRenderer.showWarning(
|
|
357
|
+
message || "Soft Maintenance: Updates in progress",
|
|
358
|
+
);
|
|
359
|
+
break;
|
|
360
|
+
|
|
361
|
+
case 14:
|
|
362
|
+
uiRenderer.comingSoon(message);
|
|
363
|
+
break;
|
|
364
|
+
case 15:
|
|
365
|
+
uiRenderer.sunsetMode(message);
|
|
366
|
+
break;
|
|
367
|
+
|
|
368
|
+
case 16:
|
|
369
|
+
uiRenderer.tierLock(message || "Free Mode: Premium features locked");
|
|
370
|
+
break;
|
|
371
|
+
case 17:
|
|
372
|
+
uiRenderer.tierLock(message || "Premium Users Only");
|
|
373
|
+
break;
|
|
374
|
+
|
|
375
|
+
case 18:
|
|
376
|
+
uiRenderer.blockPage(
|
|
377
|
+
message || "Geo-Restricted: Access not allowed from your location",
|
|
378
|
+
);
|
|
379
|
+
break;
|
|
380
|
+
case 19:
|
|
381
|
+
uiRenderer.hideFeatures("limited");
|
|
382
|
+
break;
|
|
383
|
+
|
|
384
|
+
case 20:
|
|
385
|
+
uiRenderer.freezeCursor();
|
|
386
|
+
break;
|
|
387
|
+
case 99:
|
|
388
|
+
uiRenderer.disableConsole();
|
|
389
|
+
break;
|
|
390
|
+
case 100:
|
|
391
|
+
uiRenderer.ultraLock(message);
|
|
392
|
+
break;
|
|
393
|
+
|
|
394
|
+
default:
|
|
395
|
+
console.warn("DSG: Unknown code", code);
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
// Harden the object to prevent overwriting methods
|
|
402
|
+
Object.freeze(uiRenderer);
|
|
403
|
+
|
|
404
|
+
export { uiRenderer };
|