From c127ea35f61e9f4f7fdf80d597b19fb86a19245b Mon Sep 17 00:00:00 2001 From: Joshua Ryder Date: Mon, 6 Oct 2025 18:26:01 -0400 Subject: [PATCH] Self-service password reset --- README.md | 15 ++ docker-compose.yml | 10 + nuxt.config.ts | 5 + package.json | 2 + pages/forgot-password.vue | 305 ++++++++++++++++++++++ pages/login.vue | 113 +++++++- pages/users.vue | 2 +- server/api/auth/forgot-password.post.ts | 44 ++++ server/api/auth/register.post.ts | 32 ++- server/api/auth/reset-password.post.ts | 50 ++++ server/api/auth/verify-reset-code.post.ts | 25 ++ server/utils/database.ts | 62 ++++- server/utils/email.ts | 39 +++ 13 files changed, 683 insertions(+), 21 deletions(-) create mode 100644 pages/forgot-password.vue create mode 100644 server/api/auth/forgot-password.post.ts create mode 100644 server/api/auth/reset-password.post.ts create mode 100644 server/api/auth/verify-reset-code.post.ts create mode 100644 server/utils/email.ts diff --git a/README.md b/README.md index 574f78b..586de2f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,11 @@ This application uses environment variables configured directly in `docker-compo | `AUTH_SECRET` | Secret key for authentication sessions | `change-this-secret-in-production-please` | | `ADMIN_USERNAME` | Initial admin login username | `admin` | | `ADMIN_PASSWORD` | Initial admin login password | `Admin123!` | +| `EMAIL_HOST` | SMTP server hostname | `smtp.example.com` | +| `EMAIL_PORT` | SMTP server port | `587` | +| `EMAIL_USER` | SMTP authentication username | `noreply@example.com` | +| `EMAIL_PASSWORD` | SMTP authentication password | `your-email-password` | +| `EMAIL_FROM` | Email sender address and name | `New Life Christian Church ` | ### Customizing Configuration @@ -47,11 +52,21 @@ services: - AUTH_SECRET=your-secure-random-secret-here - ADMIN_USERNAME=your-admin-username - ADMIN_PASSWORD=your-secure-password + - EMAIL_HOST=smtp.gmail.com + - EMAIL_PORT=587 + - EMAIL_USER=your-email@gmail.com + - EMAIL_PASSWORD=your-app-password + - EMAIL_FROM=Your Church Name environment: - SITE_URL=https://your-church-domain.com - AUTH_SECRET=your-secure-random-secret-here - ADMIN_USERNAME=your-admin-username - ADMIN_PASSWORD=your-secure-password + - EMAIL_HOST=smtp.gmail.com + - EMAIL_PORT=587 + - EMAIL_USER=your-email@gmail.com + - EMAIL_PASSWORD=your-app-password + - EMAIL_FROM=Your Church Name ``` **Generate a secure AUTH_SECRET:** diff --git a/docker-compose.yml b/docker-compose.yml index 46d258e..4788e9e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,6 +7,11 @@ services: - AUTH_SECRET=change-this-secret-in-production-please - ADMIN_USERNAME=admin - ADMIN_PASSWORD=Admin123! + - EMAIL_HOST=smtp.example.com + - EMAIL_PORT=587 + - EMAIL_USER=noreply@example.com + - EMAIL_PASSWORD=your-email-password + - EMAIL_FROM=New Life Christian Church container_name: nlcc-itinerary ports: - "3002:3000" @@ -18,4 +23,9 @@ services: - SITE_URL=https://nlcc.rydertech.us - ADMIN_USERNAME=admin - ADMIN_PASSWORD=Admin123! + - EMAIL_HOST=smtp.example.com + - EMAIL_PORT=587 + - EMAIL_USER=noreply@example.com + - EMAIL_PASSWORD=your-email-password + - EMAIL_FROM=New Life Christian Church restart: unless-stopped diff --git a/nuxt.config.ts b/nuxt.config.ts index fb0cfda..57d38b4 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -30,6 +30,11 @@ export default defineNuxtConfig({ authSecret: process.env.AUTH_SECRET || 'change-this-secret-in-production', adminUsername: process.env.ADMIN_USERNAME || 'admin', adminPassword: process.env.ADMIN_PASSWORD || 'admin123', + emailHost: process.env.EMAIL_HOST || 'smtp.example.com', + emailPort: process.env.EMAIL_PORT || '587', + emailUser: process.env.EMAIL_USER || 'noreply@example.com', + emailPassword: process.env.EMAIL_PASSWORD || 'your-email-password', + emailFrom: process.env.EMAIL_FROM || 'New Life Christian Church ', public: { siteUrl: process.env.SITE_URL || 'https://newlife-christian.com' } diff --git a/package.json b/package.json index 704e957..fc3c6c0 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "dependencies": { "bcrypt": "^5.1.1", "better-sqlite3": "^11.3.0", + "nodemailer": "^6.9.7", "nuxt": "^3.13.2", "qrcode": "^1.5.4", "vue": "^3.5.5", @@ -22,6 +23,7 @@ "@nuxtjs/tailwindcss": "^6.12.1", "@types/bcrypt": "^5.0.2", "@types/better-sqlite3": "^7.6.11", + "@types/nodemailer": "^6.4.14", "@types/qrcode": "^1.5.5" } } diff --git a/pages/forgot-password.vue b/pages/forgot-password.vue new file mode 100644 index 0000000..345a0ba --- /dev/null +++ b/pages/forgot-password.vue @@ -0,0 +1,305 @@ + + + diff --git a/pages/login.vue b/pages/login.vue index 30a9d6d..8f60c7c 100644 --- a/pages/login.vue +++ b/pages/login.vue @@ -10,19 +10,64 @@
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+
- +
@@ -62,6 +107,28 @@
+ +
+ + + + +
+
+ ✓ Passwords match + ✗ Passwords do not match +
+
+
+
{{ error }}
@@ -82,6 +149,11 @@ > {{ isRegistering ? 'Already have an account? Sign in' : "Don't have an account? Create one" }} +
+ + Forgot Password? + +
← Back to Sermons @@ -99,6 +171,10 @@