ploy-test-one
Version:
Passwordless authentication Study
184 lines (183 loc) • 7.17 kB
JavaScript
/**
* Copyright Amazon.com, Inc. and its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You
* may not use this file except in compliance with the License. A copy of
* the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
import { Passkey } from "react-native-passkey";
import { fido2StartCreateCredential, fido2CompleteCreateCredential, fido2ListCredentials, fido2UpdateCredential, fido2DeleteCredential, authenticateWithFido2, } from "../fido2.js";
import { configure as _configure, } from "../config.js";
import { retrieveTokens } from "../storage.js";
export { fido2ListCredentials, fido2UpdateCredential, fido2DeleteCredential, retrieveTokens, };
// The following dependencies should not be imported here and directly use
// amazon-cognito-passwordless-auth/cognito-api but React Native's Metro compiler
// does not support "exports" in package.json just yet
// Ref: https://github.com/facebook/metro/issues/670
export { initiateAuth, signUp, respondToAuthChallenge, updateUserAttributes, verifyUserAttribute, getUserAttributeVerificationCode, } from "../cognito-api.js";
export { authenticateWithPlaintextPassword } from "../plaintext.js";
import { parseJwtPayload } from "../util.js";
import { usePasswordless as _usePasswordless, PasswordlessContextProvider, } from "./hooks.js";
export { PasswordlessContextProvider };
export function usePasswordless() {
return {
..._usePasswordless(),
authenticateWithFido2: loginWithFido2,
fido2CreateCredential,
};
}
function configure(config) {
if (config && config.fido2) {
config.fido2.rp = {
id: config.fido2.passkeyDomain,
name: config.fido2.passkeyDomain,
...config.fido2.rp,
};
}
return _configure(config);
}
export const Passwordless = { configure };
export const toBase64String = (base64Url) => base64Url.replace(/-/g, "+").replace(/_/g, "/") + "==";
export async function fido2CreateCredential({ friendlyName, }) {
const config = configure();
const response = await fido2StartCreateCredential();
if (!config.fido2)
throw new Error("FIDO2 not configured");
const passkey = new Passkey(config.fido2.passkeyDomain, config.fido2.rp.name);
const credential = await passkey.register(toBase64String(response.challenge), response.user.id);
return await fido2CompleteCreateCredential({
credential: {
clientDataJSON_B64: credential.response.rawClientDataJSON,
attestationObjectB64: credential.response.rawAttestationObject,
},
friendlyName,
});
}
export async function fido2GetCredential({ challenge, username, }) {
const config = configure();
if (!config.fido2)
throw new Error("FIDO2 not configured");
const passkey = new Passkey(config.fido2.passkeyDomain, username);
const result = await passkey.auth(toBase64String(challenge));
return {
credentialIdB64: result.credentialID,
authenticatorDataB64: result.response.rawAuthenticatorData,
clientDataJSON_B64: result.response.rawClientDataJSON,
signatureB64: result.response.signature,
userHandleB64: null,
};
}
export async function loginWithFido2({ username, }) {
const response = authenticateWithFido2({
username,
credentialGetter: ({ challenge }) => {
return fido2GetCredential({
username,
challenge: toBase64String(challenge),
});
},
});
await response.signedIn;
return response;
}
export async function getAccountDetails() {
const tokens = await retrieveTokens();
if (!tokens?.idToken) {
return {};
}
return parseJwtPayload(tokens.idToken);
}
export const timeAgo = (now, date) => {
const seconds = Math.floor((now - date.getTime()) / 1000);
const years = Math.floor(seconds / 31536000);
const months = Math.floor(seconds / 2592000);
const days = Math.floor(seconds / 86400);
if (days > 548) {
return years.toString() + " years ago";
}
if (days >= 320 && days <= 547) {
return "a year ago";
}
if (days >= 45 && days <= 319) {
return months.toString() + " months ago";
}
if (days >= 26 && days <= 45) {
return "a month ago";
}
const hours = Math.floor(seconds / 3600);
if (hours >= 36 && days <= 25) {
return days.toString() + " days ago";
}
if (hours >= 22 && hours <= 35) {
return "a day ago";
}
const minutes = Math.floor(seconds / 60);
if (minutes >= 90 && hours <= 21) {
return hours.toString() + " hours ago";
}
if (minutes >= 45 && minutes <= 89) {
return "an hour ago";
}
if (seconds >= 90 && minutes <= 44) {
return minutes.toString() + " minutes ago";
}
if (seconds >= 45 && seconds <= 89) {
return "a minute ago";
}
if (seconds >= 10 && seconds <= 45) {
return seconds.toString() + " seconds ago";
}
if (seconds >= 0 && seconds <= 10) {
return "Just now";
}
};
class RNTextDecoder {
// React Native implementation in plain JS, this is slow and only works for UTF-8
decode(arrBuf) {
const bytes = [...new Uint8Array(arrBuf)];
let i = 0;
const codePoints = [];
const readByte = () => bytes[i++] ?? RNTextDecoder.throwMalformedInputError();
const readContinuationByte = () => bytes[i++] >> 6 === 0b10
? bytes[i - 1]
: RNTextDecoder.throwMalformedInputError();
while (i < bytes.length) {
const byte = readByte();
if (byte >> 7 === 0) {
codePoints.push(byte);
}
else if (byte >> 5 === 0b110) {
codePoints.push(((byte & 0x1f) << 6) | (readContinuationByte() & 0x3f));
}
else if (byte >> 4 === 0b1110) {
codePoints.push(((byte & 0x0f) << 12) |
((readContinuationByte() & 0x3f) << 6) |
(readContinuationByte() & 0x3f));
}
else if (byte >> 3 === 0b11110) {
codePoints.push(((byte & 0x07) << 18) |
((readContinuationByte() & 0x3f) << 12) |
((readContinuationByte() & 0x3f) << 6) |
(readContinuationByte() & 0x3f));
}
else {
RNTextDecoder.throwMalformedInputError();
}
}
return String.fromCodePoint(...codePoints);
}
}
RNTextDecoder.throwMalformedInputError = () => {
throw new Error("Malformed input");
};
if (typeof global.TextDecoder === "undefined") {
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment
global.TextDecoder = RNTextDecoder;
}