UNPKG

ploy-test-one

Version:

Passwordless authentication Study

122 lines (121 loc) 4.58 kB
/** * 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 { ConditionalCheckFailedException } from "@aws-sdk/client-dynamodb"; export class UserFacingError extends Error { constructor(msg) { super(msg); this.name = "UserFacingError"; } } export function handleConditionalCheckFailedException(msg) { return (err) => { if (err instanceof ConditionalCheckFailedException) { throw new UserFacingError(msg); } throw err; }; } export var LogLevel; (function (LogLevel) { LogLevel[LogLevel["none"] = 0] = "none"; LogLevel[LogLevel["error"] = 10] = "error"; LogLevel[LogLevel["info"] = 20] = "info"; LogLevel[LogLevel["debug"] = 30] = "debug"; })(LogLevel || (LogLevel = {})); export class Logger { logLevel; constructor(logLevel) { this.logLevel = logLevel; } error(...args) { if (this.logLevel >= LogLevel.error) { console.error(...args); } } info(...args) { if (this.logLevel >= LogLevel.info) { console.log(...args); } } debug(...args) { if (this.logLevel >= LogLevel.debug) { console.trace(...args); } } } export const logLevel = { ERROR: LogLevel.error, INFO: LogLevel.info, DEBUG: LogLevel.debug, }[process.env.LOG_LEVEL ?? "NONE"] ?? LogLevel.none; // eslint-disable-next-line prefer-const export let logger = new Logger(logLevel); /** * Returns a suitable userHandle given the username and the sub * If possible we'll use the username (so that usernameless sign-in can be supported), * but this requires the username to be opaque. */ export function determineUserHandle({ sub, cognitoUsername, }) { if (sub === cognitoUsername) return sub; // usernameless sign-in supported if (!sub || isOpaqueIdentifier(cognitoUsername)) { /** * prefix username with "u|" so it will never (accidentally, or maliciously) collide with the sub of another user * (the Cognito sub is a hexadecimally represented UUID that will not start with "u|") */ return `u|${cognitoUsername}`; // usernameless sign-in supported } return `s|${sub}`; // usernameless sign-in NOT supported, we prefix with "s|" so the UI can detect this } function isOpaqueIdentifier(cognitoUsername) { return isUuid(cognitoUsername); } function isUuid(cognitoUsername) { return !!cognitoUsername.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/); } const allowedOrigins = process.env.CORS_ALLOWED_ORIGINS; const allowedMethods = process.env.CORS_ALLOWED_METHODS; const allowedHeaders = process.env.CORS_ALLOWED_HEADERS; const maxAge = process.env.CORS_MAX_AGE; const corsHeaderAvailable = !!(allowedOrigins && allowedMethods && allowedHeaders && maxAge); export function withCommonHeaders(handler) { const wrapped = (event, context, cb) => { return handler(event, context, () => cb(new Error("Callback style response from wrapped handler not supported")))?.then((response) => { const origin = event.headers && Object.entries(event.headers).find(([k, v]) => k.toLowerCase() === "origin" && v)?.[1]; const headers = { "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "Content-Type": "application/json", "Cache-Control": "no-store", }; if (origin && corsHeaderAvailable && allowedOrigins.split(",").includes(origin)) { Object.assign(headers, { "Access-Control-Allow-Origin": origin, "Access-Control-Allow-Methods": allowedMethods, "Access-Control-Allow-Headers": allowedHeaders, "Access-Control-Max-Age": maxAge, }); } response.headers = { ...response.headers, ...headers }; return response; }); }; return wrapped; }