reaper-arcade-hub 1.1.0 → 1.1.2

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/js/app.js CHANGED
@@ -105,14 +105,21 @@ class ReaperHubApp {
105
105
  window.reaperFirebase.listenBannedUsers((bannedList) => {
106
106
  this.bannedUsers = bannedList || [];
107
107
  this.renderBannedUsersList();
108
- if (this.currentUser.rank !== 'owner' && this.bannedUsers.includes(this.currentUser.username)) {
108
+ const currentNameLower = (this.currentUser.username || '').toLowerCase();
109
+ const isBannedOnServer = this.bannedUsers.some(u => u.toLowerCase() === currentNameLower);
110
+
111
+ if (this.currentUser.rank !== 'owner' && isBannedOnServer) {
109
112
  this.currentUser.isBanned = true;
110
113
  localStorage.setItem('reaper_is_banned', 'true');
111
- localStorage.removeItem('reaper_verified_token');
112
- localStorage.removeItem('reaper_token_expires');
113
- localStorage.removeItem('reaper_gateway_verified');
114
- localStorage.removeItem('reaper_playtime_' + this.currentUser.username);
115
114
  this.renderBanScreen("Your account has been permanently blacklisted and all recorded progress has been purged.");
115
+ } else {
116
+ // If unbanned!
117
+ if (this.currentUser.isBanned || document.getElementById('ban-screen-overlay')) {
118
+ this.currentUser.isBanned = false;
119
+ localStorage.removeItem('reaper_is_banned');
120
+ this.removeBanScreen();
121
+ this.showToast("Your account was UNBANNED by an Administrator!");
122
+ }
116
123
  }
117
124
  });
118
125
  window.reaperFirebase.listenShutdownMode((isShutdown) => {
@@ -1464,14 +1471,16 @@ class ReaperHubApp {
1464
1471
  if (!check.allowed) {
1465
1472
  input.value = '';
1466
1473
  this.updateChatStateUI();
1467
- this.showToast("Message blocked by AI filter. You are timed out for 5 minutes.");
1474
+ this.showToast(check.reason || "Message blocked by AI filter.");
1468
1475
  return;
1469
1476
  }
1470
1477
  }
1471
1478
 
1472
1479
  input.value = '';
1473
1480
 
1481
+ const msgId = 'msg_' + Date.now() + '_' + Math.random().toString(36).substring(2, 6);
1474
1482
  const msgData = {
1483
+ id: msgId,
1475
1484
  username: this.currentUser.username,
1476
1485
  rank: this.currentUser.rank,
1477
1486
  playtimeStr: this.formatPlaytime(this.playtimeSeconds),
@@ -1488,6 +1497,7 @@ class ReaperHubApp {
1488
1497
  }
1489
1498
 
1490
1499
  async deleteMessage(msgId, authorName) {
1500
+ if (!msgId) return;
1491
1501
  const isPrivileged = this.currentUser.rank === 'owner' || this.currentUser.rank === 'chat_mod' || this.currentUser.rank === 'mod';
1492
1502
  const canDelete = isPrivileged || (authorName === this.currentUser.username);
1493
1503
  if (!canDelete) {
@@ -1495,12 +1505,13 @@ class ReaperHubApp {
1495
1505
  return;
1496
1506
  }
1497
1507
 
1498
- if (confirm("Delete this message?")) {
1499
- this.chatMessages = this.chatMessages.filter(m => m.id !== msgId);
1500
- this.renderChatMessages();
1508
+ this.chatMessages = this.chatMessages.filter(m => m.id !== msgId);
1509
+ localStorage.setItem('reaper_local_chat', JSON.stringify(this.chatMessages));
1510
+ this.renderChatMessages();
1511
+ if (window.reaperFirebase) {
1501
1512
  await window.reaperFirebase.deleteChatMessage(msgId);
1502
- this.showToast("Message deleted.");
1503
1513
  }
1514
+ this.showToast("Message deleted globally.");
1504
1515
  }
1505
1516
 
1506
1517
  renderChatMessages() {
@@ -2118,7 +2129,17 @@ class ReaperHubApp {
2118
2129
  }
2119
2130
 
2120
2131
  renderBanScreen(customReason) {
2121
- document.body.innerHTML = `
2132
+ let overlay = document.getElementById('ban-screen-overlay');
2133
+ if (!overlay) {
2134
+ overlay = document.createElement('div');
2135
+ overlay.id = 'ban-screen-overlay';
2136
+ overlay.style.position = 'fixed';
2137
+ overlay.style.inset = '0';
2138
+ overlay.style.zIndex = '9999999';
2139
+ overlay.style.background = '#000';
2140
+ document.body.appendChild(overlay);
2141
+ }
2142
+ overlay.innerHTML = `
2122
2143
  <div style="display: flex; height: 100vh; width: 100vw; background: #000; color: #ff2a2a; font-family: var(--font-mono); align-items: center; justify-content: center; text-align: center; padding: 2rem;">
2123
2144
  <div style="border: 2px solid #ff2a2a; padding: 3rem 2rem; max-width: 540px; background: #0c0202; border-radius: 10px; box-shadow: 0 0 40px rgba(255, 42, 42, 0.4);">
2124
2145
  <h1 style="font-size: 2.2rem; margin-bottom: 1rem; color: #ff3333;">[PERMANENT BAN]</h1>
@@ -2131,6 +2152,14 @@ class ReaperHubApp {
2131
2152
  </div>
2132
2153
  </div>
2133
2154
  `;
2155
+ overlay.style.display = 'block';
2156
+ }
2157
+
2158
+ removeBanScreen() {
2159
+ const overlay = document.getElementById('ban-screen-overlay');
2160
+ if (overlay) {
2161
+ overlay.remove();
2162
+ }
2134
2163
  }
2135
2164
 
2136
2165
  renderPermanentShutdownScreen() {
@@ -2341,12 +2370,21 @@ class ReaperHubApp {
2341
2370
  }
2342
2371
 
2343
2372
  async unbanUser(username) {
2344
- this.bannedUsers = this.bannedUsers.filter(u => u !== username);
2373
+ if (!username) return;
2374
+ const cleanUser = username.trim();
2375
+ this.bannedUsers = this.bannedUsers.filter(u => u.toLowerCase() !== cleanUser.toLowerCase());
2345
2376
  localStorage.setItem('reaper_banned_users', JSON.stringify(this.bannedUsers));
2377
+
2378
+ if ((this.currentUser.username || '').toLowerCase() === cleanUser.toLowerCase()) {
2379
+ this.currentUser.isBanned = false;
2380
+ localStorage.removeItem('reaper_is_banned');
2381
+ this.removeBanScreen();
2382
+ }
2383
+
2346
2384
  if (window.reaperFirebase) {
2347
- await window.reaperFirebase.unbanUser(username);
2385
+ await window.reaperFirebase.unbanUser(cleanUser);
2348
2386
  }
2349
- this.showToast(`User ${username} Unbanned.`);
2387
+ this.showToast(`User ${cleanUser} UNBANNED.`);
2350
2388
  this.renderBannedUsersList();
2351
2389
  }
2352
2390
 
@@ -257,16 +257,17 @@ class FirebaseService {
257
257
 
258
258
  async banUser(username) {
259
259
  if (!username || username === 'owner') return;
260
+ const cleanUser = username.trim();
260
261
 
261
262
  if (this.db) {
262
263
  try {
263
- await this.db.ref(`reaperBannedUsers/${username}`).set(true);
264
- await this.db.ref(`reaperPlaytime/${username}`).remove();
264
+ await this.db.ref(`reaperBannedUsers/${cleanUser}`).set(true);
265
+ await this.db.ref(`reaperPlaytime/${cleanUser}`).remove();
265
266
  const chatSnap = await this.db.ref('reaperChat').once('value');
266
267
  if (chatSnap.exists()) {
267
268
  const chats = chatSnap.val();
268
269
  for (const msgId of Object.keys(chats)) {
269
- if (chats[msgId].username === username) {
270
+ if (chats[msgId].username && chats[msgId].username.toLowerCase() === cleanUser.toLowerCase()) {
270
271
  await this.db.ref(`reaperChat/${msgId}`).remove();
271
272
  }
272
273
  }
@@ -277,21 +278,34 @@ class FirebaseService {
277
278
  }
278
279
 
279
280
  const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]');
280
- if (!localBans.includes(username)) {
281
- localBans.push(username);
281
+ if (!localBans.some(u => u.toLowerCase() === cleanUser.toLowerCase())) {
282
+ localBans.push(cleanUser);
282
283
  localStorage.setItem('reaper_banned_users', JSON.stringify(localBans));
283
284
  }
284
285
  }
285
286
 
286
287
  async unbanUser(username) {
288
+ if (!username) return;
289
+ const cleanUser = username.trim();
290
+
287
291
  if (this.db) {
288
292
  try {
289
- await this.db.ref(`reaperBannedUsers/${username}`).remove();
293
+ await this.db.ref(`reaperBannedUsers/${cleanUser}`).remove();
294
+ const snap = await this.db.ref('reaperBannedUsers').once('value');
295
+ if (snap.exists()) {
296
+ const bans = snap.val();
297
+ for (const k of Object.keys(bans)) {
298
+ if (k.toLowerCase() === cleanUser.toLowerCase()) {
299
+ await this.db.ref(`reaperBannedUsers/${k}`).remove();
300
+ }
301
+ }
302
+ }
290
303
  } catch (e) {
291
304
  console.warn("Error unbanning user on Firebase:", e);
292
305
  }
293
306
  }
294
- const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]').filter(u => u !== username);
307
+
308
+ const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]').filter(u => u.toLowerCase() !== cleanUser.toLowerCase());
295
309
  localStorage.setItem('reaper_banned_users', JSON.stringify(localBans));
296
310
  }
297
311
 
package/js/moderator.js CHANGED
@@ -1,4 +1,5 @@
1
- // AI Content Moderator & Timeout Engine
1
+ // REAPER HUB - AI Content Moderator & Privacy Name Filter Engine
2
+ // Blocks profanity, slurs, drug references, and real personal names (Male & Female) for user safety and privacy.
2
3
 
3
4
  class AIContentModerator {
4
5
  constructor() {
@@ -19,6 +20,40 @@ class AIContentModerator {
19
20
  'porn', 'porno', 'xxx', 'hentai', 'rule34', 'xvideos', 'pornhub', 'onlyfans',
20
21
  'nsfw', 'sex', 'blowjob', 'handjob', 'dildo'
21
22
  ];
23
+
24
+ // Real Personal Names Filter (Male & Female Names) for Privacy & Safety
25
+ this.bannedNames = [
26
+ // Specific Requested Names
27
+ 'kaidan', 'kaiden', 'kayden', 'caiden', 'kaden', 'loki', 'harry', 'will', 'william',
28
+
29
+ // Male Names
30
+ 'liam', 'noah', 'oliver', 'james', 'elijah', 'mateo', 'theodore', 'henry', 'lucas',
31
+ 'benjamin', 'levi', 'sebastian', 'jack', 'ezra', 'michael', 'daniel', 'logan', 'jackson',
32
+ 'owen', 'samuel', 'alex', 'alexander', 'ryan', 'ethan', 'john', 'david', 'luke', 'mason',
33
+ 'connor', 'caleb', 'isaiah', 'anthony', 'charles', 'thomas', 'leo', 'jordan', 'jayden',
34
+ 'nathan', 'gabriel', 'carter', 'hunter', 'christian', 'aaron', 'eli', 'colton', 'landon',
35
+ 'adrian', 'brayden', 'tyler', 'austin', 'kevin', 'brandon', 'justin', 'george', 'jason',
36
+ 'cody', 'travis', 'dylan', 'kyle', 'brian', 'eric', 'steven', 'adam', 'joshua', 'jacob',
37
+ 'andrew', 'nicholas', 'zachary', 'zack', 'cameron', 'dominic', 'trevor', 'tristan', 'kobe',
38
+ 'brody', 'colin', 'damon', 'declan', 'derek', 'graham', 'ian', 'jasper', 'jonah', 'kai',
39
+ 'kieran', 'milo', 'nico', 'rowan', 'silas', 'tanner', 'tucker', 'wesley', 'zane',
40
+
41
+ // Female Names
42
+ 'olivia', 'emma', 'charlotte', 'amelia', 'sophia', 'isabella', 'ava', 'mia', 'evelyn',
43
+ 'luna', 'harper', 'camila', 'sofia', 'scarlett', 'elizabeth', 'eleanor', 'emily', 'chloe',
44
+ 'mila', 'violet', 'penelope', 'gianna', 'aria', 'abigail', 'ella', 'avery', 'hazel',
45
+ 'nora', 'layla', 'lily', 'isla', 'elena', 'aurora', 'zoey', 'stella', 'nova', 'hannah',
46
+ 'leah', 'maya', 'claire', 'lucy', 'madelyn', 'sarah', 'grace', 'zoe', 'natalie',
47
+ 'kinsley', 'audrey', 'riley', 'savannah', 'brooklyn', 'clara', 'genesis', 'piper', 'ivy',
48
+ 'sadie', 'delilah', 'serenity', 'autumn', 'ruby', 'alice', 'eva', 'hailey', 'madison',
49
+ 'kayla', 'alyssa', 'brianna', 'taylor', 'megan', 'katelyn', 'sydney', 'destiny', 'jessica',
50
+ 'ashley', 'amanda', 'brittany', 'stephanie', 'samantha', 'jennifer', 'rachel', 'lauren',
51
+ 'morgan', 'kaylee', 'vanessa', 'paige', 'victoria', 'valerie', 'chelsea', 'kaitlyn',
52
+ 'melanie', 'amber', 'erica', 'brooke', 'tara', 'courtney', 'holly', 'heather', 'kelsey',
53
+ 'shelby', 'leslie', 'shannon', 'whitney', 'dana', 'fiona', 'gemma', 'heidi', 'jenna',
54
+ 'kendra', 'kira', 'laura', 'nadia', 'nina', 'poppy', 'rosie', 'sienna', 'skye', 'talia',
55
+ 'tessa', 'willa', 'zara'
56
+ ];
22
57
  }
23
58
 
24
59
  getTimeoutRemaining() {
@@ -42,15 +77,28 @@ class AIContentModerator {
42
77
 
43
78
  const cleanText = text.toLowerCase();
44
79
 
80
+ // 1. Check Bad Words & Controlled Substances
45
81
  for (const term of this.bannedTerms) {
46
- // Strictly check whole words with boundary regex
47
82
  const regex = new RegExp(`(?:^|\\s|[^a-zA-Z0-9])${term}(?:$|\\s|[^a-zA-Z0-9])`, 'i');
48
83
  if (regex.test(cleanText)) {
49
84
  if (!isAdmin) this.applyTimeout(5);
50
85
  return {
51
86
  allowed: false,
52
87
  flaggedTerm: term,
53
- reason: `Message deleted by AI. You are timed out for 5 minutes.`
88
+ reason: `Message blocked by AI filter for prohibited language. You are timed out for 5 minutes.`
89
+ };
90
+ }
91
+ }
92
+
93
+ // 2. Check Real Personal Names (Male & Female) for Safety & Privacy
94
+ for (const name of this.bannedNames) {
95
+ const regex = new RegExp(`(?:^|\\s|[^a-zA-Z0-9])${name}(?:$|\\s|[^a-zA-Z0-9])`, 'i');
96
+ if (regex.test(cleanText)) {
97
+ if (!isAdmin) this.applyTimeout(2);
98
+ return {
99
+ allowed: false,
100
+ flaggedTerm: name,
101
+ reason: `Privacy Alert: Real personal names (${name}) are strictly prohibited in chat for your safety.`
54
102
  };
55
103
  }
56
104
  }
package/main/js/app.js CHANGED
@@ -105,14 +105,21 @@ class ReaperHubApp {
105
105
  window.reaperFirebase.listenBannedUsers((bannedList) => {
106
106
  this.bannedUsers = bannedList || [];
107
107
  this.renderBannedUsersList();
108
- if (this.currentUser.rank !== 'owner' && this.bannedUsers.includes(this.currentUser.username)) {
108
+ const currentNameLower = (this.currentUser.username || '').toLowerCase();
109
+ const isBannedOnServer = this.bannedUsers.some(u => u.toLowerCase() === currentNameLower);
110
+
111
+ if (this.currentUser.rank !== 'owner' && isBannedOnServer) {
109
112
  this.currentUser.isBanned = true;
110
113
  localStorage.setItem('reaper_is_banned', 'true');
111
- localStorage.removeItem('reaper_verified_token');
112
- localStorage.removeItem('reaper_token_expires');
113
- localStorage.removeItem('reaper_gateway_verified');
114
- localStorage.removeItem('reaper_playtime_' + this.currentUser.username);
115
114
  this.renderBanScreen("Your account has been permanently blacklisted and all recorded progress has been purged.");
115
+ } else {
116
+ // If unbanned!
117
+ if (this.currentUser.isBanned || document.getElementById('ban-screen-overlay')) {
118
+ this.currentUser.isBanned = false;
119
+ localStorage.removeItem('reaper_is_banned');
120
+ this.removeBanScreen();
121
+ this.showToast("Your account was UNBANNED by an Administrator!");
122
+ }
116
123
  }
117
124
  });
118
125
  window.reaperFirebase.listenShutdownMode((isShutdown) => {
@@ -1464,14 +1471,16 @@ class ReaperHubApp {
1464
1471
  if (!check.allowed) {
1465
1472
  input.value = '';
1466
1473
  this.updateChatStateUI();
1467
- this.showToast("Message blocked by AI filter. You are timed out for 5 minutes.");
1474
+ this.showToast(check.reason || "Message blocked by AI filter.");
1468
1475
  return;
1469
1476
  }
1470
1477
  }
1471
1478
 
1472
1479
  input.value = '';
1473
1480
 
1481
+ const msgId = 'msg_' + Date.now() + '_' + Math.random().toString(36).substring(2, 6);
1474
1482
  const msgData = {
1483
+ id: msgId,
1475
1484
  username: this.currentUser.username,
1476
1485
  rank: this.currentUser.rank,
1477
1486
  playtimeStr: this.formatPlaytime(this.playtimeSeconds),
@@ -1488,6 +1497,7 @@ class ReaperHubApp {
1488
1497
  }
1489
1498
 
1490
1499
  async deleteMessage(msgId, authorName) {
1500
+ if (!msgId) return;
1491
1501
  const isPrivileged = this.currentUser.rank === 'owner' || this.currentUser.rank === 'chat_mod' || this.currentUser.rank === 'mod';
1492
1502
  const canDelete = isPrivileged || (authorName === this.currentUser.username);
1493
1503
  if (!canDelete) {
@@ -1495,12 +1505,13 @@ class ReaperHubApp {
1495
1505
  return;
1496
1506
  }
1497
1507
 
1498
- if (confirm("Delete this message?")) {
1499
- this.chatMessages = this.chatMessages.filter(m => m.id !== msgId);
1500
- this.renderChatMessages();
1508
+ this.chatMessages = this.chatMessages.filter(m => m.id !== msgId);
1509
+ localStorage.setItem('reaper_local_chat', JSON.stringify(this.chatMessages));
1510
+ this.renderChatMessages();
1511
+ if (window.reaperFirebase) {
1501
1512
  await window.reaperFirebase.deleteChatMessage(msgId);
1502
- this.showToast("Message deleted.");
1503
1513
  }
1514
+ this.showToast("Message deleted globally.");
1504
1515
  }
1505
1516
 
1506
1517
  renderChatMessages() {
@@ -2118,7 +2129,17 @@ class ReaperHubApp {
2118
2129
  }
2119
2130
 
2120
2131
  renderBanScreen(customReason) {
2121
- document.body.innerHTML = `
2132
+ let overlay = document.getElementById('ban-screen-overlay');
2133
+ if (!overlay) {
2134
+ overlay = document.createElement('div');
2135
+ overlay.id = 'ban-screen-overlay';
2136
+ overlay.style.position = 'fixed';
2137
+ overlay.style.inset = '0';
2138
+ overlay.style.zIndex = '9999999';
2139
+ overlay.style.background = '#000';
2140
+ document.body.appendChild(overlay);
2141
+ }
2142
+ overlay.innerHTML = `
2122
2143
  <div style="display: flex; height: 100vh; width: 100vw; background: #000; color: #ff2a2a; font-family: var(--font-mono); align-items: center; justify-content: center; text-align: center; padding: 2rem;">
2123
2144
  <div style="border: 2px solid #ff2a2a; padding: 3rem 2rem; max-width: 540px; background: #0c0202; border-radius: 10px; box-shadow: 0 0 40px rgba(255, 42, 42, 0.4);">
2124
2145
  <h1 style="font-size: 2.2rem; margin-bottom: 1rem; color: #ff3333;">[PERMANENT BAN]</h1>
@@ -2131,6 +2152,14 @@ class ReaperHubApp {
2131
2152
  </div>
2132
2153
  </div>
2133
2154
  `;
2155
+ overlay.style.display = 'block';
2156
+ }
2157
+
2158
+ removeBanScreen() {
2159
+ const overlay = document.getElementById('ban-screen-overlay');
2160
+ if (overlay) {
2161
+ overlay.remove();
2162
+ }
2134
2163
  }
2135
2164
 
2136
2165
  renderPermanentShutdownScreen() {
@@ -2341,12 +2370,21 @@ class ReaperHubApp {
2341
2370
  }
2342
2371
 
2343
2372
  async unbanUser(username) {
2344
- this.bannedUsers = this.bannedUsers.filter(u => u !== username);
2373
+ if (!username) return;
2374
+ const cleanUser = username.trim();
2375
+ this.bannedUsers = this.bannedUsers.filter(u => u.toLowerCase() !== cleanUser.toLowerCase());
2345
2376
  localStorage.setItem('reaper_banned_users', JSON.stringify(this.bannedUsers));
2377
+
2378
+ if ((this.currentUser.username || '').toLowerCase() === cleanUser.toLowerCase()) {
2379
+ this.currentUser.isBanned = false;
2380
+ localStorage.removeItem('reaper_is_banned');
2381
+ this.removeBanScreen();
2382
+ }
2383
+
2346
2384
  if (window.reaperFirebase) {
2347
- await window.reaperFirebase.unbanUser(username);
2385
+ await window.reaperFirebase.unbanUser(cleanUser);
2348
2386
  }
2349
- this.showToast(`User ${username} Unbanned.`);
2387
+ this.showToast(`User ${cleanUser} UNBANNED.`);
2350
2388
  this.renderBannedUsersList();
2351
2389
  }
2352
2390
 
@@ -257,16 +257,17 @@ class FirebaseService {
257
257
 
258
258
  async banUser(username) {
259
259
  if (!username || username === 'owner') return;
260
+ const cleanUser = username.trim();
260
261
 
261
262
  if (this.db) {
262
263
  try {
263
- await this.db.ref(`reaperBannedUsers/${username}`).set(true);
264
- await this.db.ref(`reaperPlaytime/${username}`).remove();
264
+ await this.db.ref(`reaperBannedUsers/${cleanUser}`).set(true);
265
+ await this.db.ref(`reaperPlaytime/${cleanUser}`).remove();
265
266
  const chatSnap = await this.db.ref('reaperChat').once('value');
266
267
  if (chatSnap.exists()) {
267
268
  const chats = chatSnap.val();
268
269
  for (const msgId of Object.keys(chats)) {
269
- if (chats[msgId].username === username) {
270
+ if (chats[msgId].username && chats[msgId].username.toLowerCase() === cleanUser.toLowerCase()) {
270
271
  await this.db.ref(`reaperChat/${msgId}`).remove();
271
272
  }
272
273
  }
@@ -277,21 +278,34 @@ class FirebaseService {
277
278
  }
278
279
 
279
280
  const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]');
280
- if (!localBans.includes(username)) {
281
- localBans.push(username);
281
+ if (!localBans.some(u => u.toLowerCase() === cleanUser.toLowerCase())) {
282
+ localBans.push(cleanUser);
282
283
  localStorage.setItem('reaper_banned_users', JSON.stringify(localBans));
283
284
  }
284
285
  }
285
286
 
286
287
  async unbanUser(username) {
288
+ if (!username) return;
289
+ const cleanUser = username.trim();
290
+
287
291
  if (this.db) {
288
292
  try {
289
- await this.db.ref(`reaperBannedUsers/${username}`).remove();
293
+ await this.db.ref(`reaperBannedUsers/${cleanUser}`).remove();
294
+ const snap = await this.db.ref('reaperBannedUsers').once('value');
295
+ if (snap.exists()) {
296
+ const bans = snap.val();
297
+ for (const k of Object.keys(bans)) {
298
+ if (k.toLowerCase() === cleanUser.toLowerCase()) {
299
+ await this.db.ref(`reaperBannedUsers/${k}`).remove();
300
+ }
301
+ }
302
+ }
290
303
  } catch (e) {
291
304
  console.warn("Error unbanning user on Firebase:", e);
292
305
  }
293
306
  }
294
- const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]').filter(u => u !== username);
307
+
308
+ const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]').filter(u => u.toLowerCase() !== cleanUser.toLowerCase());
295
309
  localStorage.setItem('reaper_banned_users', JSON.stringify(localBans));
296
310
  }
297
311
 
@@ -1,4 +1,5 @@
1
- // AI Content Moderator & Timeout Engine
1
+ // REAPER HUB - AI Content Moderator & Privacy Name Filter Engine
2
+ // Blocks profanity, slurs, drug references, and real personal names (Male & Female) for user safety and privacy.
2
3
 
3
4
  class AIContentModerator {
4
5
  constructor() {
@@ -19,6 +20,40 @@ class AIContentModerator {
19
20
  'porn', 'porno', 'xxx', 'hentai', 'rule34', 'xvideos', 'pornhub', 'onlyfans',
20
21
  'nsfw', 'sex', 'blowjob', 'handjob', 'dildo'
21
22
  ];
23
+
24
+ // Real Personal Names Filter (Male & Female Names) for Privacy & Safety
25
+ this.bannedNames = [
26
+ // Specific Requested Names
27
+ 'kaidan', 'kaiden', 'kayden', 'caiden', 'kaden', 'loki', 'harry', 'will', 'william',
28
+
29
+ // Male Names
30
+ 'liam', 'noah', 'oliver', 'james', 'elijah', 'mateo', 'theodore', 'henry', 'lucas',
31
+ 'benjamin', 'levi', 'sebastian', 'jack', 'ezra', 'michael', 'daniel', 'logan', 'jackson',
32
+ 'owen', 'samuel', 'alex', 'alexander', 'ryan', 'ethan', 'john', 'david', 'luke', 'mason',
33
+ 'connor', 'caleb', 'isaiah', 'anthony', 'charles', 'thomas', 'leo', 'jordan', 'jayden',
34
+ 'nathan', 'gabriel', 'carter', 'hunter', 'christian', 'aaron', 'eli', 'colton', 'landon',
35
+ 'adrian', 'brayden', 'tyler', 'austin', 'kevin', 'brandon', 'justin', 'george', 'jason',
36
+ 'cody', 'travis', 'dylan', 'kyle', 'brian', 'eric', 'steven', 'adam', 'joshua', 'jacob',
37
+ 'andrew', 'nicholas', 'zachary', 'zack', 'cameron', 'dominic', 'trevor', 'tristan', 'kobe',
38
+ 'brody', 'colin', 'damon', 'declan', 'derek', 'graham', 'ian', 'jasper', 'jonah', 'kai',
39
+ 'kieran', 'milo', 'nico', 'rowan', 'silas', 'tanner', 'tucker', 'wesley', 'zane',
40
+
41
+ // Female Names
42
+ 'olivia', 'emma', 'charlotte', 'amelia', 'sophia', 'isabella', 'ava', 'mia', 'evelyn',
43
+ 'luna', 'harper', 'camila', 'sofia', 'scarlett', 'elizabeth', 'eleanor', 'emily', 'chloe',
44
+ 'mila', 'violet', 'penelope', 'gianna', 'aria', 'abigail', 'ella', 'avery', 'hazel',
45
+ 'nora', 'layla', 'lily', 'isla', 'elena', 'aurora', 'zoey', 'stella', 'nova', 'hannah',
46
+ 'leah', 'maya', 'claire', 'lucy', 'madelyn', 'sarah', 'grace', 'zoe', 'natalie',
47
+ 'kinsley', 'audrey', 'riley', 'savannah', 'brooklyn', 'clara', 'genesis', 'piper', 'ivy',
48
+ 'sadie', 'delilah', 'serenity', 'autumn', 'ruby', 'alice', 'eva', 'hailey', 'madison',
49
+ 'kayla', 'alyssa', 'brianna', 'taylor', 'megan', 'katelyn', 'sydney', 'destiny', 'jessica',
50
+ 'ashley', 'amanda', 'brittany', 'stephanie', 'samantha', 'jennifer', 'rachel', 'lauren',
51
+ 'morgan', 'kaylee', 'vanessa', 'paige', 'victoria', 'valerie', 'chelsea', 'kaitlyn',
52
+ 'melanie', 'amber', 'erica', 'brooke', 'tara', 'courtney', 'holly', 'heather', 'kelsey',
53
+ 'shelby', 'leslie', 'shannon', 'whitney', 'dana', 'fiona', 'gemma', 'heidi', 'jenna',
54
+ 'kendra', 'kira', 'laura', 'nadia', 'nina', 'poppy', 'rosie', 'sienna', 'skye', 'talia',
55
+ 'tessa', 'willa', 'zara'
56
+ ];
22
57
  }
23
58
 
24
59
  getTimeoutRemaining() {
@@ -42,15 +77,28 @@ class AIContentModerator {
42
77
 
43
78
  const cleanText = text.toLowerCase();
44
79
 
80
+ // 1. Check Bad Words & Controlled Substances
45
81
  for (const term of this.bannedTerms) {
46
- // Strictly check whole words with boundary regex
47
82
  const regex = new RegExp(`(?:^|\\s|[^a-zA-Z0-9])${term}(?:$|\\s|[^a-zA-Z0-9])`, 'i');
48
83
  if (regex.test(cleanText)) {
49
84
  if (!isAdmin) this.applyTimeout(5);
50
85
  return {
51
86
  allowed: false,
52
87
  flaggedTerm: term,
53
- reason: `Message deleted by AI. You are timed out for 5 minutes.`
88
+ reason: `Message blocked by AI filter for prohibited language. You are timed out for 5 minutes.`
89
+ };
90
+ }
91
+ }
92
+
93
+ // 2. Check Real Personal Names (Male & Female) for Safety & Privacy
94
+ for (const name of this.bannedNames) {
95
+ const regex = new RegExp(`(?:^|\\s|[^a-zA-Z0-9])${name}(?:$|\\s|[^a-zA-Z0-9])`, 'i');
96
+ if (regex.test(cleanText)) {
97
+ if (!isAdmin) this.applyTimeout(2);
98
+ return {
99
+ allowed: false,
100
+ flaggedTerm: name,
101
+ reason: `Privacy Alert: Real personal names (${name}) are strictly prohibited in chat for your safety.`
54
102
  };
55
103
  }
56
104
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "reaper-arcade-hub",
3
- "version": "1.1.0",
4
- "description": "Reaper Hub - 788 High-Speed HTML5 Games, Potato PC Performance Mode, Top Plays, Realtime Chat, Private DMs, Playtime Leaderboard & Verification Gateway",
3
+ "version": "1.1.2",
4
+ "description": "Reaper Hub - 788 High-Speed HTML5 Games, Instant Reactive Unban & Ban Engine, AI Name Privacy Filter, Global Chat Deletion, Potato PC Performance Mode, Top Plays, Realtime Chat, Private DMs, Playtime Leaderboard & Verification Gateway",
5
5
  "main": "main/index.html",
6
6
  "unpkg": "main/index.html",
7
7
  "jsdelivr": "main/index.html",
@@ -14,8 +14,10 @@
14
14
  "html5",
15
15
  "unblocked",
16
16
  "arcade",
17
+ "unban",
18
+ "moderation",
19
+ "privacy",
17
20
  "performance",
18
- "potatomode",
19
21
  "leaderboard",
20
22
  "dms",
21
23
  "topplays"
@@ -257,16 +257,17 @@ class FirebaseService {
257
257
 
258
258
  async banUser(username) {
259
259
  if (!username || username === 'owner') return;
260
+ const cleanUser = username.trim();
260
261
 
261
262
  if (this.db) {
262
263
  try {
263
- await this.db.ref(`reaperBannedUsers/${username}`).set(true);
264
- await this.db.ref(`reaperPlaytime/${username}`).remove();
264
+ await this.db.ref(`reaperBannedUsers/${cleanUser}`).set(true);
265
+ await this.db.ref(`reaperPlaytime/${cleanUser}`).remove();
265
266
  const chatSnap = await this.db.ref('reaperChat').once('value');
266
267
  if (chatSnap.exists()) {
267
268
  const chats = chatSnap.val();
268
269
  for (const msgId of Object.keys(chats)) {
269
- if (chats[msgId].username === username) {
270
+ if (chats[msgId].username && chats[msgId].username.toLowerCase() === cleanUser.toLowerCase()) {
270
271
  await this.db.ref(`reaperChat/${msgId}`).remove();
271
272
  }
272
273
  }
@@ -277,21 +278,34 @@ class FirebaseService {
277
278
  }
278
279
 
279
280
  const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]');
280
- if (!localBans.includes(username)) {
281
- localBans.push(username);
281
+ if (!localBans.some(u => u.toLowerCase() === cleanUser.toLowerCase())) {
282
+ localBans.push(cleanUser);
282
283
  localStorage.setItem('reaper_banned_users', JSON.stringify(localBans));
283
284
  }
284
285
  }
285
286
 
286
287
  async unbanUser(username) {
288
+ if (!username) return;
289
+ const cleanUser = username.trim();
290
+
287
291
  if (this.db) {
288
292
  try {
289
- await this.db.ref(`reaperBannedUsers/${username}`).remove();
293
+ await this.db.ref(`reaperBannedUsers/${cleanUser}`).remove();
294
+ const snap = await this.db.ref('reaperBannedUsers').once('value');
295
+ if (snap.exists()) {
296
+ const bans = snap.val();
297
+ for (const k of Object.keys(bans)) {
298
+ if (k.toLowerCase() === cleanUser.toLowerCase()) {
299
+ await this.db.ref(`reaperBannedUsers/${k}`).remove();
300
+ }
301
+ }
302
+ }
290
303
  } catch (e) {
291
304
  console.warn("Error unbanning user on Firebase:", e);
292
305
  }
293
306
  }
294
- const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]').filter(u => u !== username);
307
+
308
+ const localBans = JSON.parse(localStorage.getItem('reaper_banned_users') || '[]').filter(u => u.toLowerCase() !== cleanUser.toLowerCase());
295
309
  localStorage.setItem('reaper_banned_users', JSON.stringify(localBans));
296
310
  }
297
311