- Add GUIDE.md: complete user documentation covering installation, Docker deployment, AI providers, MCP server, N8N integration, email config, admin panel, env var reference, troubleshooting - Add mcp-server/.env.example with all MCP-specific variables - Update .env.docker.example with all 42 environment variables - Fix docker-compose.yml: parameterize PostgreSQL credentials, add missing env vars (CUSTOM_OPENAI, AI_PROVIDER_CHAT, ALLOW_REGISTRATION, RESEND_API_KEY) - Track memento-note/.env.example
91 lines
2.6 KiB
TypeScript
91 lines
2.6 KiB
TypeScript
'use server'
|
|
|
|
import prisma from '@/lib/prisma'
|
|
import { sendEmail } from '@/lib/mail'
|
|
import { getSystemConfig } from '@/lib/config'
|
|
import bcrypt from 'bcryptjs'
|
|
import { getEmailTemplate } from '@/lib/email-template'
|
|
|
|
// Simple helper to generate a token without heavy external dependencies
|
|
function generateToken() {
|
|
const array = new Uint8Array(32);
|
|
globalThis.crypto.getRandomValues(array);
|
|
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
|
|
}
|
|
|
|
export async function forgotPassword(email: string) {
|
|
if (!email) return { error: "Email is required" };
|
|
|
|
try {
|
|
const user = await prisma.user.findUnique({ where: { email: email.toLowerCase() } });
|
|
if (!user) {
|
|
// For security reasons, don't reveal whether the email exists
|
|
return { success: true };
|
|
}
|
|
|
|
const token = generateToken();
|
|
const expiry = new Date(Date.now() + 3600000); // 1 hour
|
|
|
|
await prisma.user.update({
|
|
where: { id: user.id },
|
|
data: {
|
|
resetToken: token,
|
|
resetTokenExpiry: expiry
|
|
}
|
|
});
|
|
|
|
const resetLink = `${process.env.NEXTAUTH_URL}/reset-password?token=${token}`;
|
|
|
|
const html = getEmailTemplate(
|
|
"Reset your Password",
|
|
"<p>You requested a password reset for your Memento account.</p><p>Click the button below to set a new password. This link is valid for 1 hour.</p>",
|
|
resetLink,
|
|
"Reset Password"
|
|
);
|
|
|
|
const sysConfig = await getSystemConfig()
|
|
const emailProvider = (sysConfig.EMAIL_PROVIDER || 'auto') as 'resend' | 'smtp' | 'auto'
|
|
|
|
await sendEmail({
|
|
to: user.email,
|
|
subject: "Reset your Memento password",
|
|
html
|
|
}, emailProvider);
|
|
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error('Forgot password error:', error);
|
|
return { error: "Failed to send reset email" };
|
|
}
|
|
}
|
|
|
|
export async function resetPassword(token: string, newPassword: string) {
|
|
if (!token || !newPassword) return { error: "Missing token or password" };
|
|
|
|
try {
|
|
const user = await prisma.user.findUnique({
|
|
where: { resetToken: token }
|
|
});
|
|
|
|
if (!user || !user.resetTokenExpiry || user.resetTokenExpiry < new Date()) {
|
|
return { error: "Invalid or expired token" };
|
|
}
|
|
|
|
const hashedPassword = await bcrypt.hash(newPassword, 10);
|
|
|
|
await prisma.user.update({
|
|
where: { id: user.id },
|
|
data: {
|
|
password: hashedPassword,
|
|
resetToken: null,
|
|
resetTokenExpiry: null
|
|
}
|
|
});
|
|
|
|
return { success: true };
|
|
} catch (error) {
|
|
console.error('Reset password error:', error);
|
|
return { error: "Failed to reset password" };
|
|
}
|
|
}
|