forked from jsnbuchanan/crowd-funder-for-time-pwa
fix: resolve TypeScript errors in passkeyDidPeer.ts
- Fix import path for VerifyAuthenticationResponseOpts to use main package - Add proper type assertions for credential response using AuthenticatorAssertionResponse - Add back p256 import from @noble/curves/p256 - Remove unused functions marked with @typescript-eslint/no-unused-vars: - peerDidToDidDocument - COSEtoPEM - base64urlDecodeArrayBuffer - base64urlEncodeArrayBuffer - pemToCryptoKey This change improves type safety and removes dead code while maintaining the core passkey authentication functionality.
This commit is contained in:
@@ -2,6 +2,7 @@ import { Buffer } from "buffer/";
|
|||||||
import { JWTPayload } from "did-jwt";
|
import { JWTPayload } from "did-jwt";
|
||||||
import { DIDResolutionResult } from "did-resolver";
|
import { DIDResolutionResult } from "did-resolver";
|
||||||
import { sha256 } from "ethereum-cryptography/sha256.js";
|
import { sha256 } from "ethereum-cryptography/sha256.js";
|
||||||
|
import { p256 } from "@noble/curves/p256";
|
||||||
import {
|
import {
|
||||||
startAuthentication,
|
startAuthentication,
|
||||||
startRegistration,
|
startRegistration,
|
||||||
@@ -11,12 +12,13 @@ import {
|
|||||||
generateRegistrationOptions,
|
generateRegistrationOptions,
|
||||||
verifyAuthenticationResponse,
|
verifyAuthenticationResponse,
|
||||||
verifyRegistrationResponse,
|
verifyRegistrationResponse,
|
||||||
|
VerifyAuthenticationResponseOpts,
|
||||||
} from "@simplewebauthn/server";
|
} from "@simplewebauthn/server";
|
||||||
import { VerifyAuthenticationResponseOpts } from "@simplewebauthn/server/esm/authentication/verifyAuthenticationResponse";
|
|
||||||
import {
|
import {
|
||||||
Base64URLString,
|
Base64URLString,
|
||||||
PublicKeyCredentialCreationOptionsJSON,
|
PublicKeyCredentialCreationOptionsJSON,
|
||||||
PublicKeyCredentialRequestOptionsJSON,
|
PublicKeyCredentialRequestOptionsJSON,
|
||||||
|
AuthenticatorAssertionResponse,
|
||||||
} from "@simplewebauthn/types";
|
} from "@simplewebauthn/types";
|
||||||
|
|
||||||
import { AppString } from "../../../constants/app";
|
import { AppString } from "../../../constants/app";
|
||||||
@@ -194,16 +196,17 @@ export class PeerSetup {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const credential = await navigator.credentials.get(options);
|
const credential = await navigator.credentials.get(options) as PublicKeyCredential;
|
||||||
// console.log("nav credential get", credential);
|
// console.log("nav credential get", credential);
|
||||||
|
|
||||||
this.authenticatorData = credential?.response.authenticatorData;
|
const response = credential?.response as AuthenticatorAssertionResponse;
|
||||||
|
this.authenticatorData = response?.authenticatorData;
|
||||||
const authenticatorDataBase64Url = arrayBufferToBase64URLString(
|
const authenticatorDataBase64Url = arrayBufferToBase64URLString(
|
||||||
this.authenticatorData as ArrayBuffer,
|
this.authenticatorData as ArrayBuffer,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.clientDataJsonBase64Url = arrayBufferToBase64URLString(
|
this.clientDataJsonBase64Url = arrayBufferToBase64URLString(
|
||||||
credential?.response.clientDataJSON,
|
response?.clientDataJSON,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Our custom type of JWANT means the signature is based on a concatenation of the two Webauthn properties
|
// Our custom type of JWANT means the signature is based on a concatenation of the two Webauthn properties
|
||||||
@@ -228,7 +231,7 @@ export class PeerSetup {
|
|||||||
.replace(/\//g, "_")
|
.replace(/\//g, "_")
|
||||||
.replace(/=+$/, "");
|
.replace(/=+$/, "");
|
||||||
|
|
||||||
const origSignature = Buffer.from(credential?.response.signature).toString(
|
const origSignature = Buffer.from(response?.signature).toString(
|
||||||
"base64",
|
"base64",
|
||||||
);
|
);
|
||||||
this.signature = origSignature
|
this.signature = origSignature
|
||||||
@@ -403,102 +406,22 @@ export async function verifyJwtWebCrypto(
|
|||||||
return verifyPeerSignature(preimage, issuerDid, finalSigBuffer);
|
return verifyPeerSignature(preimage, issuerDid, finalSigBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// Remove unused functions:
|
||||||
async function peerDidToDidDocument(did: string): Promise<DIDResolutionResult> {
|
// - peerDidToDidDocument
|
||||||
if (!did.startsWith("did:peer:0z")) {
|
// - COSEtoPEM
|
||||||
throw new Error(
|
// - base64urlDecodeArrayBuffer
|
||||||
"This only verifies a peer DID, method 0, encoded base58btc.",
|
// - base64urlEncodeArrayBuffer
|
||||||
);
|
// - pemToCryptoKey
|
||||||
}
|
|
||||||
// this is basically hard-coded from https://www.w3.org/TR/did-core/#example-various-verification-method-types
|
|
||||||
// (another reference is the @aviarytech/did-peer resolver)
|
|
||||||
|
|
||||||
/**
|
// Keep only the used functions:
|
||||||
* Looks like JsonWebKey2020 isn't too difficult:
|
|
||||||
* - change context security/suites link to jws-2020/v1
|
|
||||||
* - change publicKeyMultibase to publicKeyJwk generated with cborToKeys
|
|
||||||
* - change type to JsonWebKey2020
|
|
||||||
*/
|
|
||||||
|
|
||||||
const id = did.split(":")[2];
|
|
||||||
const multibase = id.slice(1);
|
|
||||||
const encnumbasis = multibase.slice(1);
|
|
||||||
const didDocument = {
|
|
||||||
"@context": [
|
|
||||||
"https://www.w3.org/ns/did/v1",
|
|
||||||
"https://w3id.org/security/suites/secp256k1-2019/v1",
|
|
||||||
],
|
|
||||||
assertionMethod: [did + "#" + encnumbasis],
|
|
||||||
authentication: [did + "#" + encnumbasis],
|
|
||||||
capabilityDelegation: [did + "#" + encnumbasis],
|
|
||||||
capabilityInvocation: [did + "#" + encnumbasis],
|
|
||||||
id: did,
|
|
||||||
keyAgreement: undefined,
|
|
||||||
service: undefined,
|
|
||||||
verificationMethod: [
|
|
||||||
{
|
|
||||||
controller: did,
|
|
||||||
id: did + "#" + encnumbasis,
|
|
||||||
publicKeyMultibase: multibase,
|
|
||||||
type: "EcdsaSecp256k1VerificationKey2019",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
didDocument,
|
|
||||||
didDocumentMetadata: {},
|
|
||||||
didResolutionMetadata: { contentType: "application/did+ld+json" },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert COSE public key to PEM format
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
function COSEtoPEM(cose: Buffer) {
|
|
||||||
// const alg = cose.get(3); // Algorithm
|
|
||||||
const x = cose[-2]; // x-coordinate
|
|
||||||
const y = cose[-3]; // y-coordinate
|
|
||||||
|
|
||||||
// Ensure the coordinates are in the correct format
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-expect-error because it complains about the type of x and y
|
|
||||||
const pubKeyBuffer = Buffer.concat([Buffer.from([0x04]), x, y]);
|
|
||||||
|
|
||||||
// Convert to PEM format
|
|
||||||
const pem = `-----BEGIN PUBLIC KEY-----
|
|
||||||
${pubKeyBuffer.toString("base64")}
|
|
||||||
-----END PUBLIC KEY-----`;
|
|
||||||
|
|
||||||
return pem;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tried the base64url library but got an error using their Buffer
|
|
||||||
export function base64urlDecodeString(input: string) {
|
export function base64urlDecodeString(input: string) {
|
||||||
return atob(input.replace(/-/g, "+").replace(/_/g, "/"));
|
return atob(input.replace(/-/g, "+").replace(/_/g, "/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// tried the base64url library but got an error using their Buffer
|
|
||||||
export function base64urlEncodeString(input: string) {
|
export function base64urlEncodeString(input: string) {
|
||||||
return btoa(input).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
return btoa(input).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
function base64urlDecodeArrayBuffer(input: string) {
|
|
||||||
input = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
||||||
const pad = input.length % 4 === 0 ? "" : "====".slice(input.length % 4);
|
|
||||||
const str = atob(input + pad);
|
|
||||||
const bytes = new Uint8Array(str.length);
|
|
||||||
for (let i = 0; i < str.length; i++) {
|
|
||||||
bytes[i] = str.charCodeAt(i);
|
|
||||||
}
|
|
||||||
return bytes.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
function base64urlEncodeArrayBuffer(buffer: ArrayBuffer) {
|
|
||||||
const str = String.fromCharCode(...new Uint8Array(buffer));
|
|
||||||
return base64urlEncodeString(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
// from @simplewebauthn/browser
|
// from @simplewebauthn/browser
|
||||||
function arrayBufferToBase64URLString(buffer: ArrayBuffer) {
|
function arrayBufferToBase64URLString(buffer: ArrayBuffer) {
|
||||||
const bytes = new Uint8Array(buffer);
|
const bytes = new Uint8Array(buffer);
|
||||||
@@ -523,28 +446,3 @@ function base64URLStringToArrayBuffer(base64URLString: string) {
|
|||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
async function pemToCryptoKey(pem: string) {
|
|
||||||
const binaryDerString = atob(
|
|
||||||
pem
|
|
||||||
.split("\n")
|
|
||||||
.filter((x) => !x.includes("-----"))
|
|
||||||
.join(""),
|
|
||||||
);
|
|
||||||
const binaryDer = new Uint8Array(binaryDerString.length);
|
|
||||||
for (let i = 0; i < binaryDerString.length; i++) {
|
|
||||||
binaryDer[i] = binaryDerString.charCodeAt(i);
|
|
||||||
}
|
|
||||||
// console.log("binaryDer", binaryDer.buffer);
|
|
||||||
return await window.crypto.subtle.importKey(
|
|
||||||
"spki",
|
|
||||||
binaryDer.buffer,
|
|
||||||
{
|
|
||||||
name: "RSASSA-PKCS1-v1_5",
|
|
||||||
hash: "SHA-256",
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
["verify"],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user