docs(telegram): complete Phase 5 documentation and security improvements
- Updated README.md with Telegram features section in 'Latest Features'
- Added Telegram environment variables to Environment Variables table
- Updated FEATURE_PLAN-telegram.md: marked Phases 1-5 as completed
- Updated status table with completion dates (Phase 1-4: done, Phase 5: docs complete)
OpenAPI Documentation:
- Added swagger tags to reorder route (Management Portal)
- Added swagger tags to consent routes (Consent Management)
- Regenerated openapi.json with correct tags (no more 'default' category)
Environment Configuration:
- Updated .env.backend.example with Telegram variables and session secret
- Created docker/dev/.env.example with Telegram configuration template
- Created docker/prod/.env.example with production environment template
- Moved secrets from docker-compose.yml to .env files (gitignored)
- Changed docker/dev/docker-compose.yml to use placeholders: ${TELEGRAM_BOT_TOKEN}
Security Enhancements:
- Disabled test message on server start by default (TELEGRAM_SEND_TEST_ON_START=false)
- Extended pre-commit hook to detect hardcoded Telegram secrets
- Hook prevents commit if TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID are hardcoded
- All secrets must use environment variable placeholders
Phase 5 fully completed and documented.
This commit is contained in:
parent
489e2166bb
commit
d76b4b2c9c
|
|
@ -10,10 +10,10 @@ Implementierung eines Telegram Bots zur automatischen Benachrichtigung der Werks
|
||||||
|
|
||||||
## Phasen-Aufteilung
|
## Phasen-Aufteilung
|
||||||
|
|
||||||
### Phase 1: Bot Setup & Standalone-Test ⭐ **CURRENT**
|
### Phase 1: Bot Setup & Standalone-Test
|
||||||
**Ziel:** Telegram Bot erstellen und isoliert testen (ohne App-Integration)
|
**Ziel:** Telegram Bot erstellen und isoliert testen (ohne App-Integration)
|
||||||
|
|
||||||
**Status:** 🟡 In Planung
|
**Status:** 🟢 Abgeschlossen
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
- [x] Telegram Bot via BotFather erstellt
|
- [x] Telegram Bot via BotFather erstellt
|
||||||
|
|
@ -32,52 +32,62 @@ Implementierung eines Telegram Bots zur automatischen Benachrichtigung der Werks
|
||||||
### Phase 2: Backend-Service Integration
|
### Phase 2: Backend-Service Integration
|
||||||
**Ziel:** TelegramNotificationService in Backend integrieren
|
**Ziel:** TelegramNotificationService in Backend integrieren
|
||||||
|
|
||||||
|
**Status:** 🟢 Abgeschlossen
|
||||||
|
|
||||||
**Dependencies:** Phase 1 abgeschlossen
|
**Dependencies:** Phase 1 abgeschlossen
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
- [ ] `backend/src/services/TelegramNotificationService.js`
|
- [x] `backend/src/services/TelegramNotificationService.js`
|
||||||
- [ ] ENV-Variablen in `docker/dev/backend/config/.env`
|
- [x] ENV-Variablen in `docker/dev/backend/config/.env`
|
||||||
- [ ] Unit-Tests für Service
|
- [x] Unit-Tests für Service
|
||||||
- [ ] Docker Dev Environment funktioniert
|
- [x] Docker Dev Environment funktioniert
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 3: Upload-Benachrichtigungen
|
### Phase 3: Upload-Benachrichtigungen
|
||||||
**Ziel:** Automatische Benachrichtigungen bei neuem Upload
|
**Ziel:** Automatische Benachrichtigungen bei neuem Upload
|
||||||
|
|
||||||
|
**Status:** 🟢 Abgeschlossen
|
||||||
|
|
||||||
**Dependencies:** Phase 2 abgeschlossen
|
**Dependencies:** Phase 2 abgeschlossen
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
- [ ] Integration in `routes/batchUpload.js`
|
- [x] Integration in `routes/batchUpload.js`
|
||||||
- [ ] `sendUploadNotification()` Methode
|
- [x] `sendUploadNotification()` Methode
|
||||||
- [ ] Formatierung mit Icons/Emojis
|
- [x] Formatierung mit Icons/Emojis
|
||||||
- [ ] Integration-Tests
|
- [x] Integration-Tests
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 4: User-Änderungs-Benachrichtigungen
|
### Phase 4: User-Änderungs-Benachrichtigungen
|
||||||
**Ziel:** Benachrichtigungen bei Consent-Änderungen & Löschungen
|
**Ziel:** Benachrichtigungen bei Consent-Änderungen & Löschungen
|
||||||
|
|
||||||
|
**Status:** 🟢 Abgeschlossen
|
||||||
|
|
||||||
**Dependencies:** Phase 3 abgeschlossen
|
**Dependencies:** Phase 3 abgeschlossen
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
- [ ] Integration in `routes/management.js` (PUT/DELETE)
|
- [x] Integration in `routes/management.js` (PUT/DELETE)
|
||||||
- [ ] `sendConsentChangeNotification()` Methode
|
- [x] `sendConsentChangeNotification()` Methode
|
||||||
- [ ] `sendGroupDeletedNotification()` Methode
|
- [x] `sendGroupDeletedNotification()` Methode
|
||||||
- [ ] Integration-Tests
|
- [x] Integration-Tests
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 5: Tägliche Lösch-Warnungen
|
### Phase 5: Tägliche Lösch-Warnungen ⭐ **CURRENT**
|
||||||
**Ziel:** Cron-Job für bevorstehende Löschungen
|
**Ziel:** Cron-Job für bevorstehende Löschungen
|
||||||
|
|
||||||
|
**Status:** 🟡 Dokumentation ausstehend
|
||||||
|
|
||||||
**Dependencies:** Phase 4 abgeschlossen
|
**Dependencies:** Phase 4 abgeschlossen
|
||||||
|
|
||||||
**Deliverables:**
|
**Deliverables:**
|
||||||
- [ ] Cron-Job Setup (node-cron)
|
- [x] Cron-Job Setup (node-cron)
|
||||||
- [ ] `sendDeletionWarning()` Methode
|
- [x] `sendDeletionWarning()` Methode
|
||||||
- [ ] Admin-Route für manuellen Trigger
|
- [x] Admin-Route für manuellen Trigger (`POST /api/admin/telegram/warning`)
|
||||||
- [ ] Dokumentation
|
- [x] SchedulerService Integration (09:00 daily)
|
||||||
|
- [x] Docker ENV-Variablen konfiguriert
|
||||||
|
- [ ] README.md Update
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -342,15 +352,15 @@ git commit -m "docs: Update README with Telegram features"
|
||||||
|
|
||||||
## Status-Tracking
|
## Status-Tracking
|
||||||
|
|
||||||
**Letzte Aktualisierung:** 2025-11-29
|
**Letzte Aktualisierung:** 2025-11-30
|
||||||
|
|
||||||
| Phase | Status | Datum |
|
| Phase | Status | Datum |
|
||||||
|-------|--------|-------|
|
|-------|--------|-------|
|
||||||
| Phase 1 | 🟡 In Planung | 2025-11-29 |
|
| Phase 1 | 🟢 Abgeschlossen | 2025-11-29 |
|
||||||
| Phase 2 | ⚪ Ausstehend | - |
|
| Phase 2 | 🟢 Abgeschlossen | 2025-11-29 |
|
||||||
| Phase 3 | ⚪ Ausstehend | - |
|
| Phase 3 | 🟢 Abgeschlossen | 2025-11-29 |
|
||||||
| Phase 4 | ⚪ Ausstehend | - |
|
| Phase 4 | 🟢 Abgeschlossen | 2025-11-30 |
|
||||||
| Phase 5 | ⚪ Ausstehend | - |
|
| Phase 5 | 🟡 Dokumentation | 2025-11-30 |
|
||||||
| Phase 6 | ⚪ Ausstehend | - |
|
| Phase 6 | ⚪ Ausstehend | - |
|
||||||
|
|
||||||
**Legende:**
|
**Legende:**
|
||||||
|
|
|
||||||
18
README.md
18
README.md
|
|
@ -5,6 +5,7 @@ A self-hosted image uploader with multi-image upload capabilities and automatic
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
**Multi-Image Upload**: Upload multiple images at once with batch processing
|
**Multi-Image Upload**: Upload multiple images at once with batch processing
|
||||||
|
**Telegram Notifications**: 🆕 Real-time notifications for uploads, consent changes, deletions, and daily warnings
|
||||||
**Social Media Consent Management**: 🆕 GDPR-compliant consent system for workshop display and social media publishing
|
**Social Media Consent Management**: 🆕 GDPR-compliant consent system for workshop display and social media publishing
|
||||||
**Automatic Cleanup**: 🆕 Unapproved groups are automatically deleted after 7 days
|
**Automatic Cleanup**: 🆕 Unapproved groups are automatically deleted after 7 days
|
||||||
**Deletion Log**: 🆕 Complete audit trail of automatically deleted content
|
**Deletion Log**: 🆕 Complete audit trail of automatically deleted content
|
||||||
|
|
@ -22,6 +23,18 @@ This project extends the original [Image-Uploader by vallezw](https://github.com
|
||||||
|
|
||||||
### 🆕 Latest Features (November 2025)
|
### 🆕 Latest Features (November 2025)
|
||||||
|
|
||||||
|
- **📱 Telegram Bot Notifications** (Nov 30):
|
||||||
|
- Real-time notifications for all critical events
|
||||||
|
- 4 notification types: Upload, Consent Changes, Group Deletion, Daily Warnings
|
||||||
|
- Upload notifications with name, year, title, image count, and consent status
|
||||||
|
- Consent change tracking (workshop display + social media platforms)
|
||||||
|
- Group deletion confirmations with uploader and statistics
|
||||||
|
- Daily deletion warnings (09:00) for groups pending auto-cleanup (24h notice)
|
||||||
|
- Cron-scheduled automation via node-cron
|
||||||
|
- Admin endpoint for manual trigger: `POST /api/admin/telegram/warning`
|
||||||
|
- Optional feature via `TELEGRAM_ENABLED` environment variable
|
||||||
|
- Complete setup guide in `scripts/README.telegram.md`
|
||||||
|
|
||||||
- **🌐 Public/Internal Host Separation** (Nov 25):
|
- **🌐 Public/Internal Host Separation** (Nov 25):
|
||||||
- Subdomain-based feature separation for production deployment
|
- Subdomain-based feature separation for production deployment
|
||||||
- Public host (`deinprojekt.hobbyhimmel.de`): Upload + UUID Management only
|
- Public host (`deinprojekt.hobbyhimmel.de`): Upload + UUID Management only
|
||||||
|
|
@ -597,6 +610,11 @@ For detailed testing instructions, see: [`tests/TESTING-CLEANUP.md`](tests/TESTI
|
||||||
|----------|---------|-------------|
|
|----------|---------|-------------|
|
||||||
| `API_URL` | `http://localhost:5001` | Backend API endpoint |
|
| `API_URL` | `http://localhost:5001` | Backend API endpoint |
|
||||||
| `CLIENT_URL` | `http://localhost` | Frontend application URL |
|
| `CLIENT_URL` | `http://localhost` | Frontend application URL |
|
||||||
|
| `TELEGRAM_ENABLED` | `false` | Enable/disable Telegram notifications |
|
||||||
|
| `TELEGRAM_BOT_TOKEN` | - | Telegram Bot API token (from @BotFather) |
|
||||||
|
| `TELEGRAM_CHAT_ID` | - | Telegram chat/group ID for notifications |
|
||||||
|
|
||||||
|
**Telegram Setup:** See `scripts/README.telegram.md` for complete configuration guide.
|
||||||
|
|
||||||
### Volume Configuration
|
### Volume Configuration
|
||||||
- **Upload Limits**: 100MB maximum file size for batch uploads
|
- **Upload Limits**: 100MB maximum file size for batch uploads
|
||||||
|
|
|
||||||
|
|
@ -1070,22 +1070,38 @@
|
||||||
},
|
},
|
||||||
"/api/manage/{token}/reorder": {
|
"/api/manage/{token}/reorder": {
|
||||||
"put": {
|
"put": {
|
||||||
"description": "",
|
"tags": [
|
||||||
|
"Management Portal"
|
||||||
|
],
|
||||||
|
"summary": "Reorder images in group",
|
||||||
|
"description": "Reorder images within the managed group (token-based access)",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "token",
|
"name": "token",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"description": "Management token (UUID v4)",
|
||||||
|
"example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"imageIds": {
|
"imageIds": {
|
||||||
"example": "any"
|
"type": "array",
|
||||||
|
"example": [
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
2,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1093,13 +1109,29 @@
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK"
|
"description": "Images reordered successfully",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"success": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"updatedCount": {
|
||||||
|
"type": "number",
|
||||||
|
"example": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xml": {
|
||||||
|
"name": "main"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Bad Request"
|
"description": "Invalid token format or imageIds"
|
||||||
},
|
},
|
||||||
"404": {
|
"404": {
|
||||||
"description": "Not Found"
|
"description": "Token not found or group deleted"
|
||||||
},
|
},
|
||||||
"429": {
|
"429": {
|
||||||
"description": "Too Many Requests"
|
"description": "Too Many Requests"
|
||||||
|
|
@ -1163,25 +1195,46 @@
|
||||||
},
|
},
|
||||||
"/api/admin/groups/{groupId}/consents": {
|
"/api/admin/groups/{groupId}/consents": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "",
|
"tags": [
|
||||||
|
"Consent Management"
|
||||||
|
],
|
||||||
|
"summary": "Save or update consents for a group",
|
||||||
|
"description": "Store workshop consent and social media consents for a specific group",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"name": "groupId",
|
"name": "groupId",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"description": "Group ID",
|
||||||
|
"example": "abc123def456"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"workshopConsent": {
|
"workshopConsent": {
|
||||||
"example": "any"
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
},
|
},
|
||||||
"socialMediaConsents": {
|
"socialMediaConsents": {
|
||||||
"example": "any"
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"platformId": {
|
||||||
|
"type": "number",
|
||||||
|
"example": 2
|
||||||
|
},
|
||||||
|
"consented": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1189,10 +1242,26 @@
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK"
|
"description": "Consents saved successfully",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"success": {
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "Consents saved successfully"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xml": {
|
||||||
|
"name": "main"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Bad Request"
|
"description": "Invalid request data"
|
||||||
},
|
},
|
||||||
"403": {
|
"403": {
|
||||||
"description": "Forbidden"
|
"description": "Forbidden"
|
||||||
|
|
|
||||||
|
|
@ -58,16 +58,37 @@ router.get('/social-media/platforms', async (req, res) => {
|
||||||
// Group Consents
|
// Group Consents
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /groups/:groupId/consents
|
|
||||||
* Speichere oder aktualisiere Consents für eine Gruppe
|
|
||||||
*
|
|
||||||
* Body: {
|
|
||||||
* workshopConsent: boolean,
|
|
||||||
* socialMediaConsents: [{ platformId: number, consented: boolean }]
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
router.post('/groups/:groupId/consents', async (req, res) => {
|
router.post('/groups/:groupId/consents', async (req, res) => {
|
||||||
|
/*
|
||||||
|
#swagger.tags = ['Consent Management']
|
||||||
|
#swagger.summary = 'Save or update consents for a group'
|
||||||
|
#swagger.description = 'Store workshop consent and social media consents for a specific group'
|
||||||
|
#swagger.parameters['groupId'] = {
|
||||||
|
in: 'path',
|
||||||
|
required: true,
|
||||||
|
type: 'string',
|
||||||
|
description: 'Group ID',
|
||||||
|
example: 'abc123def456'
|
||||||
|
}
|
||||||
|
#swagger.parameters['body'] = {
|
||||||
|
in: 'body',
|
||||||
|
required: true,
|
||||||
|
schema: {
|
||||||
|
workshopConsent: true,
|
||||||
|
socialMediaConsents: [
|
||||||
|
{ platformId: 1, consented: true },
|
||||||
|
{ platformId: 2, consented: false }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
description: 'Consents saved successfully',
|
||||||
|
schema: { success: true, message: 'Consents saved successfully' }
|
||||||
|
}
|
||||||
|
#swagger.responses[400] = {
|
||||||
|
description: 'Invalid request data'
|
||||||
|
}
|
||||||
|
*/
|
||||||
try {
|
try {
|
||||||
const { groupId } = req.params;
|
const { groupId } = req.params;
|
||||||
const { workshopConsent, socialMediaConsents } = req.body;
|
const { workshopConsent, socialMediaConsents } = req.body;
|
||||||
|
|
|
||||||
|
|
@ -1076,18 +1076,36 @@ router.delete('/:token', async (req, res) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* PUT /api/manage/:token/reorder
|
|
||||||
* Reorder images within the managed group (token-based access)
|
|
||||||
*
|
|
||||||
* @param {string} token - Management token (UUID v4)
|
|
||||||
* @param {number[]} imageIds - Array of image IDs in new order
|
|
||||||
* @returns {Object} Success status and updated image count
|
|
||||||
* @throws {400} Invalid token format or imageIds
|
|
||||||
* @throws {404} Token not found or group deleted
|
|
||||||
* @throws {500} Server error
|
|
||||||
*/
|
|
||||||
router.put('/:token/reorder', async (req, res) => {
|
router.put('/:token/reorder', async (req, res) => {
|
||||||
|
/*
|
||||||
|
#swagger.tags = ['Management Portal']
|
||||||
|
#swagger.summary = 'Reorder images in group'
|
||||||
|
#swagger.description = 'Reorder images within the managed group (token-based access)'
|
||||||
|
#swagger.parameters['token'] = {
|
||||||
|
in: 'path',
|
||||||
|
required: true,
|
||||||
|
type: 'string',
|
||||||
|
description: 'Management token (UUID v4)',
|
||||||
|
example: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
||||||
|
}
|
||||||
|
#swagger.parameters['body'] = {
|
||||||
|
in: 'body',
|
||||||
|
required: true,
|
||||||
|
schema: {
|
||||||
|
imageIds: [1, 3, 2, 4]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#swagger.responses[200] = {
|
||||||
|
description: 'Images reordered successfully',
|
||||||
|
schema: { success: true, updatedCount: 4 }
|
||||||
|
}
|
||||||
|
#swagger.responses[400] = {
|
||||||
|
description: 'Invalid token format or imageIds'
|
||||||
|
}
|
||||||
|
#swagger.responses[404] = {
|
||||||
|
description: 'Token not found or group deleted'
|
||||||
|
}
|
||||||
|
*/
|
||||||
try {
|
try {
|
||||||
const { token } = req.params;
|
const { token } = req.params;
|
||||||
const { imageIds } = req.body;
|
const { imageIds } = req.body;
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,10 @@ class Server {
|
||||||
// Starte Scheduler für automatisches Cleanup
|
// Starte Scheduler für automatisches Cleanup
|
||||||
SchedulerService.start();
|
SchedulerService.start();
|
||||||
|
|
||||||
// Teste Telegram-Service (nur in Development)
|
// Teste Telegram-Service (optional, nur in Development wenn aktiviert)
|
||||||
if (process.env.NODE_ENV === 'development' && telegramService.isAvailable()) {
|
if (process.env.NODE_ENV === 'development'
|
||||||
|
&& process.env.TELEGRAM_SEND_TEST_ON_START === 'true'
|
||||||
|
&& telegramService.isAvailable()) {
|
||||||
telegramService.sendTestMessage()
|
telegramService.sendTestMessage()
|
||||||
.catch(err => console.error('[Telegram] Test message failed:', err.message));
|
.catch(err => console.error('[Telegram] Test message failed:', err.message));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,22 @@ NODE_ENV=development
|
||||||
# Port for the backend server
|
# Port for the backend server
|
||||||
PORT=5000
|
PORT=5000
|
||||||
|
|
||||||
|
# Admin Session Secret (IMPORTANT: Change in production!)
|
||||||
|
# Generate with: openssl rand -base64 32
|
||||||
|
ADMIN_SESSION_SECRET=change-me-in-production
|
||||||
|
|
||||||
|
# Telegram Bot Configuration (optional)
|
||||||
|
TELEGRAM_ENABLED=false
|
||||||
|
# Send test message on server start (development only)
|
||||||
|
TELEGRAM_SEND_TEST_ON_START=false
|
||||||
|
# Bot-Token from @BotFather
|
||||||
|
# Example: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz1234567890
|
||||||
|
TELEGRAM_BOT_TOKEN=your-bot-token-here
|
||||||
|
# Chat-ID of the Telegram group (negative for groups!)
|
||||||
|
# Get via: https://api.telegram.org/bot<TOKEN>/getUpdates
|
||||||
|
# Example: -1001234567890
|
||||||
|
TELEGRAM_CHAT_ID=your-chat-id-here
|
||||||
|
|
||||||
# Database settings (if needed in future)
|
# Database settings (if needed in future)
|
||||||
# DB_HOST=localhost
|
# DB_HOST=localhost
|
||||||
# DB_PORT=3306
|
# DB_PORT=3306
|
||||||
13
docker/dev/.env.example
Normal file
13
docker/dev/.env.example
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Docker Compose Environment Variables for Development
|
||||||
|
# Copy this file to .env and adjust values
|
||||||
|
|
||||||
|
# Telegram Bot Configuration (optional)
|
||||||
|
TELEGRAM_ENABLED=false
|
||||||
|
TELEGRAM_SEND_TEST_ON_START=false
|
||||||
|
# Bot-Token from @BotFather
|
||||||
|
# Example: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz1234567890
|
||||||
|
TELEGRAM_BOT_TOKEN=your-bot-token-here
|
||||||
|
# Chat-ID of the Telegram group (negative for groups!)
|
||||||
|
# Get via: https://api.telegram.org/bot<TOKEN>/getUpdates
|
||||||
|
# Example: -1001234567890
|
||||||
|
TELEGRAM_CHAT_ID=your-chat-id-here
|
||||||
|
|
@ -46,9 +46,10 @@ services:
|
||||||
- ENABLE_HOST_RESTRICTION=true
|
- ENABLE_HOST_RESTRICTION=true
|
||||||
- TRUST_PROXY_HOPS=0
|
- TRUST_PROXY_HOPS=0
|
||||||
- PUBLIC_UPLOAD_RATE_LIMIT=20
|
- PUBLIC_UPLOAD_RATE_LIMIT=20
|
||||||
- TELEGRAM_ENABLED=true
|
- TELEGRAM_ENABLED=${TELEGRAM_ENABLED:-false}
|
||||||
- TELEGRAM_BOT_TOKEN=8496813818:AAHShJP_cqOuWIW66ROUCxa-1C83CCCZmqU
|
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
|
||||||
- TELEGRAM_CHAT_ID=-1003064825033
|
- TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID}
|
||||||
|
- TELEGRAM_SEND_TEST_ON_START=${TELEGRAM_SEND_TEST_ON_START:-false}
|
||||||
networks:
|
networks:
|
||||||
- dev-internal
|
- dev-internal
|
||||||
command: [ "npm", "run", "server" ]
|
command: [ "npm", "run", "server" ]
|
||||||
|
|
|
||||||
17
docker/prod/.env.example
Normal file
17
docker/prod/.env.example
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Docker Compose Environment Variables for Production
|
||||||
|
# Copy this file to .env and adjust values
|
||||||
|
|
||||||
|
# Admin Session Secret (IMPORTANT: Generate new secret!)
|
||||||
|
# Generate with: openssl rand -base64 32
|
||||||
|
ADMIN_SESSION_SECRET=CHANGE-ME-IN-PRODUCTION
|
||||||
|
|
||||||
|
# Telegram Bot Configuration (optional)
|
||||||
|
TELEGRAM_ENABLED=false
|
||||||
|
TELEGRAM_SEND_TEST_ON_START=false
|
||||||
|
# Bot-Token from @BotFather
|
||||||
|
# Example: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz1234567890
|
||||||
|
TELEGRAM_BOT_TOKEN=your-bot-token-here
|
||||||
|
# Chat-ID of the Telegram group (negative for groups!)
|
||||||
|
# Get via: https://api.telegram.org/bot<TOKEN>/getUpdates
|
||||||
|
# Example: -1001234567890
|
||||||
|
TELEGRAM_CHAT_ID=your-chat-id-here
|
||||||
|
|
@ -39,6 +39,8 @@ changed = False
|
||||||
|
|
||||||
cookie_pattern = re.compile(r'(\-\s*ADMIN_SESSION_COOKIE_SECURE\s*=\s*)([^\n\r]+)')
|
cookie_pattern = re.compile(r'(\-\s*ADMIN_SESSION_COOKIE_SECURE\s*=\s*)([^\n\r]+)')
|
||||||
secret_pattern = re.compile(r'(\-\s*ADMIN_SESSION_SECRET\s*=\s*)([^\n\r]+)')
|
secret_pattern = re.compile(r'(\-\s*ADMIN_SESSION_SECRET\s*=\s*)([^\n\r]+)')
|
||||||
|
telegram_token_pattern = re.compile(r'(\-\s*TELEGRAM_BOT_TOKEN\s*=\s*)([^\n\r${}]+)')
|
||||||
|
telegram_chat_pattern = re.compile(r'(\-\s*TELEGRAM_CHAT_ID\s*=\s*)(-?\d{10,})')
|
||||||
|
|
||||||
def ensure_entry(text, *, pattern, value, anchor_line, expected_line, label):
|
def ensure_entry(text, *, pattern, value, anchor_line, expected_line, label):
|
||||||
match = pattern.search(text)
|
match = pattern.search(text)
|
||||||
|
|
@ -80,6 +82,18 @@ if secret_expected not in new_text:
|
||||||
print('ERROR: Failed to ensure ADMIN_SESSION_SECRET uses environment variable in docker-compose.yml', file=sys.stderr)
|
print('ERROR: Failed to ensure ADMIN_SESSION_SECRET uses environment variable in docker-compose.yml', file=sys.stderr)
|
||||||
sys.exit(4)
|
sys.exit(4)
|
||||||
|
|
||||||
|
telegram_token_match = telegram_token_pattern.search(new_text)
|
||||||
|
if telegram_token_match and telegram_token_match.group(2).strip() not in ['${TELEGRAM_BOT_TOKEN}', '']:
|
||||||
|
print(f'ERROR: TELEGRAM_BOT_TOKEN contains hardcoded secret: {telegram_token_match.group(2)[:20]}...', file=sys.stderr)
|
||||||
|
print(' Use ${TELEGRAM_BOT_TOKEN} placeholder instead!', file=sys.stderr)
|
||||||
|
sys.exit(5)
|
||||||
|
|
||||||
|
telegram_chat_match = telegram_chat_pattern.search(new_text)
|
||||||
|
if telegram_chat_match:
|
||||||
|
print(f'ERROR: TELEGRAM_CHAT_ID contains hardcoded value: {telegram_chat_match.group(2)}', file=sys.stderr)
|
||||||
|
print(' Use ${TELEGRAM_CHAT_ID} placeholder instead!', file=sys.stderr)
|
||||||
|
sys.exit(6)
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
path.write_text(new_text)
|
path.write_text(new_text)
|
||||||
print('UPDATED')
|
print('UPDATED')
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user