@rapidmx/meet-plugin 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -40,9 +40,11 @@
|
|
|
40
40
|
* request carries no `Authorization` header at all and instead relies on `fetch()`'s own default same-origin
|
|
41
41
|
* credentials mode, which already attaches the browser's real `jwt` cookie to a same-origin request with zero
|
|
42
42
|
* extra code - `JWTStrategy.getAuthToken()`'s cookie fallback authenticates it exactly as it would any other
|
|
43
|
-
* same-origin authenticated call.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* same-origin authenticated call. Either way `send()` also attaches the CSRF double-submit header
|
|
44
|
+
* (`withCsrfHeader()`) - required server-side only for the cookie case, but harmless to send for the bearer one
|
|
45
|
+
* too - see `send()`'s own doc comment. Fire-and-forget either way, matching every other push publish in this
|
|
46
|
+
* codebase - a failed send is logged, never thrown, since a caller (`MeshConnectionManager`) has no meaningful
|
|
47
|
+
* per-message retry of its own.
|
|
46
48
|
* - An incoming meeting message arrives wrapped `{ type: "MESSAGE", channel, data: <the posted body> }` - this
|
|
47
49
|
* client unwraps it and delivers `data` (expected to be a `SignalMessage`) to `onMessage()` listeners.
|
|
48
50
|
*
|
|
@@ -63,7 +65,7 @@
|
|
|
63
65
|
* absent, as described above - the browser's real cookie was always going to win that write anyway, so the
|
|
64
66
|
* correct behavior is to not fight it and let it authenticate normally instead.
|
|
65
67
|
*/
|
|
66
|
-
import { apiOrigin } from "@rapidmx/web-client/lib/util/api.js";
|
|
68
|
+
import { apiOrigin, withCsrfHeader } from "@rapidmx/web-client/lib/util/api.js";
|
|
67
69
|
import { pushUrl } from "@rapidmx/web-client/lib/mail/pushClient.js";
|
|
68
70
|
import type { SignalMessage, SignalingChannel } from "../webrtc/types.js";
|
|
69
71
|
|
|
@@ -174,7 +176,16 @@ export class GuestSignalingClient implements SignalingChannel {
|
|
|
174
176
|
|
|
175
177
|
/** Publishes over `POST /push/:id`, with `token` as a bearer credential when present - see this module's doc
|
|
176
178
|
* comment on why this, unlike subscribing, needs no cookie workaround at all, and on the omitted-`token` case
|
|
177
|
-
* (an already-authenticated real caller), which relies on the browser's own real `jwt` cookie instead
|
|
179
|
+
* (an already-authenticated real caller), which relies on the browser's own real `jwt` cookie instead - and,
|
|
180
|
+
* because that's a *cookie*-authenticated request, also needs the matching CSRF header
|
|
181
|
+
* (`@rapidmx/web-client`'s `withCsrfHeader()`, the same double-submit echo `apiFetch()` applies to every other
|
|
182
|
+
* mutating call this server answers): without it, `RouteUtils.checkCsrf()` refuses the request with 403
|
|
183
|
+
* `"This request is missing a valid CSRF token."` before it ever reaches `BasePushRoute.send()`'s own ACL
|
|
184
|
+
* check - every `hello`/offer/answer/ICE candidate/`bye` a participant on that path sends 403s and is
|
|
185
|
+
* silently dropped (`send()` is fire-and-forget), which looks exactly like "stuck connecting, then no audio or
|
|
186
|
+
* video" from everyone else's side. `withCsrfHeader()` is harmless to also add on the bearer-token (guest)
|
|
187
|
+
* branch - the server only enforces the check for `req.auth.source === "cookie"` - so it's applied
|
|
188
|
+
* unconditionally here rather than only for the cookie case.
|
|
178
189
|
* Fire-and-forget: a failure is swallowed (there is nothing a signaling message's own sender can usefully do
|
|
179
190
|
* about a dropped publish beyond what the mesh's own `hello` re-announcement/renegotiation already tolerates -
|
|
180
191
|
* see `MeshConnectionManager`'s doc comment on fire-and-forget delivery). */
|
|
@@ -190,7 +201,7 @@ export class GuestSignalingClient implements SignalingChannel {
|
|
|
190
201
|
}
|
|
191
202
|
void fetchImpl(`${origin}/push/${encodeURIComponent(this.options.channel)}`, {
|
|
192
203
|
method: "POST",
|
|
193
|
-
headers,
|
|
204
|
+
headers: withCsrfHeader(headers, "POST"),
|
|
194
205
|
body: JSON.stringify(message),
|
|
195
206
|
// Only a `bye` needs to survive the page unloading - every other message is sent while the page (and
|
|
196
207
|
// the rest of this call's signaling) is very much alive. `keepalive` is a real-world liability to set
|
|
@@ -60,7 +60,16 @@ export declare class GuestSignalingClient implements SignalingChannel {
|
|
|
60
60
|
onMessage(handler: (message: SignalMessage) => void): () => void;
|
|
61
61
|
/** Publishes over `POST /push/:id`, with `token` as a bearer credential when present - see this module's doc
|
|
62
62
|
* comment on why this, unlike subscribing, needs no cookie workaround at all, and on the omitted-`token` case
|
|
63
|
-
* (an already-authenticated real caller), which relies on the browser's own real `jwt` cookie instead
|
|
63
|
+
* (an already-authenticated real caller), which relies on the browser's own real `jwt` cookie instead - and,
|
|
64
|
+
* because that's a *cookie*-authenticated request, also needs the matching CSRF header
|
|
65
|
+
* (`@rapidmx/web-client`'s `withCsrfHeader()`, the same double-submit echo `apiFetch()` applies to every other
|
|
66
|
+
* mutating call this server answers): without it, `RouteUtils.checkCsrf()` refuses the request with 403
|
|
67
|
+
* `"This request is missing a valid CSRF token."` before it ever reaches `BasePushRoute.send()`'s own ACL
|
|
68
|
+
* check - every `hello`/offer/answer/ICE candidate/`bye` a participant on that path sends 403s and is
|
|
69
|
+
* silently dropped (`send()` is fire-and-forget), which looks exactly like "stuck connecting, then no audio or
|
|
70
|
+
* video" from everyone else's side. `withCsrfHeader()` is harmless to also add on the bearer-token (guest)
|
|
71
|
+
* branch - the server only enforces the check for `req.auth.source === "cookie"` - so it's applied
|
|
72
|
+
* unconditionally here rather than only for the cookie case.
|
|
64
73
|
* Fire-and-forget: a failure is swallowed (there is nothing a signaling message's own sender can usefully do
|
|
65
74
|
* about a dropped publish beyond what the mesh's own `hello` re-announcement/renegotiation already tolerates -
|
|
66
75
|
* see `MeshConnectionManager`'s doc comment on fire-and-forget delivery). */
|
|
@@ -40,9 +40,11 @@
|
|
|
40
40
|
* request carries no `Authorization` header at all and instead relies on `fetch()`'s own default same-origin
|
|
41
41
|
* credentials mode, which already attaches the browser's real `jwt` cookie to a same-origin request with zero
|
|
42
42
|
* extra code - `JWTStrategy.getAuthToken()`'s cookie fallback authenticates it exactly as it would any other
|
|
43
|
-
* same-origin authenticated call.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* same-origin authenticated call. Either way `send()` also attaches the CSRF double-submit header
|
|
44
|
+
* (`withCsrfHeader()`) - required server-side only for the cookie case, but harmless to send for the bearer one
|
|
45
|
+
* too - see `send()`'s own doc comment. Fire-and-forget either way, matching every other push publish in this
|
|
46
|
+
* codebase - a failed send is logged, never thrown, since a caller (`MeshConnectionManager`) has no meaningful
|
|
47
|
+
* per-message retry of its own.
|
|
46
48
|
* - An incoming meeting message arrives wrapped `{ type: "MESSAGE", channel, data: <the posted body> }` - this
|
|
47
49
|
* client unwraps it and delivers `data` (expected to be a `SignalMessage`) to `onMessage()` listeners.
|
|
48
50
|
*
|
|
@@ -63,7 +65,7 @@
|
|
|
63
65
|
* absent, as described above - the browser's real cookie was always going to win that write anyway, so the
|
|
64
66
|
* correct behavior is to not fight it and let it authenticate normally instead.
|
|
65
67
|
*/
|
|
66
|
-
import { apiOrigin } from "@rapidmx/web-client/lib/util/api.js";
|
|
68
|
+
import { apiOrigin, withCsrfHeader } from "@rapidmx/web-client/lib/util/api.js";
|
|
67
69
|
import { pushUrl } from "@rapidmx/web-client/lib/mail/pushClient.js";
|
|
68
70
|
const SOCKET_OPEN = 1;
|
|
69
71
|
function defaultSocketFactory() {
|
|
@@ -132,7 +134,16 @@ export class GuestSignalingClient {
|
|
|
132
134
|
}
|
|
133
135
|
/** Publishes over `POST /push/:id`, with `token` as a bearer credential when present - see this module's doc
|
|
134
136
|
* comment on why this, unlike subscribing, needs no cookie workaround at all, and on the omitted-`token` case
|
|
135
|
-
* (an already-authenticated real caller), which relies on the browser's own real `jwt` cookie instead
|
|
137
|
+
* (an already-authenticated real caller), which relies on the browser's own real `jwt` cookie instead - and,
|
|
138
|
+
* because that's a *cookie*-authenticated request, also needs the matching CSRF header
|
|
139
|
+
* (`@rapidmx/web-client`'s `withCsrfHeader()`, the same double-submit echo `apiFetch()` applies to every other
|
|
140
|
+
* mutating call this server answers): without it, `RouteUtils.checkCsrf()` refuses the request with 403
|
|
141
|
+
* `"This request is missing a valid CSRF token."` before it ever reaches `BasePushRoute.send()`'s own ACL
|
|
142
|
+
* check - every `hello`/offer/answer/ICE candidate/`bye` a participant on that path sends 403s and is
|
|
143
|
+
* silently dropped (`send()` is fire-and-forget), which looks exactly like "stuck connecting, then no audio or
|
|
144
|
+
* video" from everyone else's side. `withCsrfHeader()` is harmless to also add on the bearer-token (guest)
|
|
145
|
+
* branch - the server only enforces the check for `req.auth.source === "cookie"` - so it's applied
|
|
146
|
+
* unconditionally here rather than only for the cookie case.
|
|
136
147
|
* Fire-and-forget: a failure is swallowed (there is nothing a signaling message's own sender can usefully do
|
|
137
148
|
* about a dropped publish beyond what the mesh's own `hello` re-announcement/renegotiation already tolerates -
|
|
138
149
|
* see `MeshConnectionManager`'s doc comment on fire-and-forget delivery). */
|
|
@@ -148,7 +159,7 @@ export class GuestSignalingClient {
|
|
|
148
159
|
}
|
|
149
160
|
void fetchImpl(`${origin}/push/${encodeURIComponent(this.options.channel)}`, {
|
|
150
161
|
method: "POST",
|
|
151
|
-
headers,
|
|
162
|
+
headers: withCsrfHeader(headers, "POST"),
|
|
152
163
|
body: JSON.stringify(message),
|
|
153
164
|
// Only a `bye` needs to survive the page unloading - every other message is sent while the page (and
|
|
154
165
|
// the rest of this call's signaling) is very much alive. `keepalive` is a real-world liability to set
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rapidmx/meet-plugin",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "RapidMX plugin that provides WebRTC video conferencing, joinable from a calendar invite or a shared link.",
|
|
5
5
|
"repository": "https://github.com/rapidmx/meet-plugin.git",
|
|
6
6
|
"author": "RapidREST <rapidrests@gmail.com>",
|