mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Use URLs for channel identifiers
In the future these can potentially be used to dereference them
This commit is contained in:
@@ -14,6 +14,7 @@ import type { InteractionRoute } from '../../identity/interaction/routing/Intera
|
||||
import { ContextDocumentLoader } from '../../storage/conversion/ConversionUtil';
|
||||
import { UnprocessableEntityHttpError } from '../../util/errors/UnprocessableEntityHttpError';
|
||||
import { IdentifierSetMultiMap } from '../../util/map/IdentifierMap';
|
||||
import { joinUrl } from '../../util/PathUtil';
|
||||
import { readableToQuads } from '../../util/StreamUtil';
|
||||
import { msToDuration } from '../../util/StringUtil';
|
||||
import { NOTIFY, RDF, XSD } from '../../util/Vocabularies';
|
||||
@@ -201,7 +202,9 @@ export abstract class BaseChannelType implements NotificationChannelType {
|
||||
|
||||
/**
|
||||
* Converts a set of quads to a {@link NotificationChannel}.
|
||||
* Assumes the data is valid, so this should be called after {@link validateSubscription}
|
||||
* Assumes the data is valid, so this should be called after {@link validateSubscription}.
|
||||
*
|
||||
* The generated identifier will be a URL made by combining the base URL of the channel type with a unique identifier.
|
||||
*
|
||||
* The values of the default features will be added to the resulting channel,
|
||||
* subclasses with additional features that need to be added are responsible for parsing those quads.
|
||||
@@ -216,7 +219,7 @@ export abstract class BaseChannelType implements NotificationChannelType {
|
||||
const type = data.getObjects(subject, RDF.terms.type, null)[0] as NamedNode;
|
||||
|
||||
const channel: NotificationChannel = {
|
||||
id: `${v4()}:${topic.value}`,
|
||||
id: joinUrl(this.path, v4()),
|
||||
type: type.value,
|
||||
topic: topic.value,
|
||||
};
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { joinUrl } from '../../../util/PathUtil';
|
||||
|
||||
/**
|
||||
* Generates a specific unsubscribe URL for a WebHookSubscription2021
|
||||
* by combining the default unsubscribe URL with the given identifier.
|
||||
* @param url - The default unsubscribe URL.
|
||||
* @param id - The identifier.
|
||||
*/
|
||||
export function generateWebHookUnsubscribeUrl(url: string, id: string): string {
|
||||
return joinUrl(url, encodeURIComponent(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a WebHookSubscription2021 unsubscribe URL to extract the identifier.
|
||||
* @param url - The unsubscribe URL that is being called.
|
||||
*/
|
||||
export function parseWebHookUnsubscribeUrl(url: string): string {
|
||||
// Split always returns an array of at least length 1 so result can not be undefined
|
||||
return decodeURIComponent(url.split(/\//u).pop()!);
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import { BaseChannelType, DEFAULT_NOTIFICATION_FEATURES } from '../BaseChannelTy
|
||||
import type { NotificationChannel } from '../NotificationChannel';
|
||||
import type { SubscriptionService } from '../NotificationChannelType';
|
||||
import type { StateHandler } from '../StateHandler';
|
||||
import { generateWebHookUnsubscribeUrl } from './WebHook2021Util';
|
||||
|
||||
/**
|
||||
* A {@link NotificationChannel} containing the necessary fields for a WebHookSubscription2021 channel.
|
||||
@@ -57,19 +56,17 @@ export function isWebHook2021Channel(channel: NotificationChannel): channel is W
|
||||
export class WebHookSubscription2021 extends BaseChannelType {
|
||||
protected readonly logger = getLoggerFor(this);
|
||||
|
||||
private readonly unsubscribePath: string;
|
||||
private readonly stateHandler: StateHandler;
|
||||
private readonly webId: string;
|
||||
|
||||
/**
|
||||
* @param route - The route corresponding to the URL of the subscription service of this channel type.
|
||||
* @param webIdRoute - The route to the WebID that needs to be used when generating DPoP tokens for notifications.
|
||||
* @param unsubscribeRoute - The route where the request needs to be sent to unsubscribe.
|
||||
* @param stateHandler - The {@link StateHandler} that will be called after a successful subscription.
|
||||
* @param features - The features that need to be enabled for this channel type.
|
||||
*/
|
||||
public constructor(route: InteractionRoute, webIdRoute: InteractionRoute, unsubscribeRoute: InteractionRoute,
|
||||
stateHandler: StateHandler, features: string[] = DEFAULT_NOTIFICATION_FEATURES) {
|
||||
public constructor(route: InteractionRoute, webIdRoute: InteractionRoute, stateHandler: StateHandler,
|
||||
features: string[] = DEFAULT_NOTIFICATION_FEATURES) {
|
||||
super(NOTIFY.terms.WebHookSubscription2021,
|
||||
route,
|
||||
[ ...features, NOTIFY.webhookAuth ],
|
||||
@@ -80,7 +77,6 @@ export class WebHookSubscription2021 extends BaseChannelType {
|
||||
// which would make this more annoying so we are lenient here.
|
||||
// Could change in the future once this field is updated and part of the context.
|
||||
[{ path: NOTIFY.target, minCount: 1, maxCount: 1 }]);
|
||||
this.unsubscribePath = unsubscribeRoute.getPath();
|
||||
this.stateHandler = stateHandler;
|
||||
this.webId = webIdRoute.getPath();
|
||||
}
|
||||
@@ -114,7 +110,7 @@ export class WebHookSubscription2021 extends BaseChannelType {
|
||||
webId,
|
||||
target: target.value,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
unsubscribe_endpoint: generateWebHookUnsubscribeUrl(this.unsubscribePath, channel.id),
|
||||
unsubscribe_endpoint: channel.id,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import { NotFoundHttpError } from '../../../util/errors/NotFoundHttpError';
|
||||
import type { OperationHttpHandlerInput } from '../../OperationHttpHandler';
|
||||
import { OperationHttpHandler } from '../../OperationHttpHandler';
|
||||
import type { NotificationChannelStorage } from '../NotificationChannelStorage';
|
||||
import { parseWebHookUnsubscribeUrl } from './WebHook2021Util';
|
||||
import { isWebHook2021Channel } from './WebHookSubscription2021';
|
||||
|
||||
/**
|
||||
@@ -27,7 +26,7 @@ export class WebHookUnsubscriber extends OperationHttpHandler {
|
||||
}
|
||||
|
||||
public async handle({ operation, request }: OperationHttpHandlerInput): Promise<ResponseDescription> {
|
||||
const id = parseWebHookUnsubscribeUrl(operation.target.path);
|
||||
const id = operation.target.path;
|
||||
const channel = await this.storage.get(id);
|
||||
if (!channel || !isWebHook2021Channel(channel)) {
|
||||
throw new NotFoundHttpError();
|
||||
|
||||
Reference in New Issue
Block a user