zudoku 0.43.2 → 0.44.0
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.
- package/dist/lib/authentication/components/CallbackHandler.js +5 -1
- package/dist/lib/authentication/components/CallbackHandler.js.map +1 -1
- package/dist/lib/authentication/providers/auth0.js +1 -1
- package/dist/lib/authentication/providers/auth0.js.map +1 -1
- package/dist/lib/authentication/providers/clerk.js +13 -5
- package/dist/lib/authentication/providers/clerk.js.map +1 -1
- package/dist/lib/authentication/providers/openid.d.ts +6 -9
- package/dist/lib/authentication/providers/openid.js +17 -29
- package/dist/lib/authentication/providers/openid.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/QueryParams.js +1 -1
- package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
- package/dist/lib/util/url.d.ts +4 -0
- package/dist/lib/util/url.js +13 -0
- package/dist/lib/util/url.js.map +1 -0
- package/dist/lib/util/url.test.d.ts +1 -0
- package/dist/lib/util/url.test.js +26 -0
- package/dist/lib/util/url.test.js.map +1 -0
- package/lib/{AuthenticationPlugin-BxoEZCSJ.js → AuthenticationPlugin-BlJsiGuX.js} +2 -2
- package/lib/{AuthenticationPlugin-BxoEZCSJ.js.map → AuthenticationPlugin-BlJsiGuX.js.map} +1 -1
- package/lib/{MdxPage-DUcuusMU.js → MdxPage-DlJaCSPf.js} +3 -3
- package/lib/{MdxPage-DUcuusMU.js.map → MdxPage-DlJaCSPf.js.map} +1 -1
- package/lib/{OasProvider-CjMm8pB7.js → OasProvider-DHPC9PnR.js} +2 -2
- package/lib/{OasProvider-CjMm8pB7.js.map → OasProvider-DHPC9PnR.js.map} +1 -1
- package/lib/{OperationList-BhJcPgGi.js → OperationList-C6Ky0zQa.js} +5 -5
- package/lib/{OperationList-BhJcPgGi.js.map → OperationList-C6Ky0zQa.js.map} +1 -1
- package/lib/{Pagination-BgQxwq5j.js → Pagination-C5Fi7z_v.js} +2 -2
- package/lib/{Pagination-BgQxwq5j.js.map → Pagination-C5Fi7z_v.js.map} +1 -1
- package/lib/{SchemaList-BexhT_Z0.js → SchemaList-Cu7rWQ_k.js} +3 -3
- package/lib/{SchemaList-BexhT_Z0.js.map → SchemaList-Cu7rWQ_k.js.map} +1 -1
- package/lib/{SchemaView-Dt_-u8rW.js → SchemaView-Ci_CnNlv.js} +2 -2
- package/lib/{SchemaView-Dt_-u8rW.js.map → SchemaView-Ci_CnNlv.js.map} +1 -1
- package/lib/{circular-BWEIet3w.js → circular-P9P1oxbQ.js} +2 -2
- package/lib/{circular-BWEIet3w.js.map → circular-P9P1oxbQ.js.map} +1 -1
- package/lib/{createServer-BQD3Eeqb.js → createServer-Iclzdx0h.js} +3 -3
- package/lib/{createServer-BQD3Eeqb.js.map → createServer-Iclzdx0h.js.map} +1 -1
- package/lib/{index-CFf9AN-y.js → index-C56xKbMM.js} +7 -7
- package/lib/{index-CFf9AN-y.js.map → index-C56xKbMM.js.map} +1 -1
- package/lib/{index-DGNSSXgR.js → index-CzUOM_vE.js} +3 -3
- package/lib/{index-DGNSSXgR.js.map → index-CzUOM_vE.js.map} +1 -1
- package/lib/zudoku.auth-auth0.js +7 -7
- package/lib/zudoku.auth-auth0.js.map +1 -1
- package/lib/zudoku.auth-clerk.js +26 -26
- package/lib/zudoku.auth-clerk.js.map +1 -1
- package/lib/zudoku.auth-openid.js +407 -405
- package/lib/zudoku.auth-openid.js.map +1 -1
- package/lib/zudoku.components.js +1 -1
- package/lib/zudoku.plugin-api-catalog.js +1 -1
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +1 -1
- package/package.json +1 -1
- package/src/lib/authentication/components/CallbackHandler.tsx +11 -1
- package/src/lib/authentication/providers/auth0.tsx +1 -1
- package/src/lib/authentication/providers/clerk.tsx +14 -10
- package/src/lib/authentication/providers/openid.tsx +24 -42
- package/src/lib/plugins/openapi/playground/QueryParams.tsx +1 -1
- package/src/lib/util/url.test.ts +51 -0
- package/src/lib/util/url.ts +18 -0
package/lib/zudoku.components.js
CHANGED
|
@@ -3,7 +3,7 @@ import "./index-DwT-v3zK.js";
|
|
|
3
3
|
import "./chunk-BAXFHI7N-BLTsN6tl.js";
|
|
4
4
|
import "./hook-8GM2HXNM.js";
|
|
5
5
|
import "./SlotletProvider-wWbHYqWf.js";
|
|
6
|
-
import { e as d, f as k, n as l, B as S, C as h, j as B, l as c, H as E, d as H, L, M, g as R, R as Z, S as f, k as g, i as y, Z as A,
|
|
6
|
+
import { e as d, f as k, n as l, B as S, C as h, j as B, l as c, H as E, d as H, L, M, g as R, R as Z, S as f, k as g, i as y, Z as A, b, h as j, c as v, m as w, a as x } from "./index-CzUOM_vE.js";
|
|
7
7
|
import "./ui/Button.js";
|
|
8
8
|
import "./ui/Callout.js";
|
|
9
9
|
import "./ClientOnly-E7hGysn1.js";
|
|
@@ -3,7 +3,7 @@ import { s as h } from "./index-LNp6rxyU.js";
|
|
|
3
3
|
import { d as b, m as x } from "./chunk-BAXFHI7N-BLTsN6tl.js";
|
|
4
4
|
import { u as j, d as y, f as p } from "./hook-8GM2HXNM.js";
|
|
5
5
|
import { H as v } from "./RouteGuard-D2gX29iI.js";
|
|
6
|
-
import { L as N } from "./index-
|
|
6
|
+
import { L as N } from "./index-CzUOM_vE.js";
|
|
7
7
|
import { H as S, M as w } from "./Markdown-DvdVn1O7.js";
|
|
8
8
|
const H = ({
|
|
9
9
|
items: r,
|
|
@@ -53,7 +53,7 @@ const P = (e) => ({
|
|
|
53
53
|
const u = {
|
|
54
54
|
path: r,
|
|
55
55
|
lazy: async () => {
|
|
56
|
-
const { MdxPage: p } = await import("./MdxPage-
|
|
56
|
+
const { MdxPage: p } = await import("./MdxPage-DlJaCSPf.js"), { default: f, ...l } = await i();
|
|
57
57
|
return {
|
|
58
58
|
element: /* @__PURE__ */ d.jsx(
|
|
59
59
|
p,
|
|
@@ -3,7 +3,7 @@ import "lucide-react";
|
|
|
3
3
|
import "./chunk-BAXFHI7N-BLTsN6tl.js";
|
|
4
4
|
import "./hook-8GM2HXNM.js";
|
|
5
5
|
import "./ui/Button.js";
|
|
6
|
-
import { z as a, U as s, A } from "./index-
|
|
6
|
+
import { z as a, U as s, A } from "./index-C56xKbMM.js";
|
|
7
7
|
export {
|
|
8
8
|
a as GetSidebarOperationsQuery,
|
|
9
9
|
s as UNTAGGED_PATH,
|
package/package.json
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
|
2
2
|
import { Navigate } from "react-router";
|
|
3
|
+
import { useZudoku } from "zudoku/components";
|
|
3
4
|
import { ZudokuError } from "../../util/invariant.js";
|
|
5
|
+
import { joinUrl } from "../../util/joinUrl.js";
|
|
6
|
+
import { normalizeRedirectUrl } from "../../util/url.js";
|
|
4
7
|
|
|
5
8
|
export function CallbackHandler({
|
|
6
9
|
handleCallback,
|
|
7
10
|
}: {
|
|
8
11
|
handleCallback: () => Promise<string>;
|
|
9
12
|
}) {
|
|
13
|
+
const { options } = useZudoku();
|
|
10
14
|
const executeCallback = useSuspenseQuery({
|
|
11
15
|
retry: false,
|
|
12
16
|
queryKey: ["oauth-callback"],
|
|
13
17
|
queryFn: async () => {
|
|
14
18
|
try {
|
|
15
|
-
return
|
|
19
|
+
return joinUrl(
|
|
20
|
+
normalizeRedirectUrl(
|
|
21
|
+
await handleCallback(),
|
|
22
|
+
window.location.origin,
|
|
23
|
+
options.basePath,
|
|
24
|
+
),
|
|
25
|
+
);
|
|
16
26
|
} catch (error) {
|
|
17
27
|
throw new ZudokuError("Could not validate user", {
|
|
18
28
|
cause: error,
|
|
@@ -37,7 +37,7 @@ class Auth0AuthenticationProvider extends OpenIDAuthenticationProvider {
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
const redirectUrl = new URL(window.location.origin);
|
|
40
|
-
redirectUrl.pathname = this.
|
|
40
|
+
redirectUrl.pathname = this.redirectToAfterSignOut;
|
|
41
41
|
|
|
42
42
|
// SEE: https://auth0.com/docs/authenticate/login/logout/log-users-out-of-auth0
|
|
43
43
|
// For Auth0 tenants created on or after 14 November 2023, RP-Initiated
|
|
@@ -50,8 +50,8 @@ const clerkAuth: AuthenticationProviderInitializer<
|
|
|
50
50
|
> = ({
|
|
51
51
|
clerkPubKey,
|
|
52
52
|
redirectToAfterSignOut = "/",
|
|
53
|
-
redirectToAfterSignUp
|
|
54
|
-
redirectToAfterSignIn
|
|
53
|
+
redirectToAfterSignUp,
|
|
54
|
+
redirectToAfterSignIn,
|
|
55
55
|
}) => {
|
|
56
56
|
let clerkApi: Clerk | undefined;
|
|
57
57
|
const ensureLoaded = (async () => {
|
|
@@ -129,19 +129,23 @@ const clerkAuth: AuthenticationProviderInitializer<
|
|
|
129
129
|
signIn: async ({ redirectTo }: { redirectTo?: string } = {}) => {
|
|
130
130
|
await ensureLoaded;
|
|
131
131
|
await clerkApi?.redirectToSignIn({
|
|
132
|
-
signInForceRedirectUrl:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
signInForceRedirectUrl: redirectToAfterSignIn
|
|
133
|
+
? window.location.origin + redirectToAfterSignIn
|
|
134
|
+
: redirectTo,
|
|
135
|
+
signUpForceRedirectUrl: redirectToAfterSignUp
|
|
136
|
+
? window.location.origin + redirectToAfterSignUp
|
|
137
|
+
: redirectTo,
|
|
136
138
|
});
|
|
137
139
|
},
|
|
138
140
|
signUp: async ({ redirectTo }: { redirectTo?: string } = {}) => {
|
|
139
141
|
await ensureLoaded;
|
|
140
142
|
await clerkApi?.redirectToSignUp({
|
|
141
|
-
signInForceRedirectUrl:
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
signInForceRedirectUrl: redirectToAfterSignIn
|
|
144
|
+
? window.location.origin + redirectToAfterSignIn
|
|
145
|
+
: redirectTo,
|
|
146
|
+
signUpForceRedirectUrl: redirectToAfterSignUp
|
|
147
|
+
? window.location.origin + redirectToAfterSignUp
|
|
148
|
+
: redirectTo,
|
|
145
149
|
});
|
|
146
150
|
},
|
|
147
151
|
getAuthenticationPlugin() {
|
|
@@ -23,18 +23,17 @@ export interface OpenIdProviderData {
|
|
|
23
23
|
tokenType: string;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
export const OPENID_CALLBACK_PATH = "/oauth/callback";
|
|
27
|
+
|
|
26
28
|
class OpenIdAuthPlugin extends AuthenticationPlugin {
|
|
27
|
-
constructor(
|
|
28
|
-
private callbackUrlPath: string,
|
|
29
|
-
private handleCallback: () => Promise<string>,
|
|
30
|
-
) {
|
|
29
|
+
constructor(private handleCallback: () => Promise<string>) {
|
|
31
30
|
super();
|
|
32
31
|
}
|
|
33
32
|
getRoutes() {
|
|
34
33
|
return [
|
|
35
34
|
...super.getRoutes(),
|
|
36
35
|
{
|
|
37
|
-
path:
|
|
36
|
+
path: OPENID_CALLBACK_PATH,
|
|
38
37
|
element: (
|
|
39
38
|
<ClientOnly>
|
|
40
39
|
<CallbackHandler handleCallback={this.handleCallback} />
|
|
@@ -48,29 +47,28 @@ class OpenIdAuthPlugin extends AuthenticationPlugin {
|
|
|
48
47
|
export class OpenIDAuthenticationProvider implements AuthenticationProvider {
|
|
49
48
|
protected client: oauth.Client;
|
|
50
49
|
protected issuer: string;
|
|
51
|
-
|
|
52
50
|
protected authorizationServer: oauth.AuthorizationServer | undefined;
|
|
53
51
|
|
|
54
|
-
protected
|
|
55
|
-
|
|
56
|
-
protected logoutRedirectUrlPath: string;
|
|
52
|
+
protected callbackUrlPath: string;
|
|
53
|
+
|
|
57
54
|
protected onAuthorizationUrl?: (
|
|
58
55
|
authorizationUrl: URL,
|
|
59
56
|
options: { isSignIn: boolean; isSignUp: boolean },
|
|
60
57
|
) => void;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
|
|
59
|
+
protected readonly redirectToAfterSignUp: string | undefined;
|
|
60
|
+
protected readonly redirectToAfterSignIn: string | undefined;
|
|
61
|
+
protected readonly redirectToAfterSignOut: string;
|
|
64
62
|
private readonly audience?: string;
|
|
65
63
|
private readonly scopes: string[];
|
|
66
|
-
|
|
64
|
+
|
|
67
65
|
constructor({
|
|
68
66
|
issuer,
|
|
69
67
|
audience,
|
|
70
68
|
clientId,
|
|
71
69
|
redirectToAfterSignUp,
|
|
72
70
|
redirectToAfterSignIn,
|
|
73
|
-
redirectToAfterSignOut,
|
|
71
|
+
redirectToAfterSignOut = "/",
|
|
74
72
|
basePath,
|
|
75
73
|
scopes,
|
|
76
74
|
}: OpenIDAuthenticationConfig) {
|
|
@@ -80,19 +78,13 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
|
|
|
80
78
|
};
|
|
81
79
|
this.audience = audience;
|
|
82
80
|
this.issuer = issuer;
|
|
83
|
-
|
|
84
|
-
this.
|
|
85
|
-
basePath,
|
|
86
|
-
this.relativeCallbackUrlPath,
|
|
87
|
-
);
|
|
81
|
+
// This is the callback URL for the OAuth provider. So it needs the base path.
|
|
82
|
+
this.callbackUrlPath = joinUrl(basePath, OPENID_CALLBACK_PATH);
|
|
88
83
|
this.scopes = scopes ?? ["openid", "profile", "email"];
|
|
89
84
|
|
|
90
|
-
this.
|
|
91
|
-
|
|
92
|
-
this.
|
|
93
|
-
this.redirectToAfterSignUp = redirectToAfterSignUp ?? this.root;
|
|
94
|
-
this.redirectToAfterSignIn = redirectToAfterSignIn ?? this.root;
|
|
95
|
-
this.redirectToAfterSignOut = redirectToAfterSignOut ?? this.root;
|
|
85
|
+
this.redirectToAfterSignUp = redirectToAfterSignUp;
|
|
86
|
+
this.redirectToAfterSignIn = redirectToAfterSignIn;
|
|
87
|
+
this.redirectToAfterSignOut = redirectToAfterSignOut;
|
|
96
88
|
}
|
|
97
89
|
|
|
98
90
|
protected async getAuthServer() {
|
|
@@ -138,14 +130,14 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
|
|
|
138
130
|
|
|
139
131
|
async signUp({ redirectTo }: { redirectTo?: string } = {}) {
|
|
140
132
|
return this.authorize({
|
|
141
|
-
redirectTo: redirectTo ??
|
|
133
|
+
redirectTo: this.redirectToAfterSignUp ?? redirectTo ?? "/",
|
|
142
134
|
isSignUp: true,
|
|
143
135
|
});
|
|
144
136
|
}
|
|
145
137
|
|
|
146
138
|
async signIn({ redirectTo }: { redirectTo?: string } = {}) {
|
|
147
139
|
return this.authorize({
|
|
148
|
-
redirectTo: redirectTo ??
|
|
140
|
+
redirectTo: this.redirectToAfterSignIn ?? redirectTo ?? "/",
|
|
149
141
|
});
|
|
150
142
|
}
|
|
151
143
|
|
|
@@ -178,17 +170,10 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
|
|
|
178
170
|
authorizationServer.authorization_endpoint,
|
|
179
171
|
);
|
|
180
172
|
|
|
181
|
-
|
|
182
|
-
? this.root !== "/" &&
|
|
183
|
-
redirectTo.startsWith(window.location.origin + this.root)
|
|
184
|
-
? redirectTo.slice(window.location.origin.length + this.root.length)
|
|
185
|
-
: redirectTo.slice(window.location.origin.length)
|
|
186
|
-
: redirectTo;
|
|
187
|
-
|
|
188
|
-
sessionStorage.setItem("redirect-to", finalRedirect);
|
|
173
|
+
sessionStorage.setItem("redirect-to", redirectTo);
|
|
189
174
|
|
|
190
175
|
const redirectUrl = new URL(window.location.origin);
|
|
191
|
-
redirectUrl.pathname = this.
|
|
176
|
+
redirectUrl.pathname = this.callbackUrlPath;
|
|
192
177
|
redirectUrl.search = "";
|
|
193
178
|
|
|
194
179
|
authorizationUrl.searchParams.set("client_id", this.client.client_id);
|
|
@@ -282,7 +267,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
|
|
|
282
267
|
const redirectUrl = new URL(
|
|
283
268
|
window.location.origin + this.redirectToAfterSignOut,
|
|
284
269
|
);
|
|
285
|
-
redirectUrl.pathname = this.
|
|
270
|
+
redirectUrl.pathname = this.callbackUrlPath;
|
|
286
271
|
|
|
287
272
|
let logoutUrl: URL;
|
|
288
273
|
// The endSessionEndpoint is set, the IdP supports some form of logout,
|
|
@@ -338,7 +323,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
|
|
|
338
323
|
}
|
|
339
324
|
|
|
340
325
|
const redirectUrl = new URL(url);
|
|
341
|
-
redirectUrl.pathname = this.
|
|
326
|
+
redirectUrl.pathname = this.callbackUrlPath;
|
|
342
327
|
redirectUrl.search = "";
|
|
343
328
|
|
|
344
329
|
const response = await oauth.authorizationCodeGrantRequest(
|
|
@@ -396,10 +381,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
|
|
|
396
381
|
getAuthenticationPlugin() {
|
|
397
382
|
// TODO: This API is a bit messy, we need to refactor auth plugins/providers
|
|
398
383
|
// to remove the extra layers of abstraction.
|
|
399
|
-
return new OpenIdAuthPlugin(
|
|
400
|
-
this.relativeCallbackUrlPath,
|
|
401
|
-
this.handleCallback,
|
|
402
|
-
);
|
|
384
|
+
return new OpenIdAuthPlugin(this.handleCallback);
|
|
403
385
|
}
|
|
404
386
|
}
|
|
405
387
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { normalizeRedirectUrl } from "./url.js";
|
|
3
|
+
|
|
4
|
+
describe("normalizeRedirectUrl", () => {
|
|
5
|
+
const mockOrigin = "https://example.com";
|
|
6
|
+
|
|
7
|
+
it("should return original URL if it doesn't start with origin", () => {
|
|
8
|
+
const result = normalizeRedirectUrl(
|
|
9
|
+
"https://other.com/path",
|
|
10
|
+
mockOrigin,
|
|
11
|
+
"/",
|
|
12
|
+
);
|
|
13
|
+
expect(result).toBe("https://other.com/path");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("should remove origin when root is /", () => {
|
|
17
|
+
const result = normalizeRedirectUrl(
|
|
18
|
+
"https://example.com/some/path",
|
|
19
|
+
mockOrigin,
|
|
20
|
+
"/",
|
|
21
|
+
);
|
|
22
|
+
expect(result).toBe("/some/path");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should remove origin and root path when root is not /", () => {
|
|
26
|
+
const result = normalizeRedirectUrl(
|
|
27
|
+
"https://example.com/docs/some/path",
|
|
28
|
+
mockOrigin,
|
|
29
|
+
"/docs",
|
|
30
|
+
);
|
|
31
|
+
expect(result).toBe("/some/path");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should only remove origin when URL doesn't match root path", () => {
|
|
35
|
+
const result = normalizeRedirectUrl(
|
|
36
|
+
"https://example.com/other/path",
|
|
37
|
+
mockOrigin,
|
|
38
|
+
"/docs",
|
|
39
|
+
);
|
|
40
|
+
expect(result).toBe("/other/path");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should handle empty root path", () => {
|
|
44
|
+
const result = normalizeRedirectUrl(
|
|
45
|
+
"https://example.com/path",
|
|
46
|
+
mockOrigin,
|
|
47
|
+
"",
|
|
48
|
+
);
|
|
49
|
+
expect(result).toBe("/path");
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes a redirect URL by removing the origin and optionally the root path
|
|
3
|
+
*/
|
|
4
|
+
export function normalizeRedirectUrl(
|
|
5
|
+
redirectTo: string,
|
|
6
|
+
origin: string,
|
|
7
|
+
basePath: string = "/",
|
|
8
|
+
): string {
|
|
9
|
+
if (!redirectTo.startsWith(origin)) {
|
|
10
|
+
return redirectTo;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (basePath !== "/" && redirectTo.startsWith(origin + basePath)) {
|
|
14
|
+
return redirectTo.slice(origin.length + basePath.length);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return redirectTo.slice(origin.length);
|
|
18
|
+
}
|