@atproto/oauth-types 0.7.2 → 0.7.4

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/util.d.ts +1 -1
  3. package/dist/util.d.ts.map +1 -1
  4. package/dist/util.js.map +1 -1
  5. package/package.json +11 -7
  6. package/src/atproto-loopback-client-id.ts +0 -78
  7. package/src/atproto-loopback-client-metadata.ts +0 -47
  8. package/src/atproto-loopback-client-redirect-uris.ts +0 -4
  9. package/src/atproto-oauth-scope.ts +0 -34
  10. package/src/atproto-oauth-token-response.ts +0 -16
  11. package/src/constants.ts +0 -2
  12. package/src/index.ts +0 -50
  13. package/src/oauth-access-token.ts +0 -4
  14. package/src/oauth-authorization-code-grant-token-request.ts +0 -19
  15. package/src/oauth-authorization-details.ts +0 -48
  16. package/src/oauth-authorization-request-jar.ts +0 -16
  17. package/src/oauth-authorization-request-par.ts +0 -12
  18. package/src/oauth-authorization-request-parameters.ts +0 -100
  19. package/src/oauth-authorization-request-query.ts +0 -21
  20. package/src/oauth-authorization-request-uri.ts +0 -10
  21. package/src/oauth-authorization-response-error.ts +0 -25
  22. package/src/oauth-authorization-server-metadata.ts +0 -120
  23. package/src/oauth-client-credentials-grant-token-request.ts +0 -9
  24. package/src/oauth-client-credentials.ts +0 -53
  25. package/src/oauth-client-id-discoverable.ts +0 -130
  26. package/src/oauth-client-id-loopback.ts +0 -164
  27. package/src/oauth-client-id.ts +0 -4
  28. package/src/oauth-client-metadata.ts +0 -80
  29. package/src/oauth-code-challenge-method.ts +0 -3
  30. package/src/oauth-endpoint-auth-method.ts +0 -13
  31. package/src/oauth-endpoint-name.ts +0 -8
  32. package/src/oauth-grant-type.ts +0 -13
  33. package/src/oauth-introspection-response.ts +0 -23
  34. package/src/oauth-issuer-identifier.ts +0 -47
  35. package/src/oauth-par-response.ts +0 -8
  36. package/src/oauth-password-grant-token-request.ts +0 -11
  37. package/src/oauth-prompt-mode.ts +0 -18
  38. package/src/oauth-protected-resource-metadata.ts +0 -94
  39. package/src/oauth-redirect-uri.ts +0 -73
  40. package/src/oauth-refresh-token-grant-token-request.ts +0 -11
  41. package/src/oauth-refresh-token.ts +0 -4
  42. package/src/oauth-request-uri.ts +0 -5
  43. package/src/oauth-response-mode.ts +0 -9
  44. package/src/oauth-response-type.ts +0 -17
  45. package/src/oauth-scope.ts +0 -21
  46. package/src/oauth-token-identification.ts +0 -12
  47. package/src/oauth-token-request.ts +0 -14
  48. package/src/oauth-token-response.ts +0 -29
  49. package/src/oauth-token-type.ts +0 -15
  50. package/src/oidc-authorization-error-response.ts +0 -29
  51. package/src/oidc-claims-parameter.ts +0 -40
  52. package/src/oidc-claims-properties.ts +0 -11
  53. package/src/oidc-entity-type.ts +0 -5
  54. package/src/oidc-userinfo.ts +0 -15
  55. package/src/uri.ts +0 -221
  56. package/src/util.ts +0 -170
  57. package/tsconfig.build.json +0 -8
  58. package/tsconfig.build.tsbuildinfo +0 -1
  59. package/tsconfig.json +0 -4
package/src/uri.ts DELETED
@@ -1,221 +0,0 @@
1
- import { TypeOf, ZodIssueCode, z } from 'zod'
2
- import {
3
- canParseUrl,
4
- isHostnameIP,
5
- isLocalHostname,
6
- isLoopbackHost,
7
- } from './util.js'
8
-
9
- /**
10
- * Valid, but potentially dangerous URL (`data:`, `file:`, `javascript:`, etc.).
11
- *
12
- * Any value that matches this schema is safe to parse using `new URL()`.
13
- */
14
- export const dangerousUriSchema = z
15
- .string()
16
- .refine(
17
- (data): data is `${string}:${string}` =>
18
- data.includes(':') && canParseUrl(data),
19
- {
20
- message: 'Invalid URL',
21
- },
22
- )
23
-
24
- /**
25
- * Valid, but potentially dangerous URL (`data:`, `file:`, `javascript:`, etc.).
26
- */
27
- export type DangerousUrl = TypeOf<typeof dangerousUriSchema>
28
-
29
- export const loopbackUriSchema = dangerousUriSchema.superRefine(
30
- (
31
- value,
32
- ctx,
33
- ): value is
34
- | `http://[::1]${string}`
35
- | `http://localhost${'' | `${':' | '/' | '?' | '#'}${string}`}`
36
- | `http://127.0.0.1${'' | `${':' | '/' | '?' | '#'}${string}`}` => {
37
- // Loopback url must use the "http:" protocol
38
- if (!value.startsWith('http://')) {
39
- ctx.addIssue({
40
- code: ZodIssueCode.custom,
41
- message: 'URL must use the "http:" protocol',
42
- })
43
- return false
44
- }
45
-
46
- const url = new URL(value)
47
-
48
- if (!isLoopbackHost(url.hostname)) {
49
- ctx.addIssue({
50
- code: ZodIssueCode.custom,
51
- message: 'URL must use "localhost", "127.0.0.1" or "[::1]" as hostname',
52
- })
53
- return false
54
- }
55
-
56
- return true
57
- },
58
- )
59
-
60
- export type LoopbackUri = TypeOf<typeof loopbackUriSchema>
61
-
62
- export const httpsUriSchema = dangerousUriSchema.superRefine(
63
- (value, ctx): value is `https://${string}` => {
64
- if (!value.startsWith('https://')) {
65
- ctx.addIssue({
66
- code: ZodIssueCode.custom,
67
- message: 'URL must use the "https:" protocol',
68
- })
69
- return false
70
- }
71
-
72
- const url = new URL(value)
73
-
74
- // Disallow loopback URLs with the `https:` protocol
75
- if (isLoopbackHost(url.hostname)) {
76
- ctx.addIssue({
77
- code: ZodIssueCode.custom,
78
- message: 'https: URL must not use a loopback host',
79
- })
80
- return false
81
- }
82
-
83
- if (isHostnameIP(url.hostname)) {
84
- // Hostname is an IP address
85
- } else {
86
- // Hostname is a domain name
87
- if (!url.hostname.includes('.')) {
88
- // we don't depend on PSL here, so we only check for a dot
89
- ctx.addIssue({
90
- code: ZodIssueCode.custom,
91
- message: 'Domain name must contain at least two segments',
92
- })
93
- return false
94
- }
95
-
96
- if (url.hostname.endsWith('.local')) {
97
- ctx.addIssue({
98
- code: ZodIssueCode.custom,
99
- message: 'Domain name must not end with ".local"',
100
- })
101
- return false
102
- }
103
- }
104
-
105
- return true
106
- },
107
- )
108
-
109
- export type HttpsUri = TypeOf<typeof httpsUriSchema>
110
-
111
- export const webUriSchema = z
112
- .string()
113
- .superRefine((value, ctx): value is LoopbackUri | HttpsUri => {
114
- // discriminated union of `loopbackUriSchema` and `httpsUriSchema`
115
- if (value.startsWith('http://')) {
116
- const result = loopbackUriSchema.safeParse(value)
117
- if (!result.success) result.error.issues.forEach(ctx.addIssue, ctx)
118
- return result.success
119
- }
120
-
121
- if (value.startsWith('https://')) {
122
- const result = httpsUriSchema.safeParse(value)
123
- if (!result.success) result.error.issues.forEach(ctx.addIssue, ctx)
124
- return result.success
125
- }
126
-
127
- ctx.addIssue({
128
- code: ZodIssueCode.custom,
129
- message: 'URL must use the "http:" or "https:" protocol',
130
- })
131
- return false
132
- })
133
-
134
- export type WebUri = TypeOf<typeof webUriSchema>
135
-
136
- export const privateUseUriSchema = dangerousUriSchema.superRefine(
137
- (value, ctx): value is `${string}.${string}:/${string}` => {
138
- const dotIdx = value.indexOf('.')
139
- const colonIdx = value.indexOf(':')
140
-
141
- // Optimization: avoid parsing the URL if the protocol does not contain a "."
142
- if (dotIdx === -1 || colonIdx === -1 || dotIdx > colonIdx) {
143
- ctx.addIssue({
144
- code: ZodIssueCode.custom,
145
- message:
146
- 'Private-use URI scheme requires a "." as part of the protocol',
147
- })
148
- return false
149
- }
150
-
151
- const url = new URL(value)
152
-
153
- // Should be covered by the check before, but let's be extra sure
154
- if (!url.protocol.includes('.')) {
155
- ctx.addIssue({
156
- code: ZodIssueCode.custom,
157
- message: 'Invalid private-use URI scheme',
158
- })
159
- return false
160
- }
161
-
162
- // https://datatracker.ietf.org/doc/html/rfc8252#section-7.1
163
- //
164
- // > When choosing a URI scheme to associate with the app, apps MUST use a
165
- // > URI scheme based on a domain name under their control, expressed in
166
- // > reverse order
167
- //
168
- // https://datatracker.ietf.org/doc/html/rfc8252#section-8.4
169
- //
170
- // > In addition to the collision-resistant properties, requiring a URI
171
- // > scheme based on a domain name that is under the control of the app can
172
- // > help to prove ownership in the event of a dispute where two apps claim
173
- // > the same private-use URI scheme (where one app is acting maliciously).
174
- //
175
- // We can't check for ownership here (as there is no concept of proven
176
- // ownership in a generic validation logic), besides excluding local domains
177
- // as they can't be controlled/owned by the app.
178
- //
179
- // https://atproto.com/specs/oauth
180
- //
181
- // > Any custom scheme must match the `client_id` hostname in reverse-domain
182
- // > order.
183
- //
184
- // This ATPROTO specific requirement cannot be enforced here, (as there is
185
- // no concept of `client_id` in this context).
186
-
187
- const uriScheme = url.protocol.slice(0, -1) // remove trailing ":"
188
- const urlDomain = uriScheme.split('.').reverse().join('.')
189
-
190
- if (isLocalHostname(urlDomain)) {
191
- ctx.addIssue({
192
- code: ZodIssueCode.custom,
193
- message: `Private-use URI Scheme redirect URI must not be a local hostname`,
194
- })
195
- }
196
-
197
- // https://datatracker.ietf.org/doc/html/rfc8252#section-7.1
198
- //
199
- // > Following the requirements of Section 3.2 of [RFC3986], as there is no
200
- // > naming authority for private-use URI scheme redirects, only a single
201
- // > slash ("/") appears after the scheme component.
202
- if (
203
- url.href.startsWith(`${url.protocol}//`) ||
204
- url.username ||
205
- url.password ||
206
- url.hostname ||
207
- url.port
208
- ) {
209
- ctx.addIssue({
210
- code: ZodIssueCode.custom,
211
- message:
212
- 'Private-Use URI Scheme must be in the form <scheme>:/{path} (notice the single slash!) as per RFC 8252',
213
- })
214
- return false
215
- }
216
-
217
- return true
218
- },
219
- )
220
-
221
- export type PrivateUseUri = TypeOf<typeof privateUseUriSchema>
package/src/util.ts DELETED
@@ -1,170 +0,0 @@
1
- export const canParseUrl =
2
- // eslint-disable-next-line n/no-unsupported-features/node-builtins
3
- URL.canParse?.bind(URL) ??
4
- // URL.canParse is not available in Node.js < 18.7.0
5
- ((urlStr: string): boolean => {
6
- try {
7
- new URL(urlStr)
8
- return true
9
- } catch {
10
- return false
11
- }
12
- })
13
-
14
- export function isHostnameIP(hostname: string) {
15
- // IPv4
16
- if (hostname.match(/^\d+\.\d+\.\d+\.\d+$/)) return true
17
-
18
- // IPv6
19
- if (hostname.startsWith('[') && hostname.endsWith(']')) return true
20
-
21
- return false
22
- }
23
-
24
- export type LoopbackHost = 'localhost' | '127.0.0.1' | '[::1]'
25
-
26
- export function isLoopbackHost(host: unknown): host is LoopbackHost {
27
- return host === 'localhost' || host === '127.0.0.1' || host === '[::1]'
28
- }
29
-
30
- export function isLocalHostname(hostname: string): boolean {
31
- const parts = hostname.split('.')
32
- if (parts.length < 2) return true
33
-
34
- const tld = parts.at(-1)!.toLowerCase()
35
- return (
36
- tld === 'test' ||
37
- tld === 'local' ||
38
- tld === 'localhost' ||
39
- tld === 'invalid' ||
40
- tld === 'example'
41
- )
42
- }
43
-
44
- export function safeUrl(input: URL | string): URL | null {
45
- try {
46
- return new URL(input)
47
- } catch {
48
- return null
49
- }
50
- }
51
-
52
- export function extractUrlPath(url) {
53
- // Extracts the path from a URL, without relying on the URL constructor
54
- // (because it normalizes the URL)
55
- const endOfProtocol = url.startsWith('https://')
56
- ? 8
57
- : url.startsWith('http://')
58
- ? 7
59
- : -1
60
- if (endOfProtocol === -1) {
61
- throw new TypeError('URL must use the "https:" or "http:" protocol')
62
- }
63
-
64
- const hashIdx = url.indexOf('#', endOfProtocol)
65
- const questionIdx = url.indexOf('?', endOfProtocol)
66
-
67
- const queryStrIdx =
68
- questionIdx !== -1 && (hashIdx === -1 || questionIdx < hashIdx)
69
- ? questionIdx
70
- : -1
71
-
72
- const pathEnd =
73
- hashIdx === -1
74
- ? queryStrIdx === -1
75
- ? url.length
76
- : queryStrIdx
77
- : queryStrIdx === -1
78
- ? hashIdx
79
- : Math.min(hashIdx, queryStrIdx)
80
-
81
- const slashIdx = url.indexOf('/', endOfProtocol)
82
-
83
- const pathStart = slashIdx === -1 || slashIdx > pathEnd ? pathEnd : slashIdx
84
-
85
- if (endOfProtocol === pathStart) {
86
- throw new TypeError('URL must contain a host')
87
- }
88
-
89
- return url.substring(pathStart, pathEnd)
90
- }
91
-
92
- export const jsonObjectPreprocess = (val: unknown) => {
93
- if (typeof val === 'string' && val.startsWith('{') && val.endsWith('}')) {
94
- try {
95
- return JSON.parse(val)
96
- } catch {
97
- return val
98
- }
99
- }
100
-
101
- return val
102
- }
103
-
104
- export const numberPreprocess = (val: unknown): unknown => {
105
- if (typeof val === 'string') {
106
- const number = Number(val)
107
- if (!Number.isNaN(number)) return number
108
- }
109
- return val
110
- }
111
-
112
- /**
113
- * Returns true if the two arrays contain the same elements, regardless of order
114
- * or duplicates.
115
- */
116
- export function arrayEquivalent<T>(a: readonly T[], b: readonly T[]) {
117
- if (a === b) return true
118
- return a.every(includedIn, b) && b.every(includedIn, a)
119
- }
120
-
121
- export function includedIn<T>(this: readonly T[], item: T) {
122
- return this.includes(item)
123
- }
124
-
125
- export function asArray<T>(
126
- value: Iterable<T> | undefined,
127
- ): undefined | readonly T[] {
128
- if (value == null) return undefined
129
- if (Array.isArray(value)) return value // already a (possibly readonly) array
130
- return Array.from(value)
131
- }
132
-
133
- export type SpaceSeparatedValue<Value extends string> =
134
- `${'' | `${string} `}${Value}${'' | ` ${string}`}`
135
-
136
- export const isSpaceSeparatedValue = <Value extends string>(
137
- value: Value,
138
- input: string,
139
- ): input is SpaceSeparatedValue<Value> => {
140
- if (value.length === 0) throw new TypeError('Value cannot be empty')
141
- if (value.includes(' ')) throw new TypeError('Value cannot contain spaces')
142
-
143
- // Optimized version of:
144
- // return input.split(' ').includes(value)
145
-
146
- const inputLength = input.length
147
- const valueLength = value.length
148
-
149
- if (inputLength < valueLength) return false
150
-
151
- let idx = input.indexOf(value)
152
- let idxEnd: number
153
-
154
- while (idx !== -1) {
155
- idxEnd = idx + valueLength
156
-
157
- if (
158
- // at beginning or preceded by space
159
- (idx === 0 || input.charCodeAt(idx - 1) === 32) &&
160
- // at end or followed by space
161
- (idxEnd === inputLength || input.charCodeAt(idxEnd) === 32)
162
- ) {
163
- return true
164
- }
165
-
166
- idx = input.indexOf(value, idxEnd + 1)
167
- }
168
-
169
- return false
170
- }
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig/isomorphic.json",
3
- "compilerOptions": {
4
- "rootDir": "./src",
5
- "outDir": "./dist",
6
- },
7
- "include": ["./src"],
8
- }
@@ -1 +0,0 @@
1
- {"version":"7.0.0-dev.20260614.1","root":["./src/atproto-loopback-client-id.ts","./src/atproto-loopback-client-metadata.ts","./src/atproto-loopback-client-redirect-uris.ts","./src/atproto-oauth-scope.ts","./src/atproto-oauth-token-response.ts","./src/constants.ts","./src/index.ts","./src/oauth-access-token.ts","./src/oauth-authorization-code-grant-token-request.ts","./src/oauth-authorization-details.ts","./src/oauth-authorization-request-jar.ts","./src/oauth-authorization-request-par.ts","./src/oauth-authorization-request-parameters.ts","./src/oauth-authorization-request-query.ts","./src/oauth-authorization-request-uri.ts","./src/oauth-authorization-response-error.ts","./src/oauth-authorization-server-metadata.ts","./src/oauth-client-credentials-grant-token-request.ts","./src/oauth-client-credentials.ts","./src/oauth-client-id-discoverable.ts","./src/oauth-client-id-loopback.ts","./src/oauth-client-id.ts","./src/oauth-client-metadata.ts","./src/oauth-code-challenge-method.ts","./src/oauth-endpoint-auth-method.ts","./src/oauth-endpoint-name.ts","./src/oauth-grant-type.ts","./src/oauth-introspection-response.ts","./src/oauth-issuer-identifier.ts","./src/oauth-par-response.ts","./src/oauth-password-grant-token-request.ts","./src/oauth-prompt-mode.ts","./src/oauth-protected-resource-metadata.ts","./src/oauth-redirect-uri.ts","./src/oauth-refresh-token-grant-token-request.ts","./src/oauth-refresh-token.ts","./src/oauth-request-uri.ts","./src/oauth-response-mode.ts","./src/oauth-response-type.ts","./src/oauth-scope.ts","./src/oauth-token-identification.ts","./src/oauth-token-request.ts","./src/oauth-token-response.ts","./src/oauth-token-type.ts","./src/oidc-authorization-error-response.ts","./src/oidc-claims-parameter.ts","./src/oidc-claims-properties.ts","./src/oidc-entity-type.ts","./src/oidc-userinfo.ts","./src/uri.ts","./src/util.ts"]}
package/tsconfig.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "include": [],
3
- "references": [{ "path": "./tsconfig.build.json" }],
4
- }