reaper-arcade-hub 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/css/styles.css +980 -0
- package/index.html +548 -0
- package/js/app.js +1758 -0
- package/js/firebase-client.js +427 -0
- package/js/games-data.js +7861 -0
- package/js/moderator.js +68 -0
- package/js/security-shield.js +225 -0
- package/js/usernames.js +112 -0
- package/js/visuals.js +74 -0
- package/main/css/styles.css +980 -0
- package/main/games.json +7860 -0
- package/main/index.html +548 -0
- package/main/js/app.js +1758 -0
- package/main/js/firebase-client.js +427 -0
- package/main/js/games-data.js +7861 -0
- package/main/js/moderator.js +68 -0
- package/main/js/security-shield.js +225 -0
- package/main/js/usernames.js +112 -0
- package/main/js/visuals.js +74 -0
- package/package.json +32 -0
- package/verify/css/styles.css +980 -0
- package/verify/index.html +437 -0
- package/verify/js/firebase-client.js +427 -0
- package/verify/js/security-shield.js +225 -0
- package/verify/js/visuals.js +74 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
// REAPER HUB - Firebase Realtime Engine, Live Chat & Server Security Service
|
|
2
|
+
|
|
3
|
+
const firebaseConfig = {
|
|
4
|
+
apiKey: "AIzaSyBuLsNUpp1DAGWI9cKni_MZJQsgB97xfHA",
|
|
5
|
+
authDomain: "gabasd-69d8a.firebaseapp.com",
|
|
6
|
+
databaseURL: "https://gabasd-69d8a-default-rtdb.firebaseio.com",
|
|
7
|
+
projectId: "gabasd-69d8a",
|
|
8
|
+
storageBucket: "gabasd-69d8a.firebasestorage.app",
|
|
9
|
+
messagingSenderId: "1088727880080",
|
|
10
|
+
appId: "1:1088727880080:web:b7765ab900e4c1dd492315",
|
|
11
|
+
measurementId: "G-S8PPR0SBKL"
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
class FirebaseService {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.app = null;
|
|
17
|
+
this.db = null;
|
|
18
|
+
this.isInitialized = false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async init() {
|
|
22
|
+
try {
|
|
23
|
+
if (typeof firebase !== 'undefined' && firebase.initializeApp) {
|
|
24
|
+
if (!firebase.apps.length) {
|
|
25
|
+
this.app = firebase.initializeApp(firebaseConfig);
|
|
26
|
+
} else {
|
|
27
|
+
this.app = firebase.app();
|
|
28
|
+
}
|
|
29
|
+
this.db = firebase.database();
|
|
30
|
+
this.isInitialized = true;
|
|
31
|
+
console.log("[REAPER HUB] Realtime DB Connected successfully.");
|
|
32
|
+
}
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.warn("[REAPER HUB] Firebase init error:", e);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Realtime Live Chat
|
|
39
|
+
listenChatMessages(callback) {
|
|
40
|
+
if (this.db) {
|
|
41
|
+
try {
|
|
42
|
+
const chatRef = this.db.ref("reaperChat").limitToLast(60);
|
|
43
|
+
chatRef.on("value", (snapshot) => {
|
|
44
|
+
const val = snapshot.val();
|
|
45
|
+
let messages = [];
|
|
46
|
+
if (val) {
|
|
47
|
+
messages = Object.values(val);
|
|
48
|
+
messages.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0));
|
|
49
|
+
}
|
|
50
|
+
callback(messages);
|
|
51
|
+
}, (error) => {
|
|
52
|
+
console.error("[REAPER CHAT ERROR]", error);
|
|
53
|
+
const localChat = JSON.parse(localStorage.getItem("reaper_local_chat") || "[]");
|
|
54
|
+
callback(localChat);
|
|
55
|
+
});
|
|
56
|
+
} catch (err) {
|
|
57
|
+
const localChat = JSON.parse(localStorage.getItem("reaper_local_chat") || "[]");
|
|
58
|
+
callback(localChat);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
const localChat = JSON.parse(localStorage.getItem("reaper_local_chat") || "[]");
|
|
62
|
+
callback(localChat);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async sendChatMessage(msgData) {
|
|
67
|
+
const msgId = 'msg_' + Date.now() + '_' + Math.random().toString(36).substring(2, 6);
|
|
68
|
+
msgData.id = msgId;
|
|
69
|
+
|
|
70
|
+
const localChat = JSON.parse(localStorage.getItem("reaper_local_chat") || "[]");
|
|
71
|
+
localChat.push(msgData);
|
|
72
|
+
if (localChat.length > 80) localChat.shift();
|
|
73
|
+
localStorage.setItem("reaper_local_chat", JSON.stringify(localChat));
|
|
74
|
+
|
|
75
|
+
if (this.db) {
|
|
76
|
+
try {
|
|
77
|
+
await this.db.ref(`reaperChat/${msgId}`).set(msgData);
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.error("[REAPER CHAT SEND ERROR]", e);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async deleteChatMessage(msgId) {
|
|
86
|
+
let localChat = JSON.parse(localStorage.getItem("reaper_local_chat") || "[]");
|
|
87
|
+
localChat = localChat.filter(m => m.id !== msgId);
|
|
88
|
+
localStorage.setItem("reaper_local_chat", JSON.stringify(localChat));
|
|
89
|
+
|
|
90
|
+
if (this.db) {
|
|
91
|
+
try {
|
|
92
|
+
await this.db.ref(`reaperChat/${msgId}`).remove();
|
|
93
|
+
} catch (e) {
|
|
94
|
+
console.error("[REAPER CHAT DELETE ERROR]", e);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
listenChatLock(callback) {
|
|
101
|
+
if (this.db) {
|
|
102
|
+
try {
|
|
103
|
+
this.db.ref("reaperChatLocked").on("value", (snap) => {
|
|
104
|
+
callback(Boolean(snap.val()));
|
|
105
|
+
});
|
|
106
|
+
} catch (e) {}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async setChatLock(isLocked) {
|
|
111
|
+
localStorage.setItem("reaper_chat_locked", isLocked ? 'true' : 'false');
|
|
112
|
+
if (this.db) {
|
|
113
|
+
try {
|
|
114
|
+
await this.db.ref("reaperChatLocked").set(isLocked);
|
|
115
|
+
} catch (e) {}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Realtime Bans & Leaderboard Progress Purge
|
|
120
|
+
listenBannedUsers(callback) {
|
|
121
|
+
if (this.db) {
|
|
122
|
+
try {
|
|
123
|
+
this.db.ref("reaperBannedUsers").on("value", (snap) => {
|
|
124
|
+
const bans = snap.val() || {};
|
|
125
|
+
const bannedList = Object.keys(bans);
|
|
126
|
+
localStorage.setItem('reaper_banned_users', JSON.stringify(bannedList));
|
|
127
|
+
callback(bannedList);
|
|
128
|
+
});
|
|
129
|
+
} catch (e) {
|
|
130
|
+
const local = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]');
|
|
131
|
+
callback(local);
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
const local = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]');
|
|
135
|
+
callback(local);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async banUser(username) {
|
|
140
|
+
if (!username || username === 'owner') return;
|
|
141
|
+
|
|
142
|
+
if (this.db) {
|
|
143
|
+
try {
|
|
144
|
+
await this.db.ref(`reaperBannedUsers/${username}`).set(true);
|
|
145
|
+
await this.db.ref(`reaperPlaytime/${username}`).remove();
|
|
146
|
+
const chatSnap = await this.db.ref('reaperChat').once('value');
|
|
147
|
+
if (chatSnap.exists()) {
|
|
148
|
+
const chats = chatSnap.val();
|
|
149
|
+
for (const msgId of Object.keys(chats)) {
|
|
150
|
+
if (chats[msgId].username === username) {
|
|
151
|
+
await this.db.ref(`reaperChat/${msgId}`).remove();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} catch (e) {
|
|
156
|
+
console.warn("Error banning user on Firebase:", e);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]');
|
|
161
|
+
if (!localBans.includes(username)) {
|
|
162
|
+
localBans.push(username);
|
|
163
|
+
localStorage.setItem('reaper_banned_users', JSON.stringify(localBans));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async unbanUser(username) {
|
|
168
|
+
if (this.db) {
|
|
169
|
+
try {
|
|
170
|
+
await this.db.ref(`reaperBannedUsers/${username}`).remove();
|
|
171
|
+
} catch (e) {
|
|
172
|
+
console.warn("Error unbanning user on Firebase:", e);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]').filter(u => u !== username);
|
|
176
|
+
localStorage.setItem('reaper_banned_users', JSON.stringify(localBans));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Realtime Site Lockdown (Main Portal)
|
|
180
|
+
listenSiteLockdown(callback) {
|
|
181
|
+
if (this.db) {
|
|
182
|
+
try {
|
|
183
|
+
this.db.ref("reaperSiteLockdown").on("value", (snap) => {
|
|
184
|
+
const isLocked = Boolean(snap.val());
|
|
185
|
+
localStorage.setItem('reaper_site_lockdown', isLocked ? 'true' : 'false');
|
|
186
|
+
callback(isLocked);
|
|
187
|
+
});
|
|
188
|
+
} catch (e) {
|
|
189
|
+
callback(localStorage.getItem('reaper_site_lockdown') === 'true');
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
callback(localStorage.getItem('reaper_site_lockdown') === 'true');
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async setSiteLockdown(isLocked) {
|
|
197
|
+
localStorage.setItem('reaper_site_lockdown', isLocked ? 'true' : 'false');
|
|
198
|
+
if (this.db) {
|
|
199
|
+
try {
|
|
200
|
+
await this.db.ref("reaperSiteLockdown").set(isLocked);
|
|
201
|
+
} catch (e) {}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Realtime Verify Gateway Lockdown
|
|
206
|
+
listenVerifyLockdown(callback) {
|
|
207
|
+
if (this.db) {
|
|
208
|
+
try {
|
|
209
|
+
this.db.ref("reaperVerifyLockdown").on("value", (snap) => {
|
|
210
|
+
const isLocked = Boolean(snap.val());
|
|
211
|
+
localStorage.setItem('reaper_verify_lockdown', isLocked ? 'true' : 'false');
|
|
212
|
+
callback(isLocked);
|
|
213
|
+
});
|
|
214
|
+
} catch (e) {
|
|
215
|
+
callback(localStorage.getItem('reaper_verify_lockdown') === 'true');
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
callback(localStorage.getItem('reaper_verify_lockdown') === 'true');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async setVerifyLockdown(isLocked) {
|
|
223
|
+
localStorage.setItem('reaper_verify_lockdown', isLocked ? 'true' : 'false');
|
|
224
|
+
if (this.db) {
|
|
225
|
+
try {
|
|
226
|
+
await this.db.ref("reaperVerifyLockdown").set(isLocked);
|
|
227
|
+
} catch (e) {}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Realtime Keys Pause / Freeze Lock
|
|
232
|
+
listenKeysLocked(callback) {
|
|
233
|
+
if (this.db) {
|
|
234
|
+
try {
|
|
235
|
+
this.db.ref("reaperKeysLocked").on("value", (snap) => {
|
|
236
|
+
const isLocked = Boolean(snap.val());
|
|
237
|
+
localStorage.setItem('reaper_keys_locked', isLocked ? 'true' : 'false');
|
|
238
|
+
callback(isLocked);
|
|
239
|
+
});
|
|
240
|
+
} catch (e) {
|
|
241
|
+
callback(localStorage.getItem('reaper_keys_locked') === 'true');
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
callback(localStorage.getItem('reaper_keys_locked') === 'true');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async setKeysLocked(isLocked) {
|
|
249
|
+
localStorage.setItem('reaper_keys_locked', isLocked ? 'true' : 'false');
|
|
250
|
+
if (this.db) {
|
|
251
|
+
try {
|
|
252
|
+
await this.db.ref("reaperKeysLocked").set(isLocked);
|
|
253
|
+
} catch (e) {}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Realtime Emergency Google Redirect Lock (Panic Mode)
|
|
258
|
+
listenRedirectGoogle(callback) {
|
|
259
|
+
if (this.db) {
|
|
260
|
+
try {
|
|
261
|
+
this.db.ref("reaperRedirectGoogle").on("value", (snap) => {
|
|
262
|
+
const isRedirect = Boolean(snap.val());
|
|
263
|
+
localStorage.setItem('reaper_redirect_google', isRedirect ? 'true' : 'false');
|
|
264
|
+
callback(isRedirect);
|
|
265
|
+
});
|
|
266
|
+
} catch (e) {
|
|
267
|
+
callback(localStorage.getItem('reaper_redirect_google') === 'true');
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
callback(localStorage.getItem('reaper_redirect_google') === 'true');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async setRedirectGoogle(isRedirect) {
|
|
275
|
+
localStorage.setItem('reaper_redirect_google', isRedirect ? 'true' : 'false');
|
|
276
|
+
if (this.db) {
|
|
277
|
+
try {
|
|
278
|
+
await this.db.ref("reaperRedirectGoogle").set(isRedirect);
|
|
279
|
+
} catch (e) {}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Permanent Shutdown Mode ("WE ARE SHUTTING DOWN FOR GOOD")
|
|
284
|
+
listenShutdownMode(callback) {
|
|
285
|
+
if (this.db) {
|
|
286
|
+
try {
|
|
287
|
+
this.db.ref("reaperShutdownMode").on("value", (snap) => {
|
|
288
|
+
const isShutdown = Boolean(snap.val());
|
|
289
|
+
localStorage.setItem('reaper_shutdown_mode', isShutdown ? 'true' : 'false');
|
|
290
|
+
callback(isShutdown);
|
|
291
|
+
});
|
|
292
|
+
} catch (e) {}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async setShutdownMode(isShutdown) {
|
|
297
|
+
localStorage.setItem('reaper_shutdown_mode', isShutdown ? 'true' : 'false');
|
|
298
|
+
if (this.db) {
|
|
299
|
+
try {
|
|
300
|
+
await this.db.ref("reaperShutdownMode").set(isShutdown);
|
|
301
|
+
} catch (e) {}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Purge All Server Data
|
|
306
|
+
async purgeAllServerData() {
|
|
307
|
+
if (this.db) {
|
|
308
|
+
try {
|
|
309
|
+
await this.db.ref('reaperChat').remove();
|
|
310
|
+
await this.db.ref('reaperPlaytime').remove();
|
|
311
|
+
await this.db.ref('reaperGeneratedKeys').remove();
|
|
312
|
+
await this.db.ref('reaperTimeouts').remove();
|
|
313
|
+
} catch (e) {
|
|
314
|
+
console.error("Purge error on Firebase:", e);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
localStorage.removeItem('reaper_local_chat');
|
|
318
|
+
localStorage.removeItem('reaper_generated_keys');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Cross-Domain Realtime Key Management
|
|
322
|
+
listenGeneratedKeys(callback) {
|
|
323
|
+
if (this.db) {
|
|
324
|
+
try {
|
|
325
|
+
this.db.ref("reaperGeneratedKeys").on("value", (snap) => {
|
|
326
|
+
const keys = snap.val() || {};
|
|
327
|
+
localStorage.setItem('reaper_generated_keys', JSON.stringify(keys));
|
|
328
|
+
callback(keys);
|
|
329
|
+
});
|
|
330
|
+
} catch (e) {
|
|
331
|
+
const local = JSON.parse(localStorage.getItem('reaper_generated_keys') || '{}');
|
|
332
|
+
callback(local);
|
|
333
|
+
}
|
|
334
|
+
} else {
|
|
335
|
+
const local = JSON.parse(localStorage.getItem('reaper_generated_keys') || '{}');
|
|
336
|
+
callback(local);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async saveKey(keyName, keyInfo) {
|
|
341
|
+
const local = JSON.parse(localStorage.getItem('reaper_generated_keys') || '{}');
|
|
342
|
+
local[keyName] = keyInfo;
|
|
343
|
+
localStorage.setItem('reaper_generated_keys', JSON.stringify(local));
|
|
344
|
+
|
|
345
|
+
if (this.db) {
|
|
346
|
+
try {
|
|
347
|
+
await this.db.ref(`reaperGeneratedKeys/${keyName}`).set(keyInfo);
|
|
348
|
+
} catch (e) {
|
|
349
|
+
console.warn("Error saving key to Firebase:", e);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async deleteKey(keyName) {
|
|
355
|
+
const local = JSON.parse(localStorage.getItem('reaper_generated_keys') || '{}');
|
|
356
|
+
delete local[keyName];
|
|
357
|
+
localStorage.setItem('reaper_generated_keys', JSON.stringify(local));
|
|
358
|
+
|
|
359
|
+
if (this.db) {
|
|
360
|
+
try {
|
|
361
|
+
await this.db.ref(`reaperGeneratedKeys/${keyName}`).remove();
|
|
362
|
+
} catch (e) {
|
|
363
|
+
console.warn("Error deleting key from Firebase:", e);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async fetchKeyInfo(keyName) {
|
|
369
|
+
if (!keyName) return null;
|
|
370
|
+
const cleanKey = keyName.trim().toUpperCase();
|
|
371
|
+
|
|
372
|
+
if (this.db) {
|
|
373
|
+
try {
|
|
374
|
+
// 1. Direct match
|
|
375
|
+
let snap = await this.db.ref(`reaperGeneratedKeys/${cleanKey}`).once('value');
|
|
376
|
+
if (snap.exists()) return snap.val();
|
|
377
|
+
|
|
378
|
+
// 2. Prefixed with REAPER-
|
|
379
|
+
if (!cleanKey.startsWith('REAPER-')) {
|
|
380
|
+
snap = await this.db.ref(`reaperGeneratedKeys/REAPER-${cleanKey}`).once('value');
|
|
381
|
+
if (snap.exists()) return snap.val();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 3. Case-insensitive scan across all keys
|
|
385
|
+
const allSnap = await this.db.ref('reaperGeneratedKeys').once('value');
|
|
386
|
+
if (allSnap.exists()) {
|
|
387
|
+
const allKeys = allSnap.val();
|
|
388
|
+
for (const k of Object.keys(allKeys)) {
|
|
389
|
+
if (k.toUpperCase() === cleanKey || k.toUpperCase() === 'REAPER-' + cleanKey) {
|
|
390
|
+
return allKeys[k];
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
} catch (e) {}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const local = JSON.parse(localStorage.getItem('reaper_generated_keys') || '{}');
|
|
398
|
+
if (local[cleanKey]) return local[cleanKey];
|
|
399
|
+
if (local['REAPER-' + cleanKey]) return local['REAPER-' + cleanKey];
|
|
400
|
+
for (const k of Object.keys(local)) {
|
|
401
|
+
if (k.toUpperCase() === cleanKey || k.toUpperCase() === 'REAPER-' + cleanKey) {
|
|
402
|
+
return local[k];
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async incrementKeyUsage(keyName) {
|
|
409
|
+
if (this.db) {
|
|
410
|
+
try {
|
|
411
|
+
const keyRef = this.db.ref(`reaperGeneratedKeys/${keyName}`);
|
|
412
|
+
const snap = await keyRef.once('value');
|
|
413
|
+
if (snap.exists()) {
|
|
414
|
+
const info = snap.val();
|
|
415
|
+
const newUsed = (info.usedCount || 0) + 1;
|
|
416
|
+
if (newUsed >= (info.maxUses || 999999)) {
|
|
417
|
+
await keyRef.remove();
|
|
418
|
+
} else {
|
|
419
|
+
await keyRef.update({ usedCount: newUsed });
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
} catch (e) {}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
window.reaperFirebase = new FirebaseService();
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// REAPER HUB - Universal Anti-Extension Spy Shield & System Defense Engine
|
|
2
|
+
// Scans, detects, isolates, and terminates browser extension hooks, surveillance content-scripts, and DOM inspectors.
|
|
3
|
+
|
|
4
|
+
(function() {
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
class ReaperSecurityShield {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.bannedSignatures = [
|
|
10
|
+
{ id: 'goguardian', name: 'GoGuardian Surveillance Hook', category: 'School Spyware', risk: 'CRITICAL' },
|
|
11
|
+
{ id: 'securly', name: 'Securly Filter & Activity Probe', category: 'School Spyware', risk: 'CRITICAL' },
|
|
12
|
+
{ id: 'hapara', name: 'Hapara Highlights Screen Grabber', category: 'School Spyware', risk: 'CRITICAL' },
|
|
13
|
+
{ id: 'blocksi', name: 'Blocksi Web Content Scanner', category: 'School Spyware', risk: 'CRITICAL' },
|
|
14
|
+
{ id: 'lightspeed', name: 'Lightspeed Relay Screen Spy', category: 'School Spyware', risk: 'HIGH' },
|
|
15
|
+
{ id: 'lanschool', name: 'LanSchool Classroom Monitor', category: 'School Spyware', risk: 'CRITICAL' },
|
|
16
|
+
{ id: 'imperosoftware', name: 'Impero Education Spy Hook', category: 'School Spyware', risk: 'CRITICAL' },
|
|
17
|
+
{ id: 'contentkeeper', name: 'ContentKeeper Behavioral Monitor', category: 'School Spyware', risk: 'HIGH' },
|
|
18
|
+
{ id: 'deledao', name: 'Deledao AI Web Telemetry', category: 'School Spyware', risk: 'HIGH' },
|
|
19
|
+
{ id: 'linewize', name: 'Linewize School Filter Probe', category: 'School Spyware', risk: 'HIGH' },
|
|
20
|
+
{ id: 'bark', name: 'Bark Youth Monitoring Probe', category: 'Activity Spy', risk: 'MEDIUM' },
|
|
21
|
+
{ id: 'cisco-umbrella', name: 'Cisco Umbrella DNS Sniffer', category: 'Network Filter', risk: 'HIGH' },
|
|
22
|
+
{ id: 'netsupport', name: 'NetSupport School Screen Catcher', category: 'School Spyware', risk: 'CRITICAL' },
|
|
23
|
+
{ id: 'aristotle', name: 'Aristotle Insight Telemetry', category: 'School Spyware', risk: 'HIGH' },
|
|
24
|
+
{ id: 'smoothwall', name: 'Smoothwall Web Policy Monitor', category: 'School Spyware', risk: 'HIGH' },
|
|
25
|
+
{ id: 'grammarly', name: 'Grammarly DOM Text Keystroke Hook', category: 'Input Sniffer', risk: 'MEDIUM' },
|
|
26
|
+
{ id: 'lastpass', name: 'LastPass Autofill Hook', category: 'Autofill Extension', risk: 'LOW' },
|
|
27
|
+
{ id: 'tampermonkey', name: 'UserScript / Userscript Manager', category: 'DOM Injector', risk: 'MEDIUM' },
|
|
28
|
+
{ id: 'adblock', name: 'AdBlocker Content Scraper', category: 'Ad Filter', risk: 'LOW' }
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
this.autoShield = localStorage.getItem('reaper_auto_shield') !== 'false';
|
|
32
|
+
this.detectedExtensions = [];
|
|
33
|
+
this.blockedCount = 0;
|
|
34
|
+
this.isScanning = false;
|
|
35
|
+
|
|
36
|
+
this.init();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
init() {
|
|
40
|
+
// 1. Defend Against DevTools Inspection Shortcuts
|
|
41
|
+
window.addEventListener('keydown', (e) => {
|
|
42
|
+
if (e.key === 'F12' || e.keyCode === 123) {
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
e.stopPropagation();
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (e.ctrlKey && e.shiftKey && ['I','i','J','j','C','c','K','k','E','e','S','s'].includes(e.key)) {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (e.ctrlKey && (e.key === 'U' || e.key === 'u')) {
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
e.stopPropagation();
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}, true);
|
|
58
|
+
|
|
59
|
+
// 2. Cloak chrome.runtime messaging
|
|
60
|
+
try {
|
|
61
|
+
if (window.chrome && window.chrome.runtime) {
|
|
62
|
+
const origSendMessage = window.chrome.runtime.sendMessage;
|
|
63
|
+
const bannedIds = this.bannedSignatures.map(s => s.id);
|
|
64
|
+
window.chrome.runtime.sendMessage = function() {
|
|
65
|
+
if (arguments[0] && typeof arguments[0] === 'object') {
|
|
66
|
+
const payload = JSON.stringify(arguments[0]).toLowerCase();
|
|
67
|
+
for (let i = 0; i < bannedIds.length; i++) {
|
|
68
|
+
if (payload.includes(bannedIds[i])) {
|
|
69
|
+
return Promise.resolve({ blocked: true });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (origSendMessage) {
|
|
74
|
+
try {
|
|
75
|
+
return origSendMessage.apply(this, arguments);
|
|
76
|
+
} catch (err) {}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
} catch (e) {}
|
|
81
|
+
|
|
82
|
+
// 3. Setup continuous MutationObserver to instantly strip injected extension nodes
|
|
83
|
+
if (typeof MutationObserver !== 'undefined') {
|
|
84
|
+
const observer = new MutationObserver((mutations) => {
|
|
85
|
+
for (let i = 0; i < mutations.length; i++) {
|
|
86
|
+
const added = mutations[i].addedNodes;
|
|
87
|
+
for (let j = 0; j < added.length; j++) {
|
|
88
|
+
const node = added[j];
|
|
89
|
+
if (this.isSpyElement(node)) {
|
|
90
|
+
if (node.parentNode) {
|
|
91
|
+
node.parentNode.removeChild(node);
|
|
92
|
+
this.blockedCount++;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const target = document.documentElement || document;
|
|
100
|
+
observer.observe(target, { childList: true, subtree: true });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 4. Auto-Purge Loop if enabled
|
|
104
|
+
if (this.autoShield) {
|
|
105
|
+
setInterval(() => this.purgeSpyInjections(), 800);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Initial scan
|
|
109
|
+
setTimeout(() => this.scanExtensions(), 500);
|
|
110
|
+
console.log("%c[REAPER SECURITY SHIELD]%c Active & Monitoring.", "color: #00d2ff; font-weight: 900;", "color: #88ccff;");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
isSpyElement(node) {
|
|
114
|
+
if (!node || node.nodeType !== 1) return false;
|
|
115
|
+
try {
|
|
116
|
+
const id = (node.id || '').toLowerCase();
|
|
117
|
+
const cls = (typeof node.className === 'string' ? node.className : '').toLowerCase();
|
|
118
|
+
const src = (node.src || '').toLowerCase();
|
|
119
|
+
const href = (node.href || '').toLowerCase();
|
|
120
|
+
|
|
121
|
+
for (let i = 0; i < this.bannedSignatures.length; i++) {
|
|
122
|
+
const sig = this.bannedSignatures[i].id;
|
|
123
|
+
if (id.includes(sig) || cls.includes(sig) || src.includes(sig) || href.includes(sig)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if ((src.startsWith('chrome-extension://') || href.startsWith('chrome-extension://')) &&
|
|
129
|
+
!src.includes('firebase') && !src.includes('gstatic')) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
} catch (e) {}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
scanExtensions() {
|
|
137
|
+
this.isScanning = true;
|
|
138
|
+
const detected = [];
|
|
139
|
+
|
|
140
|
+
// Probe DOM elements, scripts, styles, iframes
|
|
141
|
+
this.bannedSignatures.forEach(sig => {
|
|
142
|
+
let isPresent = false;
|
|
143
|
+
let details = 'No active DOM hooks found';
|
|
144
|
+
|
|
145
|
+
// Check DOM selectors
|
|
146
|
+
const found = document.querySelectorAll(`[id*="${sig.id}" i], [class*="${sig.id}" i], script[src*="${sig.id}" i], link[href*="${sig.id}" i]`);
|
|
147
|
+
if (found.length > 0) {
|
|
148
|
+
isPresent = true;
|
|
149
|
+
details = `${found.length} injected DOM element(s) detected`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Check global window artifacts
|
|
153
|
+
const keys = Object.keys(window);
|
|
154
|
+
for (let i = 0; i < keys.length; i++) {
|
|
155
|
+
if (keys[i].toLowerCase().includes(sig.id)) {
|
|
156
|
+
isPresent = true;
|
|
157
|
+
details = `Global object window.${keys[i]} detected`;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
detected.push({
|
|
163
|
+
id: sig.id,
|
|
164
|
+
name: sig.name,
|
|
165
|
+
category: sig.category,
|
|
166
|
+
risk: sig.risk,
|
|
167
|
+
status: isPresent ? 'ACTIVE_BLOCKED' : 'NEUTRALIZED',
|
|
168
|
+
details: details
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Probe for generic chrome-extension scripts
|
|
173
|
+
const extElements = document.querySelectorAll('script[src^="chrome-extension://"], iframe[src^="chrome-extension://"]');
|
|
174
|
+
if (extElements.length > 0) {
|
|
175
|
+
detected.unshift({
|
|
176
|
+
id: 'generic-ext',
|
|
177
|
+
name: 'External Chrome Extension Content Script',
|
|
178
|
+
category: 'Browser Extension',
|
|
179
|
+
risk: 'HIGH',
|
|
180
|
+
status: 'ACTIVE_BLOCKED',
|
|
181
|
+
details: `${extElements.length} chrome-extension:// script/iframe hook(s)`
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.detectedExtensions = detected;
|
|
186
|
+
this.isScanning = false;
|
|
187
|
+
return detected;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
purgeSpyInjections() {
|
|
191
|
+
let count = 0;
|
|
192
|
+
try {
|
|
193
|
+
this.bannedSignatures.forEach(sig => {
|
|
194
|
+
const found = document.querySelectorAll(`[id*="${sig.id}" i], [class*="${sig.id}" i], iframe[src*="${sig.id}" i], script[src*="${sig.id}" i]`);
|
|
195
|
+
for (let i = 0; i < found.length; i++) {
|
|
196
|
+
const el = found[i];
|
|
197
|
+
if (el && el.parentNode && el.id !== 'app-splash-screen' && !el.closest('#app-layout')) {
|
|
198
|
+
el.parentNode.removeChild(el);
|
|
199
|
+
count++;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// Kill generic chrome-extension injections
|
|
205
|
+
const extNodes = document.querySelectorAll('iframe[src^="chrome-extension://"], script[src^="chrome-extension://"]');
|
|
206
|
+
for (let i = 0; i < extNodes.length; i++) {
|
|
207
|
+
if (extNodes[i] && extNodes[i].parentNode) {
|
|
208
|
+
extNodes[i].parentNode.removeChild(extNodes[i]);
|
|
209
|
+
count++;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} catch (e) {}
|
|
213
|
+
|
|
214
|
+
this.blockedCount += count;
|
|
215
|
+
return count;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
setAutoPurge(enabled) {
|
|
219
|
+
this.autoShield = enabled;
|
|
220
|
+
localStorage.setItem('reaper_auto_shield', enabled ? 'true' : 'false');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
window.reaperShield = new ReaperSecurityShield();
|
|
225
|
+
})();
|