Skip to content

Commit

Permalink
[feat] remove unused function
Browse files Browse the repository at this point in the history
  • Loading branch information
zetsuboii committed Jan 20, 2024
1 parent 1e1f927 commit 2e83dc5
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 98 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clave-passkey",
"version": "1.0.8",
"name": "clave-rn-passkey",
"version": "1.0.11",
"description": "Passkey implementation for React Native",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down
177 changes: 81 additions & 96 deletions src/Passkey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,140 +2,125 @@ import { NotSupportedError } from './PasskeyError';
import { Platform } from 'react-native';
import { PasskeyAndroid } from './PasskeyAndroid';
import { PasskeyiOS } from './PasskeyiOS';

const generateCreateRequest = (
userId: string,
userName: string,
challenge: string,
options: Partial<CreateOptions>
): PasskeyRegistrationRequest => {
return {
challenge,
rp: {
id: 'https://getclave.io',
name: 'Clave',
},
user: {
id: userId,
name: userName,
displayName: userName,
},
pubKeyCredParams: [
{ alg: -7, type: 'public-key' }, // ES256 (Webauthn's default algorithm)
],
timeout: options.timeout ?? 60000,
authenticatorSelection: {
userVerification: options.userVerification ?? 'required', // Webauthn default is "preferred"
authenticatorAttachment: 'platform',
residentKey: options.discoverable ?? 'preferred', // official default is 'discouraged'
requireResidentKey: options.discoverable === 'required', // mainly for backwards compatibility, see https://www.w3.org/TR/webauthn/#dictionary-authenticatorSelection
},
attestation: options.attestation ? 'direct' : 'none',
};
};

const generateSignRequest = (
credentialIds: Array<string>,
challenge: string,
options: Partial<SignOptions>
): PasskeyAuthenticationRequest => {
return {
challenge,
rpId: 'https://getclave.io',
allowCredentials: credentialIds.map((id) => {
return {
id,
type: 'public-key',
transports: ['hybrid', 'usb', 'ble', 'nfc'],
};
}),
userVerification: options.userVerification ?? 'required',
timeout: options.timeout ?? 60000,
};
};
import * as utils from './utils';

export class Passkey {
public static async create(
static generateCreateRequest(
userId: string,
userName: string,
challenge: string,
options: Partial<CreateOptions> = {}
) {
if (!Passkey.isSupported) {
throw NotSupportedError;
}

const request = generateCreateRequest(userId, userName, challenge, options);
options: Partial<CreateOptions>
): PasskeyRegistrationRequest {
return {
challenge,
rp: {
id: 'getclave.io',
name: 'Clave',
},
user: {
id: userId,
name: userName,
displayName: userName,
},
pubKeyCredParams: [
{ alg: -7, type: 'public-key' }, // ES256 (Webauthn's default algorithm)
],
timeout: options.timeout ?? 60000,
authenticatorSelection: {
userVerification: options.userVerification ?? 'preferred',
authenticatorAttachment: 'platform',
residentKey: options.discoverable ?? 'preferred',
requireResidentKey: options.discoverable === 'required',
},
attestation: options.attestation ? 'direct' : 'none',
};
}

if (Platform.OS === 'android') {
return PasskeyAndroid.register(request);
}
return PasskeyiOS.register(request, options.withSecurityKey ?? false);
static generateSignRequest(
credentialIds: Array<string>,
challenge: string,
options: Partial<SignOptions>
): PasskeyAuthenticationRequest {
return {
challenge,
rpId: 'getclave.io',
allowCredentials: credentialIds.map((id) => {
return {
id,
type: 'public-key',
transports: ['hybrid', 'usb', 'ble', 'nfc'],
};
}),
userVerification: options.userVerification ?? 'required',
timeout: options.timeout ?? 60000,
};
}

/**
* Creates a new Passkey
*
* @param request The FIDO2 Attestation Request in JSON format
* @param userId The user's unique identifier
* @param userName The user's name
* @param challenge The FIDO2 Challenge without formatting
* @param options An object containing options for the registration process
* @returns The FIDO2 Attestation Result in JSON format
* @throws
*/
public static async register(
request: PasskeyRegistrationRequest,
{ withSecurityKey }: { withSecurityKey: boolean } = {
withSecurityKey: false,
}
): Promise<PasskeyRegistrationResult> {
if (!Passkey.isSupported) {
throw NotSupportedError;
}

if (Platform.OS === 'android') {
return PasskeyAndroid.register(request);
}
return PasskeyiOS.register(request, withSecurityKey);
}

public static async sign(
credentialIds: Array<string>,
public static async create(
userId: string,
userName: string,
challenge: string,
options: Partial<SignOptions> = {}
options: Partial<CreateOptions> = {}
) {
if (!Passkey.isSupported) {
throw NotSupportedError;
}

const request = generateSignRequest(credentialIds, challenge, options);
const challengeBase64 = utils.toBase64(challenge);

const request = this.generateCreateRequest(
userId,
userName,
challengeBase64,
options
);

if (Platform.OS === 'android') {
return PasskeyAndroid.authenticate(request);
return PasskeyAndroid.register(request);
}
return PasskeyiOS.authenticate(request, options.withSecurityKey ?? false);
return PasskeyiOS.register(request, options.withSecurityKey ?? false);
}

/**
* Authenticates using an existing Passkey
*
* @param request The FIDO2 Assertion Request in JSON format
* @param options An object containing options for the authentication process
* @param credentialIds The credential IDs of the Passkey to authenticate with
* @param challenge The FIDO2 Challenge without formatting
* @options An object containing options for the authentication process
* @returns The FIDO2 Assertion Result in JSON format
* @throws
*/
public static async authenticate(
request: PasskeyAuthenticationRequest,
{ withSecurityKey }: { withSecurityKey: boolean } = {
withSecurityKey: false,
}
): Promise<PasskeyAuthenticationResult> {
public static async sign(
credentialIds: Array<string>,
challenge: string,
options: Partial<SignOptions> = {}
) {
if (!Passkey.isSupported) {
throw NotSupportedError;
}

const challengeBase64 = utils.toBase64(challenge);

const request = this.generateSignRequest(
credentialIds,
challengeBase64,
options
);

if (Platform.OS === 'android') {
return PasskeyAndroid.authenticate(request);
}
return PasskeyiOS.authenticate(request, withSecurityKey);
return PasskeyiOS.authenticate(request, options.withSecurityKey ?? false);
}

/**
Expand Down Expand Up @@ -233,7 +218,7 @@ export interface PasskeyAuthenticationResult {
type?: string;
response: {
authenticatorData: string;
clientDataJSON: string;
clientDataJSON: string; // Base64 and DER encoded
signature: string;
userHandle: string;
};
Expand Down
45 changes: 45 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Buffer } from 'buffer';

export const fromBase64 = (text: string) => {
return Buffer.from(text, 'base64').toString('ascii');
};

export const toBase64 = (text: string) => {
return Buffer.from(text).toString('base64');
};

/** Removes 0x from hex */
export const parseHex = (hex: string): string => {
if (hex.startsWith('0x')) {
return hex.slice(2);
}
return hex;
};

/** Converts hex to buffer */
export const hexToBuffer = (hex: string): Buffer => {
return Buffer.from(parseHex(hex), 'hex');
};

/**
* Converts DER signature to R and S
* R and S are hex strings
*/
export const derToRs = (derSignature: string): { r: string; s: string } => {
/*
DER signature format:
0x30 <length total> 0x02 <length r> <r> 0x02 <length s> <s>
*/
const derBuffer = hexToBuffer(derSignature);

const rLen = derBuffer[3]!;
const rOffset = 4;
const rBuffer = derBuffer.slice(rOffset, rOffset + rLen);
const sLen = derBuffer[5 + rLen]!;
const sOffset = 6 + rLen;
const sBuffer = derBuffer.slice(sOffset, sOffset + sLen);

const r = rBuffer.toString('hex');
const s = sBuffer.toString('hex');
return { r, s };
};

0 comments on commit 2e83dc5

Please sign in to comment.