added mail service
This commit is contained in:
75
config/auth.ts
Normal file
75
config/auth.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import NextAuth from 'next-auth'
|
||||
import { UserRole } from '@prisma/client'
|
||||
import { PrismaAdapter } from '@auth/prisma-adapter'
|
||||
import { db } from '@/lib/db'
|
||||
import authConfig from '@/auth.config'
|
||||
import { getUserById } from '@/data/user'
|
||||
import { AUTH_ERROR_URL, AUTH_LOGIN_URL } from '@/config/routes'
|
||||
|
||||
declare module 'next-auth' {
|
||||
interface Session {
|
||||
user: { role: UserRole }
|
||||
}
|
||||
}
|
||||
|
||||
export const VERIFICATION_TOKEN_EXPIRATION_DURATION = 3_600_000
|
||||
|
||||
export const {
|
||||
handlers: { GET, POST },
|
||||
auth,
|
||||
signIn,
|
||||
signOut,
|
||||
} = NextAuth({
|
||||
pages: {
|
||||
signIn: AUTH_LOGIN_URL,
|
||||
error: AUTH_ERROR_URL,
|
||||
},
|
||||
events: {
|
||||
async linkAccount ({ user }) {
|
||||
await db.user.update({
|
||||
where: { id: user.id as string },
|
||||
data: { emailVerified: new Date() },
|
||||
})
|
||||
},
|
||||
},
|
||||
callbacks: {
|
||||
async signIn ({ user, account }) {
|
||||
// Bypass email verification when Oauth are being used
|
||||
if (account?.provider !== 'credentials') return true
|
||||
|
||||
const existingUser = await getUserById(user.id as string)
|
||||
|
||||
// Prevent sign in without email verification
|
||||
if (!existingUser?.emailVerified) return false
|
||||
|
||||
// TODO: Add 2FA check
|
||||
|
||||
return true
|
||||
},
|
||||
async session ({ token, session }) {
|
||||
if (token.sub && session.user) {
|
||||
session.user.id = token.sub
|
||||
}
|
||||
|
||||
if (token.role && session.user) {
|
||||
session.user.role = token.role as UserRole
|
||||
}
|
||||
|
||||
return session
|
||||
},
|
||||
async jwt ({ token }) {
|
||||
if (!token.sub) return token
|
||||
|
||||
const existingUser = await getUserById(token.sub)
|
||||
|
||||
if (!existingUser) return token
|
||||
|
||||
token.role = existingUser.role
|
||||
|
||||
return token
|
||||
},
|
||||
},
|
||||
adapter: PrismaAdapter(db),
|
||||
session: { strategy: 'jwt' },
|
||||
...authConfig,
|
||||
})
|
||||
1
config/layout.ts
Normal file
1
config/layout.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const bg: string = 'bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-sky-400 to-blue-800'
|
||||
30
config/locales.ts
Normal file
30
config/locales.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
// @https://www.localeplanet.com/icu/index.html
|
||||
|
||||
const defaultLocale = 'uk'
|
||||
|
||||
export type loc = ('uk' | 'en')
|
||||
|
||||
const importLocales = {
|
||||
uk: () => import('@/locales/uk'), en: () => import('@/locales/en'),
|
||||
}
|
||||
const LC = [
|
||||
{
|
||||
id: 'uk_UA',
|
||||
java: 'uk-UA',
|
||||
iso: 'ukr',
|
||||
code: 'uk',
|
||||
name: 'Ukrainian',
|
||||
originalName: 'Українська',
|
||||
},
|
||||
{
|
||||
id: 'en_US',
|
||||
java: 'en-US',
|
||||
iso: 'eng',
|
||||
code: 'en',
|
||||
name: 'English',
|
||||
originalName: 'English',
|
||||
}]
|
||||
|
||||
const locales = LC.map(locale => locale.code)
|
||||
|
||||
export { locales, defaultLocale, LC, importLocales }
|
||||
16
config/mailer.ts
Normal file
16
config/mailer.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { env } from 'process'
|
||||
import SMTPTransport from 'nodemailer/lib/smtp-transport'
|
||||
|
||||
export const from: string = `"${env.MAIL_SERVER_SENDER_NAME}" <${env.MAIL_SERVER_USERNAME}>`
|
||||
|
||||
export const transportOptions: SMTPTransport | SMTPTransport.Options | string = {
|
||||
host: env.MAIL_SERVER_HOST,
|
||||
debug: env.MAIL_SERVER_DEBUG === 'true',
|
||||
logger: env.MAIL_SERVER_LOG === 'true',
|
||||
port: parseInt(env.MAIL_SERVER_PORT as string),
|
||||
secure: env.MAIL_SERVER_PORT === '465', // Use `true` for port 465, `false` for all other ports
|
||||
auth: {
|
||||
user: env.MAIL_SERVER_USERNAME, pass: env.MAIL_SERVER_PASSWORD,
|
||||
},
|
||||
}
|
||||
|
||||
44
config/routes.ts
Normal file
44
config/routes.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { locales } from '@/config/locales'
|
||||
|
||||
export const USER_PROFILE_URL: string = '/cabinet'
|
||||
export const AUTH_LOGIN_URL: string = '/auth/login'
|
||||
export const AUTH_REGISTER_URL: string = '/auth/register'
|
||||
export const AUTH_ERROR_URL: string = '/auth/error'
|
||||
export const AUTH_EMAIL_VERIFICATION_URL: string = '/auth/email-verification'
|
||||
|
||||
/**
|
||||
* An array of routes that accessible to the public.
|
||||
* These routes do not requite authentication.
|
||||
* @type {string[]}
|
||||
*/
|
||||
export const publicRoutes: string[] = [
|
||||
'/', '/about']
|
||||
|
||||
/**
|
||||
* An array of routes that are used for authentication.
|
||||
* These routes will redirect logged-in users to /cabinet
|
||||
* @type {string[]}
|
||||
*/
|
||||
export const authRoutes: string[] = [
|
||||
AUTH_LOGIN_URL, AUTH_REGISTER_URL, AUTH_ERROR_URL, AUTH_EMAIL_VERIFICATION_URL]
|
||||
|
||||
/**
|
||||
* The prefix for API authentication routes.
|
||||
* Routes that start with this prefix are used for API authentication purpose.
|
||||
* @type {string}
|
||||
*/
|
||||
export const apiAuthPrefix: string = '/api/auth'
|
||||
|
||||
/**
|
||||
* The default redirect path after logging in.
|
||||
* @type {string}
|
||||
*/
|
||||
export const DEFAULT_LOGIN_REDIRECT: string = USER_PROFILE_URL
|
||||
|
||||
export const testPathnameRegex = (
|
||||
pages: string[], pathName: string): boolean => {
|
||||
const pattern: string = `^(/(${locales.join('|')}))?(${pages.flatMap(
|
||||
(p) => (p === '/' ? ['', '/'] : p)).join('|')})/?$`
|
||||
|
||||
return RegExp(pattern, 'is').test(pathName)
|
||||
}
|
||||
2
config/validation.ts
Normal file
2
config/validation.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export const MIN_PASSWORD_LENGTH: number = 6
|
||||
export const PASSWORD_SALT_LENGTH: number = 10
|
||||
Reference in New Issue
Block a user