@alteran/astro 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/index.js +8 -0
- package/migrations/0009_oauth_session_state.sql +31 -0
- package/migrations/meta/0009_snapshot.json +749 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +2 -1
- package/src/db/account.ts +134 -1
- package/src/db/schema.ts +31 -0
- package/src/handlers/root.ts +1 -1
- package/src/lib/appview/proxy.ts +11 -8
- package/src/lib/auth.ts +34 -3
- package/src/lib/jwt.ts +4 -0
- package/src/lib/oauth/as-keys.ts +29 -0
- package/src/lib/oauth/clients.ts +453 -24
- package/src/lib/oauth/consent.ts +180 -0
- package/src/lib/oauth/dpop.ts +39 -5
- package/src/lib/oauth/resource.ts +93 -21
- package/src/lib/oauth/store.ts +64 -7
- package/src/lib/refresh-session.ts +16 -0
- package/src/lib/session-tokens.ts +33 -5
- package/src/lib/token-cleanup.ts +4 -2
- package/src/lib/util.ts +0 -1
- package/src/pages/.well-known/oauth-authorization-server.ts +16 -3
- package/src/pages/.well-known/oauth-protected-resource.ts +8 -4
- package/src/pages/oauth/authorize.ts +31 -52
- package/src/pages/oauth/consent.ts +163 -66
- package/src/pages/oauth/jwks.ts +15 -0
- package/src/pages/oauth/par.ts +34 -56
- package/src/pages/oauth/revoke.ts +75 -0
- package/src/pages/oauth/token.ts +148 -89
- package/src/pages/xrpc/[...nsid].ts +7 -6
- package/src/pages/xrpc/app.bsky.actor.getPreferences.ts +3 -4
- package/src/pages/xrpc/app.bsky.actor.putPreferences.ts +3 -4
- package/src/pages/xrpc/app.bsky.unspecced.getAgeAssuranceState.ts +3 -4
- package/src/pages/xrpc/chat.bsky.convo.getLog.ts +3 -4
- package/src/pages/xrpc/chat.bsky.convo.listConvos.ts +3 -4
- package/src/pages/xrpc/com.atproto.identity.getRecommendedDidCredentials.ts +3 -4
- package/src/pages/xrpc/com.atproto.identity.requestPlcOperationSignature.ts +3 -4
- package/src/pages/xrpc/com.atproto.identity.signPlcOperation.ts +3 -4
- package/src/pages/xrpc/com.atproto.identity.submitPlcOperation.ts +3 -4
- package/src/pages/xrpc/com.atproto.repo.listMissingBlobs.ts +3 -4
- package/src/pages/xrpc/com.atproto.server.checkAccountStatus.ts +3 -4
- package/src/pages/xrpc/com.atproto.server.deleteSession.ts +28 -9
- package/src/pages/xrpc/com.atproto.server.getSession.ts +3 -4
- package/src/worker/runtime.ts +23 -1
- package/types/env.d.ts +1 -0
|
@@ -1,20 +1,39 @@
|
|
|
1
1
|
import type { APIContext } from 'astro';
|
|
2
|
+
import { bearerToken } from '../../lib/util';
|
|
3
|
+
import { verifyRefreshToken } from '../../lib/session-tokens';
|
|
4
|
+
import { getRefreshToken, revokeOAuthSession, deleteRefreshToken } from '../../db/account';
|
|
2
5
|
|
|
3
6
|
export const prerender = false;
|
|
4
7
|
|
|
5
8
|
/**
|
|
6
9
|
* com.atproto.server.deleteSession
|
|
7
|
-
* Delete the current
|
|
10
|
+
* Delete the current refresh credential. OAuth refresh rows also revoke the
|
|
11
|
+
* owning OAuth session, which invalidates the current DPoP-bound access token.
|
|
8
12
|
*/
|
|
9
|
-
export async function POST({ locals }: APIContext) {
|
|
13
|
+
export async function POST({ locals, request }: APIContext) {
|
|
10
14
|
const { env } = locals.runtime;
|
|
15
|
+
const token = bearerToken(request);
|
|
16
|
+
if (!token) {
|
|
17
|
+
return new Response(JSON.stringify({ error: 'AuthRequired', message: 'No authorization token provided' }), {
|
|
18
|
+
status: 401,
|
|
19
|
+
headers: { 'Content-Type': 'application/json' },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
11
22
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
const verification = await verifyRefreshToken(env, token, { ignoreExpiration: true }).catch(() => null);
|
|
24
|
+
const jti = verification?.decoded?.jti;
|
|
25
|
+
if (!jti) {
|
|
26
|
+
return new Response(JSON.stringify({ error: 'InvalidToken', message: 'Invalid refresh token' }), {
|
|
27
|
+
status: 401,
|
|
28
|
+
headers: { 'Content-Type': 'application/json' },
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const stored = await getRefreshToken(env, jti);
|
|
33
|
+
if (stored?.tokenKind === 'oauth' && stored.oauthSessionId) {
|
|
34
|
+
await revokeOAuthSession(env, stored.oauthSessionId);
|
|
35
|
+
}
|
|
36
|
+
await deleteRefreshToken(env, jti);
|
|
18
37
|
|
|
19
38
|
return new Response(JSON.stringify({}), {
|
|
20
39
|
status: 200,
|
|
@@ -22,4 +41,4 @@ export async function POST({ locals }: APIContext) {
|
|
|
22
41
|
'Content-Type': 'application/json',
|
|
23
42
|
},
|
|
24
43
|
});
|
|
25
|
-
}
|
|
44
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { APIContext } from 'astro';
|
|
2
|
-
import {
|
|
2
|
+
import { authErrorResponse, authenticateRequest, unauthorized } from '../../lib/auth';
|
|
3
3
|
import { getAccountByIdentifier } from '../../db/account';
|
|
4
4
|
|
|
5
5
|
export const prerender = false;
|
|
@@ -16,9 +16,8 @@ export async function GET({ locals, request }: APIContext) {
|
|
|
16
16
|
try {
|
|
17
17
|
authContext = await authenticateRequest(request, env);
|
|
18
18
|
} catch (error) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
19
|
+
const handled = await authErrorResponse(env, error);
|
|
20
|
+
if (handled) return handled;
|
|
22
21
|
throw error;
|
|
23
22
|
}
|
|
24
23
|
if (!authContext) {
|
package/src/worker/runtime.ts
CHANGED
|
@@ -140,11 +140,33 @@ export function createPdsFetchHandler(options?: CreatePdsFetchHandlerOptions): P
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
const astroFetch = await getAstroFetch(options);
|
|
143
|
-
const response = await astroFetch(request, resolvedEnv as any, ctx);
|
|
143
|
+
const response = await astroFetch(normalizeXrpcRequestForAstro(request), resolvedEnv as any, ctx);
|
|
144
144
|
return response as unknown as WorkersResponse;
|
|
145
145
|
};
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
export function normalizeXrpcRequestForAstro(request: WorkersRequest): WorkersRequest {
|
|
149
|
+
const url = new URL(request.url);
|
|
150
|
+
if (!url.pathname.startsWith('/xrpc/')) {
|
|
151
|
+
return request;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Astro's SSR origin-check middleware rejects unsafe requests when Origin is
|
|
155
|
+
// absent or cross-origin. XRPC is a bearer-token API, not cookie/form auth,
|
|
156
|
+
// and atproto clients legitimately send bodyless POSTs from native runtimes.
|
|
157
|
+
if (request.headers.get('origin') === url.origin) {
|
|
158
|
+
return request;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const headerRecord: Record<string, string> = {};
|
|
162
|
+
request.headers.forEach((value, key) => {
|
|
163
|
+
headerRecord[key] = value;
|
|
164
|
+
});
|
|
165
|
+
headerRecord.origin = url.origin;
|
|
166
|
+
|
|
167
|
+
return new Request(request as any, { headers: headerRecord }) as unknown as WorkersRequest;
|
|
168
|
+
}
|
|
169
|
+
|
|
148
170
|
type AstroFetchHandler = (
|
|
149
171
|
request: WorkersRequest,
|
|
150
172
|
env: Env,
|
package/types/env.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ declare global {
|
|
|
60
60
|
// Relay crawl configuration
|
|
61
61
|
PDS_RELAY_HOSTS?: string; // CSV of relay hostnames (no scheme). Default: bsky.network
|
|
62
62
|
PDS_RELAY_NOTIFY?: string; // 'false' to disable auto notify
|
|
63
|
+
PDS_OAUTH_CLIENT_HOSTS?: string; // CSV of trusted OAuth client metadata/JWKS hostnames
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
namespace App {
|