@bradford-tech/supabase-integrity-attest 0.5.0 → 0.7.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.
|
@@ -29,7 +29,18 @@ export type AttestationContext = {
|
|
|
29
29
|
/** Custom function to extract attestation data from an incoming request. */
|
|
30
30
|
export type ExtractAttestationFn = (req: Request) => Promise<{
|
|
31
31
|
deviceId: string;
|
|
32
|
+
/** Raw challenge bytes for the `consumeChallenge` DB lookup. */
|
|
32
33
|
challenge: Uint8Array;
|
|
34
|
+
/**
|
|
35
|
+
* The challenge in the exact form the client SDK received it, before
|
|
36
|
+
* any server-side decoding. This is what the client SDK hashed to
|
|
37
|
+
* produce `clientDataHash` — Expo's `attestKeyAsync` and native
|
|
38
|
+
* `DCAppAttestService` wrappers convert this string to UTF-8 bytes
|
|
39
|
+
* and SHA-256 hash them before passing to Apple. The middleware must
|
|
40
|
+
* hash this same string to produce the matching `clientDataHash` for
|
|
41
|
+
* `verifyAttestation`.
|
|
42
|
+
*/
|
|
43
|
+
challengeAsSent: string;
|
|
33
44
|
attestation: Uint8Array;
|
|
34
45
|
}>;
|
|
35
46
|
/** Configuration for the {@linkcode withAttestation} middleware. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"with-attestation.d.ts","sourceRoot":"","sources":["../../src/src/with-attestation.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAwB,MAAM,aAAa,CAAC;AAErE;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,qFAAqF;AACrF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,OAAO,EAAE,UAAU,CAAC;IACpB,mEAAmE;IACnE,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,UAAU,CAAC;IACtB,WAAW,EAAE,UAAU,CAAC;CACzB,CAAC,CAAC;AAEH,oEAAoE;AACpE,MAAM,MAAM,sBAAsB,GAAG;IACnC,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;;OAOG;IACH,gBAAgB,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9D;;;;OAIG;IACH,cAAc,EAAE,CAAC,GAAG,EAAE;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,UAAU,CAAC;KACrB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,uEAAuE;IACvE,OAAO,CAAC,EAAE,CACR,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,OAAO,KACT,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACnC,CAAC;
|
|
1
|
+
{"version":3,"file":"with-attestation.d.ts","sourceRoot":"","sources":["../../src/src/with-attestation.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAwB,MAAM,aAAa,CAAC;AAErE;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,qFAAqF;AACrF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,OAAO,EAAE,UAAU,CAAC;IACpB,mEAAmE;IACnE,OAAO,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,SAAS,EAAE,UAAU,CAAC;IACtB;;;;;;;;OAQG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,UAAU,CAAC;CACzB,CAAC,CAAC;AAEH,oEAAoE;AACpE,MAAM,MAAM,sBAAsB,GAAG;IACnC,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;;OAOG;IACH,gBAAgB,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9D;;;;OAIG;IACH,cAAc,EAAE,CAAC,GAAG,EAAE;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,UAAU,CAAC;KACrB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,uEAAuE;IACvE,OAAO,CAAC,EAAE,CACR,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,OAAO,KACT,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACnC,CAAC;AA8EF;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,EAC/B,OAAO,EAAE,CACP,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,kBAAkB,KACxB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAChC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA2HrC"}
|
|
@@ -36,7 +36,12 @@ async function defaultExtractAttestation(req) {
|
|
|
36
36
|
catch {
|
|
37
37
|
throw new AttestationError(AttestationErrorCode.INVALID_FORMAT, "attestation is not valid base64");
|
|
38
38
|
}
|
|
39
|
-
return {
|
|
39
|
+
return {
|
|
40
|
+
deviceId: typed.keyId,
|
|
41
|
+
challenge,
|
|
42
|
+
challengeAsSent: typed.challenge,
|
|
43
|
+
attestation,
|
|
44
|
+
};
|
|
40
45
|
}
|
|
41
46
|
function defaultErrorResponse(error) {
|
|
42
47
|
const status = error.code === AttestationErrorCode.INTERNAL_ERROR
|
|
@@ -100,13 +105,20 @@ export function withAttestation(options, handler) {
|
|
|
100
105
|
if (!challengeOk) {
|
|
101
106
|
throw new AttestationError(AttestationErrorCode.CHALLENGE_INVALID, "Challenge is missing, expired, or already consumed");
|
|
102
107
|
}
|
|
103
|
-
// Hash the
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
|
|
108
|
+
// Hash the challenge AS THE CLIENT SAW IT — the exact string passed
|
|
109
|
+
// to attestKeyAsync / DCAppAttestService.attestKey. Client SDKs
|
|
110
|
+
// convert this string to UTF-8 bytes and SHA-256 hash them before
|
|
111
|
+
// passing to Apple as clientDataHash. The attestation certificate's
|
|
112
|
+
// nonce is SHA-256(authData || clientDataHash), so we must hash the
|
|
113
|
+
// same string to produce the matching clientDataHash.
|
|
114
|
+
//
|
|
115
|
+
// This is different from the assertion path, which has no encoding
|
|
116
|
+
// layer: the string passed to generateAssertionAsync IS the raw
|
|
117
|
+
// body, and both sides hash identical bytes by definition.
|
|
118
|
+
// Attestation has a transport encoding layer (base64 in a JSON
|
|
119
|
+
// body), so the middleware must hash BEFORE decoding to match what
|
|
120
|
+
// the client SDK hashed.
|
|
121
|
+
const clientDataHash = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(extracted.challengeAsSent)));
|
|
110
122
|
const verifyStart = performance.now();
|
|
111
123
|
const result = await verifyAttestation(appInfo, deviceId, clientDataHash, extracted.attestation);
|
|
112
124
|
timings.verifyMs = performance.now() - verifyStart;
|
package/package.json
CHANGED