mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-22 21:06:37 +00:00
successful log in loop poc
This commit is contained in:
@@ -16,6 +16,7 @@ import logger from "@server/logger";
|
||||
import { unauthorized } from "@server/auth/unauthorizedResponse";
|
||||
import { invalidateAllSessions } from "@server/auth/sessions/app";
|
||||
import { passwordSchema } from "@server/auth/passwordSchema";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
|
||||
export const changePasswordBody = z
|
||||
.object({
|
||||
@@ -50,6 +51,15 @@ export async function changePassword(
|
||||
const { newPassword, oldPassword, code } = parsedBody.data;
|
||||
const user = req.user as User;
|
||||
|
||||
if (user.type !== UserType.Internal) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Two-factor authentication is not supported for external users"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if (newPassword === oldPassword) {
|
||||
return next(
|
||||
@@ -62,7 +72,7 @@ export async function changePassword(
|
||||
|
||||
const validPassword = await verifyPassword(
|
||||
oldPassword,
|
||||
user.passwordHash
|
||||
user.passwordHash!
|
||||
);
|
||||
if (!validPassword) {
|
||||
return next(unauthorized());
|
||||
|
||||
@@ -14,6 +14,7 @@ import { sendEmail } from "@server/emails";
|
||||
import TwoFactorAuthNotification from "@server/emails/templates/TwoFactorAuthNotification";
|
||||
import config from "@server/lib/config";
|
||||
import { unauthorized } from "@server/auth/unauthorizedResponse";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
|
||||
export const disable2faBody = z
|
||||
.object({
|
||||
@@ -47,8 +48,17 @@ export async function disable2fa(
|
||||
const { password, code } = parsedBody.data;
|
||||
const user = req.user as User;
|
||||
|
||||
if (user.type !== UserType.Internal) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Two-factor authentication is not supported for external users"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const validPassword = await verifyPassword(password, user.passwordHash);
|
||||
const validPassword = await verifyPassword(password, user.passwordHash!);
|
||||
if (!validPassword) {
|
||||
return next(unauthorized());
|
||||
}
|
||||
@@ -99,11 +109,11 @@ export async function disable2fa(
|
||||
|
||||
sendEmail(
|
||||
TwoFactorAuthNotification({
|
||||
email: user.email,
|
||||
email: user.email!, // email is not null because we are checking user.type
|
||||
enabled: false
|
||||
}),
|
||||
{
|
||||
to: user.email,
|
||||
to: user.email!,
|
||||
from: config.getRawConfig().email?.no_reply,
|
||||
subject: "Two-factor authentication disabled"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import db from "@server/db";
|
||||
import { users } from "@server/db/schemas";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import response from "@server/lib/response";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
@@ -17,6 +17,7 @@ import config from "@server/lib/config";
|
||||
import logger from "@server/logger";
|
||||
import { verifyPassword } from "@server/auth/password";
|
||||
import { verifySession } from "@server/auth/sessions/verifySession";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
|
||||
export const loginBodySchema = z
|
||||
.object({
|
||||
@@ -69,7 +70,9 @@ export async function login(
|
||||
const existingUserRes = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.email, email));
|
||||
.where(
|
||||
and(eq(users.type, UserType.Internal), eq(users.email, email))
|
||||
);
|
||||
if (!existingUserRes || !existingUserRes.length) {
|
||||
if (config.getRawConfig().app.log_failed_attempts) {
|
||||
logger.info(
|
||||
@@ -88,7 +91,7 @@ export async function login(
|
||||
|
||||
const validPassword = await verifyPassword(
|
||||
password,
|
||||
existingUser.passwordHash
|
||||
existingUser.passwordHash!
|
||||
);
|
||||
if (!validPassword) {
|
||||
if (config.getRawConfig().app.log_failed_attempts) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { User } from "@server/db/schemas";
|
||||
import { sendEmailVerificationCode } from "../../auth/sendEmailVerificationCode";
|
||||
import config from "@server/lib/config";
|
||||
import logger from "@server/logger";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
|
||||
export type RequestEmailVerificationCodeResponse = {
|
||||
codeSent: boolean;
|
||||
@@ -28,6 +29,15 @@ export async function requestEmailVerificationCode(
|
||||
try {
|
||||
const user = req.user as User;
|
||||
|
||||
if (user.type !== UserType.Internal) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Email verification is not supported for external users"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (user.emailVerified) {
|
||||
return next(
|
||||
createHttpError(
|
||||
@@ -37,7 +47,7 @@ export async function requestEmailVerificationCode(
|
||||
);
|
||||
}
|
||||
|
||||
await sendEmailVerificationCode(user.email, user.userId);
|
||||
await sendEmailVerificationCode(user.email!, user.userId);
|
||||
|
||||
return response<RequestEmailVerificationCodeResponse>(res, {
|
||||
data: {
|
||||
|
||||
@@ -74,7 +74,7 @@ export async function requestPasswordReset(
|
||||
|
||||
await trx.insert(passwordResetTokens).values({
|
||||
userId: existingUser[0].userId,
|
||||
email: existingUser[0].email,
|
||||
email: existingUser[0].email!,
|
||||
tokenHash,
|
||||
expiresAt: createDate(new TimeSpan(2, "h")).getTime()
|
||||
});
|
||||
|
||||
@@ -12,6 +12,7 @@ import { createTOTPKeyURI } from "oslo/otp";
|
||||
import logger from "@server/logger";
|
||||
import { verifyPassword } from "@server/auth/password";
|
||||
import { unauthorized } from "@server/auth/unauthorizedResponse";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
|
||||
export const requestTotpSecretBody = z
|
||||
.object({
|
||||
@@ -46,8 +47,17 @@ export async function requestTotpSecret(
|
||||
|
||||
const user = req.user as User;
|
||||
|
||||
if (user.type !== UserType.Internal) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Two-factor authentication is not supported for external users"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const validPassword = await verifyPassword(password, user.passwordHash);
|
||||
const validPassword = await verifyPassword(password, user.passwordHash!);
|
||||
if (!validPassword) {
|
||||
return next(unauthorized());
|
||||
}
|
||||
@@ -63,7 +73,7 @@ export async function requestTotpSecret(
|
||||
|
||||
const hex = crypto.getRandomValues(new Uint8Array(20));
|
||||
const secret = encodeHex(hex);
|
||||
const uri = createTOTPKeyURI("Pangolin", user.email, hex);
|
||||
const uri = createTOTPKeyURI("Pangolin", user.email!, hex);
|
||||
|
||||
await db
|
||||
.update(users)
|
||||
|
||||
@@ -8,7 +8,7 @@ import createHttpError from "http-errors";
|
||||
import response from "@server/lib/response";
|
||||
import { SqliteError } from "better-sqlite3";
|
||||
import { sendEmailVerificationCode } from "../../auth/sendEmailVerificationCode";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import moment from "moment";
|
||||
import {
|
||||
createSession,
|
||||
@@ -21,6 +21,7 @@ import logger from "@server/logger";
|
||||
import { hashPassword } from "@server/auth/password";
|
||||
import { checkValidInvite } from "@server/auth/checkValidInvite";
|
||||
import { passwordSchema } from "@server/auth/passwordSchema";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
|
||||
export const signupBodySchema = z.object({
|
||||
email: z
|
||||
@@ -110,7 +111,9 @@ export async function signup(
|
||||
const existing = await db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.email, email));
|
||||
.where(
|
||||
and(eq(users.email, email), eq(users.type, UserType.Internal))
|
||||
);
|
||||
|
||||
if (existing && existing.length > 0) {
|
||||
if (!config.getRawConfig().flags?.require_email_verification) {
|
||||
@@ -157,6 +160,8 @@ export async function signup(
|
||||
|
||||
await db.insert(users).values({
|
||||
userId: userId,
|
||||
type: UserType.Internal,
|
||||
username: email,
|
||||
email: email,
|
||||
passwordHash,
|
||||
dateCreated: moment().toISOString()
|
||||
|
||||
@@ -14,6 +14,7 @@ import logger from "@server/logger";
|
||||
import { sendEmail } from "@server/emails";
|
||||
import TwoFactorAuthNotification from "@server/emails/templates/TwoFactorAuthNotification";
|
||||
import config from "@server/lib/config";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
|
||||
export const verifyTotpBody = z
|
||||
.object({
|
||||
@@ -48,6 +49,15 @@ export async function verifyTotp(
|
||||
|
||||
const user = req.user as User;
|
||||
|
||||
if (user.type !== UserType.Internal) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Two-factor authentication is not supported for external users"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (user.twoFactorEnabled) {
|
||||
return next(
|
||||
createHttpError(
|
||||
@@ -111,11 +121,11 @@ export async function verifyTotp(
|
||||
|
||||
sendEmail(
|
||||
TwoFactorAuthNotification({
|
||||
email: user.email,
|
||||
email: user.email!,
|
||||
enabled: true
|
||||
}),
|
||||
{
|
||||
to: user.email,
|
||||
to: user.email!,
|
||||
from: config.getRawConfig().email?.no_reply,
|
||||
subject: "Two-factor authentication enabled"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user