mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Store reset password ID in the submit URL
This commit is contained in:
@@ -79,7 +79,7 @@ export class ForgotPasswordHandler extends InteractionHttpHandler {
|
||||
*/
|
||||
private async sendResetMail(recordId: string, email: string): Promise<void> {
|
||||
this.logger.info(`Sending password reset to ${email}`);
|
||||
const resetLink = urljoin(this.baseUrl, this.idpPath, `resetpassword?rid=${recordId}`);
|
||||
const resetLink = urljoin(this.baseUrl, this.idpPath, `resetpassword/${recordId}`);
|
||||
const renderedEmail = await this.templateEngine.render({ resetLink });
|
||||
await this.emailSender.handleSafe({
|
||||
recipient: email,
|
||||
|
||||
@@ -3,15 +3,12 @@ import { getLoggerFor } from '../../../../logging/LogUtil';
|
||||
import type { HttpHandlerInput } from '../../../../server/HttpHandler';
|
||||
import { HttpHandler } from '../../../../server/HttpHandler';
|
||||
import type { TemplateHandler } from '../../../../server/util/TemplateHandler';
|
||||
import { createErrorMessage } from '../../../../util/errors/ErrorUtil';
|
||||
import { getFormDataRequestBody } from '../../util/FormDataUtil';
|
||||
import { assertPassword } from '../EmailPasswordUtil';
|
||||
import { assertPassword, throwIdpInteractionError } from '../EmailPasswordUtil';
|
||||
import type { AccountStore } from '../storage/AccountStore';
|
||||
import type { ResetPasswordRenderHandler } from './ResetPasswordRenderHandler';
|
||||
|
||||
export interface ResetPasswordHandlerArgs {
|
||||
accountStore: AccountStore;
|
||||
renderHandler: ResetPasswordRenderHandler;
|
||||
messageRenderHandler: TemplateHandler<{ message: string }>;
|
||||
}
|
||||
|
||||
@@ -23,26 +20,24 @@ export class ResetPasswordHandler extends HttpHandler {
|
||||
protected readonly logger = getLoggerFor(this);
|
||||
|
||||
private readonly accountStore: AccountStore;
|
||||
private readonly renderHandler: ResetPasswordRenderHandler;
|
||||
private readonly messageRenderHandler: TemplateHandler<{ message: string }>;
|
||||
|
||||
public constructor(args: ResetPasswordHandlerArgs) {
|
||||
super();
|
||||
this.accountStore = args.accountStore;
|
||||
this.renderHandler = args.renderHandler;
|
||||
this.messageRenderHandler = args.messageRenderHandler;
|
||||
}
|
||||
|
||||
public async handle(input: HttpHandlerInput): Promise<void> {
|
||||
let prefilledRecordId = '';
|
||||
try {
|
||||
// Extract record ID from request URL
|
||||
const recordId = /\/([^/]+)$/u.exec(input.request.url!)?.[1];
|
||||
// Validate input data
|
||||
const { password, confirmPassword, recordId } = await getFormDataRequestBody(input.request);
|
||||
const { password, confirmPassword } = await getFormDataRequestBody(input.request);
|
||||
assert(
|
||||
typeof recordId === 'string' && recordId.length > 0,
|
||||
'Invalid request. Open the link from your email again',
|
||||
);
|
||||
prefilledRecordId = recordId;
|
||||
assertPassword(password, confirmPassword);
|
||||
|
||||
await this.resetPassword(recordId, password);
|
||||
@@ -52,14 +47,8 @@ export class ResetPasswordHandler extends HttpHandler {
|
||||
message: 'Your password was successfully reset.',
|
||||
},
|
||||
});
|
||||
} catch (err: unknown) {
|
||||
await this.renderHandler.handleSafe({
|
||||
response: input.response,
|
||||
contents: {
|
||||
errorMessage: createErrorMessage(err),
|
||||
recordId: prefilledRecordId,
|
||||
},
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
throwIdpInteractionError(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { TemplateHandler } from '../../../../server/util/TemplateHandler';
|
||||
|
||||
export interface ResetPasswordRenderHandlerProps {
|
||||
errorMessage: string;
|
||||
recordId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A special {@link RenderHandler} for the Reset Password form
|
||||
* that includes the required props for rendering the reset password form.
|
||||
*/
|
||||
export abstract class ResetPasswordRenderHandler extends TemplateHandler<ResetPasswordRenderHandlerProps> {}
|
||||
@@ -1,36 +0,0 @@
|
||||
import assert from 'assert';
|
||||
import { parse } from 'url';
|
||||
import type { HttpHandlerInput } from '../../../../server/HttpHandler';
|
||||
import { HttpHandler } from '../../../../server/HttpHandler';
|
||||
import { throwIdpInteractionError } from '../EmailPasswordUtil';
|
||||
import type { ResetPasswordRenderHandler } from './ResetPasswordRenderHandler';
|
||||
|
||||
/**
|
||||
* Handles the creation of the Reset Password form
|
||||
* after the user clicks on it from the link provided in the email.
|
||||
*/
|
||||
export class ResetPasswordViewHandler extends HttpHandler {
|
||||
private readonly renderHandler: ResetPasswordRenderHandler;
|
||||
|
||||
public constructor(renderHandler: ResetPasswordRenderHandler) {
|
||||
super();
|
||||
this.renderHandler = renderHandler;
|
||||
}
|
||||
|
||||
public async handle({ request, response }: HttpHandlerInput): Promise<void> {
|
||||
try {
|
||||
assert(request.url, 'The request must have a URL');
|
||||
const recordId = parse(request.url, true).query.rid;
|
||||
assert(
|
||||
typeof recordId === 'string' && recordId.length > 0,
|
||||
'A forgot password record ID must be provided. Use the link you have received by email.',
|
||||
);
|
||||
await this.renderHandler.handleSafe({
|
||||
response,
|
||||
contents: { errorMessage: '', recordId },
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
throwIdpInteractionError(error, {});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,6 @@ export * from './identity/interaction/email-password/handler/ForgotPasswordHandl
|
||||
export * from './identity/interaction/email-password/handler/LoginHandler';
|
||||
export * from './identity/interaction/email-password/handler/RegistrationHandler';
|
||||
export * from './identity/interaction/email-password/handler/ResetPasswordHandler';
|
||||
export * from './identity/interaction/email-password/handler/ResetPasswordRenderHandler';
|
||||
export * from './identity/interaction/email-password/handler/ResetPasswordViewHandler';
|
||||
|
||||
// Identity/Interaction/Email-Password/Storage
|
||||
export * from './identity/interaction/email-password/storage/AccountStore';
|
||||
|
||||
Reference in New Issue
Block a user