Skip to content

Commit

Permalink
feat(workers): secret && meta
Browse files Browse the repository at this point in the history
  • Loading branch information
shaokeyibb committed Jul 17, 2024
1 parent 7157ba5 commit 164e491
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 9 deletions.
6 changes: 6 additions & 0 deletions cloudflare-workers/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ DROP TABLE IF EXISTS `comments`;
DROP TABLE IF EXISTS `commenters`;
DROP TABLE IF EXISTS `offsets`;
DROP TABLE IF EXISTS `pages`;
DROP TABLE IF EXISTS `metas`;

CREATE TABLE IF NOT EXISTS `metas` (
`key` TEXT PRIMARY KEY,
`value` TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS `pages` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
Expand Down
23 changes: 23 additions & 0 deletions cloudflare-workers/src/administration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getMeta, setMeta } from "./db";

const encoder = new TextEncoder();

export function validateSecret(env: Env, secret: string): boolean {
const secretBytes = encoder.encode(env.ADMINISTRATOR_SECRET);
const inputBytes = encoder.encode(secret);

if (secretBytes.byteLength !== inputBytes.byteLength) {
return false;
}

return crypto.subtle.timingSafeEqual(secretBytes, inputBytes);
}

export async function setCommitHash(env: Env, hash: string) {
await setMeta(env, 'commit_hash', hash);
}

export async function compareCommitHash(env: Env, hash: string): Promise<boolean> {
const storedHash = await getMeta(env, 'commit_hash');
return storedHash === hash;
}
14 changes: 14 additions & 0 deletions cloudflare-workers/src/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,17 @@ export async function getComment(env: Env, req: GetComment): Promise<GetCommentR
};
});
}

export async function setMeta(env: Env, key: string, value: string) {
const db = env.DB;

await db.prepare('INSERT OR REPLACE INTO metas (key, value) VALUES (?, ?)').bind(key, value).run();
}

export async function getMeta(env: Env, key: string): Promise<string | undefined> {
const db = env.DB;

const meta = await db.prepare('SELECT * FROM metas WHERE key = ?').bind(key).first<Record<'key' | 'value', string>>();

return meta?.value;
}
50 changes: 45 additions & 5 deletions cloudflare-workers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
*/

import { AutoRouter, error } from 'itty-router';
import { GetCommentBody, GetCommentRespBody, PostCommentBody, ResponseBody } from './types';
import { getComment, postComment } from './db';
import { GetCommentBody, GetCommentRespBody, GetCommitHashRespBody, PostCommentBody, PutCommitHashBody, ResponseBody } from './types';
import { getComment, getMeta, postComment } from './db';
import { validateSecret, setCommitHash, compareCommitHash } from './administration';

const router = AutoRouter();

Expand All @@ -28,7 +29,8 @@ router.post('/comment', async (req, env, ctx) => {
body.comment == undefined ||
body.offset.start == undefined ||
body.offset.end == undefined ||
body.commenter.name == undefined
body.commenter.name == undefined ||
body.commit_hash == undefined
) {
return error(400, 'Invalid request body');
}
Expand All @@ -49,6 +51,10 @@ router.post('/comment', async (req, env, ctx) => {
return error(400, 'Invalid comment');
}

if(!await compareCommitHash(env, body.commit_hash)) {
return error(409, 'Commit hash mismatch, usually due to outdated cache or running CI/CD, please retry after a few minutes');
}

await postComment(env, {
path: body.path,
offset: body.offset,
Expand All @@ -62,7 +68,7 @@ router.post('/comment', async (req, env, ctx) => {

return {
status: 200,
} as ResponseBody<{}>;
} satisfies ResponseBody;
});

router.get('/comment', async (req, env, ctx) => {
Expand All @@ -77,7 +83,41 @@ router.get('/comment', async (req, env, ctx) => {
return {
status: 200,
data: rst,
} as ResponseBody<GetCommentRespBody>;
} satisfies ResponseBody<GetCommentRespBody>;
});

router.put('/meta/commithash', async (req, env, ctx) => {
const body = await req.json<PutCommitHashBody>();

if (body == undefined || body.commit_hash == undefined) {
return error(400, 'Invalid request body');
}

if (body.commit_hash.length < 1) {
return error(400, 'Invalid commit hash');
}

const authorization = req.headers.get('Authorization');

if (!authorization) {
return error(401, 'Unauthorized');
}

const [scheme, secret] = authorization.split(' ');

if (scheme !== 'Bearer' || !secret) {
return error(400, 'Malformed authorization header');
}

if (validateSecret(env, secret) !== true) {
return error(401, 'Unauthorized');
}

setCommitHash(env, body.commit_hash);

return {
status: 200,
} satisfies ResponseBody;
});

export default { ...router } satisfies ExportedHandler<Env>;
15 changes: 12 additions & 3 deletions cloudflare-workers/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ export type PostCommentBody = {
name: string;
};
comment: string;
commit_hash: string;
};

export type PostComment = {
commenter: {
user_agent: string;
ip_address: string | null;
};
} & PostCommentBody;
} & Omit<PostCommentBody, 'commit_hash'>;

export type GetCommentBody = {
path: string;
Expand All @@ -35,7 +36,15 @@ export type GetCommentRespBody = {
created_time: string;
}[];

export type ResponseBody<T> = {
export type PutCommitHashBody = {
commit_hash: string;
};

export type GetCommitHashRespBody = {
commit_hash: string | undefined;
}

export type ResponseBody<T = {}> = {
status: 200;
data: T;
data?: T;
};
3 changes: 2 additions & 1 deletion cloudflare-workers/worker-configuration.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Generated by Wrangler on Mon Jul 15 2024 16:30:44 GMT+0800 (China Standard Time)
// Generated by Wrangler on Wed Jul 17 2024 12:23:04 GMT+0800 (China Standard Time)
// by running `wrangler types`

interface Env {
ADMINISTRATOR_SECRET: string;
DB: D1Database;
}

0 comments on commit 164e491

Please sign in to comment.