Skip to content

Commit e0efa2c

Browse files
authored
Remove space code from VA integrations (#568)
* Remove space code from VA integrations * Add changeset * prettier fix * review * format * Add target
1 parent bd3f782 commit e0efa2c

15 files changed

+303
-331
lines changed

.changeset/thick-dodos-film.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@gitbook/integration-va-auth0': patch
3+
'@gitbook/integration-va-azure': patch
4+
'@gitbook/integration-cognito': patch
5+
'@gitbook/integration-va-okta': patch
6+
'@gitbook/integration-oidc': patch
7+
---
8+
9+
Remove space code from VA integrations

integrations/cognito/gitbook-manifest.yaml

-5
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@ description: Control who has access to your published documentation with AWS Cog
88
visibility: public
99
script: ./src/index.tsx
1010
scopes:
11-
- space:metadata:read
12-
- space:visitor:auth
1311
- site:metadata:read
1412
- site:visitor:auth
15-
- space:content:read
1613
organization: gitbook
1714
summary: |
1815
# Overview
@@ -28,8 +25,6 @@ summary: |
2825
categories:
2926
- visitor-auth
3027
configurations:
31-
space:
32-
componentId: config
3328
site:
3429
componentId: config
3530
target: site

integrations/cognito/src/index.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { sign } from '@tsndr/cloudflare-worker-jwt';
22
import { Router } from 'itty-router';
33

4-
import { IntegrationInstallationConfiguration } from '@gitbook/api';
4+
import {
5+
FetchVisitorAuthenticationEvent,
6+
IntegrationInstallationConfiguration,
7+
} from '@gitbook/api';
58
import {
69
createIntegration,
710
FetchEventCallback,
@@ -317,7 +320,10 @@ const handleFetchEvent: FetchEventCallback<CognitoRuntimeContext> = async (reque
317320
export default createIntegration({
318321
fetch: handleFetchEvent,
319322
components: [configBlock],
320-
fetch_visitor_authentication: async (event, context) => {
323+
fetch_visitor_authentication: async (
324+
event: FetchVisitorAuthenticationEvent,
325+
context: CognitoRuntimeContext,
326+
) => {
321327
const { environment } = context;
322328
const siteInstallation = assertInstallation(environment);
323329

integrations/oidc/gitbook-manifest.yaml

+1-6
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,8 @@ description: Control who has access to your published documentation with your au
77
visibility: public
88
script: ./src/index.tsx
99
scopes:
10-
- space:metadata:read
11-
- space:visitor:auth
1210
- site:metadata:read
1311
- site:visitor:auth
14-
- space:content:read
1512
organization: gitbook
1613
summary: |
1714
# Overview
@@ -27,8 +24,6 @@ summary: |
2724
categories:
2825
- visitor-auth
2926
configurations:
30-
space:
31-
componentId: config
3227
site:
3328
componentId: config
34-
target: all
29+
target: site

integrations/oidc/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@gitbook/tsconfig": "workspace:*"
1414
},
1515
"scripts": {
16+
"typecheck": "tsc --noEmit",
1617
"publish-integrations-staging": "gitbook publish .",
1718
"check": "gitbook check",
1819
"publish-integrations": "gitbook publish ."

integrations/oidc/src/index.tsx

+80-85
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,31 @@ import {
99
RuntimeContext,
1010
RuntimeEnvironment,
1111
createComponent,
12+
ExposableError,
1213
} from '@gitbook/runtime';
1314

1415
const logger = Logger('oidc.visitor-auth');
1516

16-
type OIDCRuntimeEnvironment = RuntimeEnvironment<{}, OIDCSiteOrSpaceInstallationConfiguration>;
17+
type OIDCRuntimeEnvironment = RuntimeEnvironment<{}, OIDCSiteInstallationConfiguration>;
1718

1819
type OIDCRuntimeContext = RuntimeContext<OIDCRuntimeEnvironment>;
1920

20-
type OIDCSiteOrSpaceInstallationConfiguration = {
21+
type OIDCSiteInstallationConfiguration = {
2122
client_id?: string;
2223
authorization_endpoint?: string;
2324
access_token_endpoint?: string;
2425
client_secret?: string;
2526
scope?: string;
2627
};
2728

28-
type OIDCState = OIDCSiteOrSpaceInstallationConfiguration;
29+
type OIDCState = OIDCSiteInstallationConfiguration;
2930

3031
type OIDCProps = {
3132
installation: {
3233
configuration?: IntegrationInstallationConfiguration;
3334
};
34-
spaceInstallation: {
35-
configuration?: OIDCSiteOrSpaceInstallationConfiguration;
36-
};
3735
siteInstallation: {
38-
configuration?: OIDCSiteOrSpaceInstallationConfiguration;
36+
configuration?: OIDCSiteInstallationConfiguration;
3937
};
4038
};
4139

@@ -55,64 +53,50 @@ const getDomainWithHttps = (url: string): string => {
5553
const configBlock = createComponent<OIDCProps, OIDCState, OIDCAction, OIDCRuntimeContext>({
5654
componentId: 'config',
5755
initialState: (props) => {
58-
const siteOrSpaceInstallation = props.siteInstallation ?? props.spaceInstallation;
56+
const siteInstallation = props.siteInstallation;
5957
return {
60-
client_id: siteOrSpaceInstallation.configuration?.client_id?.toString() || '',
61-
authorization_endpoint:
62-
siteOrSpaceInstallation.configuration?.authorization_endpoint?.toString() || '',
63-
access_token_endpoint:
64-
siteOrSpaceInstallation.configuration?.access_token_endpoint?.toString() || '',
65-
client_secret: siteOrSpaceInstallation.configuration?.client_secret?.toString() || '',
66-
scope: siteOrSpaceInstallation.configuration?.scope?.toString() || '',
58+
client_id: siteInstallation.configuration?.client_id || '',
59+
authorization_endpoint: siteInstallation.configuration?.authorization_endpoint || '',
60+
access_token_endpoint: siteInstallation.configuration?.access_token_endpoint || '',
61+
client_secret: siteInstallation.configuration?.client_secret || '',
62+
scope: siteInstallation.configuration?.scope || '',
6763
};
6864
},
6965
action: async (element, action, context) => {
7066
switch (action.action) {
7167
case 'save.config':
7268
const { api, environment } = context;
73-
const siteOrSpaceInstallation =
74-
environment.siteInstallation ?? environment.spaceInstallation;
69+
70+
const siteInstallation = assertSiteInstallation(environment);
7571

7672
const configurationBody = {
77-
...siteOrSpaceInstallation.configuration,
73+
...siteInstallation.configuration,
7874
client_id: element.state.client_id,
7975
client_secret: element.state.client_secret,
8076
authorization_endpoint: getDomainWithHttps(
81-
element.state.authorization_endpoint,
77+
element.state.authorization_endpoint ?? '',
78+
),
79+
access_token_endpoint: getDomainWithHttps(
80+
element.state.access_token_endpoint ?? '',
8281
),
83-
access_token_endpoint: getDomainWithHttps(element.state.access_token_endpoint),
8482
scope: element.state.scope,
8583
};
86-
if ('site' in siteOrSpaceInstallation) {
87-
await api.integrations.updateIntegrationSiteInstallation(
88-
siteOrSpaceInstallation.integration,
89-
siteOrSpaceInstallation.installation,
90-
siteOrSpaceInstallation.site,
91-
{
92-
configuration: {
93-
...configurationBody,
94-
},
95-
},
96-
);
97-
} else {
98-
await api.integrations.updateIntegrationSpaceInstallation(
99-
siteOrSpaceInstallation.integration,
100-
siteOrSpaceInstallation.installation,
101-
siteOrSpaceInstallation.space,
102-
{
103-
configuration: {
104-
...configurationBody,
105-
},
84+
await api.integrations.updateIntegrationSiteInstallation(
85+
siteInstallation.integration,
86+
siteInstallation.installation,
87+
siteInstallation.site,
88+
{
89+
configuration: {
90+
...configurationBody,
10691
},
107-
);
108-
}
92+
},
93+
);
10994
return element;
11095
}
11196
},
11297
render: async (element, context) => {
113-
const siteOrSpaceInstallation =
114-
context.environment.siteInstallation ?? context.environment.spaceInstallation;
115-
const VACallbackURL = `${siteOrSpaceInstallation?.urls?.publicEndpoint}/visitor-auth/response`;
98+
const siteInstallation = context.environment.siteInstallation;
99+
const VACallbackURL = `${siteInstallation?.urls?.publicEndpoint}/visitor-auth/response`;
116100
return (
117101
<block>
118102
<input
@@ -243,38 +227,50 @@ const configBlock = createComponent<OIDCProps, OIDCState, OIDCAction, OIDCRuntim
243227
});
244228

245229
/**
246-
* Get the published content (site or space) related urls.
230+
* Get the published content related urls.
247231
*/
248232
async function getPublishedContentUrls(context: OIDCRuntimeContext) {
249-
const organizationId = context.environment.installation?.target?.organization;
250-
const siteOrSpaceInstallation =
251-
context.environment.siteInstallation ?? context.environment.spaceInstallation;
252-
const publishedContentData =
253-
'site' in siteOrSpaceInstallation
254-
? await context.api.orgs.getSiteById(organizationId, siteOrSpaceInstallation.site)
255-
: await context.api.spaces.getSpaceById(siteOrSpaceInstallation.space);
233+
const organizationId = assertOrgId(context.environment);
234+
const siteInstallation = assertSiteInstallation(context.environment);
235+
const publishedContentData = await context.api.orgs.getSiteById(
236+
organizationId,
237+
siteInstallation.site,
238+
);
256239

257240
return publishedContentData.data.urls;
258241
}
259242

243+
function assertSiteInstallation(environment: OIDCRuntimeEnvironment) {
244+
const siteInstallation = environment.siteInstallation;
245+
if (!siteInstallation) {
246+
throw new Error('No site installation found');
247+
}
248+
249+
return siteInstallation;
250+
}
251+
252+
function assertOrgId(environment: OIDCRuntimeEnvironment) {
253+
const orgId = environment.installation?.target?.organization!;
254+
if (!orgId) {
255+
throw new Error('No org ID found');
256+
}
257+
258+
return orgId;
259+
}
260+
260261
const handleFetchEvent: FetchEventCallback<OIDCRuntimeContext> = async (request, context) => {
261262
const { environment } = context;
262-
const siteOrSpaceInstallation = environment.siteInstallation ?? environment.spaceInstallation;
263-
const installationURL = siteOrSpaceInstallation?.urls?.publicEndpoint;
263+
const siteInstallation = assertSiteInstallation(environment);
264+
const installationURL = siteInstallation.urls?.publicEndpoint;
264265
if (installationURL) {
265266
const router = Router({
266267
base: new URL(installationURL).pathname,
267268
});
268269

269270
router.get('/visitor-auth/response', async (request) => {
270-
if (
271-
('site' in siteOrSpaceInstallation && siteOrSpaceInstallation.site) ||
272-
('space' in siteOrSpaceInstallation && siteOrSpaceInstallation.space)
273-
) {
271+
if ('site' in siteInstallation && siteInstallation.site) {
274272
const publishedContentUrls = await getPublishedContentUrls(context);
275-
const privateKey =
276-
context.environment.signingSecrets.siteInstallation ??
277-
context.environment.signingSecrets.spaceInstallation;
273+
const privateKey = context.environment.signingSecrets.siteInstallation!;
278274
let token;
279275
try {
280276
token = await sign(
@@ -287,11 +283,10 @@ const handleFetchEvent: FetchEventCallback<OIDCRuntimeContext> = async (request,
287283
});
288284
}
289285

290-
const accessTokenEndpoint =
291-
siteOrSpaceInstallation.configuration.access_token_endpoint;
292-
const clientId = siteOrSpaceInstallation.configuration.client_id;
293-
const clientSecret = siteOrSpaceInstallation.configuration.client_secret;
294-
if (clientId && clientSecret) {
286+
const accessTokenEndpoint = siteInstallation.configuration.access_token_endpoint;
287+
const clientId = siteInstallation.configuration.client_id;
288+
const clientSecret = siteInstallation.configuration.client_secret;
289+
if (clientId && clientSecret && accessTokenEndpoint) {
295290
const searchParams = new URLSearchParams({
296291
grant_type: 'authorization_code',
297292
client_id: clientId,
@@ -317,13 +312,13 @@ const handleFetchEvent: FetchEventCallback<OIDCRuntimeContext> = async (request,
317312

318313
if ('access_token' in resp) {
319314
let url;
320-
const state = request.query.state.toString();
315+
const state = request.query.state!.toString();
321316
const location = state.substring(state.indexOf('-') + 1);
322317
if (location) {
323318
url = new URL(`${publishedContentUrls?.published}${location}`);
324319
url.searchParams.append('jwt_token', token);
325320
} else {
326-
url = new URL(publishedContentUrls?.published);
321+
url = new URL(publishedContentUrls?.published!);
327322
url.searchParams.append('jwt_token', token);
328323
}
329324
if (publishedContentUrls?.published && token) {
@@ -351,9 +346,12 @@ const handleFetchEvent: FetchEventCallback<OIDCRuntimeContext> = async (request,
351346
);
352347
}
353348
} else {
354-
return new Response('Error: Either ClientId or Client Secret is missing', {
355-
status: 400,
356-
});
349+
return new Response(
350+
'Error: Either ClientId or Client Secret or Access Token Endpoint is missing',
351+
{
352+
status: 400,
353+
},
354+
);
357355
}
358356
}
359357
});
@@ -383,14 +381,17 @@ export default createIntegration({
383381
components: [configBlock],
384382
fetch_visitor_authentication: async (event, context) => {
385383
const { environment } = context;
386-
const siteOrSpaceInstallation =
387-
environment.siteInstallation ?? environment.spaceInstallation;
384+
const siteInstallation = assertSiteInstallation(environment);
388385

389-
const installationURL = siteOrSpaceInstallation?.urls?.publicEndpoint;
386+
const installationURL = siteInstallation.urls.publicEndpoint;
387+
const configuration = siteInstallation.configuration;
390388

391-
const authorizationEndpoint = siteOrSpaceInstallation?.configuration.authorization_endpoint;
392-
const clientId = siteOrSpaceInstallation?.configuration.client_id;
393-
const scope = siteOrSpaceInstallation?.configuration.scope;
389+
const authorizationEndpoint = configuration.authorization_endpoint;
390+
const clientId = configuration.client_id;
391+
const scope = configuration.scope;
392+
if (!clientId || !authorizationEndpoint || !scope) {
393+
throw new ExposableError('OIDC configuration is missing');
394+
}
394395

395396
const location = event.location ? event.location : '';
396397

@@ -401,12 +402,6 @@ export default createIntegration({
401402
url.searchParams.append('scope', scope.toLowerCase());
402403
url.searchParams.append('state', `state-${location}`);
403404

404-
try {
405-
return Response.redirect(url.toString());
406-
} catch (e) {
407-
return new Response(e.message, {
408-
status: e.status || 500,
409-
});
410-
}
405+
return Response.redirect(url.toString());
411406
},
412407
});

integrations/va-auth0/gitbook-manifest.yaml

-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,8 @@ description: Control who has access to your published documentation with Auth0
77
visibility: public
88
script: ./src/index.tsx
99
scopes:
10-
- space:metadata:read
11-
- space:visitor:auth
1210
- site:metadata:read
1311
- site:visitor:auth
14-
- space:content:read
1512
organization: gitbook
1613
summary: |
1714
# Overview
@@ -28,8 +25,6 @@ summary: |
2825
categories:
2926
- visitor-auth
3027
configurations:
31-
space:
32-
componentId: config
3328
site:
3429
componentId: config
3530
target: site

integrations/va-auth0/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@gitbook/tsconfig": "workspace:*"
1414
},
1515
"scripts": {
16+
"typecheck": "tsc --noEmit",
1617
"publish-integrations-staging": "gitbook publish .",
1718
"check": "gitbook check",
1819
"publish-integrations": "gitbook publish ."

0 commit comments

Comments
 (0)