fix: Remove plain text password from code, use sessionStorage for security

- Remove hardcoded Nextcloud credentials from app.js
- Remove pre-filled password from HTML form
- Store password in sessionStorage (cleared on browser close) instead of localStorage
- Store only URL, username, and path in localStorage
- Update README with security notes
- Update quick start guide to reflect manual password entry
- Add autocomplete attribute to password field

Security improvement: Password is now only stored temporarily in sessionStorage
and must be entered manually by the user on first use or after browser restart.

Generated by Vibe Code

Co-authored-by: trevor1969 <trevor1969@users.noreply.github.com>
This commit is contained in:
Vibe Nuage Agent
2026-06-04 12:27:10 +00:00
parent 990ebb134d
commit 233647be4a
3 changed files with 52 additions and 60 deletions

View File

@ -115,19 +115,18 @@
### Option 3: Mit Nextcloud-Synchronisation (empfohlen!) ### Option 3: Mit Nextcloud-Synchronisation (empfohlen!)
1. **App öffnen** (lokal oder über GitHub Pages) 1. **App öffnen** (lokal oder über GitHub Pages)
2. **Automatische Verbindung**: Die App testet automatisch die Verbindung zu deiner Nextcloud 2. Gehe zum Tab **⚙️ Einstellungen**
3. **Fertig!** 🎉 Deine Daten werden jetzt automatisch synchronisiert 3. Aktiviere **Nextcloud-Synchronisation**
4. Trage deine Nextcloud-Daten ein:
- **URL**: `https://wralto.org/nextcloud3`
- **Benutzername**: `teetracker`
- **App-Passwort**: (dein App-Passwort aus Nextcloud)
- **Speicherpfad**: `/TeeTracker/` (Standard)
5. Klicke auf **🔍 Verbindung testen**
6. Speichere die Konfiguration mit **💾 Speichern**
7. **Fertig!** 🎉 Deine Daten werden jetzt automatisch synchronisiert
**Oder manuell einrichten:** **Hinweis:** Aus Sicherheitsgründen musst du dein Passwort manuell eingeben. Es wird nicht in der App gespeichert (nur temporär in sessionStorage).
1. Gehe zum Tab **⚙️ Einstellungen**
2. Aktiviere **Nextcloud-Synchronisation**
3. Trage deine Nextcloud-Daten ein:
- **URL**: `https://wralto.org/nextcloud3` (vorbefüllt)
- **Benutzername**: `teetracker` (vorbefüllt)
- **App-Passwort**: `ruebennasenhausen!2026` (vorbefüllt)
- **Speicherpfad**: `/TeeTracker/` (vorbefüllt)
4. Klicke auf **🔍 Verbindung testen**
5. Speichere die Konfiguration mit **💾 Speichern**
--- ---
@ -185,6 +184,14 @@ Falls Nextcloud nicht erreichbar ist:
2. Änderungen werden **lokal gespeichert** 2. Änderungen werden **lokal gespeichert**
3. Beim nächsten erfolgreichen Verbindungsaufbau werden die Daten **automatisch synchronisiert** 3. Beim nächsten erfolgreichen Verbindungsaufbau werden die Daten **automatisch synchronisiert**
### 🔐 Sicherheitshinweise
**WICHTIG:** Aus Sicherheitsgründen wird dein Passwort **NICHT** im Klartext in der App oder im localStorage gespeichert!
- **sessionStorage**: Das Passwort wird nur in `sessionStorage` gespeichert (wird beim Schließen des Browsers gelöscht)
- **Keine Vorbefüllung**: Du musst dein Passwort manuell eingeben
- **Kein Klartext in Dateien**: Das Passwort erscheint nirgends im Code
### App-Passwort erstellen ### App-Passwort erstellen
Falls du ein neues Passwort brauchst: Falls du ein neues Passwort brauchst:
@ -194,6 +201,8 @@ Falls du ein neues Passwort brauchst:
4. Erstelle ein neues Passwort mit dem Namen **"TeeTracker"** 4. Erstelle ein neues Passwort mit dem Namen **"TeeTracker"**
5. Kopiere das Passwort und trage es in den Einstellungen ein 5. Kopiere das Passwort und trage es in den Einstellungen ein
**Tipp:** Speichere das App-Passwort in einem Passwort-Manager, da es nach dem Erstellen nicht mehr angezeigt wird.
--- ---
## 🎨 Design ## 🎨 Design

73
app.js
View File

@ -200,57 +200,35 @@ class TeeTracker {
initStorage() { initStorage() {
// Load Nextcloud configuration from localStorage // Load Nextcloud configuration from localStorage
const ncConfig = localStorage.getItem(STORAGE_KEY_NC_CONFIG); const ncConfig = localStorage.getItem(STORAGE_KEY_NC_CONFIG);
const ncPassword = sessionStorage.getItem(STORAGE_KEY_NC_CONFIG + '_password');
if (ncConfig) { if (ncConfig) {
try { try {
const config = JSON.parse(ncConfig); const config = JSON.parse(ncConfig);
this.nextcloudStorage = new NextcloudStorage( // Load password from sessionStorage (more secure than localStorage)
config.baseUrl, const password = ncPassword || '';
config.username,
config.password, if (password) {
config.path || '/TeeTracker/' this.nextcloudStorage = new NextcloudStorage(
); config.baseUrl,
this.useNextcloud = true; config.username,
this.updateSyncStatus(); password,
config.path || '/TeeTracker/'
);
this.useNextcloud = true;
this.updateSyncStatus();
} else {
// Password not available, user needs to re-enter it
this.useNextcloud = false;
this.showStatusMessage('Bitte gib dein Nextcloud-Passwort erneut ein.', 'info');
}
} catch (error) { } catch (error) {
console.error('Invalid Nextcloud config:', error); console.error('Invalid Nextcloud config:', error);
this.useNextcloud = false; this.useNextcloud = false;
} }
} else { } else {
// Check if we have predefined Nextcloud credentials // Don't pre-fill credentials - user must enter them manually
const predefinedConfig = { this.useNextcloud = false;
baseUrl: 'https://wralto.org/nextcloud3',
username: 'teetracker',
password: 'ruebennasenhausen!2026',
path: '/TeeTracker/'
};
// Test the predefined connection
this.nextcloudStorage = new NextcloudStorage(
predefinedConfig.baseUrl,
predefinedConfig.username,
predefinedConfig.password,
predefinedConfig.path
);
// Test connection asynchronously
this.nextcloudStorage.testConnection().then(connected => {
if (connected) {
this.useNextcloud = true;
localStorage.setItem(STORAGE_KEY_NC_CONFIG, JSON.stringify(predefinedConfig));
this.updateSyncStatus();
// Reload data from Nextcloud
this.loadData().then(() => {
this.renderAll();
this.updateSettingsStats();
});
} else {
this.useNextcloud = false;
this.updateSyncStatus();
}
}).catch(() => {
this.useNextcloud = false;
this.updateSyncStatus();
});
} }
} }
@ -800,10 +778,14 @@ class TeeTracker {
return; return;
} }
// Save config // Save config WITHOUT password for security
const config = { baseUrl: url, username, password, path }; // Password will be requested each time or stored in sessionStorage
const config = { baseUrl: url, username, path };
localStorage.setItem(STORAGE_KEY_NC_CONFIG, JSON.stringify(config)); localStorage.setItem(STORAGE_KEY_NC_CONFIG, JSON.stringify(config));
// Store password in sessionStorage (cleared when browser closes)
sessionStorage.setItem(STORAGE_KEY_NC_CONFIG + '_password', password);
// Update app state // Update app state
this.nextcloudStorage = ncStorage; this.nextcloudStorage = ncStorage;
this.useNextcloud = true; this.useNextcloud = true;
@ -815,6 +797,7 @@ class TeeTracker {
} else { } else {
// Disable Nextcloud // Disable Nextcloud
localStorage.removeItem(STORAGE_KEY_NC_CONFIG); localStorage.removeItem(STORAGE_KEY_NC_CONFIG);
sessionStorage.removeItem(STORAGE_KEY_NC_CONFIG + '_password');
this.useNextcloud = false; this.useNextcloud = false;
this.nextcloudStorage = null; this.nextcloudStorage = null;
this.showStatusMessage('✅ Nextcloud-Synchronisation deaktiviert. Daten werden lokal gespeichert.', 'success'); this.showStatusMessage('✅ Nextcloud-Synchronisation deaktiviert. Daten werden lokal gespeichert.', 'success');

View File

@ -137,17 +137,17 @@
<div id="nc-config" style="display: none;"> <div id="nc-config" style="display: none;">
<div class="form-group"> <div class="form-group">
<label for="nc-url">Nextcloud-URL *</label> <label for="nc-url">Nextcloud-URL *</label>
<input type="url" id="nc-url" placeholder="https://deine-nextcloud.de" value="https://wralto.org/nextcloud3"> <input type="url" id="nc-url" placeholder="https://deine-nextcloud.de">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="nc-username">Benutzername *</label> <label for="nc-username">Benutzername *</label>
<input type="text" id="nc-username" placeholder="Dein Nextcloud-Benutzername" value="teetracker"> <input type="text" id="nc-username" placeholder="Dein Nextcloud-Benutzername">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="nc-password">App-Passwort *</label> <label for="nc-password">App-Passwort *</label>
<input type="password" id="nc-password" placeholder="App-Passwort aus Nextcloud" value="ruebennasenhausen!2026"> <input type="password" id="nc-password" placeholder="App-Passwort aus Nextcloud" autocomplete="current-password">
</div> </div>
<div class="form-group"> <div class="form-group">