mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-22 18:30:09 +00:00
feat(syncServer): add email verification route and user deletion script
This commit is contained in:
parent
3a319eb1de
commit
8e26c96760
5 changed files with 114 additions and 5 deletions
|
|
@ -6,7 +6,8 @@
|
|||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "ts-node src/index.ts"
|
||||
"dev": "ts-node src/index.ts",
|
||||
"delete-user": "ts-node scripts/delete-user.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^11.1.0",
|
||||
|
|
|
|||
50
packages/super-sync-server/scripts/delete-user.ts
Normal file
50
packages/super-sync-server/scripts/delete-user.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import Database from 'better-sqlite3';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { loadConfigFromEnv } from '../src/config';
|
||||
|
||||
const deleteUser = (email: string) => {
|
||||
try {
|
||||
// Load config to get data directory
|
||||
const config = loadConfigFromEnv();
|
||||
const dbPath = path.join(config.dataDir, 'database.sqlite');
|
||||
|
||||
if (!fs.existsSync(dbPath)) {
|
||||
console.error(`Database not found at ${dbPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const db = new Database(dbPath);
|
||||
|
||||
// Check if user exists first
|
||||
const user = db.prepare('SELECT * FROM users WHERE email = ?').get(email);
|
||||
|
||||
if (!user) {
|
||||
console.log(`User with email "${email}" not found.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete user
|
||||
const info = db.prepare('DELETE FROM users WHERE email = ?').run(email);
|
||||
|
||||
if (info.changes > 0) {
|
||||
console.log(`Successfully deleted user: ${email}`);
|
||||
} else {
|
||||
console.log(`Failed to delete user: ${email}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting user:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Get email from command line arguments
|
||||
const email = process.argv[2];
|
||||
|
||||
if (!email) {
|
||||
console.error('Please provide an email address.');
|
||||
console.error('Usage: npm run delete-user -- <email>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
deleteUser(email);
|
||||
|
|
@ -77,10 +77,14 @@ export const loadConfigFromEnv = (
|
|||
|
||||
// SMTP Configuration
|
||||
if (process.env.SMTP_HOST) {
|
||||
const port = parseInt(process.env.SMTP_PORT || '587', 10);
|
||||
config.smtp = {
|
||||
host: process.env.SMTP_HOST,
|
||||
port: parseInt(process.env.SMTP_PORT || '587', 10),
|
||||
secure: process.env.SMTP_SECURE === 'true',
|
||||
port,
|
||||
secure:
|
||||
process.env.SMTP_SECURE !== undefined
|
||||
? process.env.SMTP_SECURE === 'true'
|
||||
: port === 465,
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS,
|
||||
from: process.env.SMTP_FROM || '"SuperSync" <noreply@example.com>',
|
||||
|
|
|
|||
47
packages/super-sync-server/src/pages.ts
Normal file
47
packages/super-sync-server/src/pages.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { FastifyInstance } from 'fastify';
|
||||
import { verifyEmail } from './auth';
|
||||
import { Logger } from './logger';
|
||||
|
||||
// Error response helper
|
||||
const errorMessage = (err: unknown): string =>
|
||||
err instanceof Error ? err.message : 'Unknown error';
|
||||
|
||||
interface VerifyEmailQuery {
|
||||
token?: string;
|
||||
}
|
||||
|
||||
export async function pageRoutes(fastify: FastifyInstance) {
|
||||
fastify.get<{ Querystring: VerifyEmailQuery }>('/verify-email', async (req, reply) => {
|
||||
try {
|
||||
const { token } = req.query;
|
||||
if (!token) {
|
||||
return reply.status(400).send('Token is required');
|
||||
}
|
||||
|
||||
verifyEmail(token);
|
||||
return reply.type('text/html').send(`
|
||||
<html>
|
||||
<head>
|
||||
<title>Email Verified</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; background: #0f172a; color: white; }
|
||||
.container { text-align: center; padding: 2rem; background: rgba(30, 41, 59, 0.7); border-radius: 1rem; border: 1px solid rgba(255,255,255,0.1); }
|
||||
h1 { color: #10b981; }
|
||||
a { color: #3b82f6; text-decoration: none; margin-top: 1rem; display: inline-block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Email Verified!</h1>
|
||||
<p>Your account has been successfully verified.</p>
|
||||
<a href="/">Return to Login</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
} catch (err) {
|
||||
Logger.error(`Verification error: ${errorMessage(err)}`);
|
||||
return reply.status(400).send(`Verification failed: ${errorMessage(err)}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import { loadConfigFromEnv, ServerConfig } from './config';
|
|||
import { Logger } from './logger';
|
||||
import { initDb } from './db';
|
||||
import { apiRoutes } from './api';
|
||||
import { pageRoutes } from './pages';
|
||||
import { verifyToken } from './auth';
|
||||
|
||||
export { ServerConfig, loadConfigFromEnv };
|
||||
|
|
@ -162,6 +163,9 @@ export const createServer = (
|
|||
// API Routes
|
||||
await fastifyServer.register(apiRoutes, { prefix: '/api' });
|
||||
|
||||
// Page Routes
|
||||
await fastifyServer.register(pageRoutes, { prefix: '/' });
|
||||
|
||||
// WebDAV Handler (Catch-all via hook)
|
||||
// We use a hook because Fastify's router validates HTTP methods and might not support all WebDAV methods
|
||||
fastifyServer.addHook('onRequest', (req, reply, done) => {
|
||||
|
|
@ -170,10 +174,13 @@ export const createServer = (
|
|||
return;
|
||||
}
|
||||
|
||||
// Allow static files to be handled by Fastify
|
||||
// Allow static files and verify-email route to be handled by Fastify
|
||||
const staticFiles = ['/', '/index.html', '/style.css', '/app.js', '/favicon.ico'];
|
||||
const urlPath = req.url.split('?')[0];
|
||||
if (req.method === 'GET' && staticFiles.includes(urlPath)) {
|
||||
if (
|
||||
(req.method === 'GET' && staticFiles.includes(urlPath)) ||
|
||||
urlPath === '/verify-email'
|
||||
) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue