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.
@@ -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();