mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-20 09:33:21 +00:00
Implement route to invalidate data cache (#2916)
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'gitbook-v2': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add route to revalidate cached data
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { type NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
import { withVerifySignature } from '@v2/lib/routes';
|
||||||
|
import { revalidateTag } from 'next/cache';
|
||||||
|
|
||||||
|
interface JsonBody {
|
||||||
|
tags: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revalidate cached data based on tags.
|
||||||
|
* The body should be a JSON with { tags: string[] }
|
||||||
|
*/
|
||||||
|
export async function POST(req: NextRequest) {
|
||||||
|
return withVerifySignature<JsonBody>(req, async (body) => {
|
||||||
|
if (!body.tags || !Array.isArray(body.tags)) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
error: 'tags must be an array',
|
||||||
|
},
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.tags.forEach((tag) => {
|
||||||
|
revalidateTag(tag);
|
||||||
|
});
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
success: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -58,3 +58,8 @@ export const GITBOOK_INTEGRATIONS_HOST =
|
|||||||
export const GITBOOK_IMAGE_RESIZE_URL = process.env.GITBOOK_IMAGE_RESIZE_URL ?? null;
|
export const GITBOOK_IMAGE_RESIZE_URL = process.env.GITBOOK_IMAGE_RESIZE_URL ?? null;
|
||||||
export const GITBOOK_IMAGE_RESIZE_SIGNING_KEY =
|
export const GITBOOK_IMAGE_RESIZE_SIGNING_KEY =
|
||||||
process.env.GITBOOK_IMAGE_RESIZE_SIGNING_KEY ?? null;
|
process.env.GITBOOK_IMAGE_RESIZE_SIGNING_KEY ?? null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secret used to validate requests from the GitBook app.
|
||||||
|
*/
|
||||||
|
export const GITBOOK_SECRET = process.env.GITBOOK_SECRET ?? null;
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import crypto from 'node:crypto';
|
||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { GITBOOK_SECRET } from './env';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the signature of the request and call the function with the body.
|
||||||
|
*/
|
||||||
|
export async function withVerifySignature<T>(
|
||||||
|
request: Request,
|
||||||
|
fn: (body: T) => Promise<NextResponse>
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const rawBody = await request.text();
|
||||||
|
const body = JSON.parse(rawBody) as T;
|
||||||
|
|
||||||
|
if (GITBOOK_SECRET) {
|
||||||
|
// Retrieve the signature header from the request
|
||||||
|
const incomingSignature = request.headers.get('x-gitbook-signature');
|
||||||
|
if (!incomingSignature) {
|
||||||
|
return NextResponse.json({ error: 'Missing signature header' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const computedSignature = crypto
|
||||||
|
.createHmac('sha256', GITBOOK_SECRET)
|
||||||
|
.update(rawBody)
|
||||||
|
.digest('hex');
|
||||||
|
|
||||||
|
// Compare incoming signature to computed signature
|
||||||
|
if (incomingSignature !== computedSignature) {
|
||||||
|
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await fn(body);
|
||||||
|
} catch (_error) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Invalid request or unable to parse JSON' },
|
||||||
|
{ status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user