mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-23 19:06:31 +00:00
Fix auth redirects with the new preview URL (#4111)
This commit is contained in:
@@ -709,6 +709,26 @@ const testCases: TestsCase[] = [
|
||||
await expect(page.locator('[data-testid="print-button"]')).toBeVisible();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Show error when missing token',
|
||||
url: async () => {
|
||||
const data = await getSiteAPIToken(
|
||||
'https://gitbook.gitbook.io/test-gitbook-open/'
|
||||
);
|
||||
|
||||
// Intentionally not setting the token to test error handling when the token is missing
|
||||
const searchParams = new URLSearchParams();
|
||||
searchParams.set('limit', '10');
|
||||
|
||||
return `~space/${data.space}/~gitbook/pdf?${searchParams.toString()}`;
|
||||
},
|
||||
screenshot: false,
|
||||
run: async (page, response) => {
|
||||
expect(response).not.toBeNull();
|
||||
expect(response?.status()).toBe(400);
|
||||
await expect(page.getByText('Missing API token')).toBeVisible();
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -887,6 +907,24 @@ const testCases: TestsCase[] = [
|
||||
).toBeVisible();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Redirect to app for authentication when missing token',
|
||||
url: async () => {
|
||||
const data = await getSiteAPIToken('https://gitbook.com/docs');
|
||||
|
||||
const searchParams = new URLSearchParams();
|
||||
// Intentionally not setting the token to test redirection for authentication
|
||||
|
||||
return `url/${getGitBookPreviewURL(`${data.site}/?${searchParams.toString()}`)}`;
|
||||
},
|
||||
screenshot: false,
|
||||
run: async (page) => {
|
||||
await page.waitForURL(
|
||||
(url) =>
|
||||
url.host === 'app.gitbook.com' && url.pathname.includes('/preview/auth')
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -473,12 +473,14 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
||||
if (isPreviewRequest(siteRequestURL)) {
|
||||
// Do not track page views for preview requests
|
||||
request.headers.set('x-gitbook-disable-tracking', 'true');
|
||||
return serveWithQueryAPIToken(
|
||||
return serveWithQueryAPIToken({
|
||||
// We scope the API token to the site ID.
|
||||
['preview', getPreviewRequestIdentifier(siteRequestURL)].join('/'),
|
||||
request,
|
||||
withAPIToken
|
||||
);
|
||||
scopePath: ['preview', getPreviewRequestIdentifier(siteRequestURL)].join('/'),
|
||||
// We keep the original request URL when using `url` mode
|
||||
requestURL: mode === 'url' ? requestURL : siteRequestURL,
|
||||
requestCookies: request.cookies,
|
||||
serve: withAPIToken,
|
||||
});
|
||||
}
|
||||
|
||||
return withAPIToken(null);
|
||||
@@ -493,18 +495,22 @@ async function serveSpacePDFRoutes(requestURL: URL, request: NextRequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return serveWithQueryAPIToken(
|
||||
pathnameParts.slice(0, 2).join('/'),
|
||||
request,
|
||||
async (apiToken) => {
|
||||
return serveWithQueryAPIToken({
|
||||
scopePath: pathnameParts.slice(0, 2).join('/'),
|
||||
requestURL,
|
||||
requestCookies: request.cookies,
|
||||
serve: async (apiToken) => {
|
||||
if (!apiToken) {
|
||||
throw new DataFetcherError('Missing API token', 400);
|
||||
}
|
||||
// Handle the rest with the router default logic
|
||||
return NextResponse.next({
|
||||
headers: {
|
||||
[MiddlewareHeaders.APIToken]: apiToken,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -522,23 +528,25 @@ function serveErrorResponse(error: Error) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Server a response with an API token obtained from the query params.
|
||||
* Serve a response with an API token obtained from the query params.
|
||||
*/
|
||||
async function serveWithQueryAPIToken(
|
||||
scopePath: string,
|
||||
request: NextRequest,
|
||||
serve: (apiToken: string) => Promise<NextResponse>
|
||||
) {
|
||||
async function serveWithQueryAPIToken(input: {
|
||||
scopePath: string;
|
||||
requestURL: URL;
|
||||
requestCookies: NextRequest['cookies'];
|
||||
serve: (apiToken: string | null) => Promise<NextResponse>;
|
||||
}) {
|
||||
const { scopePath, requestURL, requestCookies, serve } = input;
|
||||
// We store the API token in a cookie that is scoped to the specific route
|
||||
// to avoid errors when multiple previews are opened in different tabs.
|
||||
const cookieName = getPathScopedCookieName('gitbook-api-token', scopePath);
|
||||
|
||||
// Extract a potential GitBook API token passed in the request
|
||||
// If found, we redirect to the same URL but with the token in the cookie
|
||||
const queryAPIToken = request.nextUrl.searchParams.get('token');
|
||||
const queryAPIToken = requestURL.searchParams.get('token');
|
||||
if (queryAPIToken) {
|
||||
request.nextUrl.searchParams.delete('token');
|
||||
return writeResponseCookies(NextResponse.redirect(request.nextUrl.toString()), [
|
||||
requestURL.searchParams.delete('token');
|
||||
return writeResponseCookies(NextResponse.redirect(requestURL.toString()), [
|
||||
{
|
||||
name: cookieName,
|
||||
value: queryAPIToken,
|
||||
@@ -552,12 +560,9 @@ async function serveWithQueryAPIToken(
|
||||
]);
|
||||
}
|
||||
|
||||
const apiToken = request.cookies.get(cookieName)?.value;
|
||||
if (!apiToken) {
|
||||
throw new DataFetcherError('Missing API token', 400);
|
||||
}
|
||||
const apiToken = requestCookies.get(cookieName)?.value;
|
||||
|
||||
return serve(apiToken);
|
||||
return serve(apiToken ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user