104 lines
3.3 KiB
TypeScript
104 lines
3.3 KiB
TypeScript
import { SignJWT, jwtVerify } from 'jose';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import bcrypt from 'bcryptjs';
|
|
import { cookies } from 'next/headers';
|
|
|
|
// Interface for member credentials
|
|
export interface MemberCredential {
|
|
memberNumber: string;
|
|
password: string; // Hashed password
|
|
hasVoted: boolean;
|
|
lastLogin?: string; // ISO date string
|
|
}
|
|
|
|
// These functions are now only used server-side in API routes
|
|
// Client components should use the API routes instead
|
|
|
|
// Generate a one-time use token for voting
|
|
export async function generateRandomToken(memberNumber?: string): Promise<string> {
|
|
// This function is used in API routes
|
|
const tokenId = uuidv4();
|
|
|
|
const payload: any = { tokenId };
|
|
|
|
// If memberNumber is provided, include it in the token
|
|
if (memberNumber) {
|
|
payload.memberNumber = memberNumber;
|
|
}
|
|
|
|
// Use a secret key from environment variable or a default one
|
|
const secretKey = process.env.JWT_SECRET_KEY || 'schafwaschener-segelverein-secret-key-for-jwt-signing';
|
|
const encoder = new TextEncoder();
|
|
const key = encoder.encode(secretKey);
|
|
|
|
const token = await new SignJWT(payload)
|
|
.setProtectedHeader({ alg: 'HS256' })
|
|
.setIssuedAt()
|
|
.setExpirationTime('7d') // Token expires in 7 days
|
|
.sign(key);
|
|
|
|
return token;
|
|
}
|
|
|
|
// Generate an admin token
|
|
async function generateAdminToken(): Promise<string> {
|
|
// Use a secret key from environment variable or a default one
|
|
const secretKey = process.env.JWT_SECRET_KEY || 'schafwaschener-segelverein-secret-key-for-jwt-signing';
|
|
const encoder = new TextEncoder();
|
|
const key = encoder.encode(secretKey);
|
|
|
|
const token = await new SignJWT({ role: 'admin' })
|
|
.setProtectedHeader({ alg: 'HS256' })
|
|
.setIssuedAt()
|
|
.setExpirationTime('24h') // Admin token expires in 24 hours
|
|
.sign(key);
|
|
|
|
return token;
|
|
}
|
|
|
|
// Verify an admin token
|
|
async function verifyAdminToken(): Promise<boolean> {
|
|
const token = (await cookies()).get('admin-token')?.value;
|
|
if (!token) return false;
|
|
|
|
try {
|
|
// Use a secret key from environment variable or a default one
|
|
const secretKey = process.env.JWT_SECRET_KEY || 'schafwaschener-segelverein-secret-key-for-jwt-signing';
|
|
const encoder = new TextEncoder();
|
|
const key = encoder.encode(secretKey);
|
|
|
|
const { payload } = await jwtVerify(token, key);
|
|
return payload.role === 'admin';
|
|
} catch (error) {
|
|
console.error('Admin token verification failed:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export async function checkAdminAuth(password?: string): Promise<boolean> {
|
|
// Get admin password from environment variable or use default for development
|
|
const isAuthenticated = await verifyAdminToken();
|
|
if (isAuthenticated) return true;
|
|
if (password) {
|
|
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'schafwaschener-segelverein-admin';
|
|
if (password === ADMIN_PASSWORD) {
|
|
// Password is correct, generate and set admin token
|
|
const newAdminToken = await generateAdminToken();
|
|
(await cookies()).set('admin-token', newAdminToken);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// Hash a password
|
|
export function hashPassword(password: string): string {
|
|
return bcrypt.hashSync(password, 10);
|
|
}
|
|
|
|
// Compare a password with a hash
|
|
export function comparePassword(password: string, hash: string): boolean {
|
|
return bcrypt.compareSync(password, hash);
|
|
}
|