@auths-dev/sdk 0.0.1 → 0.1.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/Cargo.toml +45 -0
- package/README.md +163 -4
- package/__test__/client.spec.ts +78 -0
- package/__test__/exports.spec.ts +57 -0
- package/__test__/integration.spec.ts +407 -0
- package/__test__/policy.spec.ts +202 -0
- package/__test__/verify.spec.ts +88 -0
- package/build.rs +5 -0
- package/index.d.ts +259 -0
- package/index.js +622 -1
- package/lib/artifacts.ts +124 -0
- package/lib/attestations.ts +126 -0
- package/lib/audit.ts +189 -0
- package/lib/client.ts +293 -0
- package/lib/commits.ts +70 -0
- package/lib/devices.ts +178 -0
- package/lib/errors.ts +306 -0
- package/lib/identity.ts +280 -0
- package/lib/index.ts +125 -0
- package/lib/native.ts +255 -0
- package/lib/org.ts +235 -0
- package/lib/pairing.ts +271 -0
- package/lib/policy.ts +669 -0
- package/lib/signing.ts +204 -0
- package/lib/trust.ts +152 -0
- package/lib/types.ts +179 -0
- package/lib/verify.ts +241 -0
- package/lib/witness.ts +91 -0
- package/npm/darwin-arm64/README.md +3 -0
- package/npm/darwin-arm64/package.json +23 -0
- package/npm/linux-arm64-gnu/README.md +3 -0
- package/npm/linux-arm64-gnu/package.json +26 -0
- package/npm/linux-x64-gnu/README.md +3 -0
- package/npm/linux-x64-gnu/package.json +26 -0
- package/npm/win32-arm64-msvc/README.md +3 -0
- package/npm/win32-arm64-msvc/package.json +23 -0
- package/npm/win32-x64-msvc/README.md +3 -0
- package/npm/win32-x64-msvc/package.json +23 -0
- package/package.json +51 -16
- package/src/artifact.rs +217 -0
- package/src/attestation_query.rs +104 -0
- package/src/audit.rs +128 -0
- package/src/commit_sign.rs +63 -0
- package/src/device.rs +212 -0
- package/src/diagnostics.rs +106 -0
- package/src/error.rs +5 -0
- package/src/helpers.rs +60 -0
- package/src/identity.rs +467 -0
- package/src/lib.rs +26 -0
- package/src/org.rs +430 -0
- package/src/pairing.rs +454 -0
- package/src/policy.rs +147 -0
- package/src/sign.rs +215 -0
- package/src/trust.rs +189 -0
- package/src/types.rs +205 -0
- package/src/verify.rs +447 -0
- package/src/witness.rs +138 -0
- package/tsconfig.json +19 -0
- package/typedoc.json +18 -0
- package/vitest.config.ts +12 -0
package/lib/pairing.ts
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import native from './native'
|
|
2
|
+
import { mapNativeError, PairingError } from './errors'
|
|
3
|
+
import type { Auths } from './client'
|
|
4
|
+
|
|
5
|
+
/** An active pairing session awaiting a device connection. */
|
|
6
|
+
export interface PairingSession {
|
|
7
|
+
/** Unique session identifier. */
|
|
8
|
+
sessionId: string
|
|
9
|
+
/** Six-character code the device enters to pair. */
|
|
10
|
+
shortCode: string
|
|
11
|
+
/** HTTP endpoint the device connects to. */
|
|
12
|
+
endpoint: string
|
|
13
|
+
/** Authentication token for the session. */
|
|
14
|
+
token: string
|
|
15
|
+
/** DID of the controller identity running the session. */
|
|
16
|
+
controllerDid: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Response received when a device connects to a pairing session. */
|
|
20
|
+
export interface PairingResponse {
|
|
21
|
+
/** DID of the connecting device. */
|
|
22
|
+
deviceDid: string
|
|
23
|
+
/** Optional name of the device, or `null`. */
|
|
24
|
+
deviceName: string | null
|
|
25
|
+
/** Hex-encoded Ed25519 public key of the device. */
|
|
26
|
+
devicePublicKeyHex: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Result of completing a pairing and authorizing the device. */
|
|
30
|
+
export interface PairingResult {
|
|
31
|
+
/** DID of the paired device. */
|
|
32
|
+
deviceDid: string
|
|
33
|
+
/** Optional name of the device, or `null`. */
|
|
34
|
+
deviceName: string | null
|
|
35
|
+
/** Resource identifier of the authorization attestation. */
|
|
36
|
+
attestationRid: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Options for {@link PairingService.createSession}. */
|
|
40
|
+
export interface CreatePairingSessionOptions {
|
|
41
|
+
/** Capabilities to offer the pairing device (e.g. `['sign:commit']`). */
|
|
42
|
+
capabilities?: string[]
|
|
43
|
+
/** Timeout in seconds for the session. */
|
|
44
|
+
timeoutSecs?: number
|
|
45
|
+
/** Bind address for the pairing server (e.g. `'127.0.0.1'`). */
|
|
46
|
+
bindAddress?: string
|
|
47
|
+
/** Whether to enable mDNS discovery. */
|
|
48
|
+
enableMdns?: boolean
|
|
49
|
+
/** Override the client's passphrase. */
|
|
50
|
+
passphrase?: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Options for {@link PairingService.waitForResponse}. */
|
|
54
|
+
export interface WaitForPairingResponseOptions {
|
|
55
|
+
/** Timeout in seconds to wait for a device. */
|
|
56
|
+
timeoutSecs?: number
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Options for {@link PairingService.join}. */
|
|
60
|
+
export interface JoinPairingOptions {
|
|
61
|
+
/** Six-character short code from the pairing session. */
|
|
62
|
+
shortCode: string
|
|
63
|
+
/** HTTP endpoint of the pairing session. */
|
|
64
|
+
endpoint: string
|
|
65
|
+
/** Authentication token for the session. */
|
|
66
|
+
token: string
|
|
67
|
+
/** Optional name for this device. */
|
|
68
|
+
deviceName?: string
|
|
69
|
+
/** Override the client's passphrase. */
|
|
70
|
+
passphrase?: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Options for {@link PairingService.complete}. */
|
|
74
|
+
export interface CompletePairingOptions {
|
|
75
|
+
/** DID of the device to authorize. */
|
|
76
|
+
deviceDid: string
|
|
77
|
+
/** Hex-encoded Ed25519 public key of the device. */
|
|
78
|
+
devicePublicKeyHex: string
|
|
79
|
+
/** Capabilities to grant the device. */
|
|
80
|
+
capabilities?: string[]
|
|
81
|
+
/** Override the client's passphrase. */
|
|
82
|
+
passphrase?: string
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Handles device pairing for cross-device identity authorization.
|
|
87
|
+
*
|
|
88
|
+
* The pairing flow: controller creates a session, device joins with the
|
|
89
|
+
* short code, controller completes pairing to authorize the device.
|
|
90
|
+
*
|
|
91
|
+
* Access via {@link Auths.pairing}.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* const session = await auths.pairing.createSession({
|
|
96
|
+
* bindAddress: '127.0.0.1',
|
|
97
|
+
* capabilities: ['sign:commit'],
|
|
98
|
+
* })
|
|
99
|
+
* console.log(session.shortCode) // e.g. 'A3F7K2'
|
|
100
|
+
*
|
|
101
|
+
* // On the device side:
|
|
102
|
+
* const response = await auths.pairing.join({
|
|
103
|
+
* shortCode: 'A3F7K2',
|
|
104
|
+
* endpoint: session.endpoint,
|
|
105
|
+
* token: session.token,
|
|
106
|
+
* })
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export class PairingService {
|
|
110
|
+
private handle: any | null = null
|
|
111
|
+
|
|
112
|
+
constructor(private client: Auths) {}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Creates a pairing session and starts listening for device connections.
|
|
116
|
+
*
|
|
117
|
+
* @param opts - Session options.
|
|
118
|
+
* @returns The active pairing session with its short code and endpoint.
|
|
119
|
+
* @throws {@link PairingError} if session creation fails.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const session = await auths.pairing.createSession({
|
|
124
|
+
* bindAddress: '127.0.0.1',
|
|
125
|
+
* enableMdns: false,
|
|
126
|
+
* })
|
|
127
|
+
* console.log(session.shortCode) // 6-char code
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
async createSession(opts?: CreatePairingSessionOptions): Promise<PairingSession> {
|
|
131
|
+
const pp = opts?.passphrase ?? this.client.passphrase
|
|
132
|
+
const capsJson = opts?.capabilities ? JSON.stringify(opts.capabilities) : null
|
|
133
|
+
try {
|
|
134
|
+
this.handle = await native.NapiPairingHandle.createSession(
|
|
135
|
+
this.client.repoPath,
|
|
136
|
+
capsJson,
|
|
137
|
+
opts?.timeoutSecs ?? null,
|
|
138
|
+
opts?.bindAddress ?? null,
|
|
139
|
+
opts?.enableMdns ?? null,
|
|
140
|
+
pp,
|
|
141
|
+
)
|
|
142
|
+
const session = this.handle.session
|
|
143
|
+
return {
|
|
144
|
+
sessionId: session.sessionId,
|
|
145
|
+
shortCode: session.shortCode,
|
|
146
|
+
endpoint: session.endpoint,
|
|
147
|
+
token: session.token,
|
|
148
|
+
controllerDid: session.controllerDid,
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
throw mapNativeError(err, PairingError)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Waits for a device to connect to the active pairing session.
|
|
157
|
+
*
|
|
158
|
+
* @param opts - Wait options.
|
|
159
|
+
* @returns The connecting device's information.
|
|
160
|
+
* @throws {@link PairingError} if no session is active or timeout is reached.
|
|
161
|
+
*/
|
|
162
|
+
async waitForResponse(opts?: WaitForPairingResponseOptions): Promise<PairingResponse> {
|
|
163
|
+
if (!this.handle) {
|
|
164
|
+
throw new PairingError('No active pairing session. Call createSession first.', 'AUTHS_PAIRING_ERROR')
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const result = await this.handle.waitForResponse(opts?.timeoutSecs ?? null)
|
|
168
|
+
return {
|
|
169
|
+
deviceDid: result.deviceDid,
|
|
170
|
+
deviceName: result.deviceName ?? null,
|
|
171
|
+
devicePublicKeyHex: result.devicePublicKeyHex,
|
|
172
|
+
}
|
|
173
|
+
} catch (err) {
|
|
174
|
+
throw mapNativeError(err, PairingError)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Stops the active pairing session. Idempotent — safe to call multiple times.
|
|
180
|
+
*
|
|
181
|
+
* @throws {@link PairingError} if stopping the session fails.
|
|
182
|
+
*/
|
|
183
|
+
async stop(): Promise<void> {
|
|
184
|
+
if (this.handle) {
|
|
185
|
+
try {
|
|
186
|
+
await this.handle.stop()
|
|
187
|
+
} catch (err) {
|
|
188
|
+
throw mapNativeError(err, PairingError)
|
|
189
|
+
} finally {
|
|
190
|
+
this.handle = null
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Joins an existing pairing session from the device side.
|
|
197
|
+
*
|
|
198
|
+
* @param opts - Join options with short code and endpoint from the controller.
|
|
199
|
+
* @returns The pairing response with device identity information.
|
|
200
|
+
* @throws {@link PairingError} if joining fails.
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* const response = await auths.pairing.join({
|
|
205
|
+
* shortCode: 'A3F7K2',
|
|
206
|
+
* endpoint: 'http://127.0.0.1:8080',
|
|
207
|
+
* token: sessionToken,
|
|
208
|
+
* })
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
async join(opts: JoinPairingOptions): Promise<PairingResponse> {
|
|
212
|
+
const pp = opts.passphrase ?? this.client.passphrase
|
|
213
|
+
try {
|
|
214
|
+
const result = await native.joinPairingSession(
|
|
215
|
+
opts.shortCode,
|
|
216
|
+
opts.endpoint,
|
|
217
|
+
opts.token,
|
|
218
|
+
this.client.repoPath,
|
|
219
|
+
opts.deviceName ?? null,
|
|
220
|
+
pp,
|
|
221
|
+
)
|
|
222
|
+
return {
|
|
223
|
+
deviceDid: result.deviceDid,
|
|
224
|
+
deviceName: result.deviceName ?? null,
|
|
225
|
+
devicePublicKeyHex: result.devicePublicKeyHex,
|
|
226
|
+
}
|
|
227
|
+
} catch (err) {
|
|
228
|
+
throw mapNativeError(err, PairingError)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Completes pairing by authorizing the connected device.
|
|
234
|
+
*
|
|
235
|
+
* @param opts - Completion options with device identity and capabilities.
|
|
236
|
+
* @returns The pairing result with the device's authorization attestation.
|
|
237
|
+
* @throws {@link PairingError} if no session is active or completion fails.
|
|
238
|
+
*/
|
|
239
|
+
async complete(opts: CompletePairingOptions): Promise<PairingResult> {
|
|
240
|
+
if (!this.handle) {
|
|
241
|
+
throw new PairingError('No active pairing session. Call createSession first.', 'AUTHS_PAIRING_ERROR')
|
|
242
|
+
}
|
|
243
|
+
const pp = opts.passphrase ?? this.client.passphrase
|
|
244
|
+
const capsJson = opts.capabilities ? JSON.stringify(opts.capabilities) : null
|
|
245
|
+
try {
|
|
246
|
+
const result = await this.handle.complete(
|
|
247
|
+
opts.deviceDid,
|
|
248
|
+
opts.devicePublicKeyHex,
|
|
249
|
+
this.client.repoPath,
|
|
250
|
+
capsJson,
|
|
251
|
+
pp,
|
|
252
|
+
)
|
|
253
|
+
return {
|
|
254
|
+
deviceDid: result.deviceDid,
|
|
255
|
+
deviceName: result.deviceName ?? null,
|
|
256
|
+
attestationRid: result.attestationRid,
|
|
257
|
+
}
|
|
258
|
+
} catch (err) {
|
|
259
|
+
throw mapNativeError(err, PairingError)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
[Symbol.dispose](): void {
|
|
264
|
+
// Fire-and-forget stop for sync dispose
|
|
265
|
+
this.stop().catch(() => {})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async [Symbol.asyncDispose](): Promise<void> {
|
|
269
|
+
await this.stop()
|
|
270
|
+
}
|
|
271
|
+
}
|