mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Pass optional Interaction to InteractionHandlers
This commit is contained in:
@@ -1,29 +1,18 @@
|
||||
import type { HttpHandlerInput } from '../../server/HttpHandler';
|
||||
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
|
||||
import type { ProviderFactory } from '../configuration/ProviderFactory';
|
||||
import { InteractionHandler } from './email-password/handler/InteractionHandler';
|
||||
import type { InteractionCompleteResult } from './email-password/handler/InteractionHandler';
|
||||
import type { InteractionCompleteResult, InteractionHandlerInput } from './email-password/handler/InteractionHandler';
|
||||
|
||||
/**
|
||||
* Simple InteractionHttpHandler that sends the session accountId to the InteractionCompleter as webId.
|
||||
*/
|
||||
export class SessionHttpHandler extends InteractionHandler {
|
||||
private readonly providerFactory: ProviderFactory;
|
||||
|
||||
public constructor(providerFactory: ProviderFactory) {
|
||||
super();
|
||||
this.providerFactory = providerFactory;
|
||||
}
|
||||
|
||||
public async handle(input: HttpHandlerInput): Promise<InteractionCompleteResult> {
|
||||
const provider = await this.providerFactory.getProvider();
|
||||
const details = await provider.interactionDetails(input.request, input.response);
|
||||
if (!details.session || !details.session.accountId) {
|
||||
throw new NotImplementedHttpError('Only confirm actions with a session and accountId are supported');
|
||||
public async handle({ oidcInteraction }: InteractionHandlerInput): Promise<InteractionCompleteResult> {
|
||||
if (!oidcInteraction?.session) {
|
||||
throw new NotImplementedHttpError('Only interactions with a valid session are supported.');
|
||||
}
|
||||
return {
|
||||
type: 'complete',
|
||||
details: { webId: details.session.accountId },
|
||||
details: { webId: oidcInteraction.session.accountId },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import assert from 'assert';
|
||||
import urljoin from 'url-join';
|
||||
import { getLoggerFor } from '../../../../logging/LogUtil';
|
||||
import type { HttpHandlerInput } from '../../../../server/HttpHandler';
|
||||
import { ensureTrailingSlash } from '../../../../util/PathUtil';
|
||||
import type { TemplateEngine } from '../../../../util/templates/TemplateEngine';
|
||||
import type { EmailSender } from '../../util/EmailSender';
|
||||
@@ -9,7 +8,7 @@ import { getFormDataRequestBody } from '../../util/FormDataUtil';
|
||||
import { throwIdpInteractionError } from '../EmailPasswordUtil';
|
||||
import type { AccountStore } from '../storage/AccountStore';
|
||||
import { InteractionHandler } from './InteractionHandler';
|
||||
import type { InteractionResponseResult } from './InteractionHandler';
|
||||
import type { InteractionResponseResult, InteractionHandlerInput } from './InteractionHandler';
|
||||
|
||||
export interface ForgotPasswordHandlerArgs {
|
||||
accountStore: AccountStore;
|
||||
@@ -40,10 +39,10 @@ export class ForgotPasswordHandler extends InteractionHandler {
|
||||
this.emailSender = args.emailSender;
|
||||
}
|
||||
|
||||
public async handle(input: HttpHandlerInput): Promise<InteractionResponseResult<{ email: string }>> {
|
||||
public async handle({ request }: InteractionHandlerInput): Promise<InteractionResponseResult<{ email: string }>> {
|
||||
try {
|
||||
// Validate incoming data
|
||||
const { email } = await getFormDataRequestBody(input.request);
|
||||
const { email } = await getFormDataRequestBody(request);
|
||||
assert(typeof email === 'string' && email.length > 0, 'Email required');
|
||||
|
||||
await this.resetPassword(email);
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
import type { HttpHandlerInput } from '../../../../server/HttpHandler';
|
||||
import type { KoaContextWithOIDC } from 'oidc-provider';
|
||||
import type { HttpRequest } from '../../../../server/HttpRequest';
|
||||
import { AsyncHandler } from '../../../../util/handlers/AsyncHandler';
|
||||
import type { InteractionCompleterParams } from '../../util/InteractionCompleter';
|
||||
|
||||
// OIDC library does not directly export the Interaction type
|
||||
export type Interaction = KoaContextWithOIDC['oidc']['entities']['Interaction'];
|
||||
|
||||
export interface InteractionHandlerInput {
|
||||
/**
|
||||
* The request being made.
|
||||
*/
|
||||
request: HttpRequest;
|
||||
/**
|
||||
* Will be defined if the OIDC library expects us to resolve an interaction it can't handle itself,
|
||||
* such as logging a user in.
|
||||
*/
|
||||
oidcInteraction?: Interaction;
|
||||
}
|
||||
|
||||
export type InteractionHandlerResult = InteractionResponseResult | InteractionCompleteResult;
|
||||
|
||||
export interface InteractionResponseResult<T = NodeJS.Dict<any>> {
|
||||
@@ -17,4 +33,4 @@ export interface InteractionCompleteResult {
|
||||
/**
|
||||
* Handler used for IDP interactions.
|
||||
*/
|
||||
export abstract class InteractionHandler extends AsyncHandler<HttpHandlerInput, InteractionHandlerResult> {}
|
||||
export abstract class InteractionHandler extends AsyncHandler<InteractionHandlerInput, InteractionHandlerResult> {}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import assert from 'assert';
|
||||
import { getLoggerFor } from '../../../../logging/LogUtil';
|
||||
import type { HttpHandlerInput } from '../../../../server/HttpHandler';
|
||||
import type { HttpRequest } from '../../../../server/HttpRequest';
|
||||
import { getFormDataRequestBody } from '../../util/FormDataUtil';
|
||||
import { throwIdpInteractionError } from '../EmailPasswordUtil';
|
||||
import type { AccountStore } from '../storage/AccountStore';
|
||||
import { InteractionHandler } from './InteractionHandler';
|
||||
import type { InteractionCompleteResult } from './InteractionHandler';
|
||||
import type { InteractionCompleteResult, InteractionHandlerInput } from './InteractionHandler';
|
||||
|
||||
/**
|
||||
* Handles the submission of the Login Form and logs the user in.
|
||||
@@ -21,8 +20,8 @@ export class LoginHandler extends InteractionHandler {
|
||||
this.accountStore = accountStore;
|
||||
}
|
||||
|
||||
public async handle(input: HttpHandlerInput): Promise<InteractionCompleteResult> {
|
||||
const { email, password, remember } = await this.parseInput(input.request);
|
||||
public async handle({ request }: InteractionHandlerInput): Promise<InteractionCompleteResult> {
|
||||
const { email, password, remember } = await this.parseInput(request);
|
||||
try {
|
||||
// Try to log in, will error if email/password combination is invalid
|
||||
const webId = await this.accountStore.authenticate(email, password);
|
||||
|
||||
@@ -5,13 +5,12 @@ import { getLoggerFor } from '../../../../logging/LogUtil';
|
||||
import type { IdentifierGenerator } from '../../../../pods/generate/IdentifierGenerator';
|
||||
import type { PodManager } from '../../../../pods/PodManager';
|
||||
import type { PodSettings } from '../../../../pods/settings/PodSettings';
|
||||
import type { HttpHandlerInput } from '../../../../server/HttpHandler';
|
||||
import type { HttpRequest } from '../../../../server/HttpRequest';
|
||||
import type { OwnershipValidator } from '../../../ownership/OwnershipValidator';
|
||||
import { getFormDataRequestBody } from '../../util/FormDataUtil';
|
||||
import { assertPassword, throwIdpInteractionError } from '../EmailPasswordUtil';
|
||||
import type { AccountStore } from '../storage/AccountStore';
|
||||
import type { InteractionResponseResult } from './InteractionHandler';
|
||||
import type { InteractionResponseResult, InteractionHandlerInput } from './InteractionHandler';
|
||||
import { InteractionHandler } from './InteractionHandler';
|
||||
|
||||
const emailRegex = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/u;
|
||||
@@ -103,7 +102,7 @@ export class RegistrationHandler extends InteractionHandler {
|
||||
this.podManager = args.podManager;
|
||||
}
|
||||
|
||||
public async handle({ request }: HttpHandlerInput): Promise<InteractionResponseResult<RegistrationResponse>> {
|
||||
public async handle({ request }: InteractionHandlerInput): Promise<InteractionResponseResult<RegistrationResponse>> {
|
||||
const result = await this.parseInput(request);
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import assert from 'assert';
|
||||
import { getLoggerFor } from '../../../../logging/LogUtil';
|
||||
import type { HttpHandlerInput } from '../../../../server/HttpHandler';
|
||||
import { getFormDataRequestBody } from '../../util/FormDataUtil';
|
||||
import { assertPassword, throwIdpInteractionError } from '../EmailPasswordUtil';
|
||||
import type { AccountStore } from '../storage/AccountStore';
|
||||
import type { InteractionResponseResult } from './InteractionHandler';
|
||||
import type { InteractionResponseResult, InteractionHandlerInput } from './InteractionHandler';
|
||||
import { InteractionHandler } from './InteractionHandler';
|
||||
|
||||
/**
|
||||
@@ -21,12 +20,12 @@ export class ResetPasswordHandler extends InteractionHandler {
|
||||
this.accountStore = accountStore;
|
||||
}
|
||||
|
||||
public async handle(input: HttpHandlerInput): Promise<InteractionResponseResult> {
|
||||
public async handle({ request }: InteractionHandlerInput): Promise<InteractionResponseResult> {
|
||||
try {
|
||||
// Extract record ID from request URL
|
||||
const recordId = /\/([^/]+)$/u.exec(input.request.url!)?.[1];
|
||||
const recordId = /\/([^/]+)$/u.exec(request.url!)?.[1];
|
||||
// Validate input data
|
||||
const { password, confirmPassword } = await getFormDataRequestBody(input.request);
|
||||
const { password, confirmPassword } = await getFormDataRequestBody(request);
|
||||
assert(
|
||||
typeof recordId === 'string' && recordId.length > 0,
|
||||
'Invalid request. Open the link from your email again',
|
||||
|
||||
Reference in New Issue
Block a user