Skip to content

Commit 69dddd3

Browse files
committed
implemented db connection security, comprehensive migration validation system, implemented automated backup system, rollbacks and plans
1 parent 199aa62 commit 69dddd3

File tree

11 files changed

+404
-18
lines changed

11 files changed

+404
-18
lines changed

.gitignore

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,22 @@ yarn-error.log*
3636
*.tsbuildinfo
3737
next-env.d.ts
3838

39-
40-
# application logs (contains sensitive data)
41-
/server/logs/
42-
/logs/
43-
*.log
39+
# Database backups
40+
/backups/
41+
*.sql
42+
*.dump
43+
*.backup
44+
45+
# Logs
46+
*.log
47+
logs/
48+
49+
# IDE
50+
.vscode/
51+
.idea/
52+
*.swp
53+
*.swo
54+
55+
# OS
56+
Thumbs.db
57+
.DS_Store

server/.gitignore

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
1-
node_modules
2-
# Keep environment variables out of version control
1+
# Dependencies
2+
node_modules/
3+
4+
# Environment variables
35
.env
6+
.env.local
7+
.env.production
8+
9+
# Logs
10+
logs/
11+
*.log
12+
13+
# Database backups
14+
backups/
15+
*.sql
16+
*.dump
17+
*.backup
18+
19+
# IDE
20+
.vscode/
21+
.idea/
22+
*.swp
23+
*.swo
24+
25+
# OS
26+
Thumbs.db
27+
.DS_Store
428

5-
# application logs (contains sensitive data)
6-
/server/logs/
7-
/logs/
8-
*.log
29+
# Temporary files
30+
tmp/
31+
temp/

server/controllers/mainImages.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const { PrismaClient } = require("@prisma/client");
2-
const prisma = new PrismaClient();
2+
const prisma = require("../utills/db"); // ✅ Use shared connection
33

44
async function uploadMainImage(req, res) {
55
if (!req.files || Object.keys(req.files).length === 0) {

server/controllers/products.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
const { PrismaClient } = require("@prisma/client");
2-
const prisma = new PrismaClient();
1+
const prisma = require("../utills/db"); // ✅ Use shared connection with SSL
32

43
// Security: Define whitelists for allowed filter types and operators
54
const ALLOWED_FILTER_TYPES = ['price', 'rating', 'category', 'inStock', 'outOfStock'];

server/controllers/slugs.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
const { PrismaClient } = require("@prisma/client");
2-
const prisma = new PrismaClient();
1+
const prisma = require("../utills/db"); // ✅ Use shared connection
32

43
async function getProductBySlug(request, response) {
54
const { slug } = request.params;

server/logs/access.log

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
::1 - - [14/Sep/2025:08:57:02 +0000] "GET /api/products HTTP/1.1" 200 3367 "-" "node" reqId=oFsEO2or userId=anonymous
2+
::1 - - [14/Sep/2025:08:57:02 +0000] "GET /api/products HTTP/1.1" 200 3367 "-" "node" reqId=-Qn-9QT1 userId=anonymous
3+
::1 - - [14/Sep/2025:08:57:07 +0000] "GET /api/products HTTP/1.1" 200 3367 "-" "node" reqId=NwaelGz3 userId=anonymous
4+
::1 - - [14/Sep/2025:08:57:10 +0000] "OPTIONS /api/users/email/[email protected] HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=C-SyproK userId=anonymous
5+
::1 - - [14/Sep/2025:08:57:10 +0000] "GET /api/users/email/[email protected] HTTP/1.1" 200 71 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=aEcJKJGe userId=anonymous
6+
::1 - - [14/Sep/2025:08:57:10 +0000] "OPTIONS /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=w7VR104c userId=anonymous
7+
::1 - - [14/Sep/2025:08:57:10 +0000] "GET /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA HTTP/1.1" 200 2 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=hV-RqU_E userId=anonymous
8+
::1 - - [14/Sep/2025:09:05:16 +0000] "GET /api/products HTTP/1.1" 200 3367 "-" "node" reqId=GIozJ2oS userId=anonymous
9+
::1 - - [14/Sep/2025:09:05:19 +0000] "OPTIONS /api/users/email/[email protected] HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=WQpzS6-0 userId=anonymous
10+
::1 - - [14/Sep/2025:09:05:19 +0000] "GET /api/users/email/[email protected] HTTP/1.1" 200 71 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=V0CCtnZ- userId=anonymous
11+
::1 - - [14/Sep/2025:09:05:19 +0000] "OPTIONS /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=Mc5N2Qys userId=anonymous
12+
::1 - - [14/Sep/2025:09:05:19 +0000] "GET /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA HTTP/1.1" 200 2 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=1Ho9Ytng userId=anonymous
13+
::1 - - [14/Sep/2025:09:05:26 +0000] "GET /api/slugs/smart-watch-demo HTTP/1.1" 200 321 "-" "node" reqId=6lCwE9xN userId=anonymous
14+
::1 - - [14/Sep/2025:09:05:26 +0000] "GET /api/images/undefined HTTP/1.1" 200 2 "-" "node" reqId=16L99pBg userId=anonymous
15+
::1 - - [14/Sep/2025:09:05:26 +0000] "OPTIONS /api/users/email/[email protected] HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=J1nOGOJQ userId=anonymous
16+
::1 - - [14/Sep/2025:09:05:26 +0000] "OPTIONS /api/users/email/[email protected] HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=vqXSu5HW userId=anonymous
17+
::1 - - [14/Sep/2025:09:05:26 +0000] "GET /api/users/email/[email protected] HTTP/1.1" 200 71 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=fZ3Lkbe6 userId=anonymous
18+
::1 - - [14/Sep/2025:09:05:26 +0000] "GET /api/users/email/[email protected] HTTP/1.1" 200 71 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=0P79PwYV userId=anonymous
19+
::1 - - [14/Sep/2025:09:05:26 +0000] "OPTIONS /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/10 HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=GAV747br userId=anonymous
20+
::1 - - [14/Sep/2025:09:05:26 +0000] "OPTIONS /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/10 HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=_DxftYi3 userId=anonymous
21+
::1 - - [14/Sep/2025:09:05:26 +0000] "GET /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/10 HTTP/1.1" 304 - "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=o2KjoRkk userId=anonymous
22+
::1 - - [14/Sep/2025:09:05:26 +0000] "GET /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/10 HTTP/1.1" 304 - "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=22_csPIJ userId=anonymous
23+
::1 - - [14/Sep/2025:09:05:45 +0000] "GET /api/products HTTP/1.1" 200 3367 "-" "node" reqId=6k2UwiML userId=anonymous
24+
::1 - - [14/Sep/2025:09:05:52 +0000] "GET /api/search?query=smart HTTP/1.1" 200 495 "-" "node" reqId=ULu17Mjt userId=anonymous
25+
::1 - - [14/Sep/2025:09:05:53 +0000] "GET /api/slugs/smart-watch-demo HTTP/1.1" 200 321 "-" "node" reqId=LFBR6psl userId=anonymous
26+
::1 - - [14/Sep/2025:09:05:53 +0000] "GET /api/images/undefined HTTP/1.1" 200 2 "-" "node" reqId=phC8zwJY userId=anonymous
27+
::1 - - [14/Sep/2025:09:05:53 +0000] "OPTIONS /api/users/email/[email protected] HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=tEcefdzX userId=anonymous
28+
::1 - - [14/Sep/2025:09:05:53 +0000] "OPTIONS /api/users/email/[email protected] HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=_mLnMzCt userId=anonymous
29+
::1 - - [14/Sep/2025:09:05:54 +0000] "GET /api/users/email/[email protected] HTTP/1.1" 200 71 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=RjsqPDKU userId=anonymous
30+
::1 - - [14/Sep/2025:09:05:54 +0000] "GET /api/users/email/[email protected] HTTP/1.1" 200 71 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=59R_HHKS userId=anonymous
31+
::1 - - [14/Sep/2025:09:05:54 +0000] "OPTIONS /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/10 HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=ekuI9Ncd userId=anonymous
32+
::1 - - [14/Sep/2025:09:05:54 +0000] "OPTIONS /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/10 HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=8To29il6 userId=anonymous
33+
::1 - - [14/Sep/2025:09:05:54 +0000] "GET /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/10 HTTP/1.1" 304 - "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=NkwYGxpO userId=anonymous
34+
::1 - - [14/Sep/2025:09:05:54 +0000] "GET /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/10 HTTP/1.1" 304 - "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=3tR4x3r8 userId=anonymous
35+
::1 - - [14/Sep/2025:09:06:06 +0000] "GET /api/products HTTP/1.1" 200 3367 "-" "node" reqId=Sc66uJZS userId=anonymous
36+
::1 - - [14/Sep/2025:09:06:08 +0000] "GET /api/search?query=phone HTTP/1.1" 200 763 "-" "node" reqId=Sghv_N_G userId=anonymous
37+
::1 - - [14/Sep/2025:09:06:10 +0000] "GET /api/slugs/phone-gimbal-demo HTTP/1.1" 200 328 "-" "node" reqId=CR__6dlu userId=anonymous
38+
::1 - - [14/Sep/2025:09:06:10 +0000] "GET /api/images/undefined HTTP/1.1" 200 2 "-" "node" reqId=0htx4wF8 userId=anonymous
39+
::1 - - [14/Sep/2025:09:06:10 +0000] "OPTIONS /api/users/email/[email protected] HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=d6dJXdVI userId=anonymous
40+
::1 - - [14/Sep/2025:09:06:10 +0000] "OPTIONS /api/users/email/[email protected] HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=VhW24B5X userId=anonymous
41+
::1 - - [14/Sep/2025:09:06:10 +0000] "GET /api/users/email/[email protected] HTTP/1.1" 200 71 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=sPVoRVXM userId=anonymous
42+
::1 - - [14/Sep/2025:09:06:10 +0000] "GET /api/users/email/[email protected] HTTP/1.1" 200 71 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=MyW_r8Ct userId=anonymous
43+
::1 - - [14/Sep/2025:09:06:10 +0000] "OPTIONS /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/4 HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=hDC-cNQD userId=anonymous
44+
::1 - - [14/Sep/2025:09:06:10 +0000] "OPTIONS /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/4 HTTP/1.1" 204 0 "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=G57YdTCp userId=anonymous
45+
::1 - - [14/Sep/2025:09:06:10 +0000] "GET /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/4 HTTP/1.1" 304 - "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=2mm9Wpw5 userId=anonymous
46+
::1 - - [14/Sep/2025:09:06:10 +0000] "GET /api/wishlist/AT9Z7Hmu4dQYGzV_ITgiA/4 HTTP/1.1" 304 - "http://localhost:3000/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36" reqId=kEaGHjG_ userId=anonymous

server/package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010
"logs:access": "node view-logs.js access",
1111
"logs:error": "node view-logs.js error",
1212
"logs:security": "node view-logs.js security",
13-
"logs:analyze": "node view-logs.js analyze"
13+
"logs:analyze": "node view-logs.js analyze",
14+
"migrate:validate": "node scripts/migration-validator.js validate",
15+
"migrate:backup": "node scripts/migration-validator.js backup",
16+
"migrate:safe": "node scripts/migration-validator.js safe-migrate",
17+
"db:backup": "node scripts/backup-database.js",
18+
"db:restore": "node scripts/restore-database.js"
1419
},
1520
"keywords": [],
1621
"author": "",
@@ -21,7 +26,7 @@
2126
"bcryptjs": "^2.4.3",
2227
"cors": "^2.8.5",
2328
"express": "^4.18.3",
24-
"morgan": "^1.10.0",
29+
"morgan": "^1.10.1",
2530
"mysql": "^2.18.1",
2631
"nanoid": "^5.0.6",
2732
"prisma": "^5.12.1"

server/scripts/backup-database.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
const { exec } = require('child_process');
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
class DatabaseBackup {
6+
constructor() {
7+
this.backupDir = path.join(__dirname, '../backups');
8+
this.ensureBackupDir();
9+
}
10+
11+
ensureBackupDir() {
12+
if (!fs.existsSync(this.backupDir)) {
13+
fs.mkdirSync(this.backupDir, { recursive: true });
14+
}
15+
}
16+
17+
async createBackup() {
18+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
19+
const backupFile = path.join(this.backupDir, `full-backup-${timestamp}.sql`);
20+
21+
// Parse DATABASE_URL
22+
const databaseUrl = process.env.DATABASE_URL;
23+
if (!databaseUrl) {
24+
throw new Error('DATABASE_URL environment variable is required');
25+
}
26+
27+
const url = new URL(databaseUrl);
28+
const host = url.hostname;
29+
const port = url.port || '3306';
30+
const database = url.pathname.substring(1);
31+
const username = url.username;
32+
const password = url.password;
33+
34+
const mysqldumpCommand = `mysqldump -h ${host} -P ${port} -u ${username} -p${password} ${database} > ${backupFile}`;
35+
36+
return new Promise((resolve, reject) => {
37+
exec(mysqldumpCommand, (error, stdout, stderr) => {
38+
if (error) {
39+
console.error('❌ Backup failed:', error);
40+
reject(error);
41+
} else {
42+
console.log(`✅ Full database backup created: ${backupFile}`);
43+
resolve(backupFile);
44+
}
45+
});
46+
});
47+
}
48+
}
49+
50+
if (require.main === module) {
51+
const backup = new DatabaseBackup();
52+
backup.createBackup()
53+
.then(() => console.log('Backup completed successfully'))
54+
.catch(console.error);
55+
}
56+
57+
module.exports = DatabaseBackup;

0 commit comments

Comments
 (0)