mirror of
https://github.com/Litlyx/litlyx
synced 2025-12-10 15:58:38 +01:00
new selfhosted version
This commit is contained in:
@@ -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');
|
||||
}
|
||||
|
||||
});
|
||||
65
dashboard/server/api/auth/google/authenticate.ts
Normal file
65
dashboard/server/api/auth/google/authenticate.ts
Normal 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, '/')
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
@@ -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 }) }
|
||||
|
||||
});
|
||||
@@ -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 }) }
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 }) }
|
||||
|
||||
});
|
||||
@@ -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 };
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user