diff --git a/chat/.gitignore b/chat/.gitignore index c2658d7..e022dbe 100644 --- a/chat/.gitignore +++ b/chat/.gitignore @@ -1 +1,7 @@ node_modules/ +.data/ +*.db +*.db-wal +*.db-shm +test-*.js + diff --git a/chat/TESTING_GUIDE.md b/chat/TESTING_GUIDE.md new file mode 100644 index 0000000..ec3b76a --- /dev/null +++ b/chat/TESTING_GUIDE.md @@ -0,0 +1,401 @@ +# Testing Guide: Secure Database Implementation + +This guide walks you through testing the secure database implementation locally and in a container. + +## Prerequisites + +- Node.js 20+ installed +- Docker installed (for container testing) +- OpenSSL (for generating keys) + +## Local Testing + +### 1. Install Dependencies + +```bash +cd chat +npm install +``` + +### 2. Generate Encryption Keys + +```bash +export DATABASE_ENCRYPTION_KEY=$(openssl rand -hex 32) +export JWT_SECRET=$(openssl rand -hex 32) + +echo "Save these keys for future use:" +echo "DATABASE_ENCRYPTION_KEY=$DATABASE_ENCRYPTION_KEY" +echo "JWT_SECRET=$JWT_SECRET" +``` + +### 3. Setup Database + +```bash +node scripts/setup-database.js +``` + +Expected output: +``` +✅ Database connected +✅ Database schema created +✅ Database tables created: users, sessions, refresh_tokens, etc. +``` + +### 4. Test Encryption + +```bash +cat > test-encryption.js << 'EOF' +const { initEncryption, encrypt, decrypt } = require('./src/utils/encryption'); +const crypto = require('crypto'); + +const key = crypto.randomBytes(32).toString('hex'); +initEncryption(key); + +const plaintext = 'sensitive@email.com'; +const encrypted = encrypt(plaintext); +const decrypted = decrypt(encrypted); + +console.log('✅ Encryption test:', plaintext === decrypted ? 'PASSED' : 'FAILED'); +EOF + +node test-encryption.js +rm test-encryption.js +``` + +### 5. Test Repositories + +```bash +cat > test-repos.js << 'EOF' +const { initDatabase, closeDatabase } = require('./src/database/connection'); +const { initEncryption } = require('./src/utils/encryption'); +const userRepo = require('./src/repositories/userRepository'); +const crypto = require('crypto'); + +initEncryption(process.env.DATABASE_ENCRYPTION_KEY); +initDatabase('./.data/shopify_ai.db'); + +const user = userRepo.createUser({ + id: 'test123', + email: 'test@example.com', + passwordHash: '$2b$12$test', + emailVerified: true +}); + +console.log('✅ User created:', user.email); + +const found = userRepo.getUserById('test123'); +console.log('✅ User retrieved:', found.email); + +userRepo.deleteUser('test123'); +console.log('✅ User deleted'); + +closeDatabase(); +EOF + +node test-repos.js +rm test-repos.js +``` + +### 6. Test Migration + +Create sample JSON data: + +```bash +mkdir -p .data +cat > .data/users.json << 'EOF' +[ + { + "id": "user1", + "email": "test@example.com", + "passwordHash": "$2b$12$test", + "emailVerified": true, + "plan": "professional" + } +] +EOF + +cat > .data/user-sessions.json << 'EOF' +{ + "token123": { + "id": "session1", + "userId": "user1", + "expiresAt": 9999999999999 + } +} +EOF +``` + +Run migration: + +```bash +# Remove existing database +rm -f .data/shopify_ai.db* + +# Setup fresh database +node scripts/setup-database.js + +# Run migration +node scripts/migrate-to-database.js +``` + +Expected output: +``` +✅ Migration complete! + Users: ✓ Success: 1 + Sessions: ✓ Success: 1 +``` + +### 7. Test JSON Compatibility Mode + +```bash +# Switch to JSON mode +export USE_JSON_DATABASE=1 + +# Your app should now use JSON files instead of database +# (Integration with server.js needed) +``` + +## Container Testing + +### 1. Build Container + +```bash +cd /home/runner/work/shopify-ai-backup/shopify-ai-backup +docker build -t shopify-ai-builder:test . +``` + +### 2. Run Container with Environment Variables + +```bash +docker run -d \ + --name shopify-ai-test \ + -p 4500:4500 \ + -e DATABASE_ENCRYPTION_KEY=$(openssl rand -hex 32) \ + -e JWT_SECRET=$(openssl rand -hex 32) \ + -v shopify-data:/home/web/data \ + shopify-ai-builder:test +``` + +### 3. Check Logs + +```bash +docker logs shopify-ai-test +``` + +Expected in logs: +``` +🔍 Checking database status... +🔧 Database not found, setting up new database... +⚠️ Generated new encryption key (save this!) +✅ Database setup complete! +``` + +### 4. Verify Database Created + +```bash +docker exec shopify-ai-test ls -lh /home/web/data/.data/ +``` + +Expected output: +``` +shopify_ai.db +shopify_ai.db-wal +shopify_ai.db-shm +.encryption_key +.jwt_secret +``` + +### 5. Test Auto-Initialization on Restart + +```bash +# Restart container +docker restart shopify-ai-test + +# Check logs +docker logs shopify-ai-test | tail -20 +``` + +Expected: +``` +✅ Database already exists +``` + +### 6. Test Migration in Container + +```bash +# Copy sample JSON files +docker exec shopify-ai-test sh -c 'cat > /home/web/data/.data/users.json << EOF +[{"id":"user1","email":"test@example.com","passwordHash":"test"}] +EOF' + +# Run migration +docker exec shopify-ai-test node /opt/webchat/scripts/migrate-to-database.js +``` + +### 7. Verify Tables + +```bash +docker exec shopify-ai-test sqlite3 /home/web/data/.data/shopify_ai.db ".tables" +``` + +Expected output: +``` +affiliates payment_sessions token_blacklist +audit_log refresh_tokens users +contact_messages sessions withdrawals +feature_requests +``` + +### 8. Check Encryption Keys Persisted + +```bash +docker exec shopify-ai-test cat /home/web/data/.data/.encryption_key +docker exec shopify-ai-test cat /home/web/data/.data/.jwt_secret +``` + +Save these keys to your environment configuration! + +### 9. Test JSON Fallback Mode + +```bash +# Stop container +docker stop shopify-ai-test +docker rm shopify-ai-test + +# Start with JSON mode +docker run -d \ + --name shopify-ai-test \ + -p 4500:4500 \ + -e USE_JSON_DATABASE=1 \ + -v shopify-data:/home/web/data \ + shopify-ai-builder:test + +# Check logs +docker logs shopify-ai-test | grep "JSON" +``` + +Expected: +``` +📁 Running in JSON compatibility mode +``` + +### 10. Cleanup + +```bash +docker stop shopify-ai-test +docker rm shopify-ai-test +docker volume rm shopify-data +``` + +## Production Deployment + +### Environment Variables Required + +```bash +# Required +DATABASE_ENCRYPTION_KEY=<64-char-hex> # Generate: openssl rand -hex 32 +JWT_SECRET=<64-char-hex> # Generate: openssl rand -hex 32 + +# Optional +DATABASE_PATH=./.data/shopify_ai.db +DATABASE_BACKUP_ENABLED=1 +DATABASE_WAL_MODE=1 +USE_JSON_DATABASE=0 # Set to 1 for JSON mode +JWT_ACCESS_TOKEN_TTL=900 # 15 minutes +JWT_REFRESH_TOKEN_TTL=604800 # 7 days +``` + +### First Deployment + +1. **Generate keys** and save them securely +2. **Deploy container** with environment variables +3. **Verify logs** show database initialization +4. **Save generated keys** from logs if not pre-set +5. **Test authentication** (once integrated) + +### Subsequent Deployments + +1. **Use same keys** from first deployment +2. **Database persists** via volume +3. **No migration needed** unless upgrading from JSON + +### Rollback to JSON + +If issues occur: + +1. Set `USE_JSON_DATABASE=1` +2. Restart container +3. System uses JSON files +4. Original JSON backups preserved + +## Troubleshooting + +### Database Not Found + +```bash +# Check data directory +ls -la /home/web/data/.data/ + +# Re-run initialization +node scripts/init-database.js +``` + +### Encryption Error + +```bash +# Verify key is 64 characters (hex) +echo $DATABASE_ENCRYPTION_KEY | wc -c # Should be 65 (64 + newline) + +# Regenerate if needed +export DATABASE_ENCRYPTION_KEY=$(openssl rand -hex 32) +``` + +### Migration Failed + +```bash +# Check JSON files exist +ls -la .data/*.json + +# Check database exists +ls -la .data/shopify_ai.db + +# View backup +ls -la .data/migration_backup_*/ +``` + +### Permission Issues + +```bash +# In container +chown -R root:root /home/web/data +chmod -R 755 /home/web/data +``` + +## Security Checklist + +- [ ] Encryption keys generated securely +- [ ] Keys stored in secure environment (not in code) +- [ ] Database file permissions restricted (600/700) +- [ ] Backup encryption keys offline +- [ ] Test rollback procedure +- [ ] Verify audit logging works +- [ ] Test session revocation +- [ ] Test token refresh + +## Next Steps + +1. ✅ Database implementation complete +2. ✅ Encryption working +3. ✅ Migration tested +4. ⏳ Integrate with server.js authentication +5. ⏳ Add auth API endpoints +6. ⏳ End-to-end testing +7. ⏳ Production deployment + +## Support + +For issues: +1. Check logs: `docker logs ` +2. Verify environment variables +3. Test locally first +4. Review DATABASE_IMPLEMENTATION.md diff --git a/chat/test-encryption.js b/chat/test-encryption.js deleted file mode 100644 index 1918338..0000000 --- a/chat/test-encryption.js +++ /dev/null @@ -1,33 +0,0 @@ -const { initEncryption, encrypt, decrypt, hashValue, verifyHash } = require('./src/utils/encryption'); -const crypto = require('crypto'); - -// Initialize -const key = crypto.randomBytes(32).toString('hex'); -initEncryption(key); - -console.log('🔐 Testing Encryption...\n'); - -// Test 1: Basic encryption/decryption -const plaintext = 'test@example.com'; -const encrypted = encrypt(plaintext); -const decrypted = decrypt(encrypted); - -console.log('Test 1: Basic Encryption'); -console.log(' Plaintext:', plaintext); -console.log(' Encrypted:', encrypted.substring(0, 50) + '...'); -console.log(' Decrypted:', decrypted); -console.log(' Match:', plaintext === decrypted ? '✅' : '❌'); - -// Test 2: Hash and verify -const value = 'mytoken123'; -const { hash, salt } = hashValue(value); -const isValid = verifyHash(value, hash, salt); -const isInvalid = verifyHash('wrongvalue', hash, salt); - -console.log('\nTest 2: Hash and Verify'); -console.log(' Value:', value); -console.log(' Hash:', hash.substring(0, 30) + '...'); -console.log(' Valid verification:', isValid ? '✅' : '❌'); -console.log(' Invalid verification:', !isInvalid ? '✅' : '❌'); - -console.log('\n✅ All encryption tests passed!'); diff --git a/chat/test-repositories.js b/chat/test-repositories.js deleted file mode 100644 index dc1e4af..0000000 --- a/chat/test-repositories.js +++ /dev/null @@ -1,97 +0,0 @@ -const { initDatabase, closeDatabase } = require('./src/database/connection'); -const { initEncryption } = require('./src/utils/encryption'); -const userRepo = require('./src/repositories/userRepository'); -const sessionRepo = require('./src/repositories/sessionRepository'); -const auditRepo = require('./src/repositories/auditRepository'); -const crypto = require('crypto'); - -// Initialize -const dbPath = './.data/test_shopify_ai.db'; -const encKey = crypto.randomBytes(32).toString('hex'); - -console.log('🧪 Testing Repositories...\n'); - -initEncryption(encKey); -initDatabase(dbPath); - -// Setup schema -const fs = require('fs'); -const path = require('path'); -const db = require('./src/database/connection').getDatabase(); -const schema = fs.readFileSync(path.join(__dirname, 'src/database/schema.sql'), 'utf8'); -db.exec(schema); - -// Test 1: Create user -console.log('Test 1: Create User'); -const user = userRepo.createUser({ - id: 'user123', - email: 'test@example.com', - name: 'Test User', - passwordHash: '$2b$12$hashedpassword', - emailVerified: true, - plan: 'professional' -}); -console.log(' Created user:', user.email); -console.log(' ID:', user.id); -console.log(' Plan:', user.plan); -console.log(' Success:', user.id === 'user123' ? '✅' : '❌'); - -// Test 2: Get user by email -console.log('\nTest 2: Get User by Email'); -const foundUser = userRepo.getUserByEmail('test@example.com'); -console.log(' Found user:', foundUser.email); -console.log(' Name matches:', foundUser.name === 'Test User' ? '✅' : '❌'); - -// Test 3: Update user -console.log('\nTest 3: Update User'); -const updated = userRepo.updateUser('user123', { - plan: 'enterprise', - billingStatus: 'active' -}); -console.log(' Updated plan:', updated.plan); -console.log(' Plan correct:', updated.plan === 'enterprise' ? '✅' : '❌'); - -// Test 4: Create session -console.log('\nTest 4: Create Session'); -const session = sessionRepo.createSession({ - userId: 'user123', - token: 'session_token_123', - deviceFingerprint: 'device123', - expiresAt: Date.now() + 86400000 -}); -console.log(' Created session:', session.id); -console.log(' Token:', session.token); -console.log(' Success:', session.userId === 'user123' ? '✅' : '❌'); - -// Test 5: Get session by token -console.log('\nTest 5: Get Session by Token'); -const foundSession = sessionRepo.getSessionByToken('session_token_123'); -console.log(' Found session:', foundSession.id); -console.log(' Matches:', foundSession.id === session.id ? '✅' : '❌'); - -// Test 6: Audit log -console.log('\nTest 6: Audit Log'); -auditRepo.logAuditEvent({ - userId: 'user123', - eventType: 'login', - eventData: { method: 'email' }, - ipAddress: '127.0.0.1', - success: true -}); -const logs = auditRepo.getUserAuditLog('user123'); -console.log(' Logged event count:', logs.length); -console.log(' Event type:', logs[0].eventType); -console.log(' Success:', logs.length === 1 && logs[0].eventType === 'login' ? '✅' : '❌'); - -// Test 7: Cleanup -console.log('\nTest 7: Cleanup'); -const deleted = userRepo.deleteUser('user123'); -console.log(' User deleted:', deleted ? '✅' : '❌'); - -closeDatabase(); -console.log('\n✅ All repository tests passed!'); - -// Clean up test database -fs.unlinkSync(dbPath); -fs.unlinkSync(dbPath + '-wal'); -fs.unlinkSync(dbPath + '-shm'); diff --git a/chat/test-tokens.js b/chat/test-tokens.js deleted file mode 100644 index cb539af..0000000 --- a/chat/test-tokens.js +++ /dev/null @@ -1,52 +0,0 @@ -const { initTokenManager, generateAccessToken, verifyAccessToken, generateRefreshToken, verifyRefreshToken, generateDeviceFingerprint } = require('./src/utils/tokenManager'); -const crypto = require('crypto'); - -// Initialize -const secret = crypto.randomBytes(32).toString('hex'); -initTokenManager(secret); - -console.log('🔑 Testing Token Manager...\n'); - -// Test 1: Access token generation and verification -const payload = { - userId: 'user123', - email: 'test@example.com', - role: 'user', - plan: 'professional' -}; - -const accessToken = generateAccessToken(payload); -const decoded = verifyAccessToken(accessToken); - -console.log('Test 1: Access Token'); -console.log(' Token:', accessToken.substring(0, 50) + '...'); -console.log(' User ID:', decoded.userId); -console.log(' Email:', decoded.email); -console.log(' Valid:', decoded.userId === payload.userId ? '✅' : '❌'); - -// Test 2: Refresh token -const { token, tokenHash } = generateRefreshToken(); -const isValid = verifyRefreshToken(token, tokenHash); -const isInvalid = verifyRefreshToken('wrongtoken', tokenHash); - -console.log('\nTest 2: Refresh Token'); -console.log(' Token:', token.substring(0, 30) + '...'); -console.log(' Hash:', tokenHash.substring(0, 30) + '...'); -console.log(' Valid verification:', isValid ? '✅' : '❌'); -console.log(' Invalid verification:', !isInvalid ? '✅' : '❌'); - -// Test 3: Device fingerprint -const mockReq = { - headers: { - 'user-agent': 'Mozilla/5.0', - 'accept-language': 'en-US' - }, - ip: '127.0.0.1' -}; - -const fingerprint = generateDeviceFingerprint(mockReq); -console.log('\nTest 3: Device Fingerprint'); -console.log(' Fingerprint:', fingerprint); -console.log(' Length correct:', fingerprint.length === 32 ? '✅' : '❌'); - -console.log('\n✅ All token tests passed!');