new selfhosted version

This commit is contained in:
antonio
2025-11-28 14:11:51 +01:00
parent afda29997d
commit 951860f67e
1046 changed files with 72586 additions and 574750 deletions

View File

@@ -1,28 +1,49 @@
import { createUserJwt, readRegisterJwt } from '~/server/AuthManager';
import { UserModel } from '@schema/UserSchema';
import { PasswordModel } from '@schema/PasswordSchema';
import { EmailService } from '@services/EmailService';
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
import { RegisterModel } from '~/shared/schema/RegisterSchema';
export default defineEventHandler(async event => {
const { register_code } = getQuery(event);
//TODO: SELFHOST
const { code } = getQuery(event);
const data = readRegisterJwt(register_code as string);
if (!data) return setResponseStatus(event, 400, 'Error decoding register_code');
const registerTarget = await RegisterModel.findOne({ code });
if (!registerTarget) throw createError({ status: 400, message: 'Code not valid' });
const userExist = await UserModel.exists({ email: registerTarget.email });
if (userExist) throw createError({ status: 400, message: 'Email already registered' });
await PasswordModel.updateOne({ email: registerTarget.email }, { password: registerTarget.password }, { upsert: true });
const user = await UserModel.create({ email: registerTarget.email, given_name: '', name: 'EmailLogin', locale: '', picture: '', created_at: Date.now() });
const tRpc = useTRPC();
const customer = await tRpc.payments.customer.create.mutate({ email: user.email });
await tRpc.payments.subscription.activate.mutate({ user_id: user._id.toString(), customer_id: customer.customer_id, plan_tag: 'FREE_TRIAL_LITLYX_PRO' });
setImmediate(() => {
tRpc.emails.brevo.addToBrevoList.mutate({ email: user.email });
});
setImmediate(() => {
tRpc.emails.email.send_trial_1_started.mutate({ email: user.email });
});
await replaceUserSession(event, {
user: {
email: user.email,
name: user.name
},
secure: {
user_id: user.id
},
v: '0.0.1'
});
return sendRedirect(event, '/');
try {
await PasswordModel.create({ email: data.email, password: data.password })
await UserModel.create({ email: data.email, given_name: '', name: 'EmailLogin', locale: '', picture: '', created_at: Date.now() });
setImmediate(() => {
const emailData = EmailService.getEmailServerInfo('welcome', { target: data.email });
EmailServiceHelper.sendEmail(emailData);
});
const jwt = createUserJwt({ email: data.email, name: 'EmailLogin' });
return sendRedirect(event, `https://dashboard.litlyx.com/jwt_login?jwt_login=${jwt}`);
} catch (ex) {
return setResponseStatus(event, 400, 'Error creating user');
}
});

View File

@@ -0,0 +1,65 @@
import { UserModel } from "~/shared/schema/UserSchema"
export default defineOAuthGoogleEventHandler({
async onSuccess(event, result) {
const user = await UserModel.findOne({
email: result.user.email
});
if (!user) {
const newUser = await UserModel.create({
email: result.user.email,
name: result.user.name ?? 'NO_NAME',
given_name: result.user.given_name ?? 'NO_NAME',
locale: result.user.locale ?? '',
picture: ''
})
await replaceUserSession(event, {
user: {
email: newUser.email,
name: newUser.name
},
secure: {
user_id: newUser.id
},
v: '0.0.1'
});
const tRpc = useTRPC();
const customer = await tRpc.payments.customer.create.mutate({ email: newUser.email });
await tRpc.payments.subscription.activate.mutate({
user_id: newUser._id.toString(),
customer_id: customer.customer_id,
plan_tag: 'FREE_TRIAL_LITLYX_PRO'
});
setImmediate(() => {
tRpc.emails.email.send_trial_1_started.mutate({ email: newUser.email });
});
return sendRedirect(event, '/')
}
await replaceUserSession(event, {
user: {
email: user.email,
name: user.name
},
secure: {
user_id: user.id
},
v: '0.0.1'
});
return sendRedirect(event, '/')
}
});

View File

@@ -1,71 +0,0 @@
import { OAuth2Client } from 'google-auth-library';
import { createUserJwt } from '~/server/AuthManager';
import { UserModel } from '@schema/UserSchema';
import { EmailService } from '@services/EmailService';
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
const { GOOGLE_AUTH_CLIENT_SECRET, GOOGLE_AUTH_CLIENT_ID } = useRuntimeConfig()
const client = new OAuth2Client({
clientId: GOOGLE_AUTH_CLIENT_ID,
clientSecret: GOOGLE_AUTH_CLIENT_SECRET
});
export default defineEventHandler(async event => {
const body = await readBody(event)
const origin = event.headers.get('origin');
const tokenResponse = await client.getToken({
code: body.code,
redirect_uri: origin || ''
});
const tokens = tokenResponse.tokens;
const ticket = await client.verifyIdToken({
idToken: tokens.id_token || '',
audience: GOOGLE_AUTH_CLIENT_ID,
});
const payload = ticket.getPayload();
if (!payload) return { error: true, access_token: '' };
const user = await UserModel.findOne({ email: payload.email });
if (user) {
user.google_tokens = tokens as any;
await user.save();
return {
error: false,
access_token: createUserJwt({ email: user.email, name: user.name })
}
}
const newUser = new UserModel({
email: payload.email,
given_name: payload.given_name,
name: payload.name,
locale: payload.locale,
picture: payload.picture,
google_tokens: tokens,
created_at: Date.now()
});
const savedUser = await newUser.save();
setImmediate(() => {
console.log('SENDING WELCOME EMAIL TO', payload.email);
if (!payload.email) return;
const emailData = EmailService.getEmailServerInfo('welcome', { target: payload.email });
EmailServiceHelper.sendEmail(emailData);
});
return { error: false, access_token: createUserJwt({ email: savedUser.email, name: savedUser.name }) }
});

View File

@@ -1,24 +1,35 @@
import { z } from "zod";
import { PasswordModel } from '~/shared/schema/PasswordSchema';
import { UserModel } from '~/shared/schema/UserSchema';
import { createUserJwt } from '~/server/AuthManager';
import { UserModel } from '@schema/UserSchema';
import crypto from 'crypto';
import { PasswordModel } from '@schema/PasswordSchema';
const ZLoginBody = z.object({
email: z.string().email(),
password: z.string().min(6).max(64)
});
export default defineEventHandler(async event => {
export default defineEventHandler(async (event) => {
const { email, password } = await readBody(event);
//TODO: SELFHOST
const { email, password } = await readValidatedBody(event, ZLoginBody.parse)
const user = await UserModel.findOne({ email });
if (!user) throw createError({ status: 400, message: 'Email or Password wrong' });
if (!user) return { error: true, message: 'Email or Password wrong' }
const passwordData = await PasswordModel.findOne({ email });
if (!passwordData) throw createError({ status: 400, message: 'Email or Password wrong' });
const passwordOk = await verifyPassword(passwordData.password, password);
if (!passwordOk) throw createError({ status: 400, message: 'Email or Password wrong' });
const hash = crypto.createHash('sha256');
const hashedPassword = hash.update(password + '_litlyx').digest('hex');
await replaceUserSession(event, {
user: {
email: user.email,
name: user.name
},
secure: {
user_id: user.id
},
v: '0.0.1'
}, { maxAge: 60 * 60 * 24 * 7 });
const target = await PasswordModel.findOne({ email, password: hashedPassword });
if (!target) return { error: true, message: 'Email or Password wrong' }
return { error: false, access_token: createUserJwt({ email: target.email, name: user.name }) }
});
});

View File

@@ -1,53 +0,0 @@
import { createUserJwt } from '~/server/AuthManager';
import { UserModel } from '@schema/UserSchema';
const { NOAUTH_USER_EMAIL, NOAUTH_USER_PASS, public: publicRuntime } = useRuntimeConfig();
const noAuthMode = publicRuntime.AUTH_MODE == 'NO_AUTH';
export default defineEventHandler(async event => {
if (!noAuthMode) {
console.error('Endpoint available only in NO_AUTH mode');
return { error: true, access_token: '' }
}
if (!NOAUTH_USER_EMAIL) {
console.error('NOAUTH_USER_EMAIL is required in NO_AUTH mode');
return { error: true, access_token: '' }
}
if (!NOAUTH_USER_PASS) {
console.error('NOAUTH_USER_PASS is required in NO_AUTH mode');
return { error: true, access_token: '' }
}
const body = await readBody(event);
if (body.email != NOAUTH_USER_EMAIL || body.password != NOAUTH_USER_PASS) return { error: true, access_token: '', errorMessage: 'Username or password invalid' }
const user = await UserModel.findOne({ email: NOAUTH_USER_EMAIL });
if (user) return {
error: false,
access_token: createUserJwt({
email: user.email,
name: user.name
})
}
const newUser = new UserModel({
email: NOAUTH_USER_EMAIL,
given_name: NOAUTH_USER_EMAIL.split('@')[0] || 'NONAME',
name: NOAUTH_USER_EMAIL.split('@')[0] || 'NONAME',
locale: 'no-auth',
picture: '',
created_at: Date.now()
});
const savedUser = await newUser.save();
return { error: false, access_token: createUserJwt({ email: savedUser.email, name: savedUser.name }) }
});

View File

@@ -1,47 +1,36 @@
import crypto from 'node:crypto';
import { z } from "zod";
import { RegisterModel } from '~/shared/schema/RegisterSchema';
import { UserModel } from '~/shared/schema/UserSchema';
import { createRegisterJwt } from '~/server/AuthManager';
import { UserModel } from '@schema/UserSchema';
import { RegisterModel } from '@schema/RegisterSchema';
import { EmailService } from '@services/EmailService';
import crypto from 'crypto';
import { EmailServiceHelper } from '~/server/services/EmailServiceHelper';
const ZRegisterBody = z.object({
email: z.string().email(),
password: z.string().min(6).max(64)
});
function canRegister(email: string, password: string) {
if (email.length == 0) return false;
if (!email.includes('@')) return false;
if (!email.includes('.')) return false;
if (password.length < 6) return false;
return true;
};
export default defineEventHandler(async (event) => {
export default defineEventHandler(async event => {
//TODO: SELFHOST
const { email, password } = await readValidatedBody(event, ZRegisterBody.parse);
const { email, password } = await readBody(event);
const user = await UserModel.exists({ email });
if (user) throw createError({ statusCode: 400, message: 'Email already registered' });
if (!canRegister(email, password)) return setResponseStatus(event, 400, 'Email or Password not match criteria');
const hashedPassword = await hashPassword(password);
const user = await UserModel.findOne({ email });
const code = crypto.randomBytes(3).toString('hex').toUpperCase();
if (user) return {
error: true,
message: 'Email already registered'
}
await RegisterModel.updateOne({ email }, { password: hashedPassword, code }, { upsert: true });
const hash = crypto.createHash('sha256');
const hashedPassword = hash.update(password + '_litlyx').digest('hex');
const { BASE_URL } = useRuntimeConfig();
const jwt = createRegisterJwt(email, hashedPassword);
await RegisterModel.create({ email, password: hashedPassword });
const link = `${BASE_URL}/api/auth/confirm_email?code=${code}`;
setImmediate(() => {
const emailData = EmailService.getEmailServerInfo('confirm', { target: email, link: `https://dashboard.litlyx.com/api/auth/confirm_email?register_code=${jwt}` });
EmailServiceHelper.sendEmail(emailData);
const tRpc = useTRPC();
tRpc.emails.email.sendConfirmEmail.mutate({ email, link });
});
return {
error: false,
message: 'OK'
}
});
return { ok: true };
});