@bradford-tech/supabase-integrity-attest 0.8.0 → 0.8.1

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.
@@ -40,7 +40,12 @@ export interface AttestationCbor {
40
40
  };
41
41
  authData: Uint8Array;
42
42
  }
43
- /** Decode an Apple App Attest attestation object from raw CBOR bytes. */
43
+ /**
44
+ * Decode an Apple App Attest attestation object from raw CBOR bytes.
45
+ *
46
+ * @throws {AttestationError} with code `INVALID_FORMAT` if the data is not
47
+ * a valid attestation CBOR structure.
48
+ */
44
49
  export declare function decodeAttestationCbor(data: Uint8Array): AttestationCbor;
45
50
  /**
46
51
  * Verify an Apple App Attest attestation.
@@ -1 +1 @@
1
- {"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../../src/src/attestation.ts"],"names":[],"mappings":"AAaA,yCAAyC;AACzC,MAAM,WAAW,OAAO;IACtB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,OAAO,EAAE,UAAU,CAAC;IACpB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iDAAiD;AACjD,MAAM,WAAW,wBAAwB;IACvC,uFAAuF;IACvF,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE;QACP,GAAG,EAAE,UAAU,EAAE,CAAC;QAClB,OAAO,EAAE,UAAU,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,UAAU,CAAC;CACtB;AAsGD,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,eAAe,CAyEvE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,UAAU,GAAG,MAAM,EACnC,WAAW,EAAE,UAAU,GAAG,MAAM,EAChC,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,iBAAiB,CAAC,CAkJ5B"}
1
+ {"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../../src/src/attestation.ts"],"names":[],"mappings":"AAgBA,yCAAyC;AACzC,MAAM,WAAW,OAAO;IACtB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,kDAAkD;AAClD,MAAM,WAAW,iBAAiB;IAChC,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,OAAO,EAAE,UAAU,CAAC;IACpB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iDAAiD;AACjD,MAAM,WAAW,wBAAwB;IACvC,uFAAuF;IACvF,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE;QACP,GAAG,EAAE,UAAU,EAAE,CAAC;QAClB,OAAO,EAAE,UAAU,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,UAAU,CAAC;CACtB;AAsGD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,eAAe,CAwFvE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,UAAU,GAAG,MAAM,EACnC,WAAW,EAAE,UAAU,GAAG,MAAM,EAChC,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,iBAAiB,CAAC,CAoJ5B"}
@@ -3,7 +3,7 @@ import { decodeBase64 } from "../deps/jsr.io/@std/encoding/1.0.10/base64.js";
3
3
  import { extractNonceFromCert, extractPublicKeyFromCert, verifyCertificateChain, } from "./certificate.js";
4
4
  import { AAGUID_DEVELOPMENT, AAGUID_PRODUCTION } from "./constants.js";
5
5
  import { AttestationError, AttestationErrorCode } from "./errors.js";
6
- import { parseAttestationAuthData } from "./authdata.js";
6
+ import { parseAttestationAuthData, } from "./authdata.js";
7
7
  import { concat, constantTimeEqual, exportKeyToPem, toBytes } from "./utils.js";
8
8
  /** Read a CBOR unsigned integer (additional info + following bytes). */
9
9
  function readCborUint(data, offset) {
@@ -88,72 +88,86 @@ function findCborTextKey(data, key, startOffset) {
88
88
  }
89
89
  return -1;
90
90
  }
91
- /** Decode an Apple App Attest attestation object from raw CBOR bytes. */
91
+ /**
92
+ * Decode an Apple App Attest attestation object from raw CBOR bytes.
93
+ *
94
+ * @throws {AttestationError} with code `INVALID_FORMAT` if the data is not
95
+ * a valid attestation CBOR structure.
96
+ */
92
97
  export function decodeAttestationCbor(data) {
93
- // Verify top-level is a CBOR map
94
- const majorType = (data[0] >> 5) & 0x07;
95
- if (majorType !== 5) {
96
- throw new Error("Expected CBOR map at top level");
97
- }
98
- // Find "fmt" key and read its value
99
- const fmtKeyPos = findCborTextKey(data, "fmt", 0);
100
- if (fmtKeyPos === -1)
101
- throw new Error('Missing "fmt" key');
102
- const fmtKeyEnd = fmtKeyPos + 1 + 3; // 0x63 + "fmt"
103
- const { value: fmt } = readCborText(data, fmtKeyEnd);
104
- // Find "attStmt" key
105
- const attStmtKeyPos = findCborTextKey(data, "attStmt", 0);
106
- if (attStmtKeyPos === -1)
107
- throw new Error('Missing "attStmt" key');
108
- // After "attStmt" key: 0x67 + "attStmt" = 8 bytes
109
- const attStmtValuePos = attStmtKeyPos + 8;
110
- // attStmt value should be a map
111
- const attStmtMajor = (data[attStmtValuePos] >> 5) & 0x07;
112
- if (attStmtMajor !== 5)
113
- throw new Error("attStmt is not a CBOR map");
114
- // Find "x5c" key within attStmt
115
- const x5cKeyPos = findCborTextKey(data, "x5c", attStmtValuePos);
116
- if (x5cKeyPos === -1)
117
- throw new Error('Missing "x5c" key in attStmt');
118
- const x5cValuePos = x5cKeyPos + 4; // 0x63 + "x5c"
119
- // x5c value is an array
120
- const x5cMajor = (data[x5cValuePos] >> 5) & 0x07;
121
- if (x5cMajor !== 4)
122
- throw new Error("x5c is not a CBOR array");
123
- const { value: x5cCount, end: x5cFirstItemPos } = readCborUint(data, x5cValuePos);
124
- // Read each certificate byte string
125
- const x5c = [];
126
- let pos = x5cFirstItemPos;
127
- for (let i = 0; i < x5cCount; i++) {
128
- const { value: cert, end } = readCborBytes(data, pos);
129
- x5c.push(cert);
130
- pos = end;
98
+ try {
99
+ // Verify top-level is a CBOR map
100
+ const majorType = (data[0] >> 5) & 0x07;
101
+ if (majorType !== 5) {
102
+ throw new Error("Expected CBOR map at top level");
103
+ }
104
+ // Find "fmt" key and read its value
105
+ const fmtKeyPos = findCborTextKey(data, "fmt", 0);
106
+ if (fmtKeyPos === -1)
107
+ throw new Error('Missing "fmt" key');
108
+ const fmtKeyEnd = fmtKeyPos + 1 + 3; // 0x63 + "fmt"
109
+ const { value: fmt } = readCborText(data, fmtKeyEnd);
110
+ // Find "attStmt" key
111
+ const attStmtKeyPos = findCborTextKey(data, "attStmt", 0);
112
+ if (attStmtKeyPos === -1)
113
+ throw new Error('Missing "attStmt" key');
114
+ // After "attStmt" key: 0x67 + "attStmt" = 8 bytes
115
+ const attStmtValuePos = attStmtKeyPos + 8;
116
+ // attStmt value should be a map
117
+ const attStmtMajor = (data[attStmtValuePos] >> 5) & 0x07;
118
+ if (attStmtMajor !== 5)
119
+ throw new Error("attStmt is not a CBOR map");
120
+ // Find "x5c" key within attStmt
121
+ const x5cKeyPos = findCborTextKey(data, "x5c", attStmtValuePos);
122
+ if (x5cKeyPos === -1)
123
+ throw new Error('Missing "x5c" key in attStmt');
124
+ const x5cValuePos = x5cKeyPos + 4; // 0x63 + "x5c"
125
+ // x5c value is an array
126
+ const x5cMajor = (data[x5cValuePos] >> 5) & 0x07;
127
+ if (x5cMajor !== 4)
128
+ throw new Error("x5c is not a CBOR array");
129
+ const { value: x5cCount, end: x5cFirstItemPos } = readCborUint(data, x5cValuePos);
130
+ // Read each certificate byte string
131
+ const x5c = [];
132
+ let pos = x5cFirstItemPos;
133
+ for (let i = 0; i < x5cCount; i++) {
134
+ const { value: cert, end } = readCborBytes(data, pos);
135
+ x5c.push(cert);
136
+ pos = end;
137
+ }
138
+ // After x5c, find "receipt" key
139
+ const receiptKeyPos = findCborTextKey(data, "receipt", pos);
140
+ if (receiptKeyPos === -1) {
141
+ throw new Error('Missing "receipt" key in attStmt');
142
+ }
143
+ // Find "authData" key - search from after the receipt key position
144
+ const authDataKeyPos = findCborTextKey(data, "authData", receiptKeyPos);
145
+ if (authDataKeyPos === -1) {
146
+ throw new Error('Missing "authData" key');
147
+ }
148
+ // The receipt value is the bytes between the receipt key end and the authData key start.
149
+ // Receipt key: 0x67 + "receipt" = 8 bytes
150
+ const receiptValueStart = receiptKeyPos + 8;
151
+ // Read the receipt CBOR header to get the data start offset
152
+ const receiptMajor = (data[receiptValueStart] >> 5) & 0x07;
153
+ if (receiptMajor !== 2) {
154
+ throw new Error("receipt is not a CBOR byte string");
155
+ }
156
+ const { end: receiptDataStart } = readCborUint(data, receiptValueStart);
157
+ // The actual receipt data extends to just before the authData key.
158
+ // This handles the case where Apple's CBOR length header is incorrect.
159
+ const receipt = data.slice(receiptDataStart, authDataKeyPos);
160
+ // Read authData value
161
+ // authData key: 0x68 + "authData" = 9 bytes
162
+ const authDataValuePos = authDataKeyPos + 9;
163
+ const { value: authData } = readCborBytes(data, authDataValuePos);
164
+ return { fmt, attStmt: { x5c, receipt }, authData };
131
165
  }
132
- // After x5c, find "receipt" key
133
- const receiptKeyPos = findCborTextKey(data, "receipt", pos);
134
- if (receiptKeyPos === -1)
135
- throw new Error('Missing "receipt" key in attStmt');
136
- // Find "authData" key - search from after the receipt key position
137
- const authDataKeyPos = findCborTextKey(data, "authData", receiptKeyPos);
138
- if (authDataKeyPos === -1) {
139
- throw new Error('Missing "authData" key');
166
+ catch (e) {
167
+ if (e instanceof AttestationError)
168
+ throw e;
169
+ throw new AttestationError(AttestationErrorCode.INVALID_FORMAT, `Failed to CBOR-decode attestation object: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
140
170
  }
141
- // The receipt value is the bytes between the receipt key end and the authData key start.
142
- // Receipt key: 0x67 + "receipt" = 8 bytes
143
- const receiptValueStart = receiptKeyPos + 8;
144
- // Read the receipt CBOR header to get the data start offset
145
- const receiptMajor = (data[receiptValueStart] >> 5) & 0x07;
146
- if (receiptMajor !== 2)
147
- throw new Error("receipt is not a CBOR byte string");
148
- const { end: receiptDataStart } = readCborUint(data, receiptValueStart);
149
- // The actual receipt data extends to just before the authData key.
150
- // This handles the case where Apple's CBOR length header is incorrect.
151
- const receipt = data.slice(receiptDataStart, authDataKeyPos);
152
- // Read authData value
153
- // authData key: 0x68 + "authData" = 9 bytes
154
- const authDataValuePos = authDataKeyPos + 9;
155
- const { value: authData } = readCborBytes(data, authDataValuePos);
156
- return { fmt, attStmt: { x5c, receipt }, authData };
157
171
  }
158
172
  /**
159
173
  * Verify an Apple App Attest attestation.
@@ -188,13 +202,7 @@ export async function verifyAttestation(appInfo, keyId, clientDataHash, attestat
188
202
  attestationBytes = attestation;
189
203
  }
190
204
  // Step 1: CBOR decode attestation -> { fmt, attStmt: { x5c, receipt }, authData }
191
- let decoded;
192
- try {
193
- decoded = decodeAttestationCbor(attestationBytes);
194
- }
195
- catch {
196
- throw new AttestationError(AttestationErrorCode.INVALID_FORMAT, "Failed to CBOR-decode attestation object");
197
- }
205
+ const decoded = decodeAttestationCbor(attestationBytes);
198
206
  // Step 2: Validate fmt === "apple-appattest"
199
207
  if (decoded.fmt !== "apple-appattest") {
200
208
  throw new AttestationError(AttestationErrorCode.INVALID_FORMAT, `Invalid attestation format: expected "apple-appattest", got "${decoded.fmt}"`);
@@ -228,7 +236,13 @@ export async function verifyAttestation(appInfo, keyId, clientDataHash, attestat
228
236
  throw new AttestationError(AttestationErrorCode.KEY_ID_MISMATCH, "Public key hash does not match keyId");
229
237
  }
230
238
  // Step 11: Parse authData
231
- const parsedAuthData = parseAttestationAuthData(authData);
239
+ let parsedAuthData;
240
+ try {
241
+ parsedAuthData = parseAttestationAuthData(authData);
242
+ }
243
+ catch (e) {
244
+ throw new AttestationError(AttestationErrorCode.INVALID_FORMAT, `Invalid authenticatorData: ${e instanceof Error ? e.message : String(e)}`);
245
+ }
232
246
  // Step 12: Verify rpIdHash === SHA-256(appId)
233
247
  const appIdHash = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(appInfo.appId)));
234
248
  if (!constantTimeEqual(parsedAuthData.rpIdHash, appIdHash)) {
@@ -6,7 +6,6 @@ export interface AssertionAuthData {
6
6
  export interface AttestationAuthData extends AssertionAuthData {
7
7
  aaguid: Uint8Array;
8
8
  credentialId: Uint8Array;
9
- coseKeyBytes: Uint8Array;
10
9
  }
11
10
  export declare function parseAssertionAuthData(data: Uint8Array): AssertionAuthData;
12
11
  export declare function parseAttestationAuthData(data: Uint8Array): AttestationAuthData;
@@ -1 +1 @@
1
- {"version":3,"file":"authdata.d.ts","sourceRoot":"","sources":["../../src/src/authdata.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,UAAU,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,EAAE,UAAU,CAAC;IACzB,YAAY,EAAE,UAAU,CAAC;CAC1B;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,iBAAiB,CAgB1E;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,UAAU,GACf,mBAAmB,CAiCrB"}
1
+ {"version":3,"file":"authdata.d.ts","sourceRoot":"","sources":["../../src/src/authdata.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,UAAU,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAC5D,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,EAAE,UAAU,CAAC;CAC1B;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,iBAAiB,CAgB1E;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,UAAU,GACf,mBAAmB,CA+BrB"}
@@ -19,11 +19,9 @@ export function parseAttestationAuthData(data) {
19
19
  throw new Error(`authenticatorData truncated: credentialIdLength=${credentialIdLength} but only ${data.length - 55} bytes remain`);
20
20
  }
21
21
  const credentialId = data.slice(55, 55 + credentialIdLength);
22
- const coseKeyBytes = data.slice(55 + credentialIdLength);
23
22
  return {
24
23
  ...base,
25
24
  aaguid,
26
25
  credentialId,
27
- coseKeyBytes,
28
26
  };
29
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"with-assertion.d.ts","sourceRoot":"","sources":["../../src/src/with-assertion.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAsB,MAAM,aAAa,CAAC;AAEjE,iEAAiE;AACjE,eAAO,MAAM,wBAAwB,2BAA2B,CAAC;AACjE,0DAA0D;AAC1D,eAAO,MAAM,wBAAwB,2BAA2B,CAAC;AAEjE,0EAA0E;AAC1E,MAAM,MAAM,SAAS,GAAG;IACtB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,mFAAmF;AACnF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,OAAO,EAAE,UAAU,CAAC;IACpB,mEAAmE;IACnE,OAAO,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC,CAAC;AAEH,kEAAkE;AAClE,MAAM,MAAM,oBAAoB,GAAG;IACjC,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC9D;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9E,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,uEAAuE;IACvE,OAAO,CAAC,EAAE,CACR,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,OAAO,KACT,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACnC,CAAC;AAmCF;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,CACP,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,gBAAgB,KACtB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAChC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAmGrC"}
1
+ {"version":3,"file":"with-assertion.d.ts","sourceRoot":"","sources":["../../src/src/with-assertion.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAsB,MAAM,aAAa,CAAC;AAEjE,iEAAiE;AACjE,eAAO,MAAM,wBAAwB,2BAA2B,CAAC;AACjE,0DAA0D;AAC1D,eAAO,MAAM,wBAAwB,2BAA2B,CAAC;AAEjE,0EAA0E;AAC1E,MAAM,MAAM,SAAS,GAAG;IACtB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,mFAAmF;AACnF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,OAAO,EAAE,UAAU,CAAC;IACpB,mEAAmE;IACnE,OAAO,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF,0EAA0E;AAC1E,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC,CAAC;AAEH,kEAAkE;AAClE,MAAM,MAAM,oBAAoB,GAAG;IACjC,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,wFAAwF;IACxF,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC9D;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9E,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,uEAAuE;IACvE,OAAO,CAAC,EAAE,CACR,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,OAAO,KACT,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACnC,CAAC;AAqCF;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,CACP,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,gBAAgB,KACtB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAChC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAmGrC"}
@@ -19,7 +19,9 @@ function defaultErrorResponse(error) {
19
19
  ? 500
20
20
  : error.code === AssertionErrorCode.INVALID_FORMAT
21
21
  ? 400
22
- : 401;
22
+ : error.code === AssertionErrorCode.SIGN_COUNT_STALE
23
+ ? 409
24
+ : 401;
23
25
  return new Response(JSON.stringify({ error: error.message, code: error.code }), { status, headers: { "Content-Type": "application/json" } });
24
26
  }
25
27
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bradford-tech/supabase-integrity-attest",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Verify Apple App Attest attestations and assertions using WebCrypto.",
5
5
  "homepage": "https://integrity-attest.bradford.tech",
6
6
  "repository": {