@openverifiable/connector-bluesky 1.0.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/lib/__fixtures__/did-documents.d.ts +54 -0
- package/lib/__fixtures__/did-documents.d.ts.map +1 -0
- package/lib/__fixtures__/did-documents.js +56 -0
- package/lib/__fixtures__/metadata.d.ts +70 -0
- package/lib/__fixtures__/metadata.d.ts.map +1 -0
- package/lib/__fixtures__/metadata.js +56 -0
- package/lib/__fixtures__/oauth-errors.d.ts +42 -0
- package/lib/__fixtures__/oauth-errors.d.ts.map +1 -0
- package/lib/__fixtures__/oauth-errors.js +41 -0
- package/lib/__fixtures__/profile-responses.d.ts +34 -0
- package/lib/__fixtures__/profile-responses.d.ts.map +1 -0
- package/lib/__fixtures__/profile-responses.js +28 -0
- package/lib/__fixtures__/token-responses.d.ts +38 -0
- package/lib/__fixtures__/token-responses.d.ts.map +1 -0
- package/lib/__fixtures__/token-responses.js +33 -0
- package/lib/__tests__/integration/real-account-helpers.d.ts +43 -0
- package/lib/__tests__/integration/real-account-helpers.d.ts.map +1 -0
- package/lib/__tests__/integration/real-account-helpers.js +84 -0
- package/lib/__tests__/integration/real-account.test.d.ts +12 -0
- package/lib/__tests__/integration/real-account.test.d.ts.map +1 -0
- package/lib/__tests__/integration/real-account.test.js +118 -0
- package/lib/client-assertion.d.ts +19 -0
- package/lib/client-assertion.d.ts.map +1 -0
- package/lib/client-assertion.js +50 -0
- package/lib/client-assertion.test.d.ts +6 -0
- package/lib/client-assertion.test.d.ts.map +1 -0
- package/lib/client-assertion.test.js +234 -0
- package/lib/constant.d.ts +24 -0
- package/lib/constant.d.ts.map +1 -0
- package/lib/constant.js +77 -0
- package/lib/dpop.d.ts +24 -0
- package/lib/dpop.d.ts.map +1 -0
- package/lib/dpop.js +138 -0
- package/lib/dpop.test.d.ts +6 -0
- package/lib/dpop.test.d.ts.map +1 -0
- package/lib/dpop.test.js +266 -0
- package/lib/index.d.ts +12 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +1129 -0
- package/lib/index.test.d.ts +7 -0
- package/lib/index.test.d.ts.map +1 -0
- package/lib/index.test.js +329 -0
- package/lib/mock.d.ts +5 -0
- package/lib/mock.d.ts.map +1 -0
- package/lib/mock.js +24 -0
- package/lib/pds-discovery.d.ts +18 -0
- package/lib/pds-discovery.d.ts.map +1 -0
- package/lib/pds-discovery.js +248 -0
- package/lib/pds-discovery.test.d.ts +6 -0
- package/lib/pds-discovery.test.d.ts.map +1 -0
- package/lib/pds-discovery.test.js +281 -0
- package/lib/pkce.d.ts +16 -0
- package/lib/pkce.d.ts.map +1 -0
- package/lib/pkce.js +46 -0
- package/lib/pkce.test.d.ts +6 -0
- package/lib/pkce.test.d.ts.map +1 -0
- package/lib/pkce.test.js +117 -0
- package/lib/test-utils.d.ts +65 -0
- package/lib/test-utils.d.ts.map +1 -0
- package/lib/test-utils.js +132 -0
- package/lib/types.d.ts +221 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +95 -0
- package/package.json +96 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Utilities
|
|
3
|
+
* Shared helper functions for testing
|
|
4
|
+
*/
|
|
5
|
+
import { createHash } from 'crypto';
|
|
6
|
+
import { jwtVerify } from 'jose';
|
|
7
|
+
/**
|
|
8
|
+
* Base64url encode (URL-safe base64)
|
|
9
|
+
*/
|
|
10
|
+
export function base64UrlEncode(buffer) {
|
|
11
|
+
return buffer
|
|
12
|
+
.toString('base64')
|
|
13
|
+
.replace(/\+/g, '-')
|
|
14
|
+
.replace(/\//g, '_')
|
|
15
|
+
.replace(/=/g, '');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Base64url decode
|
|
19
|
+
*/
|
|
20
|
+
export function base64UrlDecode(str) {
|
|
21
|
+
// Add padding if needed
|
|
22
|
+
let base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
23
|
+
while (base64.length % 4) {
|
|
24
|
+
base64 += '=';
|
|
25
|
+
}
|
|
26
|
+
return Buffer.from(base64, 'base64');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Verify JWT signature and return payload
|
|
30
|
+
*/
|
|
31
|
+
export async function verifyJWT(jwt, publicKey) {
|
|
32
|
+
const { payload } = await jwtVerify(jwt, publicKey);
|
|
33
|
+
return payload;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Verify DPoP JWT signature
|
|
37
|
+
*/
|
|
38
|
+
export async function verifyDPoPJWT(jwt, keyPair) {
|
|
39
|
+
return verifyJWT(jwt, keyPair.publicKey);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generate SHA256 hash and base64url encode (same as S256 PKCE challenge)
|
|
43
|
+
*/
|
|
44
|
+
export function sha256Base64Url(input) {
|
|
45
|
+
const hash = createHash('sha256');
|
|
46
|
+
hash.update(input);
|
|
47
|
+
const digest = hash.digest();
|
|
48
|
+
return base64UrlEncode(digest);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Generate test ES256 key pair
|
|
52
|
+
*/
|
|
53
|
+
export async function generateTestKeyPair() {
|
|
54
|
+
const crypto = globalThis.crypto || (await import('crypto')).webcrypto;
|
|
55
|
+
const keyPair = await crypto.subtle.generateKey({
|
|
56
|
+
name: 'ECDSA',
|
|
57
|
+
namedCurve: 'P-256',
|
|
58
|
+
}, true, // extractable
|
|
59
|
+
['sign', 'verify'] // Both sign and verify for testing
|
|
60
|
+
);
|
|
61
|
+
return {
|
|
62
|
+
publicKey: keyPair.publicKey,
|
|
63
|
+
privateKey: keyPair.privateKey,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Export public key as JWK
|
|
68
|
+
*/
|
|
69
|
+
export async function exportPublicKeyAsJWK(publicKey) {
|
|
70
|
+
const crypto = globalThis.crypto || (await import('crypto')).webcrypto;
|
|
71
|
+
const jwk = await crypto.subtle.exportKey('jwk', publicKey);
|
|
72
|
+
// Remove private key fields if present
|
|
73
|
+
const { d, ...publicJwk } = jwk;
|
|
74
|
+
return publicJwk;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create mock HTTP response headers
|
|
78
|
+
*/
|
|
79
|
+
export function createMockHeaders(headers = {}) {
|
|
80
|
+
return {
|
|
81
|
+
'content-type': 'application/json',
|
|
82
|
+
...headers,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create mock HTTP response with DPoP nonce
|
|
87
|
+
*/
|
|
88
|
+
export function createMockResponseWithNonce(body, nonce) {
|
|
89
|
+
return {
|
|
90
|
+
statusCode: 200,
|
|
91
|
+
headers: {
|
|
92
|
+
'content-type': 'application/json',
|
|
93
|
+
'dpop-nonce': nonce,
|
|
94
|
+
},
|
|
95
|
+
body: JSON.stringify(body),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create mock HTTP error response with use_dpop_nonce
|
|
100
|
+
*/
|
|
101
|
+
export function createMockDPoPNonceError(nonce, statusCode = 401) {
|
|
102
|
+
return {
|
|
103
|
+
statusCode,
|
|
104
|
+
headers: {
|
|
105
|
+
'content-type': 'application/json',
|
|
106
|
+
'dpop-nonce': nonce,
|
|
107
|
+
'www-authenticate': `DPoP error="use_dpop_nonce", error_description="Resource server requires nonce in DPoP proof"`,
|
|
108
|
+
},
|
|
109
|
+
body: JSON.stringify({
|
|
110
|
+
error: 'use_dpop_nonce',
|
|
111
|
+
error_description: 'Resource server requires nonce in DPoP proof',
|
|
112
|
+
nonce,
|
|
113
|
+
}),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Sleep utility for testing async behavior
|
|
118
|
+
*/
|
|
119
|
+
export function sleep(ms) {
|
|
120
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Generate random string for testing
|
|
124
|
+
*/
|
|
125
|
+
export function randomString(length = 16) {
|
|
126
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
127
|
+
let result = '';
|
|
128
|
+
for (let i = 0; i < length; i++) {
|
|
129
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* BlueskyConfig
|
|
4
|
+
* Configuration for AT Protocol OAuth client
|
|
5
|
+
* Requires private_key_jwt for confidential client security
|
|
6
|
+
*/
|
|
7
|
+
export declare const blueskyConfigGuard: z.ZodEffects<z.ZodObject<{
|
|
8
|
+
clientMetadataUri: z.ZodString;
|
|
9
|
+
clientId: z.ZodOptional<z.ZodString>;
|
|
10
|
+
jwksUri: z.ZodString;
|
|
11
|
+
scope: z.ZodDefault<z.ZodString>;
|
|
12
|
+
tokenEndpointAuthMethod: z.ZodLiteral<"private_key_jwt">;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
clientMetadataUri: string;
|
|
15
|
+
jwksUri: string;
|
|
16
|
+
scope: string;
|
|
17
|
+
tokenEndpointAuthMethod: "private_key_jwt";
|
|
18
|
+
clientId?: string | undefined;
|
|
19
|
+
}, {
|
|
20
|
+
clientMetadataUri: string;
|
|
21
|
+
jwksUri: string;
|
|
22
|
+
tokenEndpointAuthMethod: "private_key_jwt";
|
|
23
|
+
clientId?: string | undefined;
|
|
24
|
+
scope?: string | undefined;
|
|
25
|
+
}>, {
|
|
26
|
+
clientMetadataUri: string;
|
|
27
|
+
jwksUri: string;
|
|
28
|
+
scope: string;
|
|
29
|
+
tokenEndpointAuthMethod: "private_key_jwt";
|
|
30
|
+
clientId?: string | undefined;
|
|
31
|
+
}, {
|
|
32
|
+
clientMetadataUri: string;
|
|
33
|
+
jwksUri: string;
|
|
34
|
+
tokenEndpointAuthMethod: "private_key_jwt";
|
|
35
|
+
clientId?: string | undefined;
|
|
36
|
+
scope?: string | undefined;
|
|
37
|
+
}>;
|
|
38
|
+
export type BlueskyConfig = z.infer<typeof blueskyConfigGuard>;
|
|
39
|
+
/**
|
|
40
|
+
* authResponseGuard
|
|
41
|
+
* Validates query parameters from AT Protocol authorization callback
|
|
42
|
+
*/
|
|
43
|
+
export declare const authResponseGuard: z.ZodObject<{
|
|
44
|
+
code: z.ZodOptional<z.ZodString>;
|
|
45
|
+
state: z.ZodOptional<z.ZodString>;
|
|
46
|
+
iss: z.ZodOptional<z.ZodString>;
|
|
47
|
+
error: z.ZodOptional<z.ZodString>;
|
|
48
|
+
error_description: z.ZodOptional<z.ZodString>;
|
|
49
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
50
|
+
code: z.ZodOptional<z.ZodString>;
|
|
51
|
+
state: z.ZodOptional<z.ZodString>;
|
|
52
|
+
iss: z.ZodOptional<z.ZodString>;
|
|
53
|
+
error: z.ZodOptional<z.ZodString>;
|
|
54
|
+
error_description: z.ZodOptional<z.ZodString>;
|
|
55
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
56
|
+
code: z.ZodOptional<z.ZodString>;
|
|
57
|
+
state: z.ZodOptional<z.ZodString>;
|
|
58
|
+
iss: z.ZodOptional<z.ZodString>;
|
|
59
|
+
error: z.ZodOptional<z.ZodString>;
|
|
60
|
+
error_description: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
62
|
+
export type AuthResponse = z.infer<typeof authResponseGuard>;
|
|
63
|
+
/**
|
|
64
|
+
* PARResponse
|
|
65
|
+
* Response from Pushed Authorization Request
|
|
66
|
+
*/
|
|
67
|
+
export declare const parResponseGuard: z.ZodObject<{
|
|
68
|
+
request_uri: z.ZodString;
|
|
69
|
+
expires_in: z.ZodOptional<z.ZodNumber>;
|
|
70
|
+
}, "strip", z.ZodTypeAny, {
|
|
71
|
+
request_uri: string;
|
|
72
|
+
expires_in?: number | undefined;
|
|
73
|
+
}, {
|
|
74
|
+
request_uri: string;
|
|
75
|
+
expires_in?: number | undefined;
|
|
76
|
+
}>;
|
|
77
|
+
export type PARResponse = z.infer<typeof parResponseGuard>;
|
|
78
|
+
/**
|
|
79
|
+
* TokenResponse
|
|
80
|
+
* AT Protocol OAuth token response
|
|
81
|
+
*/
|
|
82
|
+
export declare const tokenResponseGuard: z.ZodObject<{
|
|
83
|
+
access_token: z.ZodString;
|
|
84
|
+
refresh_token: z.ZodOptional<z.ZodString>;
|
|
85
|
+
token_type: z.ZodLiteral<"Bearer">;
|
|
86
|
+
expires_in: z.ZodNumber;
|
|
87
|
+
scope: z.ZodString;
|
|
88
|
+
sub: z.ZodString;
|
|
89
|
+
did: z.ZodOptional<z.ZodString>;
|
|
90
|
+
}, "strip", z.ZodTypeAny, {
|
|
91
|
+
scope: string;
|
|
92
|
+
expires_in: number;
|
|
93
|
+
access_token: string;
|
|
94
|
+
token_type: "Bearer";
|
|
95
|
+
sub: string;
|
|
96
|
+
refresh_token?: string | undefined;
|
|
97
|
+
did?: string | undefined;
|
|
98
|
+
}, {
|
|
99
|
+
scope: string;
|
|
100
|
+
expires_in: number;
|
|
101
|
+
access_token: string;
|
|
102
|
+
token_type: "Bearer";
|
|
103
|
+
sub: string;
|
|
104
|
+
refresh_token?: string | undefined;
|
|
105
|
+
did?: string | undefined;
|
|
106
|
+
}>;
|
|
107
|
+
export type TokenResponse = z.infer<typeof tokenResponseGuard>;
|
|
108
|
+
/**
|
|
109
|
+
* ProfileResponse
|
|
110
|
+
* AT Protocol profile response from PDS
|
|
111
|
+
*/
|
|
112
|
+
export declare const profileResponseGuard: z.ZodObject<{
|
|
113
|
+
did: z.ZodString;
|
|
114
|
+
handle: z.ZodString;
|
|
115
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
116
|
+
avatar: z.ZodOptional<z.ZodString>;
|
|
117
|
+
email: z.ZodOptional<z.ZodString>;
|
|
118
|
+
description: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, "strip", z.ZodTypeAny, {
|
|
120
|
+
did: string;
|
|
121
|
+
handle: string;
|
|
122
|
+
displayName?: string | undefined;
|
|
123
|
+
avatar?: string | undefined;
|
|
124
|
+
email?: string | undefined;
|
|
125
|
+
description?: string | undefined;
|
|
126
|
+
}, {
|
|
127
|
+
did: string;
|
|
128
|
+
handle: string;
|
|
129
|
+
displayName?: string | undefined;
|
|
130
|
+
avatar?: string | undefined;
|
|
131
|
+
email?: string | undefined;
|
|
132
|
+
description?: string | undefined;
|
|
133
|
+
}>;
|
|
134
|
+
export type ProfileResponse = z.infer<typeof profileResponseGuard>;
|
|
135
|
+
/**
|
|
136
|
+
* AuthorizationServerMetadata
|
|
137
|
+
* OAuth authorization server metadata
|
|
138
|
+
*/
|
|
139
|
+
export declare const authorizationServerMetadataGuard: z.ZodObject<{
|
|
140
|
+
issuer: z.ZodString;
|
|
141
|
+
pushed_authorization_request_endpoint: z.ZodString;
|
|
142
|
+
authorization_endpoint: z.ZodString;
|
|
143
|
+
token_endpoint: z.ZodString;
|
|
144
|
+
scopes_supported: z.ZodString;
|
|
145
|
+
}, "strip", z.ZodTypeAny, {
|
|
146
|
+
issuer: string;
|
|
147
|
+
pushed_authorization_request_endpoint: string;
|
|
148
|
+
authorization_endpoint: string;
|
|
149
|
+
token_endpoint: string;
|
|
150
|
+
scopes_supported: string;
|
|
151
|
+
}, {
|
|
152
|
+
issuer: string;
|
|
153
|
+
pushed_authorization_request_endpoint: string;
|
|
154
|
+
authorization_endpoint: string;
|
|
155
|
+
token_endpoint: string;
|
|
156
|
+
scopes_supported: string;
|
|
157
|
+
}>;
|
|
158
|
+
export type AuthorizationServerMetadata = z.infer<typeof authorizationServerMetadataGuard>;
|
|
159
|
+
/**
|
|
160
|
+
* ResourceServerMetadata
|
|
161
|
+
* OAuth protected resource metadata
|
|
162
|
+
*/
|
|
163
|
+
export declare const resourceServerMetadataGuard: z.ZodObject<{
|
|
164
|
+
authorization_servers: z.ZodArray<z.ZodString, "many">;
|
|
165
|
+
}, "strip", z.ZodTypeAny, {
|
|
166
|
+
authorization_servers: string[];
|
|
167
|
+
}, {
|
|
168
|
+
authorization_servers: string[];
|
|
169
|
+
}>;
|
|
170
|
+
export type ResourceServerMetadata = z.infer<typeof resourceServerMetadataGuard>;
|
|
171
|
+
/**
|
|
172
|
+
* DIDDocument
|
|
173
|
+
* AT Protocol DID document structure
|
|
174
|
+
*/
|
|
175
|
+
export declare const didDocumentGuard: z.ZodObject<{
|
|
176
|
+
id: z.ZodString;
|
|
177
|
+
service: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
178
|
+
type: z.ZodString;
|
|
179
|
+
serviceEndpoint: z.ZodString;
|
|
180
|
+
}, "strip", z.ZodTypeAny, {
|
|
181
|
+
type: string;
|
|
182
|
+
serviceEndpoint: string;
|
|
183
|
+
}, {
|
|
184
|
+
type: string;
|
|
185
|
+
serviceEndpoint: string;
|
|
186
|
+
}>, "many">>;
|
|
187
|
+
}, "strip", z.ZodTypeAny, {
|
|
188
|
+
id: string;
|
|
189
|
+
service?: {
|
|
190
|
+
type: string;
|
|
191
|
+
serviceEndpoint: string;
|
|
192
|
+
}[] | undefined;
|
|
193
|
+
}, {
|
|
194
|
+
id: string;
|
|
195
|
+
service?: {
|
|
196
|
+
type: string;
|
|
197
|
+
serviceEndpoint: string;
|
|
198
|
+
}[] | undefined;
|
|
199
|
+
}>;
|
|
200
|
+
export type DIDDocument = z.infer<typeof didDocumentGuard>;
|
|
201
|
+
/**
|
|
202
|
+
* PKCE Code Verifier and Challenge
|
|
203
|
+
*/
|
|
204
|
+
export interface PKCECodePair {
|
|
205
|
+
codeVerifier: string;
|
|
206
|
+
codeChallenge: string;
|
|
207
|
+
codeChallengeMethod: 'S256';
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* DPoP Key Pair and Nonce
|
|
211
|
+
*/
|
|
212
|
+
export interface DPoPKeyPair {
|
|
213
|
+
publicKey: CryptoKey;
|
|
214
|
+
privateKey: CryptoKey;
|
|
215
|
+
}
|
|
216
|
+
export interface DPoPNonce {
|
|
217
|
+
value: string;
|
|
218
|
+
server: string;
|
|
219
|
+
timestamp: number;
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkB9B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;gCAMd,CAAC;AAEjB,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE7D;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;EAG3B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE3D;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;EAQ7B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;EAO/B,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;EAM3C,CAAC;AAEH,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAE3F;;;GAGG;AACH,eAAO,MAAM,2BAA2B;;;;;;EAEtC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEjF;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;EAM3B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,SAAS,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
package/lib/types.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* BlueskyConfig
|
|
4
|
+
* Configuration for AT Protocol OAuth client
|
|
5
|
+
* Requires private_key_jwt for confidential client security
|
|
6
|
+
*/
|
|
7
|
+
export const blueskyConfigGuard = z.object({
|
|
8
|
+
clientMetadataUri: z.string().url(),
|
|
9
|
+
clientId: z.string().url().optional(),
|
|
10
|
+
jwksUri: z.string().url(),
|
|
11
|
+
scope: z.string().default('atproto transition:generic'),
|
|
12
|
+
tokenEndpointAuthMethod: z.literal('private_key_jwt'),
|
|
13
|
+
}).refine((data) => {
|
|
14
|
+
// JWKS URI is required for private_key_jwt
|
|
15
|
+
if (data.tokenEndpointAuthMethod === 'private_key_jwt' && !data.jwksUri) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}, {
|
|
20
|
+
message: 'jwksUri is required when tokenEndpointAuthMethod is private_key_jwt',
|
|
21
|
+
path: ['jwksUri'],
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* authResponseGuard
|
|
25
|
+
* Validates query parameters from AT Protocol authorization callback
|
|
26
|
+
*/
|
|
27
|
+
export const authResponseGuard = z.object({
|
|
28
|
+
code: z.string().optional(),
|
|
29
|
+
state: z.string().optional(),
|
|
30
|
+
iss: z.string().url().optional(),
|
|
31
|
+
error: z.string().optional(),
|
|
32
|
+
error_description: z.string().optional(),
|
|
33
|
+
}).passthrough();
|
|
34
|
+
/**
|
|
35
|
+
* PARResponse
|
|
36
|
+
* Response from Pushed Authorization Request
|
|
37
|
+
*/
|
|
38
|
+
export const parResponseGuard = z.object({
|
|
39
|
+
request_uri: z.string(),
|
|
40
|
+
expires_in: z.number().optional(),
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* TokenResponse
|
|
44
|
+
* AT Protocol OAuth token response
|
|
45
|
+
*/
|
|
46
|
+
export const tokenResponseGuard = z.object({
|
|
47
|
+
access_token: z.string(),
|
|
48
|
+
refresh_token: z.string().optional(),
|
|
49
|
+
token_type: z.literal('Bearer'),
|
|
50
|
+
expires_in: z.number(),
|
|
51
|
+
scope: z.string(),
|
|
52
|
+
sub: z.string(),
|
|
53
|
+
did: z.string().optional(), // Explicit DID field
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* ProfileResponse
|
|
57
|
+
* AT Protocol profile response from PDS
|
|
58
|
+
*/
|
|
59
|
+
export const profileResponseGuard = z.object({
|
|
60
|
+
did: z.string(),
|
|
61
|
+
handle: z.string(),
|
|
62
|
+
displayName: z.string().optional(),
|
|
63
|
+
avatar: z.string().optional(),
|
|
64
|
+
email: z.string().optional(),
|
|
65
|
+
description: z.string().optional(),
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* AuthorizationServerMetadata
|
|
69
|
+
* OAuth authorization server metadata
|
|
70
|
+
*/
|
|
71
|
+
export const authorizationServerMetadataGuard = z.object({
|
|
72
|
+
issuer: z.string().url(),
|
|
73
|
+
pushed_authorization_request_endpoint: z.string().url(),
|
|
74
|
+
authorization_endpoint: z.string().url(),
|
|
75
|
+
token_endpoint: z.string().url(),
|
|
76
|
+
scopes_supported: z.string(),
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* ResourceServerMetadata
|
|
80
|
+
* OAuth protected resource metadata
|
|
81
|
+
*/
|
|
82
|
+
export const resourceServerMetadataGuard = z.object({
|
|
83
|
+
authorization_servers: z.array(z.string().url()),
|
|
84
|
+
});
|
|
85
|
+
/**
|
|
86
|
+
* DIDDocument
|
|
87
|
+
* AT Protocol DID document structure
|
|
88
|
+
*/
|
|
89
|
+
export const didDocumentGuard = z.object({
|
|
90
|
+
id: z.string(),
|
|
91
|
+
service: z.array(z.object({
|
|
92
|
+
type: z.string(),
|
|
93
|
+
serviceEndpoint: z.string().url(),
|
|
94
|
+
})).optional(),
|
|
95
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openverifiable/connector-bluesky",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Bluesky/AT Protocol OAuth connector for LogTo with PAR, PKCE, and DPoP support",
|
|
5
|
+
"author": "OpenVerifiable (https://github.com/openverifiable)",
|
|
6
|
+
"homepage": "https://openverifiable.org",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"repository": "https://github.com/openverifiable/open-verifiable-logto-connectors.git",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"openverifiable",
|
|
11
|
+
"open-verifiable",
|
|
12
|
+
"logto",
|
|
13
|
+
"bluesky",
|
|
14
|
+
"atproto",
|
|
15
|
+
"oauth",
|
|
16
|
+
"dpop",
|
|
17
|
+
"pkce",
|
|
18
|
+
"par"
|
|
19
|
+
],
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/openverifiable/open-verifiable-logto-connectors/issues"
|
|
22
|
+
},
|
|
23
|
+
"main": "./lib/index.js",
|
|
24
|
+
"module": "./lib/index.js",
|
|
25
|
+
"exports": "./lib/index.js",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"files": [
|
|
28
|
+
"lib",
|
|
29
|
+
"**/*.svg",
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"package.json",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"precommit": "lint-staged",
|
|
36
|
+
"build:test": "rm -rf lib/ && tsc -p tsconfig.test.json",
|
|
37
|
+
"build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c && exit 0",
|
|
38
|
+
"format": "prettier --write 'src/**/*.{js,ts,cjs,mjs}'",
|
|
39
|
+
"lint": "eslint --ext .ts src",
|
|
40
|
+
"lint:report": "npm lint --format json --output-file report.json",
|
|
41
|
+
"test": "npm build:test && NODE_OPTIONS=--experimental-vm-modules jest",
|
|
42
|
+
"test:coverage": "npm run test --coverage --silent",
|
|
43
|
+
"test:unit": "npm build:test && NODE_OPTIONS=--experimental-vm-modules jest --testPathIgnorePatterns=integration",
|
|
44
|
+
"test:integration": "npm build:test && NODE_OPTIONS=--experimental-vm-modules jest --testPathPattern=integration"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@logto/connector-kit": "4.6.0",
|
|
48
|
+
"@silverhand/essentials": "2.8.4",
|
|
49
|
+
"got": "^14.2.1",
|
|
50
|
+
"jose": "^5.9.6",
|
|
51
|
+
"zod": "^3.22.4"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@jest/types": "^29.6.3",
|
|
55
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
56
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
57
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
58
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
59
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
60
|
+
"@semantic-release/commit-analyzer": "^11.1.0",
|
|
61
|
+
"@semantic-release/git": "^10.0.1",
|
|
62
|
+
"@semantic-release/github": "^9.2.6",
|
|
63
|
+
"@semantic-release/npm": "^11.0.3",
|
|
64
|
+
"@semantic-release/release-notes-generator": "^12.1.0",
|
|
65
|
+
"@silverhand/eslint-config": "3.0.1",
|
|
66
|
+
"@silverhand/jest-config": "4.0.0",
|
|
67
|
+
"@silverhand/ts-config": "^4.0.0",
|
|
68
|
+
"@types/jest": "^29.5.12",
|
|
69
|
+
"@types/node": "^20.12.7",
|
|
70
|
+
"@types/supertest": "^2.0.16",
|
|
71
|
+
"conventional-changelog-conventionalcommits": "^7.0.2",
|
|
72
|
+
"eslint": "^8.57.0",
|
|
73
|
+
"jest": "^29.7.0",
|
|
74
|
+
"jest-matcher-specific-error": "^1.0.0",
|
|
75
|
+
"lint-staged": "^15.2.2",
|
|
76
|
+
"nock": "^13.5.4",
|
|
77
|
+
"prettier": "^2.8.8",
|
|
78
|
+
"rollup": "^3.29.4",
|
|
79
|
+
"rollup-plugin-summary": "^2.0.0",
|
|
80
|
+
"semantic-release": "^22.0.12",
|
|
81
|
+
"supertest": "^6.3.4",
|
|
82
|
+
"typescript": "~5.1.6"
|
|
83
|
+
},
|
|
84
|
+
"eslintConfig": {
|
|
85
|
+
"extends": "@silverhand"
|
|
86
|
+
},
|
|
87
|
+
"prettier": "@silverhand/eslint-config/.prettierrc",
|
|
88
|
+
"publishConfig": {
|
|
89
|
+
"registry": "https://registry.npmjs.org/",
|
|
90
|
+
"access": "public"
|
|
91
|
+
},
|
|
92
|
+
"engines": {
|
|
93
|
+
"node": ">=20.0.0"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|