Skip to content

Commit dbccedc

Browse files
docs: update README with module refactor, XP integrity, and feature enhancements
1 parent c48ccfd commit dbccedc

4 files changed

Lines changed: 54 additions & 13 deletions

File tree

README.md

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ Missions are grouped into three categories on the Hub:
9595

9696
* **Frontend:** HTML5, CSS3 (Retro-Cyberpunk aesthetic with CRT effects, scanlines, and neon animations). Fully responsive with mobile media queries (`<600px`, `601–900px`).
9797
* **Database & Auth:** **Firebase** (Firestore for XP/Leaderboard/Daily Scores and Firebase Auth for Email/Password + Google Sign-In).
98-
* **Audio Engine:** **Web Audio API** — procedurally generated success, error, and click sounds, plus two selectable ambient music tracks (Cyberpunk and Dark Ambient) with reverb, arpeggios, kick/hihat rhythm, and LFO modulation.
99-
* **Logic:** Modular ES6+ JavaScript.
98+
* **Audio Engine:** **Web Audio API** — procedurally generated success, error, and click sounds, plus three selectable ambient music tracks (Cyberpunk, Dark Ambient, Hacker Terminal) with reverb, arpeggios, kick/hihat rhythm, and LFO modulation.
99+
* **Logic:** Modular ES6+ JavaScript with clear single-responsibility module boundaries.
100100
* **AI Integration:** OpenRouter API (Mistral-7B) for live phishing scenario generation with a local fallback engine.
101101
* **Adaptive Learning:** `adaptive.js` engine delivers difficulty scaling (timer, extra steps) and actionable safety protocols based on user XP rank.
102102

@@ -106,12 +106,13 @@ Missions are grouped into three categories on the Hub:
106106

107107
| Mechanic | Description |
108108
| :--- | :--- |
109-
| **XP & Leaderboard** | Earn XP for every successful mission and climb the global top-5 ranks (stored in Firestore). |
109+
| **XP & Leaderboard** | Earn XP for every successful mission and climb the global ranks (stored in Firestore). |
110+
| **Daily XP Cap** | Each mission awards XP only once per calendar day — enforced server-side in Firestore. Replaying a mission after earning XP that day gives 0 XP, preventing spam farming. Resets at midnight. |
110111
| **Rank System** | Novice (0 XP) → Specialist (100 XP) → Elite Guardian (500 XP), with a progress bar. |
111112
| **Adaptive Difficulty** | Timer and scenario complexity scale with XP rank. Novice: 30s timer. Specialist: 27s + extra social engineering steps. Elite: 25s + extra steps. |
112113
| **Achievements / Badges** | Unlock badges: 🔰 Rookie (0 XP), 🔍 Detective (50 XP), 🛡️ Shield (200 XP), 👑 Elite (500 XP). |
113114
| **Mission Locks** | Dark Web (50 XP), AI Crime Lab (75 XP), Incident Response (100 XP), Mission Creator (150 XP). Locked missions show a 🔒 overlay with the required XP. |
114-
| **🔔 Notification Bell** | When you earn enough XP to unlock a mission or feature, a red badge appears on the 🔔 bell icon in the top bar. Click it to see all unlocks — no intrusive popups. Mark all as read to clear the badge. |
115+
| **🔔 Notification Bell** | When you earn enough XP to unlock a mission or feature, a red badge appears on the 🔔 bell icon in the top bar. Badge only lights up for genuinely new unlocks earned since your last visit — not on every page load. Mark all as read to clear it. |
115116
| **Hard Mode** | Unlocked at 300 XP — all missions run at Elite difficulty. |
116117
| **Mission Completion Tracker** | Profile page shows ✅/⬜ status for all 10 missions. |
117118
| **Unlocks Panel** | Progress bars in the profile show how close you are to each locked mission/feature. |
@@ -128,7 +129,7 @@ Missions are grouped into three categories on the Hub:
128129
| **Activity Ticker** | Live scrolling feed on the Hub simulating global community activity. |
129130
| **High Contrast Mode** | Accessibility toggle persisted via `localStorage`. |
130131
| **⚙️ Settings Panel** | Gear icon (fixed, top-right) opens a panel with Font Size (Small/Medium/Large dropdown), Music Track selector, Volume slider, Mute button, and Music ON/OFF toggle. All settings persisted via `localStorage`. |
131-
| **Music Tracks** | Two selectable ambient tracks: ⚡ Cyberpunk (120 BPM minor pentatonic arpeggio + kick/hihat + reverb) and 🌑 Dark Ambient (slow evolving pads + sub-bass + occasional deep thuds). |
132+
| **Music Tracks** | Three selectable ambient tracks: ⚡ Cyberpunk (120 BPM minor pentatonic arpeggio + kick/hihat + reverb), 🌑 Dark Ambient (slow evolving pads + sub-bass + occasional deep thuds), and 💻 Hacker Terminal (glitchy bleeps + low pulse). |
132133
| **Audio Controls** | Volume slider, mute button, music toggle, and track selector — all inside the ⚙️ Settings panel. |
133134
| **Breadcrumbs** | Auto-injected navigation trail on all mission pages. |
134135
| **Personalized Greeting** | Hub shows "Hi, [name]!" using `displayName` for Google users or the part before `@` for email/password users. |
@@ -142,7 +143,7 @@ Missions are grouped into three categories on the Hub:
142143
CyberArena/
143144
├── hub.html # Mission Hub — missions only, top bar with Profile & Bell
144145
├── profile.html # Dedicated Profile page — XP, rank, badges, missions, unlocks, leaderboard
145-
├── index.html # Firebase Auth Portal (Email/Password + Google)
146+
├── index.html # Firebase Auth Portal (Google Sign-In)
146147
├── phishing.html # Phishing Detective Mission
147148
├── social.html # Social Engineering Simulator
148149
├── ai.html # AI Crime Lab (Deepfake Detection)
@@ -158,9 +159,13 @@ CyberArena/
158159
│ └── style.css # Neon-Cyberpunk UI Framework + mobile media queries + tour styles + settings panel
159160
└── js/
160161
├── firebase.js # Firebase Config & Initialization
161-
├── auth.js # Authentication Logic — shows "Hi, name!" greeting on login
162-
├── xp.js # XP & Firestore Data Management (updateXP, getUserData)
163-
├── common.js # Shared Navigation, Breadcrumbs, High Contrast, ⚙️ Settings Panel & Audio Engine
162+
├── auth.js # Auth boundary for the whole app — redirect, logout, XP-guard for locked missions
163+
├── xp.js # XP & Firestore Data Management (updateXP with daily cap, getUserData)
164+
├── common.js # Loader — sources music.js, sounds.js, breadcrumb.js, settings.js + navigation helpers
165+
├── music.js # Ambient music engine — 3 tracks (Cyberpunk, Dark Ambient, Hacker Terminal)
166+
├── sounds.js # UI sound effects (success, error, click) + global button click listener
167+
├── breadcrumb.js # Auto-injects navigation breadcrumb on mission pages
168+
├── settings.js # Settings panel UI, high-contrast, font size, mute, volume
164169
├── audio.js # Standalone Audio Module (ES6 export)
165170
├── adaptive.js # Adaptive Difficulty Engine — timerSeconds (30/27/25), extraSteps, safetyProtocols
166171
├── tour.js # 6-step Onboarding Tour — spotlight overlay, dots, localStorage persistence
@@ -187,6 +192,12 @@ CyberArena/
187192
```
188193
2. **Firebase Setup**
189194
* The project is pre-configured with a demo Firebase project (`cyberarena-77a96`). To use your own, update `js/firebase.js` with your project credentials.
195+
* Ensure your Firestore security rules allow authenticated users to read and write their own document:
196+
```
197+
match /users/{userId} {
198+
allow read, write: if request.auth != null && request.auth.uid == userId;
199+
}
200+
```
190201
3. **Run Locally**
191202
* Open `index.html` in any modern web browser. A local server (e.g., VS Code Live Server) is recommended for Firebase ES modules to load correctly.
192203
4. **Or visit the live hosted version directly at [https://cyberarena-77a96.web.app](https://cyberarena-77a96.web.app)**
@@ -211,15 +222,30 @@ CyberArena/
211222
| `muted` | Audio mute state |
212223
| `volume` | Master volume level (0–1) |
213224
| `musicOn` | Ambient music on/off state |
214-
| `musicTrack` | Selected music track (`cyberpunk` or `dark`) |
225+
| `musicTrack` | Selected music track (`cyberpunk`, `dark`, or `hacker`) |
215226
| `fontSize` | Font size class (`font-sm`, `font-md`, `font-lg`) |
216227
| `settingsPanelOpen` | Whether the ⚙️ settings panel is open or closed |
217228
| `openrouter_api_key` | OpenRouter API key for live AI phishing scenarios |
229+
| `lastSeenXP` | XP value at last hub visit — used to detect genuinely new unlocks for the 🔔 bell |
218230
| `seenUnlocks` | Array of unlock IDs already processed — prevents duplicate bell notifications |
219231
| `unlockNotifications` | Array of unlock notification objects `{ id, label, description, read }` for the 🔔 bell |
220232
221233
---
222234
235+
## 🔒 XP Integrity
236+
237+
XP farming is prevented by a **per-mission daily cap** enforced server-side in Firestore:
238+
239+
- Each mission can award XP only **once per calendar day** per user.
240+
- On completion, `updateXP()` writes `dailyXP.{missionId}_{YYYY-MM-DD} = true` to the user's Firestore document.
241+
- On the next call for the same mission that day, the flag is detected before any write occurs and the function returns early.
242+
- The key is date-scoped, so XP resets naturally at midnight with no cleanup job needed.
243+
- Because the check happens against Firestore (not `localStorage`), it cannot be bypassed by clearing browser storage.
244+
245+
The Daily Challenge has its own separate replay protection via `dailyScores/{dateKey}/players` in Firestore.
246+
247+
---
248+
223249
## 🛡️ Security Education at its Best
224250
CyberArena isn't just a game — it's a training ground for the digital age. By simulating the psychological and technical tactics of hackers, we empower users to become the strongest link in the security chain.
225251

public/js/ai.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ function makeDecision(userChoice) {
115115
updateXP(score, 'ai');
116116
} else {
117117
score -= 10;
118-
updateXP(0);
118+
updateXP(0, 'ai');
119119
}
120120

121121
const resultLabel = correct

public/js/password.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ verifyMFABtn.onclick = () => {
160160

161161
if (entered === actual) {
162162
alert("✅ MFA Verified! 10 XP Gained.");
163-
updateXP(10);
163+
updateXP(10, 'password');
164164
mfaPrompt.style.display = "none";
165165
} else {
166166
alert("❌ Wrong code. Try again.");

public/js/xp.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,32 @@ import {
88
arrayUnion,
99
} from "https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore.js";
1010

11+
function todayKey() {
12+
return new Date().toISOString().slice(0, 10); // "YYYY-MM-DD"
13+
}
14+
1115
export async function updateXP(points, missionId = null) {
1216
const user = auth.currentUser;
1317
if (!user) return;
1418

1519
const userRef = doc(db, "users", user.uid);
1620
const userSnap = await getDoc(userRef);
1721

22+
// Per-mission daily cap: only award XP once per mission per calendar day
23+
if (missionId && userSnap.exists()) {
24+
const played = userSnap.data().dailyXP || {};
25+
const key = `${missionId}_${todayKey()}`;
26+
if (played[key]) return;
27+
}
28+
1829
const updateData = {
1930
xp: increment(points),
2031
missionsCompleted: increment(1),
2132
};
22-
if (missionId) updateData.completedMissions = arrayUnion(missionId);
33+
if (missionId) {
34+
updateData.completedMissions = arrayUnion(missionId);
35+
updateData[`dailyXP.${missionId}_${todayKey()}`] = true;
36+
}
2337

2438
if (userSnap.exists()) {
2539
await updateDoc(userRef, updateData);
@@ -29,6 +43,7 @@ export async function updateXP(points, missionId = null) {
2943
xp: points,
3044
missionsCompleted: 1,
3145
completedMissions: missionId ? [missionId] : [],
46+
dailyXP: missionId ? { [`${missionId}_${todayKey()}`]: true } : {},
3247
achievements: [],
3348
});
3449
}

0 commit comments

Comments
 (0)