/home/techb158/cosmic-risk.abdallabala.com/src/services
Edit: /home/techb158/cosmic-risk.abdallabala.com/src/services/auth-service.js (4779B)
const { prisma } = require("../lib/prisma");
const { randomBytes } = require("crypto");
const bcrypt = require("bcryptjs");
const SESSION_DURATION_MS = 1000 * 60 * 60 * 24 * 7;
function generateSessionToken() {
return randomBytes(48).toString("hex");
}
async function hashPassword(password) {
return bcrypt.hash(password, 12);
}
async function verifyPassword(password, hash) {
if (!hash) return false;
return bcrypt.compare(password, hash);
}
async function createSession(userId) {
const token = generateSessionToken();
const session = await prisma.session.create({
data: {
userId,
token,
expiresAt: new Date(Date.now() + SESSION_DURATION_MS)
}
});
return session;
}
async function getSession(token) {
if (!token) return null;
const session = await prisma.session.findUnique({
where: { token },
include: {
user: {
include: {
memberships: {
where: { status: "ACTIVE" },
include: {
organization: true,
role: true
}
}
}
}
}
});
if (!session || session.expiresAt < new Date()) {
if (session) {
await prisma.session.delete({ where: { id: session.id } }).catch(() => {});
}
return null;
}
return session;
}
async function signup({ email, displayName, password }) {
if (!email || !password) {
const error = new Error("Email and password are required");
error.status = 400;
throw error;
}
const existing = await prisma.user.findUnique({ where: { email } });
if (existing) {
const error = new Error("Email already registered");
error.status = 409;
throw error;
}
const passwordHash = await hashPassword(password);
const user = await prisma.user.create({
data: {
email,
displayName: displayName || email.split("@")[0],
passwordHash,
emailVerifiedAt: new Date()
}
});
const slug = (displayName || email.split("@")[0])
.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "")
+ "-" + Date.now().toString(36);
const role = await prisma.role.upsert({
where: { code: "owner" },
update: {},
create: { code: "owner", name: "Owner", permissions: ["*"], system: true }
});
const org = await prisma.organization.create({
data: {
name: (displayName || email.split("@")[0]) + "'s Organization",
slug,
status: "TRIAL",
planCode: "pilot",
manualBilling: true
}
});
await prisma.membership.create({
data: {
organizationId: org.id,
userId: user.id,
roleId: role.id,
status: "ACTIVE"
}
});
await prisma.subscription.create({
data: {
organizationId: org.id,
source: "MANUAL",
status: "TRIALING",
planCode: "pilot",
userLimit: 5,
projectLimit: 3,
reportLimitMonthly: 25,
integrationLimit: 2,
adminOverride: false
}
}).catch(() => {});
const workspace = await prisma.workspace.create({
data: {
organizationId: org.id,
name: "Default Workspace",
slug: "default-workspace",
type: "B2B_TEAM",
status: "TRIAL"
}
});
await prisma.project.create({
data: {
workspaceId: workspace.id,
name: "My Project",
projectType: "AI-Enabler",
status: "Active",
riskAppetite: 50,
description: "Project created during signup"
}
});
const session = await createSession(user.id);
return { user, session };
}
async function login({ email, password }) {
if (!email || !password) {
const error = new Error("Email and password are required");
error.status = 400;
throw error;
}
const user = await prisma.user.findUnique({
where: { email },
include: {
memberships: {
where: { status: "ACTIVE" },
include: { organization: true, role: true }
}
}
});
if (!user) {
const error = new Error("Invalid email or password");
error.status = 401;
throw error;
}
const valid = await verifyPassword(password, user.passwordHash);
if (!valid) {
const error = new Error("Invalid email or password");
error.status = 401;
throw error;
}
await prisma.user.update({ where: { id: user.id }, data: { lastLoginAt: new Date() } });
const session = await createSession(user.id);
return { user, session };
}
async function logout(token) {
if (!token) return;
await prisma.session.deleteMany({ where: { token } }).catch(() => {});
}
async function getActorFromSession(token) {
const session = await getSession(token);
if (!session) return null;
return session.user;
}
module.exports = {
signup,
login,
logout,
getSession,
getActorFromSession,
createSession,
SESSION_DURATION_MS
};