UNPKG

@omneedia/auth-js

Version:
148 lines (124 loc) 4.49 kB
import { SupportedStorage } from './types' export function expiresAt(expiresIn: number) { const timeNow = Math.round(Date.now() / 1000) return timeNow + expiresIn } export function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8 return v.toString(16) }) } export const isBrowser = () => typeof document !== 'undefined' export function getParameterByName(name: string, url?: string) { if (!url) url = window?.location?.href || '' // eslint-disable-next-line no-useless-escape name = name.replace(/[\[\]]/g, '\\$&') const regex = new RegExp('[?&#]' + name + '(=([^&#]*)|&|#|$)'), results = regex.exec(url) if (!results) return null if (!results[2]) return '' return decodeURIComponent(results[2].replace(/\+/g, ' ')) } type Fetch = typeof fetch export const resolveFetch = (customFetch?: Fetch): Fetch => { let _fetch: Fetch if (customFetch) { _fetch = customFetch } else if (typeof fetch === 'undefined') { _fetch = async (...args) => await (await import('cross-fetch')).fetch(...args) } else { _fetch = fetch } return (...args) => _fetch(...args) } export const looksLikeFetchResponse = (maybeResponse: unknown): maybeResponse is Response => { return ( typeof maybeResponse === 'object' && maybeResponse !== null && 'status' in maybeResponse && 'ok' in maybeResponse && 'json' in maybeResponse && typeof (maybeResponse as any).json === 'function' ) } // Storage helpers export const setItemAsync = async ( storage: SupportedStorage, key: string, data: any ): Promise<void> => { await storage.setItem(key, JSON.stringify(data)) } export const getItemAsync = async (storage: SupportedStorage, key: string): Promise<unknown> => { const value = await storage.getItem(key) if (!value) { return null } try { return JSON.parse(value) } catch { return value } } export const removeItemAsync = async (storage: SupportedStorage, key: string): Promise<void> => { await storage.removeItem(key) } export const decodeBase64URL = (value: string): string => { try { // atob is present in all browsers and nodejs >= 16 // but if it is not it will throw a ReferenceError in which case we can try to use Buffer // replace are here to convert the Base64-URL into Base64 which is what atob supports // replace with //g regex acts like replaceAll // Decoding base64 to UTF8 see https://stackoverflow.com/a/30106551/17622044 return decodeURIComponent( atob(value.replace(/[-]/g, '+').replace(/[_]/g, '/')) .split('') .map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) .join('') ) } catch (e) { if (e instanceof ReferenceError) { // running on nodejs < 16 // Buffer supports Base64-URL transparently return Buffer.from(value, 'base64').toString('utf-8') } else { throw e } } } /** * A deferred represents some asynchronous work that is not yet finished, which * may or may not culminate in a value. * Taken from: https://github.com/mike-north/types/blob/master/src/async.ts */ export class Deferred<T = any> { public static promiseConstructor: PromiseConstructor = Promise public readonly promise!: PromiseLike<T> public readonly resolve!: (value?: T | PromiseLike<T>) => void public readonly reject!: (reason?: any) => any public constructor() { // eslint-disable-next-line @typescript-eslint/no-extra-semi ;(this as any).promise = new Deferred.promiseConstructor((res, rej) => { // eslint-disable-next-line @typescript-eslint/no-extra-semi ;(this as any).resolve = res // eslint-disable-next-line @typescript-eslint/no-extra-semi ;(this as any).reject = rej }) } } // Taken from: https://stackoverflow.com/questions/38552003/how-to-decode-jwt-token-in-javascript-without-using-a-library export function decodeJWTPayload(token: string) { // Regex checks for base64url format const base64UrlRegex = /^([a-z0-9_-]{4})*($|[a-z0-9_-]{3}=?$|[a-z0-9_-]{2}(==)?$)$/i const parts = token.split('.') if (parts.length !== 3) { throw new Error('JWT is not valid: not a JWT structure') } if (!base64UrlRegex.test(parts[1])) { throw new Error('JWT is not valid: payload is not in base64url format') } const base64Url = parts[1] return JSON.parse(decodeBase64URL(base64Url)) }