Skip to content

Commit

Permalink
refactor: Rename WebHook to Webhook
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimvh committed Oct 6, 2023
1 parent 1e3684b commit 531c299
Show file tree
Hide file tree
Showing 16 changed files with 77 additions and 73 deletions.
4 changes: 4 additions & 0 deletions RELEASE_NOTES.md
Expand Up @@ -31,6 +31,8 @@ The following changes are relevant for v6 custom configs that replaced certain f
- `/http/notifications/base/storage.json`
- `/identity/*`
- `/storage/keyvalue/storages/storages.json`
- All identifiers containing the string "WebHook" have been renamed to instead use "Webhook"
to be consistent with the notification type.

### Interface changes

Expand All @@ -41,6 +43,8 @@ These changes are relevant if you wrote custom modules for the server that depen
- `EncodingPathStorage` has been removed
and its functionality split up over `Base64EncodingStorage` and `ContainerPathStorage`.
`HashEncodingPathStorage` has similarly been replaced by introducing `HashEncodingStorage`.
- All classes with the name `WebHook*` have been renamed to `Webhook*`
to be consistent with the corresponding notification type.

## v6.1.0

Expand Down
4 changes: 2 additions & 2 deletions config/http/README.md
Expand Up @@ -22,13 +22,13 @@ Determines how notifications should be sent out from the server when resources c

* *all*: Supports all available notification types of the Solid Notifications protocol
[specification](https://solidproject.org/TR/notifications-protocol).
Currently, this includes WebHookChannel2023 and WebSocketChannel2023.
Currently, this includes WebhookChannel2023 and WebSocketChannel2023.
* *disabled*: No notifications are sent out.
* *legacy-websocket*: Follows the legacy Solid WebSocket
[specification](https://github.com/solid/solid-spec/blob/master/api-websockets.md).
Will be removed in future versions.
* *new-old-websockets.json*: Support for both the legacy Solid Websockets and the new WebSocketChannel2023.
* *webhooks*: Follows the WebHookChannel2023
* *webhooks*: Follows the WebhookChannel2023
[specification](https://solid.github.io/notifications/webhook-channel-2023) draft.
* *websockets*: Follows the WebSocketChannel2023
[specification](https://solid.github.io/notifications/websocket-channel-2023).
Expand Down
12 changes: 6 additions & 6 deletions config/http/notifications/webhooks/handler.json
Expand Up @@ -3,31 +3,31 @@
"@graph": [
{
"comment": "Handles the generation and serialization of notifications for WebhookChannel2023.",
"@id": "urn:solid-server:default:WebHookNotificationHandler",
"@id": "urn:solid-server:default:WebhookNotificationHandler",
"@type": "TypedNotificationHandler",
"type": "http://www.w3.org/ns/solid/notifications#WebhookChannel2023",
"source": {
"@type": "ComposedNotificationHandler",
"generator": { "@id": "urn:solid-server:default:BaseNotificationGenerator" },
"serializer": { "@id": "urn:solid-server:default:BaseNotificationSerializer" },
"emitter": { "@id": "urn:solid-server:default:WebHookEmitter" },
"emitter": { "@id": "urn:solid-server:default:WebhookEmitter" },
"eTagHandler": { "@id": "urn:solid-server:default:ETagHandler" }
}
},
{
"comment": "Emits serialized notifications through HTTP requests to the Webhook.",
"@id": "urn:solid-server:default:WebHookEmitter",
"@type": "WebHookEmitter",
"@id": "urn:solid-server:default:WebhookEmitter",
"@type": "WebhookEmitter",
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
"webIdRoute": { "@id": "urn:solid-server:default:WebHookWebIdRoute" },
"webIdRoute": { "@id": "urn:solid-server:default:WebhookWebIdRoute" },
"jwkGenerator": { "@id": "urn:solid-server:default:JwkGenerator" }
},

{
"@id": "urn:solid-server:default:NotificationHandler",
"@type": "WaterfallHandler",
"handlers": [
{ "@id": "urn:solid-server:default:WebHookNotificationHandler" }
{ "@id": "urn:solid-server:default:WebhookNotificationHandler" }
]
}
]
Expand Down
14 changes: 7 additions & 7 deletions config/http/notifications/webhooks/routes.json
Expand Up @@ -2,26 +2,26 @@
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^6.0.0/components/context.jsonld",
"@graph": [
{
"@id": "urn:solid-server:default:WebHookRoute",
"@id": "urn:solid-server:default:WebhookRoute",
"@type": "RelativePathInteractionRoute",
"base": { "@id": "urn:solid-server:default:NotificationRoute" },
"relativePath": "/WebhookChannel2023/"
},
{
"@id": "urn:solid-server:default:WebHookWebIdRoute",
"@id": "urn:solid-server:default:WebhookWebIdRoute",
"@type": "RelativePathInteractionRoute",
"base": { "@id": "urn:solid-server:default:WebHookRoute" },
"base": { "@id": "urn:solid-server:default:WebhookRoute" },
"relativePath": "/webId"
},

{
"comment": "Handles the WebhookChannel2023 WebID.",
"@id": "urn:solid-server:default:WebHookWebId",
"@id": "urn:solid-server:default:WebhookWebId",
"@type": "OperationRouterHandler",
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
"allowedPathNames": [ "/WebhookChannel2023/webId$" ],
"handler": {
"@type": "WebHookWebId",
"@type": "WebhookWebId",
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" }
}
},
Expand All @@ -30,8 +30,8 @@
"@id": "urn:solid-server:default:NotificationTypeHandler",
"@type": "WaterfallHandler",
"handlers": [
{ "@id": "urn:solid-server:default:WebHookRouter" },
{ "@id": "urn:solid-server:default:WebHookWebId" }
{ "@id": "urn:solid-server:default:WebhookRouter" },
{ "@id": "urn:solid-server:default:WebhookWebId" }
]
}
]
Expand Down
16 changes: 8 additions & 8 deletions config/http/notifications/webhooks/subscription.json
Expand Up @@ -3,15 +3,15 @@
"@graph": [
{
"comment": "Handles the subscriptions targeting a WebhookChannel2023.",
"@id": "urn:solid-server:default:WebHookRouter",
"@id": "urn:solid-server:default:WebhookRouter",
"@type": "OperationRouterHandler",
"baseUrl": { "@id": "urn:solid-server:default:variable:baseUrl" },
"allowedMethods": [ "HEAD", "GET", "POST" ],
"allowedPathNames": [ "/WebhookChannel2023/$" ],
"handler": {
"@id": "urn:solid-server:default:WebHookSubscriber",
"@id": "urn:solid-server:default:WebhookSubscriber",
"@type": "NotificationSubscriber",
"channelType": { "@id": "urn:solid-server:default:WebHookChannel2023Type" },
"channelType": { "@id": "urn:solid-server:default:WebhookChannel2023Type" },
"converter": { "@id": "urn:solid-server:default:RepresentationConverter" },
"credentialsExtractor": { "@id": "urn:solid-server:default:CredentialsExtractor" },
"permissionReader": { "@id": "urn:solid-server:default:PermissionReader" },
Expand All @@ -21,13 +21,13 @@
},
{
"comment": "Contains all the metadata relevant for a WebhookChannel2023.",
"@id": "urn:solid-server:default:WebHookChannel2023Type",
"@id": "urn:solid-server:default:WebhookChannel2023Type",
"@type": "WebhookChannel2023Type",
"route": { "@id": "urn:solid-server:default:WebHookRoute" },
"webIdRoute": { "@id": "urn:solid-server:default:WebHookWebIdRoute" },
"route": { "@id": "urn:solid-server:default:WebhookRoute" },
"webIdRoute": { "@id": "urn:solid-server:default:WebhookWebIdRoute" },
"stateHandler": {
"@type": "BaseStateHandler",
"handler": { "@id": "urn:solid-server:default:WebHookNotificationHandler" },
"handler": { "@id": "urn:solid-server:default:WebhookNotificationHandler" },
"storage": { "@id": "urn:solid-server:default:SubscriptionStorage" }
}
},
Expand All @@ -37,7 +37,7 @@
"@type": "NotificationDescriber",
"subscriptions": [
{
"@id": "urn:solid-server:default:WebHookChannel2023Type"
"@id": "urn:solid-server:default:WebhookChannel2023Type"
}
]
}
Expand Down
12 changes: 6 additions & 6 deletions documentation/markdown/architecture/features/notifications.md
Expand Up @@ -174,13 +174,13 @@ so that class can emit events later on, as mentioned above.
The state handler will make sure that a notification gets sent out if the subscription has a `state` feature request,
as defined in the notification specification.

## WebHookChannel2023
## WebhookChannel2023

The additions required to support
[WebHookChannel2023](https://solid.github.io/notifications/webhook-channel-2023)
[WebhookChannel2023](https://solid.github.io/notifications/webhook-channel-2023)
are quite similar to those needed for WebSocketChannel2023:

* For discovery, there is a `WebHookDescriber`, which is an extension of a `NotificationDescriber`.
* The `WebHookChannel2023Type` class contains all the necessary typing information.
* `WebHookEmitter` is the `NotificationEmitter` that sends the request.
* `WebHookUnsubscriber` and `WebHookWebId` are additional utility classes to support the spec requirements.
* For discovery, there is a `WebhookDescriber`, which is an extension of a `NotificationDescriber`.
* The `WebhookChannel2023Type` class contains all the necessary typing information.
* `WebhookEmitter` is the `NotificationEmitter` that sends the request.
* `WebhookUnsubscriber` and `WebhookWebId` are additional utility classes to support the spec requirements.
2 changes: 1 addition & 1 deletion documentation/markdown/usage/notifications.md
Expand Up @@ -228,4 +228,4 @@ You can modify this behaviour by adding the following block to your configuratio
`maxDuration` defines after how many minutes every channel will be removed.
Setting this value to 0 will allow channels to exist forever.
Similarly, to change the maximum duration of webhook channels you can use the identifier
`urn:solid-server:default:WebHookSubscriber`.
`urn:solid-server:default:WebhookSubscriber`.
8 changes: 4 additions & 4 deletions src/index.ts
Expand Up @@ -325,10 +325,10 @@ export * from './server/notifications/serialize/ConvertingNotificationSerializer
export * from './server/notifications/serialize/JsonLdNotificationSerializer';
export * from './server/notifications/serialize/NotificationSerializer';

// Server/Notifications/WebHookChannel2023
export * from './server/notifications/WebHookChannel2023/WebhookChannel2023Type';
export * from './server/notifications/WebHookChannel2023/WebHookEmitter';
export * from './server/notifications/WebHookChannel2023/WebHookWebId';
// Server/Notifications/WebhookChannel2023
export * from './server/notifications/WebhookChannel2023/WebhookChannel2023Type';
export * from './server/notifications/WebhookChannel2023/WebhookEmitter';
export * from './server/notifications/WebhookChannel2023/WebhookWebId';

// Server/Notifications/WebSocketChannel2023
export * from './server/notifications/WebSocketChannel2023/WebSocket2023Emitter';
Expand Down
Expand Up @@ -8,11 +8,11 @@ import type { NotificationChannel } from '../NotificationChannel';
import type { StateHandler } from '../StateHandler';

/**
* A {@link NotificationChannel} containing the necessary fields for a WebHookChannel2023 channel.
* A {@link NotificationChannel} containing the necessary fields for a WebhookChannel2023 channel.
*/
export interface WebhookChannel2023 extends NotificationChannel {
/**
* The "WebHookChannel2023" type.
* The "WebhookChannel2023" type.
*/
type: typeof NOTIFY.WebhookChannel2023;
/**
Expand All @@ -21,12 +21,12 @@ export interface WebhookChannel2023 extends NotificationChannel {
sendTo: string;
}

export function isWebHook2023Channel(channel: NotificationChannel): channel is WebhookChannel2023 {
export function isWebhook2023Channel(channel: NotificationChannel): channel is WebhookChannel2023 {
return channel.type === NOTIFY.WebhookChannel2023;
}

/**
* The notification channel type WebHookChannel2023 as described in
* The notification channel type WebhookChannel2023 as described in
* https://solid.github.io/notifications/webhook-channel-2023
*
* Requires read permissions on a resource to be able to receive notifications.
Expand Down
Expand Up @@ -10,10 +10,10 @@ import { readableToString } from '../../../util/StreamUtil';
import type { NotificationEmitterInput } from '../NotificationEmitter';
import { NotificationEmitter } from '../NotificationEmitter';
import type { WebhookChannel2023 } from './WebhookChannel2023Type';
import { isWebHook2023Channel } from './WebhookChannel2023Type';
import { isWebhook2023Channel } from './WebhookChannel2023Type';

/**
* Emits a notification representation using the WebHookChannel2023 specification.
* Emits a notification representation using the WebhookChannel2023 specification.
*
* At the time of writing it is not specified how exactly a notification sender should make its requests verifiable,
* so for now we use a token similar to those from Solid-OIDC, signed by the server itself.
Expand All @@ -23,7 +23,7 @@ import { isWebHook2023Channel } from './WebhookChannel2023Type';
* The `expiration` input parameter is how long the generated token should be valid in minutes.
* Default is 20.
*/
export class WebHookEmitter extends NotificationEmitter {
export class WebhookEmitter extends NotificationEmitter {
protected readonly logger = getLoggerFor(this);

private readonly issuer: string;
Expand All @@ -40,15 +40,15 @@ export class WebHookEmitter extends NotificationEmitter {
}

public async canHandle({ channel }: NotificationEmitterInput): Promise<void> {
if (!isWebHook2023Channel(channel)) {
throw new NotImplementedHttpError(`${channel.id} is not a WebHookChannel2023 channel.`);
if (!isWebhook2023Channel(channel)) {
throw new NotImplementedHttpError(`${channel.id} is not a WebhookChannel2023 channel.`);
}
}

public async handle({ channel, representation }: NotificationEmitterInput): Promise<void> {
// Cast was checked in `canHandle`
const webHookChannel = channel as WebhookChannel2023;
this.logger.debug(`Emitting WebHook notification with target ${webHookChannel.sendTo}`);
const webhookChannel = channel as WebhookChannel2023;
this.logger.debug(`Emitting Webhook notification with target ${webhookChannel.sendTo}`);

const privateKey = await this.jwkGenerator.getPrivateKey();
const publicKey = await this.jwkGenerator.getPublicKey();
Expand Down Expand Up @@ -78,14 +78,14 @@ export class WebHookEmitter extends NotificationEmitter {

// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-dpop#section-4.2
const dpopProof = await new SignJWT({
htu: webHookChannel.sendTo,
htu: webhookChannel.sendTo,
htm: 'POST',
}).setProtectedHeader({ alg: privateKey.alg, jwk: publicKey, typ: 'dpop+jwt' })
.setIssuedAt(time)
.setJti(v4())
.sign(privateKeyObject);

const response = await fetch(webHookChannel.sendTo, {
const response = await fetch(webhookChannel.sendTo, {
method: 'POST',
headers: {
'content-type': representation.metadata.contentType!,
Expand All @@ -95,7 +95,7 @@ export class WebHookEmitter extends NotificationEmitter {
body: await readableToString(representation.data),
});
if (response.status >= 400) {
this.logger.error(`There was an issue emitting a WebHook notification with target ${webHookChannel.sendTo}: ${
this.logger.error(`There was an issue emitting a Webhook notification with target ${webhookChannel.sendTo}: ${
await response.text()}`);
}
}
Expand Down
Expand Up @@ -9,11 +9,11 @@ import type { OperationHttpHandlerInput } from '../../OperationHttpHandler';
import { OperationHttpHandler } from '../../OperationHttpHandler';

/**
* Generates a fixed WebID that we use to identify the server for notifications sent using a WebHookChannel2023.
* This is used in tandem with the tokens generated by the {@link WebHookEmitter}.
* Generates a fixed WebID that we use to identify the server for notifications sent using a WebhookChannel2023.
* This is used in tandem with the tokens generated by the {@link WebhookEmitter}.
* This is a minimal WebID with only the `solid:oidcIssuer` triple.
*/
export class WebHookWebId extends OperationHttpHandler {
export class WebhookWebId extends OperationHttpHandler {
private readonly turtle: string;

public constructor(baseUrl: string) {
Expand Down
Expand Up @@ -21,14 +21,14 @@ import {
} from './Config';
import quad = DataFactory.quad;

const port = getPort('WebHookChannel2023');
const port = getPort('WebhookChannel2023');
const baseUrl = `http://localhost:${port}/`;
const clientPort = getPort('WebHookChannel2023-client');
const clientPort = getPort('WebhookChannel2023-client');
const target = `http://localhost:${clientPort}/`;
const webId = 'http://example.com/card/#me';
const notificationType = NOTIFY.WebhookChannel2023;

const rootFilePath = getTestFolder('WebHookChannel2023');
const rootFilePath = getTestFolder('WebhookChannel2023');
const stores: [string, any][] = [
[ 'in-memory storage', {
configs: [ 'storage/backend/memory.json', 'util/resource-locker/memory.json' ],
Expand All @@ -40,7 +40,7 @@ const stores: [string, any][] = [
}],
];

describe.each(stores)('A server supporting WebHookChannel2023 using %s', (name, { configs, teardown }): void => {
describe.each(stores)('A server supporting WebhookChannel2023 using %s', (name, { configs, teardown }): void => {
let app: App;
const topic = joinUrl(baseUrl, '/foo');
let storageDescriptionUrl: string;
Expand Down
Expand Up @@ -12,11 +12,11 @@ import type { NotificationChannel } from '../../../../../src/server/notification
import type { StateHandler } from '../../../../../src/server/notifications/StateHandler';
import type {
WebhookChannel2023,
} from '../../../../../src/server/notifications/WebHookChannel2023/WebhookChannel2023Type';
} from '../../../../../src/server/notifications/WebhookChannel2023/WebhookChannel2023Type';
import {
isWebHook2023Channel,
isWebhook2023Channel,
WebhookChannel2023Type,
} from '../../../../../src/server/notifications/WebHookChannel2023/WebhookChannel2023Type';
} from '../../../../../src/server/notifications/WebhookChannel2023/WebhookChannel2023Type';
import { NOTIFY, RDF } from '../../../../../src/util/Vocabularies';
import quad = DataFactory.quad;
import blankNode = DataFactory.blankNode;
Expand Down Expand Up @@ -63,10 +63,10 @@ describe('A WebhookChannel2023Type', (): void => {
});

it('exposes a utility function to verify if a channel is a webhook channel.', async(): Promise<void> => {
expect(isWebHook2023Channel(channel)).toBe(true);
expect(isWebhook2023Channel(channel)).toBe(true);

(channel as NotificationChannel).type = 'something else';
expect(isWebHook2023Channel(channel)).toBe(false);
expect(isWebhook2023Channel(channel)).toBe(false);
});

it('correctly parses notification channel bodies.', async(): Promise<void> => {
Expand Down

0 comments on commit 531c299

Please sign in to comment.