Skip to content

Commit d7af881

Browse files
feat: serve auth script for private configs and accept Bearer token
Hooks returns auth script instead of 403 for curl. Install and config endpoints verify Bearer token for private access. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent ea4796f commit d7af881

File tree

3 files changed

+43
-9
lines changed

3 files changed

+43
-9
lines changed

src/hooks.server.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Handle } from '@sveltejs/kit';
2-
import { generateInstallScript } from '$lib/server/install-script';
2+
import { generateInstallScript, generatePrivateInstallScript } from '$lib/server/install-script';
33

44
const INSTALL_SCRIPT_URL = 'https://raw.githubusercontent.com/openbootdotdev/openboot/main/scripts/install.sh';
55

@@ -48,9 +48,9 @@ export const handle: Handle = async ({ event, resolve }) => {
4848
const env = event.platform?.env;
4949

5050
if (env) {
51-
const config = await env.DB.prepare('SELECT c.slug, c.custom_script, c.dotfiles_repo, u.username FROM configs c JOIN users u ON c.user_id = u.id WHERE c.alias = ? AND c.visibility IN (?, ?)')
52-
.bind(alias, 'public', 'unlisted')
53-
.first<{ slug: string; username: string; custom_script: string; dotfiles_repo: string }>();
51+
const config = await env.DB.prepare('SELECT c.slug, c.custom_script, c.dotfiles_repo, c.visibility, u.username FROM configs c JOIN users u ON c.user_id = u.id WHERE c.alias = ?')
52+
.bind(alias)
53+
.first<{ slug: string; username: string; custom_script: string; dotfiles_repo: string; visibility: string }>();
5454

5555
if (config) {
5656
const ua = event.request.headers.get('user-agent') || '';
@@ -59,6 +59,13 @@ export const handle: Handle = async ({ event, resolve }) => {
5959
const isBrowser = accept.includes('text/html');
6060

6161
if (isCurl || !isBrowser) {
62+
if (config.visibility === 'private') {
63+
const script = generatePrivateInstallScript(env.APP_URL, config.username, config.slug);
64+
return withSecurityHeaders(new Response(script, {
65+
headers: { 'Content-Type': 'text/plain; charset=utf-8', 'Cache-Control': 'no-cache' }
66+
}));
67+
}
68+
6269
const script = generateInstallScript(config.username, config.slug, config.custom_script, config.dotfiles_repo || '');
6370

6471
env.DB.prepare('UPDATE configs SET install_count = install_count + 1 WHERE alias = ?').bind(alias).run().catch(() => {});
@@ -92,7 +99,14 @@ export const handle: Handle = async ({ event, resolve }) => {
9299
.bind(user.id, slug)
93100
.first<{ custom_script: string; visibility: string; dotfiles_repo: string }>();
94101

95-
if (config && config.visibility !== 'private') {
102+
if (config) {
103+
if (config.visibility === 'private') {
104+
const script = generatePrivateInstallScript(env.APP_URL, username, slug);
105+
return withSecurityHeaders(new Response(script, {
106+
headers: { 'Content-Type': 'text/plain; charset=utf-8', 'Cache-Control': 'no-cache' }
107+
}));
108+
}
109+
96110
const script = generateInstallScript(username, slug, config.custom_script, config.dotfiles_repo || '');
97111

98112
env.DB.prepare('UPDATE configs SET install_count = install_count + 1 WHERE user_id = ? AND slug = ?').bind(user.id, slug).run().catch(() => {});

src/routes/[username]/[slug]/config/+server.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { json } from '@sveltejs/kit';
22
import type { RequestHandler } from './$types';
33

4-
export const GET: RequestHandler = async ({ platform, params }) => {
4+
export const GET: RequestHandler = async ({ platform, params, request }) => {
55
const env = platform?.env;
66
if (!env) {
77
return json({ error: 'Platform env not available' }, { status: 500 });
@@ -26,7 +26,17 @@ export const GET: RequestHandler = async ({ platform, params }) => {
2626
}
2727

2828
if (config.visibility === 'private') {
29-
return json({ error: 'Config is private' }, { status: 403 });
29+
const authHeader = request.headers.get('authorization') || '';
30+
const token = authHeader.replace(/^Bearer\s+/i, '');
31+
if (!token) {
32+
return json({ error: 'Config is private' }, { status: 403 });
33+
}
34+
const tokenRow = await env.DB.prepare(
35+
"SELECT user_id FROM api_tokens WHERE token = ? AND expires_at > datetime('now')"
36+
).bind(token).first<{ user_id: string }>();
37+
if (!tokenRow || tokenRow.user_id !== user.id) {
38+
return json({ error: 'Config is private' }, { status: 403 });
39+
}
3040
}
3141

3242
const tapsSet = new Set<string>();

src/routes/[username]/[slug]/install/+server.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { RequestHandler } from './$types';
22
import { generateInstallScript } from '$lib/server/install-script';
33

4-
export const GET: RequestHandler = async ({ platform, params }) => {
4+
export const GET: RequestHandler = async ({ platform, params, request }) => {
55
const env = platform?.env;
66
if (!env) {
77
return new Response('Platform env not available', { status: 500 });
@@ -21,7 +21,17 @@ export const GET: RequestHandler = async ({ platform, params }) => {
2121
}
2222

2323
if (config.visibility === 'private') {
24-
return new Response('Config is private', { status: 403 });
24+
const authHeader = request.headers.get('authorization') || '';
25+
const token = authHeader.replace(/^Bearer\s+/i, '');
26+
if (!token) {
27+
return new Response('Config is private', { status: 403 });
28+
}
29+
const tokenRow = await env.DB.prepare(
30+
"SELECT user_id FROM api_tokens WHERE token = ? AND expires_at > datetime('now')"
31+
).bind(token).first<{ user_id: string }>();
32+
if (!tokenRow || tokenRow.user_id !== user.id) {
33+
return new Response('Config is private', { status: 403 });
34+
}
2535
}
2636

2737
const script = generateInstallScript(params.username, params.slug, config.custom_script, config.dotfiles_repo || '');

0 commit comments

Comments
 (0)