@atproto/jwk 0.7.1 → 0.7.3
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/CHANGELOG.md +14 -0
- package/package.json +8 -5
- package/src/alg.ts +0 -111
- package/src/errors.ts +0 -56
- package/src/index.ts +0 -14
- package/src/jwk.ts +0 -263
- package/src/jwks.ts +0 -39
- package/src/jwt-decode.ts +0 -27
- package/src/jwt-verify.ts +0 -20
- package/src/jwt.ts +0 -220
- package/src/key.ts +0 -211
- package/src/keyset.ts +0 -254
- package/src/util.ts +0 -188
- package/tsconfig.build.json +0 -8
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -4
package/src/util.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { base64url } from 'multiformats/bases/base64'
|
|
2
|
-
import { RefinementCtx, ZodIssueCode } from 'zod'
|
|
3
|
-
|
|
4
|
-
export type Simplify<T> = { [K in keyof T]: T[K] } & {}
|
|
5
|
-
export type Override<T, V> = Simplify<V & Omit<T, keyof V>>
|
|
6
|
-
|
|
7
|
-
export type RequiredKey<T, K extends keyof T = never> = Simplify<
|
|
8
|
-
T & {
|
|
9
|
-
[L in K]-?: unknown extends T[L]
|
|
10
|
-
? NonNullable<unknown> | null
|
|
11
|
-
: Exclude<T[L], undefined>
|
|
12
|
-
}
|
|
13
|
-
>
|
|
14
|
-
|
|
15
|
-
export const isDefined = <T>(i: T | undefined): i is T => i !== undefined
|
|
16
|
-
|
|
17
|
-
export const preferredOrderCmp =
|
|
18
|
-
<T>(order: readonly T[]) =>
|
|
19
|
-
(a: T, b: T) => {
|
|
20
|
-
const aIdx = order.indexOf(a)
|
|
21
|
-
const bIdx = order.indexOf(b)
|
|
22
|
-
if (aIdx === bIdx) return 0
|
|
23
|
-
if (aIdx === -1) return 1
|
|
24
|
-
if (bIdx === -1) return -1
|
|
25
|
-
return aIdx - bIdx
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/* eslint-disable @typescript-eslint/no-unused-vars -- `v` is used at runtime in the returned type guards; v8 false-positive */
|
|
29
|
-
export function matchesAny<T extends string | number | symbol | boolean>(
|
|
30
|
-
value: null | undefined | T | readonly T[],
|
|
31
|
-
): (v: unknown) => v is T {
|
|
32
|
-
return value == null
|
|
33
|
-
? (v): v is T => true
|
|
34
|
-
: Array.isArray(value)
|
|
35
|
-
? (v): v is T => value.includes(v)
|
|
36
|
-
: (v): v is T => v === value
|
|
37
|
-
}
|
|
38
|
-
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Decorator to cache the result of a getter on a class instance.
|
|
42
|
-
*/
|
|
43
|
-
export const cachedGetter = <T extends object, V>(
|
|
44
|
-
target: (this: T) => V,
|
|
45
|
-
_context: ClassGetterDecoratorContext<T, V>,
|
|
46
|
-
) => {
|
|
47
|
-
return function (this: T) {
|
|
48
|
-
const value = target.call(this)
|
|
49
|
-
Object.defineProperty(this, target.name, {
|
|
50
|
-
get: () => value,
|
|
51
|
-
enumerable: true,
|
|
52
|
-
configurable: true,
|
|
53
|
-
})
|
|
54
|
-
return value
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const decoder = new TextDecoder()
|
|
59
|
-
export function parseB64uJson(input: string): unknown {
|
|
60
|
-
const inputBytes = base64url.baseDecode(input)
|
|
61
|
-
const json = decoder.decode(inputBytes)
|
|
62
|
-
return JSON.parse(json)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* @example
|
|
67
|
-
* ```ts
|
|
68
|
-
* // jwtSchema will only allow base64url chars & "." (dot)
|
|
69
|
-
* const jwtSchema = z.string().superRefine(jwtCharsRefinement)
|
|
70
|
-
* ```
|
|
71
|
-
*/
|
|
72
|
-
export const jwtCharsRefinement = (data: string, ctx: RefinementCtx): void => {
|
|
73
|
-
// Note: this is a hot path, let's avoid using a RegExp
|
|
74
|
-
let char
|
|
75
|
-
|
|
76
|
-
for (let i = 0; i < data.length; i++) {
|
|
77
|
-
char = data.charCodeAt(i)
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
// Base64 URL encoding (most frequent)
|
|
81
|
-
(65 <= char && char <= 90) || // A-Z
|
|
82
|
-
(97 <= char && char <= 122) || // a-z
|
|
83
|
-
(48 <= char && char <= 57) || // 0-9
|
|
84
|
-
char === 45 || // -
|
|
85
|
-
char === 95 || // _
|
|
86
|
-
// Boundary (least frequent, check last)
|
|
87
|
-
char === 46 // .
|
|
88
|
-
) {
|
|
89
|
-
// continue
|
|
90
|
-
} else {
|
|
91
|
-
// Invalid char might be a surrogate pair
|
|
92
|
-
const invalidChar = String.fromCodePoint(data.codePointAt(i)!)
|
|
93
|
-
return ctx.addIssue({
|
|
94
|
-
code: ZodIssueCode.custom,
|
|
95
|
-
message: `Invalid character "${invalidChar}" in JWT at position ${i}`,
|
|
96
|
-
})
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* @example
|
|
103
|
-
* ```ts
|
|
104
|
-
* type SegmentedString3 = SegmentedString<3> // `${string}.${string}.${string}`
|
|
105
|
-
* type SegmentedString4 = SegmentedString<4> // `${string}.${string}.${string}.${string}`
|
|
106
|
-
* ```
|
|
107
|
-
*
|
|
108
|
-
* @note
|
|
109
|
-
* This utility only provides one way type safety (A SegmentedString<4> can be
|
|
110
|
-
* assigned to SegmentedString<3> but not vice versa). The purpose of this
|
|
111
|
-
* utility is to improve DX by avoiding as many potential errors as build time.
|
|
112
|
-
* DO NOT rely on this to enforce security or data integrity.
|
|
113
|
-
*/
|
|
114
|
-
type SegmentedString<
|
|
115
|
-
C extends number,
|
|
116
|
-
Acc extends string[] = [string],
|
|
117
|
-
> = Acc['length'] extends C
|
|
118
|
-
? `${Acc[0]}`
|
|
119
|
-
: `${Acc[0]}.${SegmentedString<C, [string, ...Acc]>}`
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* @example
|
|
123
|
-
* ```ts
|
|
124
|
-
* const jwtSchema = z.string().superRefine(segmentedStringRefinementFactory(3))
|
|
125
|
-
* type Jwt = z.infer<typeof jwtSchema> // `${string}.${string}.${string}`
|
|
126
|
-
* ```
|
|
127
|
-
*/
|
|
128
|
-
export const segmentedStringRefinementFactory = <C extends number>(
|
|
129
|
-
count: C,
|
|
130
|
-
minPartLength = 2,
|
|
131
|
-
) => {
|
|
132
|
-
if (!Number.isFinite(count) || count < 1 || (count | 0) !== count) {
|
|
133
|
-
throw new TypeError(`Count must be a natural number (got ${count})`)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const minTotalLength = count * minPartLength + (count - 1)
|
|
137
|
-
const errorPrefix = `Invalid JWT format`
|
|
138
|
-
|
|
139
|
-
return (data: string, ctx: RefinementCtx): data is SegmentedString<C> => {
|
|
140
|
-
if (data.length < minTotalLength) {
|
|
141
|
-
ctx.addIssue({
|
|
142
|
-
code: ZodIssueCode.custom,
|
|
143
|
-
message: `${errorPrefix}: too short`,
|
|
144
|
-
})
|
|
145
|
-
return false
|
|
146
|
-
}
|
|
147
|
-
let currentStart = 0
|
|
148
|
-
for (let i = 0; i < count - 1; i++) {
|
|
149
|
-
const nextDot = data.indexOf('.', currentStart)
|
|
150
|
-
if (nextDot === -1) {
|
|
151
|
-
ctx.addIssue({
|
|
152
|
-
code: ZodIssueCode.custom,
|
|
153
|
-
message: `${errorPrefix}: expected ${count} segments, got ${i + 1}`,
|
|
154
|
-
})
|
|
155
|
-
return false
|
|
156
|
-
}
|
|
157
|
-
if (nextDot - currentStart < minPartLength) {
|
|
158
|
-
ctx.addIssue({
|
|
159
|
-
code: ZodIssueCode.custom,
|
|
160
|
-
message: `${errorPrefix}: segment ${i + 1} is too short`,
|
|
161
|
-
})
|
|
162
|
-
return false
|
|
163
|
-
}
|
|
164
|
-
currentStart = nextDot + 1
|
|
165
|
-
}
|
|
166
|
-
if (data.indexOf('.', currentStart) !== -1) {
|
|
167
|
-
ctx.addIssue({
|
|
168
|
-
code: ZodIssueCode.custom,
|
|
169
|
-
message: `${errorPrefix}: too many segments`,
|
|
170
|
-
})
|
|
171
|
-
return false
|
|
172
|
-
}
|
|
173
|
-
if (data.length - currentStart < minPartLength) {
|
|
174
|
-
ctx.addIssue({
|
|
175
|
-
code: ZodIssueCode.custom,
|
|
176
|
-
message: `${errorPrefix}: last segment is too short`,
|
|
177
|
-
})
|
|
178
|
-
return false
|
|
179
|
-
}
|
|
180
|
-
return true
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export function isLastOccurrence<
|
|
185
|
-
T extends number | boolean | string | null | undefined | symbol | bigint,
|
|
186
|
-
>(v: T, i: number, arr: readonly T[]): boolean {
|
|
187
|
-
return arr.indexOf(v, i + 1) === -1
|
|
188
|
-
}
|
package/tsconfig.build.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":"7.0.0-dev.20260614.1","root":["./src/alg.ts","./src/errors.ts","./src/index.ts","./src/jwk.ts","./src/jwks.ts","./src/jwt-decode.ts","./src/jwt-verify.ts","./src/jwt.ts","./src/key.ts","./src/keyset.ts","./src/util.ts"]}
|
package/tsconfig.json
DELETED