diff --git a/sdk/web-pubsub/web-pubsub-express/package.json b/sdk/web-pubsub/web-pubsub-express/package.json index 9d34c677b8f9..324e7653048a 100644 --- a/sdk/web-pubsub/web-pubsub-express/package.json +++ b/sdk/web-pubsub/web-pubsub-express/package.json @@ -57,6 +57,7 @@ "sideEffects": false, "dependencies": { "tslib": "^2.2.0", + "@azure/logger": "^1.0.0", "cloudevents": "^4.0.0" }, "devDependencies": { diff --git a/sdk/web-pubsub/web-pubsub-express/review/web-pubsub-express.api.md b/sdk/web-pubsub/web-pubsub-express/review/web-pubsub-express.api.md index defcae08ac2b..bac2e3f0c6d7 100644 --- a/sdk/web-pubsub/web-pubsub-express/review/web-pubsub-express.api.md +++ b/sdk/web-pubsub/web-pubsub-express/review/web-pubsub-express.api.md @@ -32,6 +32,7 @@ export interface ConnectRequest { claims?: Record; clientCertificates?: Certificate[]; context: ConnectionContext; + headers?: Record; queries?: Record; subprotocols?: string[]; } @@ -77,14 +78,14 @@ export interface UserEventResponseHandler { // @public export class WebPubSubEventHandler { - constructor(hub: string, allowedEndpoints: string[], options?: WebPubSubEventHandlerOptions); + constructor(hub: string, options?: WebPubSubEventHandlerOptions); getMiddleware(): express.RequestHandler; readonly path: string; } // @public export interface WebPubSubEventHandlerOptions { - dumpRequest?: boolean; + allowedEndpoints?: string[]; handleConnect?: (connectRequest: ConnectRequest, connectResponse: ConnectResponseHandler) => void; handleUserEvent?: (userEventRequest: UserEventRequest, userEventResponse: UserEventResponseHandler) => void; onConnected?: (connectedRequest: ConnectedRequest) => void; @@ -92,7 +93,6 @@ export interface WebPubSubEventHandlerOptions { path?: string; } - // (No @packageDocumentation comment for this package) ``` diff --git a/sdk/web-pubsub/web-pubsub-express/samples-dev/server.ts b/sdk/web-pubsub/web-pubsub-express/samples-dev/server.ts index 609d7373ed9a..4644c6faa0ae 100644 --- a/sdk/web-pubsub/web-pubsub-express/samples-dev/server.ts +++ b/sdk/web-pubsub/web-pubsub-express/samples-dev/server.ts @@ -8,8 +8,7 @@ import { WebPubSubEventHandler } from "@azure/web-pubsub-express"; import express from "express"; -const handler = new WebPubSubEventHandler("chat", ["https://xxx.webpubsub.azure.com"], { - dumpRequest: false, +const handler = new WebPubSubEventHandler("chat", { handleConnect(req, res) { console.log(req); // You can set the state for the connection, it lasts throughout the lifetime of the connection @@ -27,7 +26,8 @@ const handler = new WebPubSubEventHandler("chat", ["https://xxx.webpubsub.azure. // You can also set the state here res.setState("calledTime", calledTime); res.success("Hello", "text"); - } + }, + allowedEndpoints: ["https://xxx.webpubsub.azure.com"] }); const app = express(); diff --git a/sdk/web-pubsub/web-pubsub-express/samples/v1/javascript/package.json b/sdk/web-pubsub/web-pubsub-express/samples/v1/javascript/package.json index c7003a47c385..e9917d8056e3 100644 --- a/sdk/web-pubsub/web-pubsub-express/samples/v1/javascript/package.json +++ b/sdk/web-pubsub/web-pubsub-express/samples/v1/javascript/package.json @@ -23,6 +23,7 @@ "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/web-pubsub/web-pubsub-express", "dependencies": { "@azure/web-pubsub-express": "next", - "dotenv": "latest" + "dotenv": "latest", + "express": "^4.17.1" } } diff --git a/sdk/web-pubsub/web-pubsub-express/samples/v1/javascript/server.js b/sdk/web-pubsub/web-pubsub-express/samples/v1/javascript/server.js index 846cc24d28a6..7c6ffd758e74 100644 --- a/sdk/web-pubsub/web-pubsub-express/samples/v1/javascript/server.js +++ b/sdk/web-pubsub/web-pubsub-express/samples/v1/javascript/server.js @@ -8,8 +8,8 @@ const { WebPubSubEventHandler } = require("@azure/web-pubsub-express"); const express = require("express"); -const handler = new WebPubSubEventHandler("chat", ["https://xxx.webpubsub.azure.com"], { - dumpRequest: false, +const handler = new WebPubSubEventHandler("chat", { + path: "/api/webpubsub", handleConnect(req, res) { console.log(req); res.success(); diff --git a/sdk/web-pubsub/web-pubsub-express/src/cloudEventsDispatcher.ts b/sdk/web-pubsub/web-pubsub-express/src/cloudEventsDispatcher.ts index 9a9fa3dbd365..2ea074e91f0e 100644 --- a/sdk/web-pubsub/web-pubsub-express/src/cloudEventsDispatcher.ts +++ b/sdk/web-pubsub/web-pubsub-express/src/cloudEventsDispatcher.ts @@ -4,7 +4,7 @@ import { HTTP, CloudEvent } from "cloudevents"; import { IncomingMessage, ServerResponse } from "http"; import { URL } from "url"; - +import { logger } from "./logger"; import * as utils from "./utils"; import { @@ -14,9 +14,9 @@ import { DisconnectedRequest, ConnectedRequest, ConnectionContext, - WebPubSubEventHandlerOptions, ConnectResponseHandler, - UserEventResponseHandler + UserEventResponseHandler, + WebPubSubEventHandlerOptions } from "./cloudEventsProtocols"; enum EventType { @@ -137,24 +137,27 @@ function tryGetWebPubSubEvent(req: IncomingMessage): EventType | undefined { } } +function isWebPubSubRequest(req: IncomingMessage): boolean { + return utils.getHttpHeader(req, "ce-awpsversion") !== undefined; +} + /** * @internal */ export class CloudEventsDispatcher { - private readonly _dumpRequest: boolean; - private readonly _allowedOrigins: string[]; - constructor( - private hub: string, - allowedEndpoints: string[], - private eventHandler?: WebPubSubEventHandlerOptions - ) { - this._dumpRequest = eventHandler?.dumpRequest ?? false; - this._allowedOrigins = allowedEndpoints.map((endpoint) => - endpoint === "*" ? "*" : new URL(endpoint).host - ); + private readonly _allowedOrigins = ["*"]; + constructor(private hub: string, private eventHandler?: WebPubSubEventHandlerOptions) { + if (eventHandler?.allowedEndpoints !== undefined) { + this._allowedOrigins = eventHandler.allowedEndpoints.map((endpoint) => + endpoint === "*" ? "*" : new URL(endpoint).host + ); + } } - public processValidateRequest(req: IncomingMessage, res: ServerResponse): boolean { + public handlePreflight(req: IncomingMessage, res: ServerResponse): boolean { + if (!isWebPubSubRequest(req)) { + return false; + } if (req.headers["webhook-request-origin"]) { res.setHeader("WebHook-Allowed-Origin", this._allowedOrigins); res.end(); @@ -164,10 +167,11 @@ export class CloudEventsDispatcher { } } - public async processRequest( - request: IncomingMessage, - response: ServerResponse - ): Promise { + public async handleRequest(request: IncomingMessage, response: ServerResponse): Promise { + if (!isWebPubSubRequest(request)) { + return false; + } + // check if it is a valid WebPubSub cloud events const origin = utils.getHttpHeader(request, "webhook-request-origin"); if (origin === undefined) { @@ -213,16 +217,14 @@ export class CloudEventsDispatcher { } break; default: - console.warn(`Unknown EventType ${eventType}`); + logger.warning(`Unknown EventType ${eventType}`); return false; } const eventRequest = await utils.convertHttpToEvent(request); const receivedEvent = HTTP.toEvent(eventRequest); - if (this._dumpRequest) { - console.log(receivedEvent); - } + logger.verbose(receivedEvent); switch (eventType) { case EventType.Connect: { @@ -277,7 +279,7 @@ export class CloudEventsDispatcher { return true; } default: - console.warn(`Unknown EventType ${eventType}`); + logger.warning(`Unknown EventType ${eventType}`); return false; } } diff --git a/sdk/web-pubsub/web-pubsub-express/src/cloudEventsProtocols.ts b/sdk/web-pubsub/web-pubsub-express/src/cloudEventsProtocols.ts index 7f653cb49d37..4201ba16ce5b 100644 --- a/sdk/web-pubsub/web-pubsub-express/src/cloudEventsProtocols.ts +++ b/sdk/web-pubsub/web-pubsub-express/src/cloudEventsProtocols.ts @@ -73,6 +73,10 @@ export interface ConnectRequest { * The queries that the client WebSocket connection has when it connects. */ queries?: Record; + /** + * The headers that the client WebSocket connection has when it connects. + */ + headers?: Record; /** * The subprotocols that the client WebSocket connection uses to do handshake. */ @@ -208,11 +212,6 @@ export interface WebPubSubEventHandlerOptions { */ path?: string; - /** - * Configures if you'd like to dump the incoming HTTP request. - */ - dumpRequest?: boolean; - /** * Handle 'connect' event, the service waits for the response to proceed. */ @@ -236,4 +235,9 @@ export interface WebPubSubEventHandlerOptions { * Event triggers for "disconnected" unblocking event. This is an unblocking event and the service does not wait for the response. */ onDisconnected?: (disconnectedRequest: DisconnectedRequest) => void; + + /** + * If not specified, by default allow all the endpoints, otherwise only allow specified endpoints + */ + allowedEndpoints?: string[]; } diff --git a/sdk/web-pubsub/web-pubsub-express/src/logger.ts b/sdk/web-pubsub/web-pubsub-express/src/logger.ts new file mode 100644 index 000000000000..33f720f92070 --- /dev/null +++ b/sdk/web-pubsub/web-pubsub-express/src/logger.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { createClientLogger } from "@azure/logger"; + +/** + * The \@azure/logger configuration for this package. + * + * @internal + */ +export const logger = createClientLogger("web-pubsub-express"); diff --git a/sdk/web-pubsub/web-pubsub-express/src/webPubSubEventHandler.ts b/sdk/web-pubsub/web-pubsub-express/src/webPubSubEventHandler.ts index f9462acb6066..a8b4d7f54408 100644 --- a/sdk/web-pubsub/web-pubsub-express/src/webPubSubEventHandler.ts +++ b/sdk/web-pubsub/web-pubsub-express/src/webPubSubEventHandler.ts @@ -25,7 +25,7 @@ export class WebPubSubEventHandler { * import express from "express"; * import { WebPubSubEventHandler } from "@azure/web-pubsub-express"; * const endpoint = "https://xxxx.webpubsubdev.azure.com" - * const handler = new WebPubSubEventHandler('chat', [ endpoint ] { + * const handler = new WebPubSubEventHandler('chat', { * handleConnect: (req, res) => { * console.log(JSON.stringify(req)); * return {}; @@ -37,22 +37,18 @@ export class WebPubSubEventHandler { * console.log(JSON.stringify(req)); * res.success("Hey " + req.data, req.dataType); * }; + * allowedEndpoints: [ endpoint ] * }, * }); * ``` * * @param hub - The name of the hub to listen to - * @param allowedEndpoints - The allowed endpoints for the incoming CloudEvents request * @param options - Options to configure the event handler */ - constructor( - private hub: string, - allowedEndpoints: string[], - options?: WebPubSubEventHandlerOptions - ) { + constructor(private hub: string, options?: WebPubSubEventHandlerOptions) { const path = (options?.path ?? `/api/webpubsub/hubs/${hub}/`).toLowerCase(); this.path = path.endsWith("/") ? path : path + "/"; - this._cloudEventsHandler = new CloudEventsDispatcher(this.hub, allowedEndpoints, options); + this._cloudEventsHandler = new CloudEventsDispatcher(this.hub, options); } /** @@ -71,12 +67,12 @@ export class WebPubSubEventHandler { requestUrl = requestUrl.endsWith("/") ? requestUrl : requestUrl + "/"; if (requestUrl.startsWith(this.path)) { if (req.method === "OPTIONS") { - if (this._cloudEventsHandler.processValidateRequest(req, res)) { + if (this._cloudEventsHandler.handlePreflight(req, res)) { return; } } else if (req.method === "POST") { try { - if (await this._cloudEventsHandler.processRequest(req, res)) { + if (await this._cloudEventsHandler.handleRequest(req, res)) { return; } } catch (err) { diff --git a/sdk/web-pubsub/web-pubsub-express/test/connect.spec.ts b/sdk/web-pubsub/web-pubsub-express/test/connect.spec.ts index 3f4152aad1af..97c5f7ddee7d 100644 --- a/sdk/web-pubsub/web-pubsub-express/test/connect.spec.ts +++ b/sdk/web-pubsub/web-pubsub-express/test/connect.spec.ts @@ -17,6 +17,7 @@ function buildRequest( ): void { req.headers["webhook-request-origin"] = "xxx.webpubsub.azure.com"; req.headers["Content-Type"] = "application/json; charset=utf-8"; + req.headers["ce-awpsversion"] = "1.0"; req.headers["ce-specversion"] = "1.0"; req.headers["ce-type"] = "azure.webpubsub.sys.connect"; req.headers["ce-source"] = `/hubs/${hub}/client/${connectionId}`; @@ -48,8 +49,8 @@ describe("Can handle connect event", function() { it("Should not handle the request if request is not cloud events", async function() { const endSpy = sinon.spy(res.end); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub1"); + const result = await dispatcher.handleRequest(req, res); assert.isFalse(result); assert.isTrue(endSpy.notCalled); }); @@ -58,8 +59,8 @@ describe("Can handle connect event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub1"); + const result = await dispatcher.handleRequest(req, res); assert.isFalse(result); assert.isTrue(endSpy.notCalled); }); @@ -68,8 +69,8 @@ describe("Can handle connect event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub"); + const result = await dispatcher.handleRequest(req, res); assert.isTrue(result, "should handle"); assert.isTrue(endSpy.calledOnce, "should call once"); assert.equal(401, res.statusCode, "should be 401"); @@ -79,8 +80,8 @@ describe("Can handle connect event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], {}); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub", {}); + const result = await dispatcher.handleRequest(req, res); assert.isTrue(result, "should handle"); assert.isTrue(endSpy.calledOnce, "should call once"); assert.equal(401, res.statusCode, "should be 401"); @@ -90,12 +91,12 @@ describe("Can handle connect event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleConnect: async (_, response) => { response.fail(400); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -107,12 +108,12 @@ describe("Can handle connect event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleConnect: async (_, response) => { response.success(); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -124,12 +125,12 @@ describe("Can handle connect event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleConnect: async (_, response) => { response.success({ userId: "vic" }); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -141,7 +142,7 @@ describe("Can handle connect event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleConnect: async (_, response) => { response.setState("key1", "val1"); response.setState("key2", "val2"); @@ -150,7 +151,7 @@ describe("Can handle connect event", function() { response.success({ userId: "vic" }); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -174,7 +175,7 @@ describe("Can handle connect event", function() { key3: "" }); buildRequest(req, "hub1", "conn1", undefined, states); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub1", { handleConnect: (request, response) => { assert.equal("val3", request.context.states["key1"][0]); assert.equal("val2", request.context.states["key2"]); @@ -182,7 +183,7 @@ describe("Can handle connect event", function() { response.success(); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -193,13 +194,13 @@ describe("Can handle connect event", function() { it("Invalid state header gets ignored", async function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub1", "conn1", undefined, ""); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub1", { handleConnect: (request, response) => { assert.deepEqual({}, request.context.states); response.success(); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); diff --git a/sdk/web-pubsub/web-pubsub-express/test/connected.spec.ts b/sdk/web-pubsub/web-pubsub-express/test/connected.spec.ts index 556815446560..d5b54d68d4d3 100644 --- a/sdk/web-pubsub/web-pubsub-express/test/connected.spec.ts +++ b/sdk/web-pubsub/web-pubsub-express/test/connected.spec.ts @@ -15,6 +15,7 @@ function buildRequest( ): void { req.headers["webhook-request-origin"] = "xxx.webpubsub.azure.com"; req.headers["Content-Type"] = "application/json; charset=utf-8"; + req.headers["ce-awpsversion"] = "1.0"; req.headers["ce-specversion"] = "1.0"; req.headers["ce-type"] = "azure.webpubsub.user.connected"; req.headers["ce-source"] = `/hubs/${hub}/client/${connectionId}`; @@ -45,8 +46,8 @@ describe("Can handle connected event", function() { it("Should not handle the request if request is not cloud events", async function() { const endSpy = sinon.spy(res.end); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub1"); + const result = await dispatcher.handleRequest(req, res); assert.isFalse(result); assert.isTrue(endSpy.notCalled); }); @@ -55,8 +56,8 @@ describe("Can handle connected event", function() { const endSpy = sinon.spy(res.end); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub1"); + const result = await dispatcher.handleRequest(req, res); assert.isFalse(result); assert.isTrue(endSpy.notCalled); }); @@ -65,8 +66,8 @@ describe("Can handle connected event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub"); + const result = await dispatcher.handleRequest(req, res); assert.isTrue(result, "should handle"); assert.isTrue(endSpy.calledOnce, "should call once"); assert.equal(200, res.statusCode, "should be 200"); @@ -76,8 +77,8 @@ describe("Can handle connected event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], {}); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub", {}); + const result = await dispatcher.handleRequest(req, res); assert.isTrue(result, "should handle"); assert.isTrue(endSpy.calledOnce, "should call once"); assert.equal(200, res.statusCode, "should be 200"); @@ -87,12 +88,12 @@ describe("Can handle connected event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { onConnected: async (_) => { throw new Error(); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); diff --git a/sdk/web-pubsub/web-pubsub-express/test/ctor.spec.ts b/sdk/web-pubsub/web-pubsub-express/test/ctor.spec.ts index 001ba9fa5cd9..9de336a3adbb 100644 --- a/sdk/web-pubsub/web-pubsub-express/test/ctor.spec.ts +++ b/sdk/web-pubsub/web-pubsub-express/test/ctor.spec.ts @@ -6,12 +6,12 @@ import { assert } from "chai"; describe("Can creat event handler", function() { it("Can provide default path", function() { - const dispatcher = new WebPubSubEventHandler("hub", ["*"]); + const dispatcher = new WebPubSubEventHandler("hub"); assert.equal("/api/webpubsub/hubs/hub/", dispatcher.path); }); it("Supports custom path", function() { - const dispatcher = new WebPubSubEventHandler("hub", ["*"], { + const dispatcher = new WebPubSubEventHandler("hub", { path: "/custom" }); assert.equal("/custom/", dispatcher.path); @@ -19,7 +19,7 @@ describe("Can creat event handler", function() { it("Throw with invalid endpoints", function() { try { - new WebPubSubEventHandler("hub", ["b.com"]); + new WebPubSubEventHandler("hub", { allowedEndpoints: ["b.com"] }); assert.fail("Should have thrown ERROR_INVALID_URL"); } catch (err) { assert.isTrue((err as any).message.startsWith("Invalid URL")); diff --git a/sdk/web-pubsub/web-pubsub-express/test/disconnected.spec.ts b/sdk/web-pubsub/web-pubsub-express/test/disconnected.spec.ts index a6d45a22426a..70dec0521a7b 100644 --- a/sdk/web-pubsub/web-pubsub-express/test/disconnected.spec.ts +++ b/sdk/web-pubsub/web-pubsub-express/test/disconnected.spec.ts @@ -15,6 +15,7 @@ function buildRequest( ): void { req.headers["webhook-request-origin"] = "xxx.webpubsub.azure.com"; req.headers["Content-Type"] = "application/json; charset=utf-8"; + req.headers["ce-awpsversion"] = "1.0"; req.headers["ce-specversion"] = "1.0"; req.headers["ce-type"] = "azure.webpubsub.user.disconnected"; req.headers["ce-source"] = `/hubs/${hub}/client/${connectionId}`; @@ -45,8 +46,8 @@ describe("Can handle disconnected event", function() { it("Should not handle the request if request is not cloud events", async function() { const endSpy = sinon.spy(res.end); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub1"); + const result = await dispatcher.handleRequest(req, res); assert.isFalse(result); assert.isTrue(endSpy.notCalled); }); @@ -55,8 +56,8 @@ describe("Can handle disconnected event", function() { const endSpy = sinon.spy(res.end); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub1"); + const result = await dispatcher.handleRequest(req, res); assert.isFalse(result); assert.isTrue(endSpy.notCalled); }); @@ -65,8 +66,8 @@ describe("Can handle disconnected event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub"); + const result = await dispatcher.handleRequest(req, res); assert.isTrue(result, "should handle"); assert.isTrue(endSpy.calledOnce, "should call once"); assert.equal(200, res.statusCode, "should be 200"); @@ -76,8 +77,8 @@ describe("Can handle disconnected event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], {}); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub", {}); + const result = await dispatcher.handleRequest(req, res); assert.isTrue(result, "should handle"); assert.isTrue(endSpy.calledOnce, "should call once"); assert.equal(200, res.statusCode, "should be 200"); @@ -87,12 +88,12 @@ describe("Can handle disconnected event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { onConnected: async (_) => { throw new Error(); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); diff --git a/sdk/web-pubsub/web-pubsub-express/test/user.spec.ts b/sdk/web-pubsub/web-pubsub-express/test/user.spec.ts index 80d78a552993..2e0fa2ffc9ed 100644 --- a/sdk/web-pubsub/web-pubsub-express/test/user.spec.ts +++ b/sdk/web-pubsub/web-pubsub-express/test/user.spec.ts @@ -15,6 +15,7 @@ function buildRequest( ): void { req.headers["webhook-request-origin"] = "xxx.webpubsub.azure.com"; req.headers["Content-Type"] = "application/json; charset=utf-8"; + req.headers["ce-awpsversion"] = "1.0"; req.headers["ce-specversion"] = "1.0"; req.headers["ce-type"] = "azure.webpubsub.user.connect"; req.headers["ce-source"] = `/hubs/${hub}/client/${connectionId}`; @@ -45,8 +46,8 @@ describe("Can handle user event", function() { it("Should not handle the request if request is not cloud events", async function() { const endSpy = sinon.spy(res.end); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub1"); + const result = await dispatcher.handleRequest(req, res); assert.isFalse(result); assert.isTrue(endSpy.notCalled); }); @@ -55,8 +56,8 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res.end); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub1", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub1"); + const result = await dispatcher.handleRequest(req, res); assert.isFalse(result); assert.isTrue(endSpy.notCalled); }); @@ -65,8 +66,8 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"]); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub"); + const result = await dispatcher.handleRequest(req, res); assert.isTrue(result, "should handle"); assert.isTrue(endSpy.calledOnce, "should call once"); assert.equal(200, res.statusCode, "should be 200"); @@ -76,8 +77,8 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], {}); - const result = await dispatcher.processRequest(req, res); + const dispatcher = new CloudEventsDispatcher("hub", {}); + const result = await dispatcher.handleRequest(req, res); assert.isTrue(result, "should handle"); assert.isTrue(endSpy.calledOnce, "should call once"); assert.equal(200, res.statusCode, "should be 200"); @@ -87,12 +88,12 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleUserEvent: async (_, response) => { response.fail(500); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -104,12 +105,12 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleUserEvent: async (_, response) => { response.success(); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -121,12 +122,12 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleUserEvent: async (_, response) => { response.success("a"); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -139,12 +140,12 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleUserEvent: async (_, response) => { response.success("a", "text"); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -157,12 +158,12 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleUserEvent: async (_, response) => { response.success("a", "json"); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); @@ -179,7 +180,7 @@ describe("Can handle user event", function() { const endSpy = sinon.spy(res, "end"); buildRequest(req, "hub", "conn1"); - const dispatcher = new CloudEventsDispatcher("hub", ["*"], { + const dispatcher = new CloudEventsDispatcher("hub", { handleUserEvent: async (_, response) => { response.setState("key1", "val1"); response.setState("key2", "val2"); @@ -188,7 +189,7 @@ describe("Can handle user event", function() { response.success(); } }); - const process = dispatcher.processRequest(req, res); + const process = dispatcher.handleRequest(req, res); mockBody(req, JSON.stringify({})); const result = await process; assert.isTrue(result, "should handle"); diff --git a/sdk/web-pubsub/web-pubsub-express/test/validate.spec.ts b/sdk/web-pubsub/web-pubsub-express/test/validate.spec.ts index becfaa546de9..dc38128682f2 100644 --- a/sdk/web-pubsub/web-pubsub-express/test/validate.spec.ts +++ b/sdk/web-pubsub/web-pubsub-express/test/validate.spec.ts @@ -10,30 +10,34 @@ describe("Abuse protection works", function() { it("Only requests with valid header will be processed", function() { const req = new IncomingMessage(new Socket()); const res = new ServerResponse(req); - const dispatcher = new CloudEventsDispatcher("hub", ["*"]); + const dispatcher = new CloudEventsDispatcher("hub"); - const result = dispatcher.processValidateRequest(req, res); + const result = dispatcher.handlePreflight(req, res); assert.isFalse(result); }); it("Support * in allowed endpoints", function() { const req = new IncomingMessage(new Socket()); + req.headers["ce-awpsversion"] = "1.0"; req.headers["webhook-request-origin"] = "a.com"; const res = new ServerResponse(req); - const dispatcher = new CloudEventsDispatcher("hub", ["*"]); + const dispatcher = new CloudEventsDispatcher("hub"); - const result = dispatcher.processValidateRequest(req, res); + const result = dispatcher.handlePreflight(req, res); assert.isTrue(result); assert.equal("*", res.getHeader("webhook-allowed-origin")); }); it("Support valid url in allowed endpoints", function() { const req = new IncomingMessage(new Socket()); + req.headers["ce-awpsversion"] = "1.0"; req.headers["webhook-request-origin"] = "a.com"; const res = new ServerResponse(req); - const dispatcher = new CloudEventsDispatcher("hub", ["*", "https://a.com/c"]); + const dispatcher = new CloudEventsDispatcher("hub", { + allowedEndpoints: ["*", "https://a.com/c"] + }); - const result = dispatcher.processValidateRequest(req, res); + const result = dispatcher.handlePreflight(req, res); assert.isTrue(result); assert.equal("*,a.com", res.getHeader("webhook-allowed-origin")); });