Refactor authentication and data handling in API; implement encryption for user and member data storage. Update relevant components to utilize new encryption methods, ensuring secure data management across the application. Enhance error handling and streamline data writing processes for improved reliability.
This commit is contained in:
@@ -1,42 +1 @@
|
||||
[
|
||||
{
|
||||
"id": "550e8400-e29b-41d4-a716-446655440001",
|
||||
"firstName": "Max",
|
||||
"lastName": "Mustermann",
|
||||
"email": "max@example.com",
|
||||
"phone": "069 123456",
|
||||
"address": "Musterstraße 1, 60437 Frankfurt",
|
||||
"notes": "Herren 1"
|
||||
},
|
||||
{
|
||||
"id": "550e8400-e29b-41d4-a716-446655440002",
|
||||
"firstName": "Anna",
|
||||
"lastName": "Schmidt",
|
||||
"email": "",
|
||||
"phone": "069 234567",
|
||||
"address": "Hauptstraße 5, 60437 Frankfurt",
|
||||
"notes": "Damen"
|
||||
},
|
||||
{
|
||||
"firstName": "Test",
|
||||
"lastName": "Antrag",
|
||||
"email": "test@antrag.de",
|
||||
"phone": "",
|
||||
"address": "Teststr 1, 60437 Frankfurt",
|
||||
"notes": "Mitgliedschaftsart: aktiv | Genehmigt: 23.10.2025",
|
||||
"source": "membership_application",
|
||||
"applicationId": "1761225361334",
|
||||
"id": "c209cb36-3aca-4ab2-b463-061e41f97d6d"
|
||||
},
|
||||
{
|
||||
"firstName": "Final",
|
||||
"lastName": "Test",
|
||||
"email": "final@test.de",
|
||||
"phone": "",
|
||||
"address": "Finalstr 1, 60437 Frankfurt",
|
||||
"notes": "Mitgliedschaftsart: aktiv | Genehmigt: 23.10.2025",
|
||||
"source": "membership_application",
|
||||
"applicationId": "1761225630365",
|
||||
"id": "952c3d3f-c73a-43ed-ae21-76387948c030"
|
||||
}
|
||||
]
|
||||
j1MPucV7uLGcNrRns92uU3f+fTt35Vpw7ImrahWaPQOAxGPJP0zZq6VOYYjuhvGlmE708rxZsPog/7PvuKc5YOwM5H9Bzhwf4HZFj98JrVU7gCkS5bm39NB1MrDS1yPblAurGFRrL28mi3d3Py+02cbV+YccQEw678jHqt6tazRfz1z005S5pYNAGf8GfJqAhtR4IA9ZTolszBiGA71gb33/RlwyZqUpnA7IEr1tlG7t21ueXcRNH+N2REgPYBrwmOkACGn6efdJpWoyglFLUOzt/uheXlrrprzJaUta3CZSPLC4JIHDHGEWgjwvAs14eDsfJbuaDegUAIpUrkGEsicPXIwj5gXrEc8FnEZSQISnrmj+jkYv86VZ8fXf8rmgSTjW5F8+tA5lSlJompb7wRQNmFLzLehdiatJtwHh1zhjfHBVG3VKKYgLppG8n0/LMc8BGKtb7xvIFshjnuTnbhbe5C7ocnefcOUVkVXhqXnbLAcmLQPn8ZjkJC0Vk9I5bTbRQr/1X0gsTPlkbtnLwtWF8puRPlx2eFimt3ZvzjTh+BxGagGM0wmTSqNh51WvbC10oPUyjCrL/tQJ2essSkufZ8KSVrnC3Tum/xATaL4fei/DFiYxoS9HqXaf1GvreiScbIPP61wgrjBSpuQmiDQfsVprdT9l+A7diF6LJXlcEpeWvSWq5E0h39QgoqYrg6uwd6Jilg6RSMcpnNWozRzqTLhTJ9ZCdaH3TLcX3qX5M9zLV/gVmy8m4gXaaiMo2WSjuryXNapT/lGIhZlFojhz0BmnId/SYUTvh2ds0WdYHfXEP1HGVcFhgLibI5tz4B9zJma/nReDle/23lhTc5coh3Gi2bvxC2CrkXUwiPK+SYW+yaBiZ5c7rGAhXtZebRJjGGZD6IA5dT6fYeQF7tVbYs3KcKWEVHVB4XomcsTd1neHPtnCVMj3d3aJ94ihJ5C5CJy3qHd60ovxcbsbqL7sK+jY84muHB2AKkSm5TdM95aGxovGpaPvXiHYMbSf+pbPKdKzS16NJ/8RnNweUYYC2Naabw+GYxrlxqS31j5ZXnLVsms1GQ9yMcJyrNmCbzu6aqM0j9HBq5Wi5Lo5y04EdIqqIzBCrNlmRllWK2Sa78j6nLLiP1W4zzF/51W/Oqp++zd2ns/TS1+JUDnHYqRUaBFHLB1lz854ODv8T9Shu85ExY/RWkCZan+P0bi24x+6hYVR0sPpgvyBjka4cY7NXnpU9nSnJpK1ve4nAA2o0vdv9OpO3CIgv37vucFIXOCJRfcWBL5rrFYE99Kaf+tTSWEwBoIm71txBLhy9yVElefY4G9C1S3Wl/cyCmgz
|
||||
@@ -1,13 +1 @@
|
||||
[
|
||||
{
|
||||
"id": "1",
|
||||
"email": "admin@harheimertc.de",
|
||||
"password": "$2a$10$7/he4Q2OC/z1ZXStsPOYWeEc2szOCEgNQFwb4txeB0zTt/Wm1eJKa",
|
||||
"name": "Admin",
|
||||
"role": "admin",
|
||||
"phone": "",
|
||||
"active": true,
|
||||
"created": "2025-10-21T00:00:00.000Z",
|
||||
"lastLogin": "2025-11-05T09:03:43.617Z"
|
||||
}
|
||||
]
|
||||
hvxN6KvvickWNnxyvIqXHN9VWFkXlbP9ivRinrShBA0a9Pq7y9QwL23SVGG/8Eu1OrbERAnSJjzyVKKfaR/5gn+a5Q+3Z8MXt+UfADTvNJB4jU+IISnRsEw8T9gXMQQNvkUygoF+qI19+vqdEjMSXTG3HvsWqvgp/0fcoT++i3v2L7UfReXm9hBJti2EiqrD03mH6t+PW31yPe8HxJTnSTCJaHzYhtjsanHE3IeYukBVhSflwtInm1hRecux1Hu1/gfnf+FqtG+9aJp81Ixdmuekk5WNckPblavBsrOHnKYHaT3GExpbK60rls2zgLqMkINg5GqePKRLIffLNU+CbOTTZkgYcLEWN4ICMGxAWAbgOxS8QLTg9iKsmhb7KkB1i4emqCFMSAbeLphbbxgEeA==
|
||||
@@ -2,6 +2,7 @@ import bcrypt from 'bcryptjs'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import { encryptObject, decryptObject } from './encryption.js'
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'harheimertc-secret-key-change-in-production'
|
||||
|
||||
@@ -21,21 +22,75 @@ const getDataPath = (filename) => {
|
||||
const USERS_FILE = getDataPath('users.json')
|
||||
const SESSIONS_FILE = getDataPath('sessions.json')
|
||||
|
||||
// Read users from file
|
||||
// Get encryption key from environment
|
||||
function getEncryptionKey() {
|
||||
return process.env.ENCRYPTION_KEY || 'default-key-change-in-production'
|
||||
}
|
||||
|
||||
// Check if data is encrypted by trying to parse as JSON first
|
||||
function isEncrypted(data) {
|
||||
try {
|
||||
const parsed = JSON.parse(data.trim())
|
||||
if (Array.isArray(parsed)) {
|
||||
return false // Unencrypted array
|
||||
}
|
||||
if (typeof parsed === 'object' && parsed !== null && !parsed.encryptedData) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
} catch (e) {
|
||||
// JSON parsing failed - likely encrypted base64
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Read users from file (with encryption support and migration)
|
||||
export async function readUsers() {
|
||||
try {
|
||||
const data = await fs.readFile(USERS_FILE, 'utf-8')
|
||||
return JSON.parse(data)
|
||||
|
||||
const encrypted = isEncrypted(data)
|
||||
|
||||
if (encrypted) {
|
||||
const encryptionKey = getEncryptionKey()
|
||||
try {
|
||||
return decryptObject(data, encryptionKey)
|
||||
} catch (decryptError) {
|
||||
console.error('Fehler beim Entschlüsseln der Benutzerdaten:', decryptError)
|
||||
try {
|
||||
const plainData = JSON.parse(data)
|
||||
console.warn('Entschlüsselung fehlgeschlagen, versuche als unverschlüsseltes Format zu lesen')
|
||||
return plainData
|
||||
} catch (parseError) {
|
||||
console.error('Konnte Benutzerdaten weder entschlüsseln noch als JSON lesen')
|
||||
return []
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Plain JSON - migrate to encrypted format
|
||||
const users = JSON.parse(data)
|
||||
console.log('Migriere unverschlüsselte Benutzerdaten zu verschlüsselter Speicherung...')
|
||||
|
||||
// Write back encrypted
|
||||
await writeUsers(users)
|
||||
|
||||
return users
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
return []
|
||||
}
|
||||
console.error('Fehler beim Lesen der Benutzerdaten:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// Write users to file
|
||||
// Write users to file (always encrypted)
|
||||
export async function writeUsers(users) {
|
||||
try {
|
||||
await fs.writeFile(USERS_FILE, JSON.stringify(users, null, 2), 'utf-8')
|
||||
const encryptionKey = getEncryptionKey()
|
||||
const encryptedData = encryptObject(users, encryptionKey)
|
||||
await fs.writeFile(USERS_FILE, encryptedData, 'utf-8')
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Schreiben der Benutzerdaten:', error)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import { randomUUID } from 'crypto'
|
||||
import { encrypt, decrypt, encryptObject, decryptObject } from './encryption.js'
|
||||
|
||||
// Handle both dev and production paths
|
||||
const getDataPath = (filename) => {
|
||||
@@ -17,11 +18,66 @@ const getDataPath = (filename) => {
|
||||
|
||||
const MEMBERS_FILE = getDataPath('members.json')
|
||||
|
||||
// Read manual members from file
|
||||
// Get encryption key from environment or config
|
||||
function getEncryptionKey() {
|
||||
return process.env.ENCRYPTION_KEY || 'default-key-change-in-production'
|
||||
}
|
||||
|
||||
// Check if data is encrypted by trying to parse as JSON first
|
||||
function isEncrypted(data) {
|
||||
try {
|
||||
// Try to parse as JSON - if successful and looks like member data, it's unencrypted
|
||||
const parsed = JSON.parse(data.trim())
|
||||
// If it's an array (members list) or object with member-like structure, it's unencrypted
|
||||
if (Array.isArray(parsed)) {
|
||||
return false // Unencrypted array
|
||||
}
|
||||
// If it's an object but not encrypted format, it's unencrypted
|
||||
if (typeof parsed === 'object' && parsed !== null && !parsed.encryptedData) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
} catch (e) {
|
||||
// JSON parsing failed - likely encrypted base64
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Read manual members from file (with encryption support and migration)
|
||||
export async function readMembers() {
|
||||
try {
|
||||
const data = await fs.readFile(MEMBERS_FILE, 'utf-8')
|
||||
return JSON.parse(data)
|
||||
|
||||
// Check if data is encrypted or plain JSON
|
||||
const encrypted = isEncrypted(data)
|
||||
|
||||
if (encrypted) {
|
||||
// Decrypt and parse
|
||||
const encryptionKey = getEncryptionKey()
|
||||
try {
|
||||
return decryptObject(data, encryptionKey)
|
||||
} catch (decryptError) {
|
||||
console.error('Fehler beim Entschlüsseln der Mitgliederdaten:', decryptError)
|
||||
// Fallback: try to read as plain JSON (migration scenario)
|
||||
try {
|
||||
const plainData = JSON.parse(data)
|
||||
console.warn('Entschlüsselung fehlgeschlagen, versuche als unverschlüsseltes Format zu lesen')
|
||||
return plainData
|
||||
} catch (parseError) {
|
||||
console.error('Konnte Mitgliederdaten weder entschlüsseln noch als JSON lesen')
|
||||
return []
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Plain JSON - migrate to encrypted format
|
||||
const members = JSON.parse(data)
|
||||
console.log('Migriere unverschlüsselte Mitgliederdaten zu verschlüsselter Speicherung...')
|
||||
|
||||
// Write back encrypted
|
||||
await writeMembers(members)
|
||||
|
||||
return members
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
return []
|
||||
@@ -31,10 +87,12 @@ export async function readMembers() {
|
||||
}
|
||||
}
|
||||
|
||||
// Write manual members to file
|
||||
// Write manual members to file (always encrypted)
|
||||
export async function writeMembers(members) {
|
||||
try {
|
||||
await fs.writeFile(MEMBERS_FILE, JSON.stringify(members, null, 2), 'utf-8')
|
||||
const encryptionKey = getEncryptionKey()
|
||||
const encryptedData = encryptObject(members, encryptionKey)
|
||||
await fs.writeFile(MEMBERS_FILE, encryptedData, 'utf-8')
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Schreiben der Mitgliederdaten:', error)
|
||||
|
||||
Reference in New Issue
Block a user