electron-webauthn 1.1.0 → 1.2.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/README.md +20 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.js +78 -3
- package/package.json +15 -11
- package/dist/additional-objc/ASCPublicKeyCredentialDescriptor.d.ts +0 -12
- package/dist/additional-objc/ASCPublicKeyCredentialDescriptor.js +0 -2
- package/dist/create/authorization-controller.d.ts +0 -10
- package/dist/create/authorization-controller.js +0 -77
- package/dist/create/handler.d.ts +0 -43
- package/dist/create/handler.js +0 -224
- package/dist/create/internal-handler.d.ts +0 -35
- package/dist/create/internal-handler.js +0 -207
- package/dist/get/authorization-controller.d.ts +0 -5
- package/dist/get/authorization-controller.js +0 -37
- package/dist/get/handler.d.ts +0 -38
- package/dist/get/handler.js +0 -137
- package/dist/get/internal-handler.d.ts +0 -24
- package/dist/get/internal-handler.js +0 -169
- package/dist/helpers/client-data.d.ts +0 -14
- package/dist/helpers/client-data.js +0 -36
- package/dist/helpers/index.d.ts +0 -8
- package/dist/helpers/index.js +0 -48
- package/dist/helpers/objc.d.ts +0 -5
- package/dist/helpers/objc.js +0 -10
- package/dist/helpers/origin.d.ts +0 -19
- package/dist/helpers/origin.js +0 -106
- package/dist/helpers/presentation.d.ts +0 -1
- package/dist/helpers/presentation.js +0 -11
- package/dist/helpers/prf.d.ts +0 -5
- package/dist/helpers/prf.js +0 -5
- package/dist/helpers/public-key.d.ts +0 -1
- package/dist/helpers/public-key.js +0 -49
- package/dist/helpers/rpid.d.ts +0 -13
- package/dist/helpers/rpid.js +0 -59
- package/dist/helpers/types.d.ts +0 -1
- package/dist/helpers/types.js +0 -1
- package/dist/helpers/validation.d.ts +0 -3
- package/dist/helpers/validation.js +0 -9
- package/dist/list/handler.d.ts +0 -2
- package/dist/list/handler.js +0 -65
- package/dist/list/types.d.ts +0 -14
- package/dist/list/types.js +0 -1
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import { generateClientDataInfo } from "../helpers/client-data.js";
|
|
2
|
-
import { generateWebauthnClientData } from "../helpers/client-data.js";
|
|
3
|
-
import { PromiseWithResolvers } from "../helpers/index.js";
|
|
4
|
-
import { encodeEC2PublicKeyToSPKI } from "../helpers/public-key.js";
|
|
5
|
-
import { createPresentationContextProviderFromNativeWindowHandle } from "../helpers/presentation.js";
|
|
6
|
-
import { createPRFInput } from "../helpers/prf.js";
|
|
7
|
-
import { removeControllerState, setControllerState, WebauthnCreateController, } from "./authorization-controller.js";
|
|
8
|
-
import { parseAttestationObject } from "@oslojs/webauthn";
|
|
9
|
-
import { NSArrayFromObjects, NSStringFromString } from "objcjs-types/helpers";
|
|
10
|
-
import { bufferFromNSDataDirect, NSDataFromBuffer } from "objcjs-types/nsdata";
|
|
11
|
-
import { ASAuthorizationPlatformPublicKeyCredentialProvider, ASAuthorizationPlatformPublicKeyCredentialRegistration, ASAuthorizationPublicKeyCredentialAttachment, ASAuthorizationPublicKeyCredentialAttestationKind, ASAuthorizationPublicKeyCredentialLargeBlobRegistrationInput, ASAuthorizationPublicKeyCredentialLargeBlobSupportRequirement, ASAuthorizationPublicKeyCredentialParameters, ASAuthorizationPublicKeyCredentialPRFRegistrationInput, ASAuthorizationPublicKeyCredentialUserVerificationPreference, ASAuthorizationSecurityKeyPublicKeyCredentialProvider, ASAuthorizationSecurityKeyPublicKeyCredentialRegistration, } from "objcjs-types/AuthenticationServices";
|
|
12
|
-
import { createDelegate } from "objcjs-types";
|
|
13
|
-
const VALID_EXTENSIONS = ["largeBlob", "prf"];
|
|
14
|
-
function setupPublicKeyCredentialRegistrationRequest(type, keyRequest, attestation, enabledExtensions, userVerification, pubKeyCredParams, additionalOptions) {
|
|
15
|
-
if (type === "platform" && enabledExtensions.includes("largeBlob")) {
|
|
16
|
-
let supportMode;
|
|
17
|
-
const largeBlobSupport = additionalOptions.largeBlobSupport;
|
|
18
|
-
if (largeBlobSupport === "required") {
|
|
19
|
-
supportMode =
|
|
20
|
-
ASAuthorizationPublicKeyCredentialLargeBlobSupportRequirement.Required;
|
|
21
|
-
}
|
|
22
|
-
else if (largeBlobSupport === "preferred") {
|
|
23
|
-
supportMode =
|
|
24
|
-
ASAuthorizationPublicKeyCredentialLargeBlobSupportRequirement.Preferred;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
console.warn("[electron-webauthn] largeBlobSupport is enabled but largeBlobSupport is not provided, skipping large blob support");
|
|
28
|
-
}
|
|
29
|
-
if (supportMode) {
|
|
30
|
-
const largeBlobInput = ASAuthorizationPublicKeyCredentialLargeBlobRegistrationInput.alloc().initWithSupportRequirement$(supportMode);
|
|
31
|
-
keyRequest.setLargeBlob$(largeBlobInput);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
let attestationPreference = ASAuthorizationPublicKeyCredentialAttestationKind.None;
|
|
35
|
-
if (type === "security-key") {
|
|
36
|
-
if (attestation === "direct") {
|
|
37
|
-
attestationPreference =
|
|
38
|
-
ASAuthorizationPublicKeyCredentialAttestationKind.Direct;
|
|
39
|
-
}
|
|
40
|
-
else if (attestation === "enterprise") {
|
|
41
|
-
attestationPreference =
|
|
42
|
-
ASAuthorizationPublicKeyCredentialAttestationKind.Enterprise;
|
|
43
|
-
}
|
|
44
|
-
else if (attestation === "indirect") {
|
|
45
|
-
attestationPreference =
|
|
46
|
-
ASAuthorizationPublicKeyCredentialAttestationKind.Indirect;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
keyRequest.setAttestationPreference$(NSStringFromString(attestationPreference));
|
|
50
|
-
let userVerificationPreference = ASAuthorizationPublicKeyCredentialUserVerificationPreference.Preferred;
|
|
51
|
-
if (userVerification === "required") {
|
|
52
|
-
userVerificationPreference =
|
|
53
|
-
ASAuthorizationPublicKeyCredentialUserVerificationPreference.Required;
|
|
54
|
-
}
|
|
55
|
-
else if (userVerification === "discouraged") {
|
|
56
|
-
userVerificationPreference =
|
|
57
|
-
ASAuthorizationPublicKeyCredentialUserVerificationPreference.Discouraged;
|
|
58
|
-
}
|
|
59
|
-
keyRequest.setUserVerificationPreference$(NSStringFromString(userVerificationPreference));
|
|
60
|
-
if (type === "platform" && additionalOptions.userDisplayName) {
|
|
61
|
-
const userDisplayName = NSStringFromString(additionalOptions.userDisplayName);
|
|
62
|
-
keyRequest.setDisplayName$(userDisplayName);
|
|
63
|
-
}
|
|
64
|
-
if (type === "security-key") {
|
|
65
|
-
const credentialParameters = [];
|
|
66
|
-
for (const param of pubKeyCredParams) {
|
|
67
|
-
if (param.type === "public-key" && param.algorithm === -7) {
|
|
68
|
-
const paramObj = ASAuthorizationPublicKeyCredentialParameters.alloc().initWithAlgorithm$(param.algorithm);
|
|
69
|
-
credentialParameters.push(paramObj);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
const nsCredentialParameters = NSArrayFromObjects(credentialParameters);
|
|
73
|
-
keyRequest.setCredentialParameters$(nsCredentialParameters);
|
|
74
|
-
}
|
|
75
|
-
if (type === "platform" && enabledExtensions.includes("prf")) {
|
|
76
|
-
if (additionalOptions.prf) {
|
|
77
|
-
const inputValues = createPRFInput(additionalOptions.prf);
|
|
78
|
-
const prfInput = ASAuthorizationPublicKeyCredentialPRFRegistrationInput.alloc().initWithInputValues$(inputValues);
|
|
79
|
-
keyRequest.setPrf$(prfInput);
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
keyRequest.setPrf$(ASAuthorizationPublicKeyCredentialPRFRegistrationInput.checkForSupport());
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
function createCredentialInternal(rpid, challenge, username, userID, nativeWindowHandle, origin, timeout, enabledExtensions, attestation = "none", supportedAlgorithmIdentifiers = [], excludeCredentials, residentKeyRequired = false, preferredAuthenticatorAttachment = "all", userVerification = "preferred", additionalOptions = {}) {
|
|
87
|
-
const { promise, resolve, reject } = PromiseWithResolvers();
|
|
88
|
-
const NS_rpID = NSStringFromString(rpid);
|
|
89
|
-
const NS_challenge = NSDataFromBuffer(challenge);
|
|
90
|
-
const NS_username = NSStringFromString(username);
|
|
91
|
-
const NS_userID = NSDataFromBuffer(userID);
|
|
92
|
-
const requestArrayInput = [];
|
|
93
|
-
if (preferredAuthenticatorAttachment === "all" ||
|
|
94
|
-
preferredAuthenticatorAttachment === "platform") {
|
|
95
|
-
const platformProvider = ASAuthorizationPlatformPublicKeyCredentialProvider.alloc().initWithRelyingPartyIdentifier$(NS_rpID);
|
|
96
|
-
const platformKeyRequest = platformProvider.createCredentialRegistrationRequestWithChallenge$name$userID$(NS_challenge, NS_username, NS_userID);
|
|
97
|
-
setupPublicKeyCredentialRegistrationRequest("platform", platformKeyRequest, attestation, enabledExtensions, userVerification, supportedAlgorithmIdentifiers, additionalOptions);
|
|
98
|
-
requestArrayInput.push(platformKeyRequest);
|
|
99
|
-
}
|
|
100
|
-
if (preferredAuthenticatorAttachment === "all" ||
|
|
101
|
-
preferredAuthenticatorAttachment === "cross-platform") {
|
|
102
|
-
const securityKeyProvider = ASAuthorizationSecurityKeyPublicKeyCredentialProvider.alloc().initWithRelyingPartyIdentifier$(NS_rpID);
|
|
103
|
-
const securityKeyRequest = securityKeyProvider.createCredentialRegistrationRequestWithChallenge$displayName$name$userID$(NS_challenge, NSStringFromString(additionalOptions.userDisplayName || username), NS_username, NS_userID);
|
|
104
|
-
setupPublicKeyCredentialRegistrationRequest("security-key", securityKeyRequest, attestation, enabledExtensions, userVerification, supportedAlgorithmIdentifiers, additionalOptions);
|
|
105
|
-
requestArrayInput.push(securityKeyRequest);
|
|
106
|
-
}
|
|
107
|
-
const requestsArray = NSArrayFromObjects(requestArrayInput);
|
|
108
|
-
const authController = WebauthnCreateController.alloc().initWithAuthorizationRequests$(requestsArray);
|
|
109
|
-
const clientData = generateWebauthnClientData("webauthn.create", origin, challenge, additionalOptions.topFrameOrigin);
|
|
110
|
-
const { clientDataHash, clientDataBuffer } = generateClientDataInfo(clientData);
|
|
111
|
-
setControllerState(authController, clientDataHash, supportedAlgorithmIdentifiers, residentKeyRequired, excludeCredentials);
|
|
112
|
-
let isFinished = false;
|
|
113
|
-
let timeoutHandlerId = null;
|
|
114
|
-
const finished = (_success) => {
|
|
115
|
-
isFinished = true;
|
|
116
|
-
removeControllerState(authController);
|
|
117
|
-
if (timeoutHandlerId) {
|
|
118
|
-
clearTimeout(timeoutHandlerId);
|
|
119
|
-
timeoutHandlerId = null;
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
const delegate = createDelegate("ASAuthorizationControllerDelegate", {
|
|
123
|
-
authorizationController$didCompleteWithAuthorization$: (_, authorization) => {
|
|
124
|
-
const credential = authorization.credential();
|
|
125
|
-
console.log("Authorization succeeded:", credential);
|
|
126
|
-
const isPlatform = credential instanceof
|
|
127
|
-
ASAuthorizationPlatformPublicKeyCredentialRegistration;
|
|
128
|
-
const isSecurityKey = credential instanceof
|
|
129
|
-
ASAuthorizationSecurityKeyPublicKeyCredentialRegistration;
|
|
130
|
-
if (!isPlatform && !isSecurityKey) {
|
|
131
|
-
reject(new Error("Resulting credential is not a platform or security key credential"));
|
|
132
|
-
finished(false);
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
const credentialIdBuffer = bufferFromNSDataDirect(credential.credentialID());
|
|
136
|
-
const attestationObjectBuffer = bufferFromNSDataDirect(credential.rawAttestationObject());
|
|
137
|
-
const attestation = parseAttestationObject(attestationObjectBuffer);
|
|
138
|
-
const publicKey = attestation.authenticatorData.credential.publicKey;
|
|
139
|
-
const ec2Key = publicKey.ec2();
|
|
140
|
-
const publicKeySPKI = encodeEC2PublicKeyToSPKI(ec2Key.x, ec2Key.y);
|
|
141
|
-
const authenticatorData = Buffer.from(JSON.stringify(attestation.authenticatorData));
|
|
142
|
-
let authenticatorAttachment = "cross-platform";
|
|
143
|
-
if (isPlatform &&
|
|
144
|
-
credential.attachment() ===
|
|
145
|
-
ASAuthorizationPublicKeyCredentialAttachment.Platform) {
|
|
146
|
-
authenticatorAttachment = "platform";
|
|
147
|
-
}
|
|
148
|
-
let isLargeBlobSupported = null;
|
|
149
|
-
if (enabledExtensions.includes("largeBlob")) {
|
|
150
|
-
const largeBlobOutput = credential.largeBlob();
|
|
151
|
-
if (largeBlobOutput) {
|
|
152
|
-
isLargeBlobSupported = largeBlobOutput.isSupported();
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
let prfFirst = null;
|
|
156
|
-
let prfSecond = null;
|
|
157
|
-
let isPRFSupported = null;
|
|
158
|
-
if (enabledExtensions.includes("prf")) {
|
|
159
|
-
const prfOutput = credential.prf();
|
|
160
|
-
if (prfOutput) {
|
|
161
|
-
const prfFirstData = prfOutput.first();
|
|
162
|
-
const prfSecondData = prfOutput.second();
|
|
163
|
-
if (prfFirstData) {
|
|
164
|
-
prfFirst = bufferFromNSDataDirect(prfFirstData);
|
|
165
|
-
}
|
|
166
|
-
if (prfSecondData) {
|
|
167
|
-
prfSecond = bufferFromNSDataDirect(prfSecondData);
|
|
168
|
-
}
|
|
169
|
-
isPRFSupported = prfOutput.isSupported();
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
const data = {
|
|
173
|
-
credentialId: credentialIdBuffer,
|
|
174
|
-
clientDataJSON: clientDataBuffer,
|
|
175
|
-
attestationObject: attestationObjectBuffer,
|
|
176
|
-
authenticatorData,
|
|
177
|
-
attachment: authenticatorAttachment,
|
|
178
|
-
transports: ["hybrid", "internal"],
|
|
179
|
-
isResidentKey: true,
|
|
180
|
-
publicKeyAlgorithm: publicKey.algorithm(),
|
|
181
|
-
publicKey: publicKeySPKI,
|
|
182
|
-
isLargeBlobSupported,
|
|
183
|
-
isPRFSupported,
|
|
184
|
-
prfFirst,
|
|
185
|
-
prfSecond,
|
|
186
|
-
};
|
|
187
|
-
resolve(data);
|
|
188
|
-
finished(true);
|
|
189
|
-
},
|
|
190
|
-
authorizationController$didCompleteWithError$: (_, error) => {
|
|
191
|
-
const errorMessage = error.localizedDescription().UTF8String();
|
|
192
|
-
reject(new Error(errorMessage));
|
|
193
|
-
finished(false);
|
|
194
|
-
},
|
|
195
|
-
});
|
|
196
|
-
authController.setDelegate$(delegate);
|
|
197
|
-
const presentationContextProvider = createPresentationContextProviderFromNativeWindowHandle(nativeWindowHandle);
|
|
198
|
-
authController.setPresentationContextProvider$(presentationContextProvider);
|
|
199
|
-
authController.performRequests();
|
|
200
|
-
timeoutHandlerId = setTimeout(() => {
|
|
201
|
-
if (isFinished)
|
|
202
|
-
return;
|
|
203
|
-
authController.cancel();
|
|
204
|
-
}, timeout);
|
|
205
|
-
return promise;
|
|
206
|
-
}
|
|
207
|
-
export { createCredentialInternal };
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { NobjcObject } from "objc-js";
|
|
2
|
-
import type { ASAuthorizationController } from "objcjs-types/AuthenticationServices";
|
|
3
|
-
export declare function setClientDataHash(self: NobjcObject, clientDataHash: Buffer): void;
|
|
4
|
-
export declare function removeClientDataHash(self: NobjcObject): void;
|
|
5
|
-
export declare const WebauthnGetController: typeof ASAuthorizationController;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { NobjcClass, NobjcObject, getPointer } from "objc-js";
|
|
2
|
-
import { NSDataFromBuffer } from "objcjs-types/nsdata";
|
|
3
|
-
const getControllerState = new Map();
|
|
4
|
-
function getObjectPointerString(self) {
|
|
5
|
-
return getPointer(self).toString("base64");
|
|
6
|
-
}
|
|
7
|
-
export function setClientDataHash(self, clientDataHash) {
|
|
8
|
-
const selfPointer = getObjectPointerString(self);
|
|
9
|
-
getControllerState.set(selfPointer, clientDataHash);
|
|
10
|
-
}
|
|
11
|
-
export function removeClientDataHash(self) {
|
|
12
|
-
const selfPointer = getObjectPointerString(self);
|
|
13
|
-
getControllerState.delete(selfPointer);
|
|
14
|
-
}
|
|
15
|
-
export const WebauthnGetController = NobjcClass.define({
|
|
16
|
-
name: "WebauthnGetController",
|
|
17
|
-
superclass: "ASAuthorizationController",
|
|
18
|
-
methods: {
|
|
19
|
-
_requestContextWithRequests$error$: {
|
|
20
|
-
types: "@@:@^@",
|
|
21
|
-
implementation: (self, requests, outError) => {
|
|
22
|
-
const context = NobjcClass.super(self, "_requestContextWithRequests$error$", requests, outError);
|
|
23
|
-
const selfPointer = getObjectPointerString(self);
|
|
24
|
-
if (getControllerState.has(selfPointer)) {
|
|
25
|
-
let assertionOptions = context.platformKeyCredentialAssertionOptions();
|
|
26
|
-
if (!assertionOptions) {
|
|
27
|
-
assertionOptions = context.securityKeyCredentialAssertionOptions();
|
|
28
|
-
}
|
|
29
|
-
const clientDataHash = getControllerState.get(selfPointer);
|
|
30
|
-
assertionOptions.setClientDataHash$(NSDataFromBuffer(clientDataHash));
|
|
31
|
-
context.setPlatformKeyCredentialAssertionOptions$(assertionOptions.copyWithZone$(null));
|
|
32
|
-
}
|
|
33
|
-
return context;
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
});
|
package/dist/get/handler.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export type GetCredentialErrorCodes = "TypeError" | "AbortError" | "NotAllowedError" | "SecurityError";
|
|
2
|
-
export interface GetCredentialSuccessData {
|
|
3
|
-
credentialId: string;
|
|
4
|
-
clientDataJSON: string;
|
|
5
|
-
authenticatorData: string;
|
|
6
|
-
signature: string;
|
|
7
|
-
userHandle: string;
|
|
8
|
-
extensions?: {
|
|
9
|
-
prf?: {
|
|
10
|
-
results?: {
|
|
11
|
-
first: string;
|
|
12
|
-
second?: string;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
largeBlob?: {
|
|
16
|
-
blob?: string;
|
|
17
|
-
written?: boolean;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
interface WebauthnGetRequestOptions {
|
|
22
|
-
currentOrigin: string;
|
|
23
|
-
topFrameOrigin: string | undefined;
|
|
24
|
-
isPublicSuffix?: (domain: string) => boolean;
|
|
25
|
-
nativeWindowHandle: Buffer;
|
|
26
|
-
}
|
|
27
|
-
interface GetCredentialSuccessResult {
|
|
28
|
-
success: true;
|
|
29
|
-
data: GetCredentialSuccessData;
|
|
30
|
-
}
|
|
31
|
-
interface GetCredentialErrorResult {
|
|
32
|
-
success: false;
|
|
33
|
-
error: GetCredentialErrorCodes;
|
|
34
|
-
errorObject?: Error;
|
|
35
|
-
}
|
|
36
|
-
export type GetCredentialResult = GetCredentialSuccessResult | GetCredentialErrorResult;
|
|
37
|
-
export declare function getCredential(publicKeyOptions: PublicKeyCredentialRequestOptions | undefined, additionalOptions: WebauthnGetRequestOptions): Promise<GetCredentialResult>;
|
|
38
|
-
export {};
|
package/dist/get/handler.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { bufferSourceToBuffer, bufferToBase64Url } from "../helpers/index.js";
|
|
2
|
-
import { isRpIdAllowedForOrigin } from "../helpers/rpid.js";
|
|
3
|
-
import { isNumber, isString } from "../helpers/validation.js";
|
|
4
|
-
import { getCredentialInternal, } from "./internal-handler.js";
|
|
5
|
-
function getExtensionsConfiguration(extensionsData) {
|
|
6
|
-
if (!(extensionsData && typeof extensionsData === "object")) {
|
|
7
|
-
return {
|
|
8
|
-
extensions: [],
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
const extensions = [];
|
|
12
|
-
let largeBlobWriteBuffer;
|
|
13
|
-
if (extensionsData.largeBlob) {
|
|
14
|
-
const largeBlobConfig = extensionsData.largeBlob;
|
|
15
|
-
if (largeBlobConfig.read) {
|
|
16
|
-
extensions.push("largeBlobRead");
|
|
17
|
-
}
|
|
18
|
-
if (largeBlobConfig.write) {
|
|
19
|
-
extensions.push("largeBlobWrite");
|
|
20
|
-
largeBlobWriteBuffer = bufferSourceToBuffer(largeBlobConfig.write);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
let prf;
|
|
24
|
-
let prfByCredential;
|
|
25
|
-
const prfExtension = extensionsData.prf;
|
|
26
|
-
if (prfExtension && (prfExtension.eval || prfExtension.evalByCredential)) {
|
|
27
|
-
extensions.push("prf");
|
|
28
|
-
if (prfExtension.eval) {
|
|
29
|
-
prf = {
|
|
30
|
-
first: bufferSourceToBuffer(prfExtension.eval.first),
|
|
31
|
-
second: prfExtension.eval.second
|
|
32
|
-
? bufferSourceToBuffer(prfExtension.eval.second)
|
|
33
|
-
: undefined,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
if (prfExtension.evalByCredential) {
|
|
37
|
-
prfByCredential = {};
|
|
38
|
-
for (const [credId, value] of Object.entries(prfExtension.evalByCredential)) {
|
|
39
|
-
prfByCredential[credId] = {
|
|
40
|
-
first: bufferSourceToBuffer(value.first),
|
|
41
|
-
second: value.second ? bufferSourceToBuffer(value.second) : undefined,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return {
|
|
47
|
-
extensions,
|
|
48
|
-
largeBlobWriteBuffer,
|
|
49
|
-
prf,
|
|
50
|
-
prfByCredential,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
export async function getCredential(publicKeyOptions, additionalOptions) {
|
|
54
|
-
if (!publicKeyOptions) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
const rpId = publicKeyOptions.rpId;
|
|
58
|
-
if (!isString(rpId)) {
|
|
59
|
-
return { success: false, error: "TypeError" };
|
|
60
|
-
}
|
|
61
|
-
let timeout = publicKeyOptions.timeout;
|
|
62
|
-
if (!isNumber(timeout) || timeout <= 0) {
|
|
63
|
-
timeout = 10 * 60 * 1000;
|
|
64
|
-
}
|
|
65
|
-
else if (timeout > 60 * 60 * 1000) {
|
|
66
|
-
timeout = 60 * 60 * 1000;
|
|
67
|
-
}
|
|
68
|
-
const challenge = bufferSourceToBuffer(publicKeyOptions.challenge);
|
|
69
|
-
if (!challenge) {
|
|
70
|
-
return { success: false, error: "TypeError" };
|
|
71
|
-
}
|
|
72
|
-
const userVerification = publicKeyOptions.userVerification;
|
|
73
|
-
if (userVerification && !isString(userVerification)) {
|
|
74
|
-
return { success: false, error: "TypeError" };
|
|
75
|
-
}
|
|
76
|
-
const allowedCredentialsArray = [];
|
|
77
|
-
const allowedCredentials = publicKeyOptions.allowCredentials;
|
|
78
|
-
if (allowedCredentials && Array.isArray(allowedCredentials)) {
|
|
79
|
-
for (const allowedCredential of allowedCredentials) {
|
|
80
|
-
if (!(allowedCredential && typeof allowedCredential === "object"))
|
|
81
|
-
continue;
|
|
82
|
-
if (allowedCredential.type !== "public-key")
|
|
83
|
-
continue;
|
|
84
|
-
const id = bufferSourceToBuffer(allowedCredential.id);
|
|
85
|
-
if (!id)
|
|
86
|
-
continue;
|
|
87
|
-
allowedCredentialsArray.push(id);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const { extensions: enabledExtensions, largeBlobWriteBuffer, prf, prfByCredential, } = getExtensionsConfiguration(publicKeyOptions.extensions);
|
|
91
|
-
const { currentOrigin, topFrameOrigin, isPublicSuffix, nativeWindowHandle } = additionalOptions;
|
|
92
|
-
const isRpIdAllowed = isRpIdAllowedForOrigin(currentOrigin, rpId, {
|
|
93
|
-
isPublicSuffix,
|
|
94
|
-
});
|
|
95
|
-
if (!isRpIdAllowed.ok) {
|
|
96
|
-
return { success: false, error: "NotAllowedError" };
|
|
97
|
-
}
|
|
98
|
-
let errorResult = null;
|
|
99
|
-
const result = await getCredentialInternal(rpId, challenge, nativeWindowHandle, currentOrigin, timeout, enabledExtensions, allowedCredentialsArray, userVerification, {
|
|
100
|
-
topFrameOrigin,
|
|
101
|
-
largeBlobDataToWrite: largeBlobWriteBuffer,
|
|
102
|
-
prf,
|
|
103
|
-
prfByCredential,
|
|
104
|
-
}).catch((error) => {
|
|
105
|
-
errorResult = error;
|
|
106
|
-
if (error.message.startsWith("The operation couldn’t be completed.")) {
|
|
107
|
-
return "NotAllowedError";
|
|
108
|
-
}
|
|
109
|
-
return "NotAllowedError";
|
|
110
|
-
});
|
|
111
|
-
if (typeof result === "string") {
|
|
112
|
-
return { success: false, error: result, errorObject: errorResult };
|
|
113
|
-
}
|
|
114
|
-
const data = {
|
|
115
|
-
credentialId: bufferToBase64Url(result.id),
|
|
116
|
-
clientDataJSON: bufferToBase64Url(result.clientDataJSON),
|
|
117
|
-
authenticatorData: bufferToBase64Url(result.authenticatorData),
|
|
118
|
-
signature: bufferToBase64Url(result.signature),
|
|
119
|
-
userHandle: bufferToBase64Url(result.userHandle),
|
|
120
|
-
extensions: {},
|
|
121
|
-
};
|
|
122
|
-
if (result.prf && (result.prf[0] || result.prf[1])) {
|
|
123
|
-
data.extensions.prf = {
|
|
124
|
-
results: {
|
|
125
|
-
first: bufferToBase64Url(result.prf[0]),
|
|
126
|
-
second: result.prf[1] ? bufferToBase64Url(result.prf[1]) : undefined,
|
|
127
|
-
},
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
if (result.largeBlob || result.largeBlobWritten) {
|
|
131
|
-
data.extensions.largeBlob = {
|
|
132
|
-
blob: result.largeBlob ? bufferToBase64Url(result.largeBlob) : undefined,
|
|
133
|
-
written: result.largeBlobWritten !== null ? result.largeBlobWritten : undefined,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
return { success: true, data };
|
|
137
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type PRFInput } from "../helpers/prf.js";
|
|
2
|
-
import type { AuthenticatorAttachment } from "../helpers/types.js";
|
|
3
|
-
export type UserVerificationPreference = "preferred" | "required" | "discouraged";
|
|
4
|
-
declare const VALID_EXTENSIONS: readonly ["largeBlobRead", "largeBlobWrite", "prf"];
|
|
5
|
-
export type CredentialAssertionExtensions = (typeof VALID_EXTENSIONS)[number];
|
|
6
|
-
export interface GetCredentialResult {
|
|
7
|
-
id: Buffer;
|
|
8
|
-
authenticatorAttachment: AuthenticatorAttachment;
|
|
9
|
-
clientDataJSON: Buffer;
|
|
10
|
-
authenticatorData: Buffer;
|
|
11
|
-
signature: Buffer;
|
|
12
|
-
userHandle: Buffer;
|
|
13
|
-
prf: [Buffer | null, Buffer | null];
|
|
14
|
-
largeBlob: Buffer | null;
|
|
15
|
-
largeBlobWritten: boolean | null;
|
|
16
|
-
}
|
|
17
|
-
export interface GetCredentialAdditionalOptions {
|
|
18
|
-
largeBlobDataToWrite?: Buffer;
|
|
19
|
-
prf?: PRFInput;
|
|
20
|
-
prfByCredential?: Record<string, PRFInput>;
|
|
21
|
-
topFrameOrigin?: string;
|
|
22
|
-
}
|
|
23
|
-
declare function getCredentialInternal(rpid: string, challenge: Buffer, nativeWindowHandle: Buffer, origin: string, timeout: number, enabledExtensions: CredentialAssertionExtensions[], allowedCredentialIds: Buffer[], userVerificationPreference?: UserVerificationPreference, additionalOptions?: GetCredentialAdditionalOptions): Promise<GetCredentialResult>;
|
|
24
|
-
export { getCredentialInternal };
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { base64UrlToBuffer, PromiseWithResolvers } from "../helpers/index.js";
|
|
2
|
-
import { removeClientDataHash, setClientDataHash, WebauthnGetController, } from "../get/authorization-controller.js";
|
|
3
|
-
import { createPRFInput } from "../helpers/prf.js";
|
|
4
|
-
import { generateClientDataInfo, generateWebauthnClientData, } from "../helpers/client-data.js";
|
|
5
|
-
import { createPresentationContextProviderFromNativeWindowHandle } from "../helpers/presentation.js";
|
|
6
|
-
import { NSStringFromString } from "objcjs-types/helpers";
|
|
7
|
-
import { ASAuthorizationPlatformPublicKeyCredentialProvider, ASAuthorizationPublicKeyCredentialLargeBlobAssertionInput, ASAuthorizationPublicKeyCredentialLargeBlobAssertionOperation, ASAuthorizationPlatformPublicKeyCredentialDescriptor, ASAuthorizationSecurityKeyPublicKeyCredentialProvider, ASAuthorizationPublicKeyCredentialPRFAssertionInput, ASAuthorizationPublicKeyCredentialAttachment, ASAuthorizationPlatformPublicKeyCredentialAssertion, ASAuthorizationSecurityKeyPublicKeyCredentialAssertion, } from "objcjs-types/AuthenticationServices";
|
|
8
|
-
import { NSDataFromBuffer, bufferFromNSDataDirect } from "objcjs-types/nsdata";
|
|
9
|
-
import { createDelegate } from "objcjs-types/delegates";
|
|
10
|
-
import { NSArray, NSDictionary, } from "objcjs-types/Foundation";
|
|
11
|
-
import { NSArrayFromObjects, NSDictionaryFromKeysAndValues, } from "objcjs-types/helpers";
|
|
12
|
-
const VALID_EXTENSIONS = ["largeBlobRead", "largeBlobWrite", "prf"];
|
|
13
|
-
function setupPublicKeyCredentialRequest(type, keyRequest, userVerificationPreference, enabledExtensions, allowedCredentialIds, additionalOptions) {
|
|
14
|
-
if (userVerificationPreference === "preferred") {
|
|
15
|
-
keyRequest.setUserVerificationPreference$(NSStringFromString("preferred"));
|
|
16
|
-
}
|
|
17
|
-
else if (userVerificationPreference === "required") {
|
|
18
|
-
keyRequest.setUserVerificationPreference$(NSStringFromString("required"));
|
|
19
|
-
}
|
|
20
|
-
else if (userVerificationPreference === "discouraged") {
|
|
21
|
-
keyRequest.setUserVerificationPreference$(NSStringFromString("discouraged"));
|
|
22
|
-
}
|
|
23
|
-
if (type === "platform") {
|
|
24
|
-
const largeBlobRead = enabledExtensions.includes("largeBlobRead");
|
|
25
|
-
const largeBlobWrite = enabledExtensions.includes("largeBlobWrite");
|
|
26
|
-
if (largeBlobRead) {
|
|
27
|
-
const operation = ASAuthorizationPublicKeyCredentialLargeBlobAssertionOperation.Read;
|
|
28
|
-
const largeBlobInput = ASAuthorizationPublicKeyCredentialLargeBlobAssertionInput.alloc().initWithOperation$(operation);
|
|
29
|
-
keyRequest.setLargeBlob$(largeBlobInput);
|
|
30
|
-
}
|
|
31
|
-
else if (largeBlobWrite) {
|
|
32
|
-
if (additionalOptions.largeBlobDataToWrite) {
|
|
33
|
-
const operation = ASAuthorizationPublicKeyCredentialLargeBlobAssertionOperation.Write;
|
|
34
|
-
const largeBlobInput = ASAuthorizationPublicKeyCredentialLargeBlobAssertionInput.alloc().initWithOperation$(operation);
|
|
35
|
-
largeBlobInput.setDataToWrite$(NSDataFromBuffer(additionalOptions.largeBlobDataToWrite));
|
|
36
|
-
keyRequest.setLargeBlob$(largeBlobInput);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
console.warn("[electron-webauthn] largeBlobWrite is enabled but largeBlobDataToWrite is not provided, skipping large blob write");
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (type === "platform" && enabledExtensions.includes("prf")) {
|
|
44
|
-
if (additionalOptions.prf || additionalOptions.prfByCredential) {
|
|
45
|
-
let inputValues = null;
|
|
46
|
-
if (additionalOptions.prf) {
|
|
47
|
-
inputValues = createPRFInput(additionalOptions.prf);
|
|
48
|
-
}
|
|
49
|
-
let perCredentialInputValues = null;
|
|
50
|
-
if (additionalOptions.prfByCredential &&
|
|
51
|
-
allowedCredentialIds.length > 0) {
|
|
52
|
-
const keys = [];
|
|
53
|
-
const values = [];
|
|
54
|
-
for (const [credentialId, prfInput] of Object.entries(additionalOptions.prfByCredential)) {
|
|
55
|
-
const credentialIdBuffer = base64UrlToBuffer(credentialId);
|
|
56
|
-
const credentialIdData = NSDataFromBuffer(credentialIdBuffer);
|
|
57
|
-
keys.push(credentialIdData);
|
|
58
|
-
values.push(createPRFInput(prfInput));
|
|
59
|
-
}
|
|
60
|
-
perCredentialInputValues = NSDictionaryFromKeysAndValues(keys, values);
|
|
61
|
-
}
|
|
62
|
-
const prfInput = ASAuthorizationPublicKeyCredentialPRFAssertionInput.alloc().initWithInputValues$perCredentialInputValues$(inputValues, perCredentialInputValues);
|
|
63
|
-
keyRequest.setPrf$(prfInput);
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
console.warn("[electron-webauthn] prf is enabled but prf or prfByCredential is not provided, skipping PRF");
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
function getCredentialInternal(rpid, challenge, nativeWindowHandle, origin, timeout, enabledExtensions = [], allowedCredentialIds, userVerificationPreference, additionalOptions = {}) {
|
|
71
|
-
const { promise, resolve, reject } = PromiseWithResolvers();
|
|
72
|
-
const NS_rpID = NSStringFromString(rpid);
|
|
73
|
-
const NS_challenge = NSDataFromBuffer(challenge);
|
|
74
|
-
const platformProvider = ASAuthorizationPlatformPublicKeyCredentialProvider.alloc().initWithRelyingPartyIdentifier$(NS_rpID);
|
|
75
|
-
const platformKeyRequest = platformProvider.createCredentialAssertionRequestWithChallenge$(NS_challenge);
|
|
76
|
-
setupPublicKeyCredentialRequest("platform", platformKeyRequest, userVerificationPreference, enabledExtensions, allowedCredentialIds, additionalOptions);
|
|
77
|
-
const securityKeyProvider = ASAuthorizationSecurityKeyPublicKeyCredentialProvider.alloc().initWithRelyingPartyIdentifier$(NS_rpID);
|
|
78
|
-
const securityKeyRequest = securityKeyProvider.createCredentialAssertionRequestWithChallenge$(NS_challenge);
|
|
79
|
-
setupPublicKeyCredentialRequest("security-key", securityKeyRequest, userVerificationPreference, enabledExtensions, allowedCredentialIds, additionalOptions);
|
|
80
|
-
const requestsArray = NSArrayFromObjects([
|
|
81
|
-
platformKeyRequest,
|
|
82
|
-
securityKeyRequest,
|
|
83
|
-
]);
|
|
84
|
-
const authController = WebauthnGetController.alloc().initWithAuthorizationRequests$(requestsArray);
|
|
85
|
-
const clientData = generateWebauthnClientData("webauthn.get", origin, challenge, additionalOptions.topFrameOrigin);
|
|
86
|
-
const { clientDataHash, clientDataBuffer } = generateClientDataInfo(clientData);
|
|
87
|
-
setClientDataHash(authController, clientDataHash);
|
|
88
|
-
let isFinished = false;
|
|
89
|
-
let timeoutHandlerId = null;
|
|
90
|
-
const finished = (_success) => {
|
|
91
|
-
isFinished = true;
|
|
92
|
-
removeClientDataHash(authController);
|
|
93
|
-
if (timeoutHandlerId) {
|
|
94
|
-
clearTimeout(timeoutHandlerId);
|
|
95
|
-
timeoutHandlerId = null;
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
if (allowedCredentialIds.length > 0) {
|
|
99
|
-
const allowedCredentials = NSArrayFromObjects(allowedCredentialIds.map((id) => ASAuthorizationPlatformPublicKeyCredentialDescriptor.alloc().initWithCredentialID$(NSDataFromBuffer(id))));
|
|
100
|
-
platformKeyRequest.setAllowedCredentials$(allowedCredentials);
|
|
101
|
-
}
|
|
102
|
-
const delegate = createDelegate("ASAuthorizationControllerDelegate", {
|
|
103
|
-
authorizationController$didCompleteWithAuthorization$: (_, authorization) => {
|
|
104
|
-
const credential = authorization.credential();
|
|
105
|
-
const isPlatform = credential instanceof
|
|
106
|
-
ASAuthorizationPlatformPublicKeyCredentialAssertion;
|
|
107
|
-
const isSecurityKey = credential instanceof
|
|
108
|
-
ASAuthorizationSecurityKeyPublicKeyCredentialAssertion;
|
|
109
|
-
if (!isPlatform && !isSecurityKey) {
|
|
110
|
-
reject(new Error("Resulting credential is not a platform or security key credential"));
|
|
111
|
-
finished(false);
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
const id_data = credential.credentialID();
|
|
115
|
-
const id = bufferFromNSDataDirect(id_data);
|
|
116
|
-
let authenticatorAttachment = "cross-platform";
|
|
117
|
-
if (isPlatform &&
|
|
118
|
-
credential.attachment() ===
|
|
119
|
-
ASAuthorizationPublicKeyCredentialAttachment.Platform) {
|
|
120
|
-
authenticatorAttachment = "platform";
|
|
121
|
-
}
|
|
122
|
-
const prf = credential.prf();
|
|
123
|
-
const prfFirst = prf?.first ? prf.first() : null;
|
|
124
|
-
const prfSecond = prf?.second ? prf.second() : null;
|
|
125
|
-
let largeBlobBuffer = null;
|
|
126
|
-
let largeBlobWritten = null;
|
|
127
|
-
if (credential.largeBlob()) {
|
|
128
|
-
const largeBlobData = credential.largeBlob().readData();
|
|
129
|
-
if (largeBlobData) {
|
|
130
|
-
largeBlobBuffer = bufferFromNSDataDirect(largeBlobData);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
largeBlobWritten = credential.largeBlob().didWrite();
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
resolve({
|
|
137
|
-
id,
|
|
138
|
-
authenticatorAttachment,
|
|
139
|
-
clientDataJSON: clientDataBuffer,
|
|
140
|
-
authenticatorData: bufferFromNSDataDirect(credential.rawAuthenticatorData()),
|
|
141
|
-
signature: bufferFromNSDataDirect(credential.signature()),
|
|
142
|
-
userHandle: bufferFromNSDataDirect(credential.userID()),
|
|
143
|
-
prf: [
|
|
144
|
-
prfFirst ? bufferFromNSDataDirect(prfFirst) : null,
|
|
145
|
-
prfSecond ? bufferFromNSDataDirect(prfSecond) : null,
|
|
146
|
-
],
|
|
147
|
-
largeBlob: largeBlobBuffer,
|
|
148
|
-
largeBlobWritten,
|
|
149
|
-
});
|
|
150
|
-
finished(true);
|
|
151
|
-
},
|
|
152
|
-
authorizationController$didCompleteWithError$: (_, error) => {
|
|
153
|
-
const errorMessage = error.localizedDescription().UTF8String();
|
|
154
|
-
reject(new Error(errorMessage));
|
|
155
|
-
finished(false);
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
authController.setDelegate$(delegate);
|
|
159
|
-
const presentationContextProvider = createPresentationContextProviderFromNativeWindowHandle(nativeWindowHandle);
|
|
160
|
-
authController.setPresentationContextProvider$(presentationContextProvider);
|
|
161
|
-
authController.performRequests();
|
|
162
|
-
timeoutHandlerId = setTimeout(() => {
|
|
163
|
-
if (isFinished)
|
|
164
|
-
return;
|
|
165
|
-
authController.cancel();
|
|
166
|
-
}, timeout);
|
|
167
|
-
return promise;
|
|
168
|
-
}
|
|
169
|
-
export { getCredentialInternal };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
interface WebauthnClientData {
|
|
2
|
-
type: "webauthn.get" | "webauthn.create";
|
|
3
|
-
challenge: string;
|
|
4
|
-
origin: string;
|
|
5
|
-
topOrigin?: string;
|
|
6
|
-
crossOrigin: boolean;
|
|
7
|
-
}
|
|
8
|
-
export declare function generateWebauthnClientData(type: "webauthn.get" | "webauthn.create", origin: string, challenge: Buffer, topFrameOrigin?: string): WebauthnClientData;
|
|
9
|
-
export declare function generateClientDataInfo(clientData: WebauthnClientData): {
|
|
10
|
-
clientDataJSON: string;
|
|
11
|
-
clientDataBuffer: Buffer<ArrayBuffer>;
|
|
12
|
-
clientDataHash: Buffer<ArrayBufferLike>;
|
|
13
|
-
};
|
|
14
|
-
export {};
|