fixed members login and permissions issues
This commit is contained in:
@@ -15,7 +15,7 @@ export const changePasswordHandler: Handler = async function (ctx) {
|
||||
|
||||
const dbUser = await officerdb.query.Users.findFirst({
|
||||
where: eq(Users.id, reqUser.id),
|
||||
columns: { password: true },
|
||||
columns: { password: true, username: true },
|
||||
});
|
||||
|
||||
if (!dbUser) throw errors.UNAUTHORIZED();
|
||||
@@ -31,7 +31,8 @@ export const changePasswordHandler: Handler = async function (ctx) {
|
||||
await officerdb.update(Users).set({ password: newPasswordHash, passwordChangedAt }).where(eq(Users.id, reqUser.id));
|
||||
|
||||
const { id, email, name, role } = reqUser;
|
||||
const token = await sign({ id, email, name, role });
|
||||
const username = dbUser.username ?? reqUser.username;
|
||||
const token = await sign({ id, email, name, username, role });
|
||||
|
||||
return ctx.json({ token });
|
||||
};
|
||||
|
||||
@@ -3,10 +3,9 @@ import { officerdb, eq, Users } from 'officerdb';
|
||||
import { sign } from '@@/jwt';
|
||||
import { sendMail } from 'emailer';
|
||||
|
||||
const { PUBLIC_URL } = process.env;
|
||||
|
||||
export const forgotPasswordHandler: Handler = async function (ctx) {
|
||||
const { email } = ctx.get('body');
|
||||
const origin = ctx.get('origin');
|
||||
|
||||
const dbUser = await officerdb.query.Users.findFirst({
|
||||
where: eq(Users.email, email),
|
||||
@@ -14,7 +13,7 @@ export const forgotPasswordHandler: Handler = async function (ctx) {
|
||||
|
||||
if (!dbUser) return ctx.json({ ok: true });
|
||||
const verificationCode = await sign({ id: dbUser.id, email, purpose: 'reset-password' }, '6h');
|
||||
const url = `${PUBLIC_URL}/auth/reset-password?verificationCode=${verificationCode}`;
|
||||
const url = `${origin}/auth/reset-password?verificationCode=${verificationCode}`;
|
||||
|
||||
await sendMail({
|
||||
template: 'ForgotPassword',
|
||||
|
||||
@@ -200,12 +200,13 @@ const passkeyRouterPostVerify: Handler = async (ctx) => {
|
||||
|
||||
if (!dbUser) throw errors.UNAUTHORIZED();
|
||||
|
||||
const { id, name, role } = dbUser;
|
||||
const { id, name, username, role } = dbUser;
|
||||
const passkeys = dbUser.passkeys?.length ?? 0;
|
||||
const token = await sign({
|
||||
id,
|
||||
email,
|
||||
name,
|
||||
username,
|
||||
role,
|
||||
passkeys,
|
||||
});
|
||||
@@ -216,6 +217,7 @@ const passkeyRouterPostVerify: Handler = async (ctx) => {
|
||||
id,
|
||||
email,
|
||||
name,
|
||||
username,
|
||||
role,
|
||||
passkeys,
|
||||
},
|
||||
|
||||
@@ -27,12 +27,12 @@ export const signinHandler: Handler = async function (ctx) {
|
||||
const isValidPassword = TEST_USERS.includes(dbUser.id) || (await argon2.verify(dbUser.password, password));
|
||||
if (!isValidPassword) throw errors.UNAUTHORIZED();
|
||||
|
||||
const { id, name, role } = dbUser;
|
||||
const { id, name, username, role } = dbUser;
|
||||
|
||||
mkdir(join(getClaudeDir(email), 'archived'), { recursive: true }).catch(() => {});
|
||||
syncUserPiConfig(email).catch(() => {});
|
||||
|
||||
const tokenUser = { id, email, name, role, passkeys: passkeys.length };
|
||||
const tokenUser = { id, email, name, username, role, passkeys: passkeys.length };
|
||||
|
||||
if (passkeys.length > 0 && !origin.startsWith('chrome-extension://') && !TEST_USERS.includes(dbUser.id)) {
|
||||
return ctx.json({ user: tokenUser });
|
||||
|
||||
@@ -17,7 +17,7 @@ export const verifyTokenHandler: Handler = async function (ctx) {
|
||||
|
||||
// Bootstrap token: has email but no id (user not yet created)
|
||||
if (userInfo?.email && !userInfo?.id) {
|
||||
return ctx.json({ ok: true, email: userInfo.email });
|
||||
return ctx.json({ ok: true, email: userInfo.email, flow: 'bootstrap' });
|
||||
}
|
||||
|
||||
if (!userInfo?.id) throw errors.BAD_REQUEST('Token is invalid or expired');
|
||||
@@ -29,7 +29,7 @@ export const verifyTokenHandler: Handler = async function (ctx) {
|
||||
|
||||
// Reset-password tokens skip the verification status check
|
||||
const isResetToken = (userInfo as Record<string, unknown>).purpose === 'reset-password';
|
||||
if (!isResetToken && user.status !== 'Unverified') throw errors.BAD_REQUEST('Account is already verified');
|
||||
if (!isResetToken && user.status !== 'Unverified' && user.status !== 'Invited') throw errors.BAD_REQUEST('Account is already verified');
|
||||
|
||||
return ctx.json({ ok: true, email: user.email });
|
||||
return ctx.json({ ok: true, email: user.email, flow: user.status === 'Invited' ? 'invite' : 'verify' });
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as errors from '@@/custom-errors';
|
||||
import { validatePassword } from './validate-password';
|
||||
|
||||
export const verifyHandler: Handler = async function (ctx) {
|
||||
const { verificationCode, name, password, confirmPassword } = ctx.get('body');
|
||||
const { verificationCode, name, username, password, confirmPassword } = ctx.get('body');
|
||||
const userInfo = (await verifyJwt(verificationCode)) as User;
|
||||
if (!userInfo) throw errors.BAD_REQUEST();
|
||||
|
||||
@@ -25,6 +25,10 @@ export const verifyHandler: Handler = async function (ctx) {
|
||||
updates.name = name.trim();
|
||||
}
|
||||
|
||||
if (username && typeof username === 'string' && username.trim()) {
|
||||
updates.username = username.trim();
|
||||
}
|
||||
|
||||
if (password) {
|
||||
validatePassword(password);
|
||||
if (password !== confirmPassword) {
|
||||
@@ -33,10 +37,26 @@ export const verifyHandler: Handler = async function (ctx) {
|
||||
updates.password = await argon2.hash(password);
|
||||
}
|
||||
|
||||
await officerdb.update(Users).set(updates).where(eq(Users.id, userInfo.id));
|
||||
const [updatedUser] = await officerdb
|
||||
.update(Users)
|
||||
.set(updates)
|
||||
.where(eq(Users.id, userInfo.id))
|
||||
.returning({ username: Users.username });
|
||||
|
||||
// Re-fetch user to get final values after update
|
||||
const finalUser = await officerdb.query.Users.findFirst({
|
||||
where: eq(Users.id, userInfo.id),
|
||||
});
|
||||
if (!finalUser) throw errors.NOT_FOUND('User not found');
|
||||
|
||||
// Issue a token so the user is logged in immediately
|
||||
const token = await sign({ id: userInfo.id, email: userInfo.email });
|
||||
const token = await sign({
|
||||
id: finalUser.id,
|
||||
email: finalUser.email,
|
||||
name: finalUser.name,
|
||||
username: finalUser.username,
|
||||
role: finalUser.role,
|
||||
});
|
||||
|
||||
return ctx.json({ ok: true, token });
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user