diff --git a/packages/server/src/routes/index/users.ts b/packages/server/src/routes/index/users.ts index 428bc698a5..eed00145a2 100644 --- a/packages/server/src/routes/index/users.ts +++ b/packages/server/src/routes/index/users.ts @@ -2,7 +2,7 @@ import { SubPath, redirect } from '../../utils/routeUtils'; import Router from '../../utils/Router'; import { RouteType } from '../../utils/types'; import { AppContext, HttpMethod } from '../../utils/types'; -import { bodyFields, contextSessionId, formParse } from '../../utils/requestUtils'; +import { bodyFields, formParse } from '../../utils/requestUtils'; import { ErrorForbidden, ErrorUnprocessableEntity } from '../../utils/errors'; import { User, UserFlagType, userFlagTypeToLabel, Uuid } from '../../services/database/types'; import config from '../../config'; @@ -291,7 +291,7 @@ interface FormFields { send_account_confirmation_email: string; update_subscription_basic_button: string; update_subscription_pro_button: string; - user_cancel_subscription_button: string; + // user_cancel_subscription_button: string; impersonate_button: string; stop_impersonate_button: string; } @@ -324,13 +324,13 @@ router.post('users', async (path: SubPath, ctx: AppContext) => { await models.user().save(userToSave, { isNew: false }); } - } else if (fields.user_cancel_subscription_button) { - await cancelSubscriptionByUserId(models, userId); - const sessionId = contextSessionId(ctx, false); - if (sessionId) { - await models.session().logout(sessionId); - return redirect(ctx, config().baseUrl); - } + // } else if (fields.user_cancel_subscription_button) { + // await cancelSubscriptionByUserId(models, userId); + // const sessionId = contextSessionId(ctx, false); + // if (sessionId) { + // await models.session().logout(sessionId); + // return redirect(ctx, config().baseUrl); + // } } else if (fields.stop_impersonate_button) { await stopImpersonating(ctx); return redirect(ctx, config().baseUrl); diff --git a/packages/server/src/routes/index/utils/users/impersonate.ts b/packages/server/src/routes/index/utils/users/impersonate.ts index 76af4bc29a..09c0c79e7e 100644 --- a/packages/server/src/routes/index/utils/users/impersonate.ts +++ b/packages/server/src/routes/index/utils/users/impersonate.ts @@ -11,6 +11,7 @@ export function getImpersonatorAdminSessionId(ctx: AppContext): string { export async function startImpersonating(ctx: AppContext, userId: Uuid) { const adminSessionId = contextSessionId(ctx); const user = await ctx.joplin.models.session().sessionUser(adminSessionId); + if (!user) throw new Error(`No user for session: ${adminSessionId}`); if (!user.is_admin) throw new ErrorForbidden('Impersonator must be an admin'); const impersonatedSession = await ctx.joplin.models.session().createUserSession(userId); @@ -22,9 +23,11 @@ export async function stopImpersonating(ctx: AppContext) { const adminSessionId = cookieGet(ctx, 'adminSessionId'); if (!adminSessionId) throw new Error('Missing cookie adminSessionId'); - const adminUser = await ctx.joplin.models.session().sessionUser(adminSessionId); - if (!adminUser.is_admin) throw new ErrorForbidden('User must be an admin'); - + // This function simply moves the adminSessionId back to sessionId. There's + // no need to check if anything is valid because that will be done by other + // session checking routines. We also don't want this function to fail + // because it would leave the cookies in an invalid state (for example if + // the admin has lost their sessions, or the user no longer exists). cookieDelete(ctx, 'adminSessionId'); cookieSet(ctx, 'sessionId', adminSessionId); }