diff --git a/.pgpass b/.pgpass new file mode 100644 index 0000000..1704bef --- /dev/null +++ b/.pgpass @@ -0,0 +1 @@ +localhost:5432:ninjacross:reptil1990:!Delfine1!!! \ No newline at end of file diff --git a/PUSH_NOTIFICATIONS_SETUP.md b/PUSH_NOTIFICATIONS_SETUP.md new file mode 100644 index 0000000..8075105 --- /dev/null +++ b/PUSH_NOTIFICATIONS_SETUP.md @@ -0,0 +1,108 @@ +# 🚀 Push Notifications Setup - Ninja Cross + +## ✅ Status: Vollständig funktionsfähig! + +Alle PWA Push Notification Probleme wurden behoben: + +### 🔧 Was wurde behoben: +1. **✅ VAPID Keys** generiert und konfiguriert +2. **✅ Push Service Backend** erstellt (`push-service.js`) +3. **✅ API Endpoints** für Push erweitert +4. **✅ Manifest.json** Icons korrigiert (PNG statt ICO) +5. **✅ Service Worker** Icons aktualisiert +6. **✅ HTTPS** funktioniert über Apache2 Proxy +7. **✅ UUID-Fehler** behoben (anonymous users bekommen UUID) +8. **✅ Test-Seite** für Debugging erstellt + +## 🧪 Push Notifications testen: + +### **1. Test-Seite aufrufen:** +``` +https://ninja.reptilfpv.de/test-push.html +``` + +### **2. Auf dem iPhone testen:** +1. **Safari öffnen** und zu `https://ninja.reptilfpv.de/test-push.html` gehen +2. **"Berechtigung anfordern"** klicken → iOS fragt nach Notification-Permission +3. **"Push abonnieren"** klicken → Service Worker registriert Push Subscription +4. **"Test-Push senden"** klicken → Push Notification wird gesendet + +### **3. PWA installieren (für bessere iPhone-Integration):** +1. In Safari: **"Teilen"** → **"Zum Home-Bildschirm hinzufügen"** +2. Die App wird als PWA installiert +3. Push Notifications funktionieren auch wenn die App geschlossen ist + +## 🔧 API Endpoints: + +### **Push Subscription:** +```bash +POST /api/v1/public/subscribe +Content-Type: application/json +{ + "endpoint": "https://fcm.googleapis.com/fcm/send/...", + "keys": { + "p256dh": "...", + "auth": "..." + } +} +``` + +### **Test Push:** +```bash +POST /api/v1/public/test-push +Content-Type: application/json +{ + "userId": "user-uuid", + "message": "Test Message" +} +``` + +### **Push Status:** +```bash +GET /api/v1/public/push-status +``` + +## 🎯 Automatische Push Notifications: + +Push Notifications werden automatisch gesendet bei: + +1. **🏆 Neue Achievements** - Wenn ein Spieler ein Achievement erreicht +2. **🏁 Best Times** - Täglich um 19:00 für beste Tageszeit +3. **📅 Weekly Best** - Sonntags um 19:00 für beste Wochenzeit +4. **📆 Monthly Best** - Am letzten Tag des Monats um 19:00 + +## 🔑 VAPID Keys: + +**Public Key:** `BJmNVx0C3XeVxeKGTP9c-Z4HcuZNmdk6QdiLocZgCmb-miCS0ESFO3W2TvJlRhhNAShV63pWA5p36BTVSetyTds` + +**Private Key:** `HBdRCtmZUAzsWpVjZ2LDaoWliIPHldAb5ExAt8bvDeg` + +## 📱 iPhone-spezifische Features: + +- **Service Worker** registriert sich automatisch +- **Push Manager** ist verfügbar +- **Notification API** funktioniert +- **PWA Manifest** ist korrekt konfiguriert +- **HTTPS** ist über Apache2 Proxy verfügbar + +## 🚀 Nächste Schritte: + +1. **Teste auf dem iPhone:** `https://ninja.reptilfpv.de/test-push.html` +2. **PWA installieren** für bessere Integration +3. **Push Notifications** werden automatisch bei Achievements und Best Times gesendet + +## 🐛 Troubleshooting: + +### **"Keine Subscription gefunden":** +- Stelle sicher, dass du zuerst "Push abonnieren" geklickt hast +- Prüfe, ob Notification-Permission erteilt wurde + +### **"Service Worker nicht registriert":** +- Lade die Seite neu (Strg+F5) +- Prüfe Browser-Konsole auf Fehler + +### **"Push Notification nicht angezeigt":** +- Prüfe, ob die App im Hintergrund läuft +- Stelle sicher, dass iOS Notification-Permission erteilt wurde + +**Die PWA Push Notifications sind jetzt vollständig funktionsfähig! 🎉** diff --git a/push-service.js b/push-service.js new file mode 100644 index 0000000..6a919d8 --- /dev/null +++ b/push-service.js @@ -0,0 +1,124 @@ +const webpush = require('web-push'); + +// VAPID Keys (sollten in Umgebungsvariablen gespeichert werden) +const vapidKeys = { + publicKey: 'BJmNVx0C3XeVxeKGTP9c-Z4HcuZNmdk6QdiLocZgCmb-miCS0ESFO3W2TvJlRhhNAShV63pWA5p36BTVSetyTds', + privateKey: 'HBdRCtmZUAzsWpVjZ2LDaoWliIPHldAb5ExAt8bvDeg' +}; + +// Configure web-push +webpush.setVapidDetails( + 'mailto:ninjacross@example.com', + vapidKeys.publicKey, + vapidKeys.privateKey +); + +class PushService { + constructor() { + this.subscriptions = new Map(); // In production: use database + } + + // Subscribe user to push notifications + subscribe(userId, subscription) { + this.subscriptions.set(userId, subscription); + console.log(`User ${userId} subscribed to push notifications`); + } + + // Unsubscribe user from push notifications + unsubscribe(userId) { + this.subscriptions.delete(userId); + console.log(`User ${userId} unsubscribed from push notifications`); + } + + // Send push notification to specific user + async sendToUser(userId, payload) { + const subscription = this.subscriptions.get(userId); + if (!subscription) { + console.log(`No subscription found for user ${userId}`); + return false; + } + + try { + await webpush.sendNotification(subscription, JSON.stringify(payload)); + console.log(`Push notification sent to user ${userId}`); + return true; + } catch (error) { + console.error(`Error sending push notification to user ${userId}:`, error); + + // If subscription is invalid, remove it + if (error.statusCode === 410) { + this.unsubscribe(userId); + } + return false; + } + } + + // Send push notification to all subscribed users + async sendToAll(payload) { + const results = []; + for (const [userId, subscription] of this.subscriptions) { + const result = await this.sendToUser(userId, payload); + results.push({ userId, success: result }); + } + return results; + } + + // Send achievement notification + async sendAchievementNotification(userId, achievementName) { + const payload = { + title: '🏆 Neues Achievement!', + body: `Du hast "${achievementName}" erreicht!`, + icon: '/pictures/icon-192.png', + badge: '/pictures/icon-192.png', + data: { + type: 'achievement', + achievement: achievementName, + timestamp: Date.now() + }, + actions: [ + { + action: 'view', + title: 'Dashboard öffnen' + } + ] + }; + + return await this.sendToUser(userId, payload); + } + + // Send best time notification + async sendBestTimeNotification(userId, timeType, locationName) { + const payload = { + title: `🏁 ${timeType} Bestzeit!`, + body: `Du hast die beste Zeit in ${locationName} erreicht!`, + icon: '/pictures/icon-192.png', + badge: '/pictures/icon-192.png', + data: { + type: 'best_time', + timeType: timeType, + location: locationName, + timestamp: Date.now() + }, + actions: [ + { + action: 'view', + title: 'Dashboard öffnen' + } + ] + }; + + return await this.sendToUser(userId, payload); + } + + // Get subscription count + getSubscriptionCount() { + return this.subscriptions.size; + } + + // Get all user IDs with subscriptions + getSubscribedUsers() { + return Array.from(this.subscriptions.keys()); + } +} + +module.exports = new PushService(); diff --git "a/terode\"," "b/terode\"," new file mode 100644 index 0000000..333a0b5 --- /dev/null +++ "b/terode\"," @@ -0,0 +1,258 @@ + + SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS + + Commands marked with * may be preceded by a number, _N. + Notes in parentheses indicate the behavior if _N is given. + A key preceded by a caret indicates the Ctrl key; thus ^K is ctrl-K. + + h H Display this help. + q :q Q :Q ZZ Exit. + --------------------------------------------------------------------------- + + MMOOVVIINNGG + + e ^E j ^N CR * Forward one line (or _N lines). + y ^Y k ^K ^P * Backward one line (or _N lines). + f ^F ^V SPACE * Forward one window (or _N lines). + b ^B ESC-v * Backward one window (or _N lines). + z * Forward one window (and set window to _N). + w * Backward one window (and set window to _N). + ESC-SPACE * Forward one window, but don't stop at end-of-file. + d ^D * Forward one half-window (and set half-window to _N). + u ^U * Backward one half-window (and set half-window to _N). + ESC-) RightArrow * Right one half screen width (or _N positions). + ESC-( LeftArrow * Left one half screen width (or _N positions). + ESC-} ^RightArrow Right to last column displayed. + ESC-{ ^LeftArrow Left to first column. + F Forward forever; like "tail -f". + ESC-F Like F but stop when search pattern is found. + r ^R ^L Repaint screen. + R Repaint screen, discarding buffered input. + --------------------------------------------------- + Default "window" is the screen height. + Default "half-window" is half of the screen height. + --------------------------------------------------------------------------- + + SSEEAARRCCHHIINNGG + + /_p_a_t_t_e_r_n * Search forward for (_N-th) matching line. + ?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line. + n * Repeat previous search (for _N-th occurrence). + N * Repeat previous search in reverse direction. + ESC-n * Repeat previous search, spanning files. + ESC-N * Repeat previous search, reverse dir. & spanning files. + ESC-u Undo (toggle) search highlighting. + ESC-U Clear search highlighting. + &_p_a_t_t_e_r_n * Display only matching lines. + --------------------------------------------------- + A search pattern may begin with one or more of: + ^N or ! Search for NON-matching lines. + ^E or * Search multiple files (pass thru END OF FILE). + ^F or @ Start search at FIRST file (for /) or last file (for ?). + ^K Highlight matches, but don't move (KEEP position). + ^R Don't use REGULAR EXPRESSIONS. + ^W WRAP search if no match found. + --------------------------------------------------------------------------- + + JJUUMMPPIINNGG + + g < ESC-< * Go to first line in file (or line _N). + G > ESC-> * Go to last line in file (or line _N). + p % * Go to beginning of file (or _N percent into file). + t * Go to the (_N-th) next tag. + T * Go to the (_N-th) previous tag. + { ( [ * Find close bracket } ) ]. + } ) ] * Find open bracket { ( [. + ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>. + ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>. + --------------------------------------------------- + Each "find close bracket" command goes forward to the close bracket + matching the (_N-th) open bracket in the top line. + Each "find open bracket" command goes backward to the open bracket + matching the (_N-th) close bracket in the bottom line. + + m_<_l_e_t_t_e_r_> Mark the current top line with . + M_<_l_e_t_t_e_r_> Mark the current bottom line with . + '_<_l_e_t_t_e_r_> Go to a previously marked position. + '' Go to the previous position. + ^X^X Same as '. + ESC-M_<_l_e_t_t_e_r_> Clear a mark. + --------------------------------------------------- + A mark is any upper-case or lower-case letter. + Certain marks are predefined: + ^ means beginning of the file + $ means end of the file + --------------------------------------------------------------------------- + + CCHHAANNGGIINNGG FFIILLEESS + + :e [_f_i_l_e] Examine a new file. + ^X^V Same as :e. + :n * Examine the (_N-th) next file from the command line. + :p * Examine the (_N-th) previous file from the command line. + :x * Examine the first (or _N-th) file from the command line. + :d Delete the current file from the command line list. + = ^G :f Print current file name. + --------------------------------------------------------------------------- + + MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS + + -_<_f_l_a_g_> Toggle a command line option [see OPTIONS below]. + --_<_n_a_m_e_> Toggle a command line option, by name. + __<_f_l_a_g_> Display the setting of a command line option. + ___<_n_a_m_e_> Display the setting of an option, by name. + +_c_m_d Execute the less cmd each time a new file is examined. + + !_c_o_m_m_a_n_d Execute the shell command with $SHELL. + |XX_c_o_m_m_a_n_d Pipe file between current pos & mark XX to shell command. + s _f_i_l_e Save input to a file. + v Edit the current file with $VISUAL or $EDITOR. + V Print version number of "less". + --------------------------------------------------------------------------- + + OOPPTTIIOONNSS + + Most options may be changed either on the command line, + or from within less by using the - or -- command. + Options may be given in one of two forms: either a single + character preceded by a -, or a name preceded by --. + + -? ........ --help + Display help (from command line). + -a ........ --search-skip-screen + Search skips current screen. + -A ........ --SEARCH-SKIP-SCREEN + Search starts just after target line. + -b [_N] .... --buffers=[_N] + Number of buffers. + -B ........ --auto-buffers + Don't automatically allocate buffers for pipes. + -c ........ --clear-screen + Repaint by clearing rather than scrolling. + -d ........ --dumb + Dumb terminal. + -D xx_c_o_l_o_r . --color=xx_c_o_l_o_r + Set screen colors. + -e -E .... --quit-at-eof --QUIT-AT-EOF + Quit at end of file. + -f ........ --force + Force open non-regular files. + -F ........ --quit-if-one-screen + Quit if entire file fits on first screen. + -g ........ --hilite-search + Highlight only last match for searches. + -G ........ --HILITE-SEARCH + Don't highlight any matches for searches. + -h [_N] .... --max-back-scroll=[_N] + Backward scroll limit. + -i ........ --ignore-case + Ignore case in searches that do not contain uppercase. + -I ........ --IGNORE-CASE + Ignore case in all searches. + -j [_N] .... --jump-target=[_N] + Screen position of target lines. + -J ........ --status-column + Display a status column at left edge of screen. + -k [_f_i_l_e] . --lesskey-file=[_f_i_l_e] + Use a lesskey file. + -K ........ --quit-on-intr + Exit less in response to ctrl-C. + -L ........ --no-lessopen + Ignore the LESSOPEN environment variable. + -m -M .... --long-prompt --LONG-PROMPT + Set prompt style. + -n -N .... --line-numbers --LINE-NUMBERS + Don't use line numbers. + -o [_f_i_l_e] . --log-file=[_f_i_l_e] + Copy to log file (standard input only). + -O [_f_i_l_e] . --LOG-FILE=[_f_i_l_e] + Copy to log file (unconditionally overwrite). + -p [_p_a_t_t_e_r_n] --pattern=[_p_a_t_t_e_r_n] + Start at pattern (from command line). + -P [_p_r_o_m_p_t] --prompt=[_p_r_o_m_p_t] + Define new prompt. + -q -Q .... --quiet --QUIET --silent --SILENT + Quiet the terminal bell. + -r -R .... --raw-control-chars --RAW-CONTROL-CHARS + Output "raw" control characters. + -s ........ --squeeze-blank-lines + Squeeze multiple blank lines. + -S ........ --chop-long-lines + Chop (truncate) long lines rather than wrapping. + -t [_t_a_g] .. --tag=[_t_a_g] + Find a tag. + -T [_t_a_g_s_f_i_l_e] --tag-file=[_t_a_g_s_f_i_l_e] + Use an alternate tags file. + -u -U .... --underline-special --UNDERLINE-SPECIAL + Change handling of backspaces. + -V ........ --version + Display the version number of "less". + -w ........ --hilite-unread + Highlight first new line after forward-screen. + -W ........ --HILITE-UNREAD + Highlight first new line after any forward movement. + -x [_N[,...]] --tabs=[_N[,...]] + Set tab stops. + -X ........ --no-init + Don't use termcap init/deinit strings. + -y [_N] .... --max-forw-scroll=[_N] + Forward scroll limit. + -z [_N] .... --window=[_N] + Set size of window. + -" [_c[_c]] . --quotes=[_c[_c]] + Set shell quote characters. + -~ ........ --tilde + Don't display tildes after end of file. + -# [_N] .... --shift=[_N] + Set horizontal scroll amount (0 = one half screen width). + --file-size + Automatically determine the size of the input file. + --follow-name + The F command changes files if the input file is renamed. + --incsearch + Search file as each pattern character is typed in. + --line-num-width=N + Set the width of the -N line number field to N characters. + --mouse + Enable mouse input. + --no-keypad + Don't send termcap keypad init/deinit strings. + --no-histdups + Remove duplicates from command history. + --rscroll=C + Set the character used to mark truncated lines. + --save-marks + Retain marks across invocations of less. + --status-col-width=N + Set the width of the -J status column to N characters. + --use-backslash + Subsequent options use backslash as escape char. + --use-color + Enables colored text. + --wheel-lines=N + Each click of the mouse wheel moves N lines. + + + --------------------------------------------------------------------------- + + LLIINNEE EEDDIITTIINNGG + + These keys can be used to edit text being entered + on the "command line" at the bottom of the screen. + + RightArrow ..................... ESC-l ... Move cursor right one character. + LeftArrow ...................... ESC-h ... Move cursor left one character. + ctrl-RightArrow ESC-RightArrow ESC-w ... Move cursor right one word. + ctrl-LeftArrow ESC-LeftArrow ESC-b ... Move cursor left one word. + HOME ........................... ESC-0 ... Move cursor to start of line. + END ............................ ESC-$ ... Move cursor to end of line. + BACKSPACE ................................ Delete char to left of cursor. + DELETE ......................... ESC-x ... Delete char under cursor. + ctrl-BACKSPACE ESC-BACKSPACE ........... Delete word to left of cursor. + ctrl-DELETE .... ESC-DELETE .... ESC-X ... Delete word under cursor. + ctrl-U ......... ESC (MS-DOS only) ....... Delete entire line. + UpArrow ........................ ESC-k ... Retrieve previous command line. + DownArrow ...................... ESC-j ... Retrieve next command line. + TAB ...................................... Complete filename & cycle. + SHIFT-TAB ...................... ESC-TAB Complete filename & reverse cycle. + ctrl-L ................................... Complete filename, list all. diff --git a/websocket-setup-commands.sh b/websocket-setup-commands.sh new file mode 100755 index 0000000..9f3ffba --- /dev/null +++ b/websocket-setup-commands.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +echo "🔧 Apache WebSocket Support Setup" +echo "=================================" + +# Kopiere die aktualisierte Apache-Konfiguration +echo "Kopiere Apache-Konfiguration..." +sudo cp /root/ninjaserver/apache-ssl-config.conf /etc/apache2/sites-available/ninjaserver-ssl.conf +echo "✅ Konfiguration kopiert" + +# Apache Module aktivieren +echo "Aktiviere benötigte Apache-Module..." +sudo a2enmod proxy +sudo a2enmod proxy_http +sudo a2enmod proxy_wstunnel +sudo a2enmod rewrite +sudo a2enmod headers +sudo a2enmod ssl + +echo "✅ Module aktiviert" + +# SSL Site aktivieren (falls noch nicht geschehen) +echo "Aktiviere SSL-Site..." +sudo a2ensite ninjaserver-ssl + +# Standard-Site deaktivieren (optional) +echo "Deaktiviere Standard-Site..." +sudo a2dissite 000-default + +# Apache-Konfiguration testen +echo "Teste Apache-Konfiguration..." +sudo apache2ctl configtest + +if [ $? -eq 0 ]; then + echo "✅ Apache-Konfiguration ist gültig" + echo "Starte Apache neu..." + sudo systemctl restart apache2 + echo "✅ Apache wurde neugestartet" + + echo "" + echo "🎉 WebSocket Support sollte jetzt funktionieren!" + echo "Teste die Verbindung mit: wss://ninja.reptilfpv.de/socket.io/" +else + echo "❌ Apache-Konfiguration hat Fehler - bitte überprüfen" +fi