@criipto/verify-react
Version:
Verify SDK for React Single Page Applications
1,388 lines • 110 kB
JavaScript
import React, { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import CriiptoAuth, { OAuth2Error, OAuth2Error as OAuth2Error$1, UserCancelledError, clearPKCEState, generatePKCE, parseAuthorizeResponseFromLocation, savePKCEState } from "@criipto/auth-js";
import jwtDecode from "jwt-decode";
import { jsx, jsxs } from "react/jsx-runtime";
import { UAParser } from "@ua-parser-js/pro-enterprise";
import QRCode$1 from "qrcode";
import classNames from "classnames";
//#region src/context.ts
const actions = [
"confirm",
"accept",
"approve",
"sign",
"login"
];
/**
* @ignore
*/
const stub = () => {
throw new Error("You forgot to wrap your component in <CriiptoVerifyProvider>.");
};
const CriiptoVerifyContext = createContext({
loginWithRedirect: stub,
loginWithPopup: stub,
checkSession: stub,
logout: stub,
fetchOpenIDConfiguration: stub,
buildAuthorizeUrl: stub,
initializePAR: stub,
generatePKCE: stub,
buildOptions: stub,
handleResponse: stub,
responseType: "token",
completionStrategy: "client",
result: null,
claims: null,
domain: "",
action: "login",
pkce: void 0,
store: null,
isLoading: false,
isInitializing: true,
client: null,
loginHint: void 0
});
//#endregion
//#region package.json
var version = "5.0.2";
//#endregion
//#region src/i18n/en.ts
const en = {
loginWith: "Login with",
approveWith: "Approve with",
signWith: "Sign with",
confirmWith: "Confirm with",
acceptWith: "Accept with",
sameDevice: "On this device",
anotherDevice: "With your SSN",
anotherDeviceQR: "On another device",
mitidBusiness: "MitID Business",
finnishMobileID: "Finnish Mobile Certificate",
finnishBankID: "Finnish Bank ID",
swedishBankID: "Swedish BankID",
norwegianBankID: "Norwegian BankID",
biometrics: "Biometrics",
openAndScan: "Open the BankID app on your mobile device and scan the QR code.",
thisIsTheQR: "This is a BankID QR Code. You can click it to view it in full screen.",
completingLogin: "Completing your login."
};
//#endregion
//#region src/i18n/da.ts
const da = {
loginWith: "Login med",
approveWith: "Godkend med",
signWith: "Underskriv med",
confirmWith: "Bekræft med",
acceptWith: "Accepter med",
sameDevice: "På denne enhed",
anotherDevice: "Med dit personnummer",
anotherDeviceQR: "På anden enhed",
mitidBusiness: "MitID Erhverv",
finnishMobileID: "Finsk Mobilcertifikat",
finnishBankID: "Finsk Bank ID",
swedishBankID: "Svensk BankID",
norwegianBankID: "Norsk BankID",
biometrics: "Biometri",
openAndScan: "Åbn BankID appen på din telefon og scan QR koden.",
thisIsTheQR: "Dette er en BankID QR-kode. Du kan klikke på den for at se den i fuld skærm.",
completingLogin: "Fuldfører dit login."
};
//#endregion
//#region src/i18n/sv.ts
const sv = {
loginWith: "Logga in med",
approveWith: "Godkänn med",
signWith: "Signera med",
confirmWith: "Bekräfta med",
acceptWith: "Acceptera med",
sameDevice: "På denna enhet",
anotherDevice: "Med ditt personnummer",
anotherDeviceQR: "På annan enhet",
mitidBusiness: "MitID Erhverv",
finnishMobileID: "Finskt Mobilcertifikat",
finnishBankID: "Finskt Bank ID",
swedishBankID: "Svenskt BankID",
norwegianBankID: "Norska BankID",
biometrics: "Biometri",
openAndScan: "Öppna BankID-appen på din mobila enhet och skanna QR-koden.",
thisIsTheQR: "Detta är en QR-kod från BankID. Du kan klicka på den för att visa den i fullskärm.",
completingLogin: "Slutför din inloggning."
};
//#endregion
//#region src/i18n/nb.ts
const nb = {
loginWith: "Logg inn med",
approveWith: "Godkjenne med",
signWith: "Signer med",
confirmWith: "Bekreft med",
acceptWith: "Aksepterer med",
sameDevice: "På denne enhet",
anotherDevice: "Med personnummeret ditt",
anotherDeviceQR: "På annan enhet",
mitidBusiness: "MitID Erhverv",
finnishMobileID: "Finsk Mobilsertifikat",
finnishBankID: "Finsk Bank ID",
swedishBankID: "Svensk BankID",
norwegianBankID: "Norsk BankID",
biometrics: "Biometri",
openAndScan: "Åpne BankID-appen på mobilenheten din og skann QR-koden.",
thisIsTheQR: "Dette er en BankID QR-kode. Du kan klikke på den for å se den i fullskjerm.",
completingLogin: "Fullfører påloggingen."
};
//#endregion
//#region src/i18n/fi.ts
const fi = {
loginWith: "Kirjaudu sisään",
approveWith: "Hyväksy",
signWith: "Allekirjoita",
confirmWith: "Vahvista",
acceptWith: "Hyväksy",
sameDevice: "Tällä laitteella",
anotherDevice: "Henkilötunnuksellasi",
anotherDeviceQR: "Toisella laitteella",
mitidBusiness: "MitID Businessilla",
finnishMobileID: "Suomalaisella Mobiilivarmenteella",
finnishBankID: "Suomalaisella BankID:llä",
swedishBankID: "Ruotsalaisella BankID:llä",
norwegianBankID: "Norjalaisella BankID:llä",
biometrics: "Biometrisella tunnistautumisella",
openAndScan: "Avaa BankID-sovellus mobiililaitteellasi ja skannaa QR-koodi.",
thisIsTheQR: "Tämä on BankID-QR-koodi. Voit napsauttaa sitä nähdäksesi sen koko näytöllä",
completingLogin: "Sisäänkirjautumista viimeistellään."
};
//#endregion
//#region src/i18n/de.ts
const de = {
loginWith: "Anmelden mit",
approveWith: "Genehmigen mit",
signWith: "Unterschreiben mit",
confirmWith: "Bestätigen mit",
acceptWith: "Akzeptieren mit",
sameDevice: "Auf diesem Gerät",
anotherDevice: "Mit Ihrer Sozialversicherungsnummer",
anotherDeviceQR: "Auf einem anderen Gerät",
mitidBusiness: "MitID Business",
finnishMobileID: "Finnischem Mobilfunkzertifikat",
finnishBankID: "Finnische BankID",
swedishBankID: "Schwedische BankID",
norwegianBankID: "Norwegische BankID",
biometrics: "Biometrie",
openAndScan: "Öffnen Sie die BankID-App auf Ihrem mobilen Endgerät und scannen Sie den QR-Code.",
thisIsTheQR: "Dies ist ein BankID QR-Code. Sie können darauf klicken, um ihn im Vollbildmodus anzuzeigen",
completingLogin: "Ihre Anmeldung wird abgeschlossen."
};
//#endregion
//#region src/i18n/nl.ts
const nl = {
loginWith: "Inloggen met",
approveWith: "Goedkeuren met",
signWith: "Ondertekenen met",
confirmWith: "Bevestigen met",
acceptWith: "Accepteren met",
sameDevice: "Op dit apparaat",
anotherDevice: "Met uw SSN",
anotherDeviceQR: "Op een ander apparaat",
mitidBusiness: "MitID Business",
finnishMobileID: "Finse mobiel certificaat",
finnishBankID: "Finse BankID",
swedishBankID: "Zweedse BankID",
norwegianBankID: "Noorse BankID",
biometrics: "Biometrie",
openAndScan: "Open de BankID-app op uw mobiele apparaat en scan de QR-code.",
thisIsTheQR: "Dit is een BankID QR-code. U kunt erop klikken om het in een volledig scherm te bekijken",
completingLogin: "Uw login voltooien."
};
//#endregion
//#region src/i18n/index.ts
function getI18n(language) {
switch (language) {
case "en": return en;
case "da": return da;
case "sv": return sv;
case "nb": return nb;
case "fi": return fi;
case "de": return de;
case "nl": return nl;
default: assertUnreachable(language);
}
}
//#endregion
//#region src/utils.ts
const DKMITID_PREFIX = "urn:grn:authn:dk:mitid";
const FTN_PREFIX = "urn:grn:authn:fi";
function lowestMitIDValue(input) {
let dkmitidMethod = null;
input.forEach((s) => {
if (s.startsWith("urn:grn:authn:dk:mitid") && s !== "urn:grn:authn:dk:mitid:business") if (!dkmitidMethod) dkmitidMethod = s;
else {
let newLevel = s.replace(DKMITID_PREFIX, "");
let oldLevel = dkmitidMethod.replace(DKMITID_PREFIX, "");
if (newLevel === ":low" && [":substantial", ":high"].includes(oldLevel)) dkmitidMethod = s;
else if (newLevel === ":substantial" && oldLevel === ":high") dkmitidMethod = s;
}
});
return dkmitidMethod;
}
function autoTitleCase(input) {
return input.split(/:|-/).map((segment) => {
segment = segment.replace(/id(\s|$)/, "ID");
if (segment.length === 2) return segment.toUpperCase();
return segment.substr(0, 1).toUpperCase() + segment.substr(1);
}).join(" ");
}
function assertUnreachable(x) {
throw new Error("Didn't expect to get here");
}
function stringifyAction(language, action) {
const i18n = getI18n(language);
switch (action) {
case "login": return i18n.loginWith;
case "approve": return i18n.approveWith;
case "sign": return i18n.signWith;
case "confirm": return i18n.confirmWith;
case "accept": return i18n.acceptWith;
default: assertUnreachable(action);
}
}
function acrValueToProviderPrefix(value) {
value = value.replace("urn:grn:authn:", "");
if (value.startsWith("fi")) return "fi";
else if (value.startsWith("itsme")) return "itsme";
else return value.split(":").slice(0, 2).join(":");
}
function acrValueToTitle(language, value, { disambiguate }) {
const i18n = getI18n(language);
value = value.replace("urn:grn:authn:", "");
const provider = acrValueToProviderPrefix(value);
if (provider === "dk:mitid") {
if (value.replace("dk:mitid:", "") === "business") return { title: i18n.mitidBusiness };
return { title: "MitID" };
}
if (value === "fi:mobile-id") return { title: i18n.finnishMobileID };
if (value === "fi:bank-id") return { title: i18n.finnishBankID };
if (provider === "fi") return { title: autoTitleCase(value).replace("FI", "FTN") };
if (provider === "itsme") return { title: autoTitleCase(value).replace("me", "ME") };
if (provider === "se:bankid") {
let subtitle = void 0;
let suffix = value.replace("se:bankid:", "");
let title = "BankID";
if (suffix === "same-device") subtitle = i18n.sameDevice;
if (suffix === "another-device") subtitle = i18n.anotherDevice;
if (suffix === "another-device:qr") subtitle = i18n.anotherDeviceQR;
if (disambiguate) title = i18n.swedishBankID;
return {
title,
subtitle
};
}
if (provider === "no:bankid") {
let subtitle = void 0;
let title = "BankID";
if (value.endsWith(":substantial")) subtitle = i18n.biometrics;
if (disambiguate) title = i18n.norwegianBankID;
return {
title,
subtitle
};
}
if (provider === "no:vipps") return { title: autoTitleCase(value).replace("NO ", "") };
if (provider === "se:frejaid") return { title: "FrejaID" };
if (provider === "uk:oneid") return { title: "OneID" };
if (provider === "de:personalausweis") return { title: "Personalausweis" };
return { title: autoTitleCase(value) };
}
function filterAcrValues(input) {
let original = input.slice();
let dkmitidMethod = lowestMitIDValue(input);
let reduced = input.slice();
if (dkmitidMethod) reduced = input.filter((s) => !s.startsWith("urn:grn:authn:dk:mitid") || s === "urn:grn:authn:dk:mitid:business").concat([dkmitidMethod]).sort((a, b) => original.indexOf(a) - original.indexOf(b));
if (input.includes(`urn:grn:authn:fi:all`)) {
if (!reduced.includes(`urn:grn:authn:fi:bank-id`)) reduced.push(`${FTN_PREFIX}:bank-id`);
if (!reduced.includes(`urn:grn:authn:fi:mobile-id`)) reduced.push(`${FTN_PREFIX}:mobile-id`);
reduced = reduced.filter((s) => s !== `${FTN_PREFIX}:all`);
}
return reduced;
}
function isSingle(acrValue, acrValues) {
const provider = acrValueToProviderPrefix(acrValue);
return acrValues.reduce((memo, acrValue) => memo + (acrValueToProviderPrefix(acrValue) === provider ? 1 : 0), 0) === 1;
}
const ambigousProviders = ["se:bankid", "no:bankid"];
/**
* A provider is considered ambiguous iff:
* 1. It is in the list of ambiguous providers
* 2. There is another ambiguous provider in the arc values list
*/
function isAmbiguous(acrValue, acrValues) {
const provider = acrValueToProviderPrefix(acrValue);
const isProviderAmbiguous = ambigousProviders.includes(provider);
const otherAmbiguousProvider = acrValues.find((otherAcrValue) => {
const otherProvider = acrValueToProviderPrefix(otherAcrValue);
return provider != otherProvider && ambigousProviders.includes(otherProvider);
}) != null;
return isProviderAmbiguous && otherAmbiguousProvider;
}
function trySessionStorage() {
try {
if (typeof sessionStorage === "undefined") return null;
return sessionStorage;
} catch (err) {
/**
* Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.
* (if storage is disabled in the browser)
*/
return null;
}
}
//#endregion
//#region src/memory-storage.ts
function createMemoryStorage() {
let store = {};
return {
getItem(key) {
return store[key] || null;
},
setItem(key, value) {
store[key] = value.toString();
},
removeItem(key) {
delete store[key];
},
clear() {
store = {};
},
key(index) {
return Object.keys(store)[index];
},
get length() {
return Object.keys(store).length;
}
};
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/asyncToGenerator.js
function asyncGeneratorStep(n, t, e, r, o, a, c) {
try {
var i = n[a](c), u = i.value;
} catch (n) {
e(n);
return;
}
i.done ? t(u) : Promise.resolve(u).then(r, o);
}
function _asyncToGenerator(n) {
return function() {
var t = this, e = arguments;
return new Promise(function(r, o) {
var a = n.apply(t, e);
function _next(n) {
asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
}
function _throw(n) {
asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
}
_next(void 0);
});
};
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/typeof.js
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o) {
return typeof o;
} : function(o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/toPrimitive.js
function toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/toPropertyKey.js
function toPropertyKey(t) {
var i = toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/defineProperty.js
function _defineProperty(e, r, t) {
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
//#endregion
//#region \0@oxc-project+runtime@0.115.0/helpers/objectSpread2.js
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function(r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread2(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), !0).forEach(function(r) {
_defineProperty(e, r, t[r]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
});
}
return e;
}
//#endregion
//#region src/provider.tsx
const SESSION_KEY = `@criipto-verify-react/session`;
const ACTION_SUPPORTING_ACR_VALUES = [
"urn:grn:authn:dk:mitid:low",
"urn:grn:authn:dk:mitid:substantial",
"urn:grn:authn:dk:mitid:high",
"urn:grn:authn:se:bankid:same-device",
"urn:grn:authn:se:bankid:another-device:qr"
];
const MESSAGE_SUPPORTING_ACR_VALUES = [
"urn:grn:authn:dk:mitid:low",
"urn:grn:authn:dk:mitid:substantial",
"urn:grn:authn:dk:mitid:high",
"urn:grn:authn:se:bankid:same-device",
"urn:grn:authn:se:bankid:another-device:qr"
];
function buildLoginHint(loginHint, params) {
const { options, action, message } = params;
const acrValues = (options === null || options === void 0 ? void 0 : options.acrValues) ? Array.isArray(options === null || options === void 0 ? void 0 : options.acrValues) ? options === null || options === void 0 ? void 0 : options.acrValues : [options === null || options === void 0 ? void 0 : options.acrValues] : [];
let hints = (loginHint ? loginHint.split(" ") : []).concat((options === null || options === void 0 ? void 0 : options.loginHint) ? options === null || options === void 0 ? void 0 : options.loginHint.split(" ") : []).filter((hint) => !hint.startsWith("message:") && !hint.startsWith("action:"));
if (action) {
hints = hints.filter((h) => !h.startsWith("action:"));
if (acrValues.length === 1) {
if (ACTION_SUPPORTING_ACR_VALUES.includes(acrValues[0])) hints.push(`action:${action}`);
} else if (acrValues.length >= 2) {
if (acrValues.some((v) => ACTION_SUPPORTING_ACR_VALUES.includes(v))) hints.push(`action:${action}`);
} else hints.push(`action:${action}`);
}
if (message) if (acrValues.length === 1) {
if (MESSAGE_SUPPORTING_ACR_VALUES.includes(acrValues[0])) hints.push(`message:${btoa(message)}`);
} else if (acrValues.length >= 2) {
if (acrValues.some((v) => MESSAGE_SUPPORTING_ACR_VALUES.includes(v))) hints.push(`message:${btoa(message)}`);
} else hints.push(`message:${btoa(message)}`);
return hints.length ? hints.join(" ") : void 0;
}
function parseAction(input) {
if (!input) return;
const actionCandidate = input.split(" ").find((s) => s.startsWith("action:"));
if (!actionCandidate) return;
const action = actionCandidate.replace("action:", "");
if (actions.includes(action)) return action;
}
function tryBase64Decode(input) {
try {
return atob(input);
} catch (_unused) {
return null;
}
}
function parseMessage(input) {
var _tryBase64Decode;
if (!input) return;
const messageCandidate = input.split(" ").find((s) => s.startsWith("message:"));
if (!messageCandidate) return;
const message = messageCandidate.replace("message:", "");
return (_tryBase64Decode = tryBase64Decode(message)) !== null && _tryBase64Decode !== void 0 ? _tryBase64Decode : message;
}
function defaultRedirectUri(input) {
if (input) return input;
if (typeof window !== "undefined" && typeof window.location !== "undefined") return window.location.origin + window.location.pathname;
throw new Error("Unable to determine default redirect uri, please provide a redirectUri");
}
const pkceStore = (() => {
const sessionStorage = trySessionStorage();
if (sessionStorage === null) {
console.warn("Creating memory store for PKCE values as no sessionStorage is available. Authentication may be broken.");
return createMemoryStorage();
}
return sessionStorage;
})();
const CriiptoVerifyProvider = (props) => {
var _ref, _props$action, _props$message;
const client = useMemo(() => new CriiptoAuth({
domain: props.domain,
clientID: props.clientID,
store: pkceStore,
redirectUri: defaultRedirectUri(props.redirectUri),
protocol: props.protocol
}), [
props.domain,
props.clientID,
props.redirectUri,
props.protocol
]);
const [configuration, setConfiguration] = useState(null);
useEffect(() => {
let isSubscribed = true;
_asyncToGenerator(function* () {
const configuration = yield client.fetchOpenIDConfiguration();
if (isSubscribed) setConfiguration(configuration);
})();
return () => {
isSubscribed = false;
};
}, [client]);
const [result, setResult] = useState(null);
useEffect(() => {
let isSubscribed = true;
_asyncToGenerator(function* () {
try {
yield client.fetchCriiptoConfiguration();
} catch (error) {
if (!isSubscribed) return;
const err = error instanceof Error ? error : new Error(String(error));
setResult((prev) => prev !== null && prev !== void 0 ? prev : err);
}
})();
return () => {
isSubscribed = false;
};
}, [client]);
const claims = useMemo(() => {
if (!result) return null;
if (!("id_token" in result)) return null;
return jwtDecode(result.id_token);
}, [result]);
const [isLoading, setIsLoading] = useState(false);
const [isInitializing, setIsInitializing] = useState(true);
const [pkce, setPKCE] = useState(props.pkce);
const responseType = props.response || "token";
const completionStrategy = props.completionStrategy || "client";
const uiLocales = props.uiLocales;
const loginHint = props.loginHint;
const action = (_ref = (_props$action = props.action) !== null && _props$action !== void 0 ? _props$action : parseAction(loginHint)) !== null && _ref !== void 0 ? _ref : "login";
const message = (_props$message = props.message) !== null && _props$message !== void 0 ? _props$message : parseMessage(loginHint);
const sessionStore = props.sessionStore;
const refreshPKCE = function() {
var _ref2 = _asyncToGenerator(function* () {
if (props.pkce) return props.pkce;
if (responseType !== "token" || completionStrategy !== "client") {
clearPKCEState(pkceStore);
setPKCE(void 0);
return;
}
clearPKCEState(pkceStore);
const pkce = yield generatePKCE();
setPKCE(pkce);
return pkce;
});
return function refreshPKCE() {
return _ref2.apply(this, arguments);
};
}();
const buildOptions = useCallback((options) => {
var _props$responseType, _props$state, _props$nonce, _props$prompt, _props$scope, _options$pkce;
return _objectSpread2(_objectSpread2({
redirectUri: defaultRedirectUri(props.redirectUri),
responseType: (_props$responseType = props.responseType) !== null && _props$responseType !== void 0 ? _props$responseType : "code",
responseMode: props.responseMode
}, options || {}), {}, {
state: (_props$state = props.state) !== null && _props$state !== void 0 ? _props$state : options === null || options === void 0 ? void 0 : options.state,
nonce: (_props$nonce = props.nonce) !== null && _props$nonce !== void 0 ? _props$nonce : options === null || options === void 0 ? void 0 : options.nonce,
prompt: (_props$prompt = props.prompt) !== null && _props$prompt !== void 0 ? _props$prompt : options === null || options === void 0 ? void 0 : options.prompt,
scope: (_props$scope = props.scope) !== null && _props$scope !== void 0 ? _props$scope : options === null || options === void 0 ? void 0 : options.scope,
uiLocales: uiLocales !== null && uiLocales !== void 0 ? uiLocales : options === null || options === void 0 ? void 0 : options.uiLocales,
pkce: (_options$pkce = options === null || options === void 0 ? void 0 : options.pkce) !== null && _options$pkce !== void 0 ? _options$pkce : pkce,
loginHint: buildLoginHint(props.loginHint, {
options,
action,
message
}),
extraUrlParams: props.criiptoSdk !== void 0 ? { criipto_sdk: props.criiptoSdk } : { criipto_sdk: `@criipto/verify-react@${version}` }
});
}, [
pkce,
props.state,
props.nonce,
props.prompt,
props.scope,
uiLocales,
action,
message,
props.redirectUri,
props.criiptoSdk,
props.loginHint,
props.responseMode,
props.responseType
]);
const buildAuthorizeUrl = useCallback(function() {
var _ref3 = _asyncToGenerator(function* (options) {
return yield client.buildAuthorizeUrl(client.buildAuthorizeParams(buildOptions(options)));
});
return function(_x) {
return _ref3.apply(this, arguments);
};
}(), [client, buildOptions]);
const initializePAR = useCallback(function() {
var _ref4 = _asyncToGenerator(function* (options) {
return (yield client.pushAuthorizationRequest(client.buildAuthorizeParams(buildOptions(options)))).authorizeUrl;
});
return function(_x2) {
return _ref4.apply(this, arguments);
};
}(), [client, buildOptions]);
const handleResponse = useCallback(function() {
var _ref5 = _asyncToGenerator(function* (response, params = {}) {
if (response instanceof OAuth2Error$1) setResult(response);
else if (response instanceof Error) setResult(response);
else if (params.pkce && responseType === "token") {
let _redirectUri = params.redirectUri || defaultRedirectUri(props.redirectUri);
if (!_redirectUri) throw new Error("redirectUri must be configured globally or per authentication component");
yield client.processResponse(response, {
code_verifier: params.pkce.code_verifier,
redirect_uri: _redirectUri
}).then((response) => {
if (response === null || response === void 0 ? void 0 : response.code) setResult({
code: response.code,
state: response.state,
source: params.source
});
else if (response === null || response === void 0 ? void 0 : response.id_token) {
setResult({
id_token: response.id_token,
state: response.state,
source: params.source
});
sessionStore === null || sessionStore === void 0 || sessionStore.setItem(SESSION_KEY, response.id_token);
} else setResult(null);
}).catch((err) => {
setResult(err);
});
} else if (response === null || response === void 0 ? void 0 : response.code) setResult({
code: response.code,
state: response.state,
source: params.source
});
else if (response === null || response === void 0 ? void 0 : response.id_token) {
setResult({
id_token: response.id_token,
state: response.state,
source: params.source
});
sessionStore === null || sessionStore === void 0 || sessionStore.setItem(SESSION_KEY, response.id_token);
} else if (response === null || response === void 0 ? void 0 : response.error) setResult(new OAuth2Error$1(response.error, response.error_description, response.state));
else setResult(null);
refreshPKCE();
});
return function(_x3) {
return _ref5.apply(this, arguments);
};
}(), [
refreshPKCE,
responseType,
setResult,
client,
sessionStore,
props.redirectUri
]);
const checkSession = useCallback(_asyncToGenerator(function* () {
return client.checkSession({ redirectUri: defaultRedirectUri(props.redirectUri) }).then((response) => {
if (response === null || response === void 0 ? void 0 : response.code) setResult({ code: response.code });
else if (response === null || response === void 0 ? void 0 : response.id_token) {
setResult({ id_token: response.id_token });
sessionStore === null || sessionStore === void 0 || sessionStore.setItem(SESSION_KEY, response.id_token);
} else setResult(null);
});
}), [
sessionStore,
client,
props.redirectUri
]);
const logout = useCallback(function() {
var _ref6 = _asyncToGenerator(function* (params) {
var _params$redirectUri;
sessionStore === null || sessionStore === void 0 || sessionStore.removeItem(SESSION_KEY);
yield client.logout({
redirectUri: (_params$redirectUri = params === null || params === void 0 ? void 0 : params.redirectUri) !== null && _params$redirectUri !== void 0 ? _params$redirectUri : defaultRedirectUri(props.redirectUri),
state: params === null || params === void 0 ? void 0 : params.state
});
});
return function(_x4) {
return _ref6.apply(this, arguments);
};
}(), [
sessionStore,
client,
props.redirectUri
]);
const context = useMemo(() => {
return {
loginWithRedirect: function() {
var _ref7 = _asyncToGenerator(function* (params) {
const pkce = yield refreshPKCE();
yield client.redirect.authorize(buildOptions(_objectSpread2(_objectSpread2({}, params), {}, { pkce })));
});
return function loginWithRedirect(_x5) {
return _ref7.apply(this, arguments);
};
}(),
loginWithPopup: function() {
var _ref8 = _asyncToGenerator(function* (params) {
return client.popup.authorize(buildOptions(params)).then((response) => {
if (response === null || response === void 0 ? void 0 : response.code) setResult({
code: response.code,
state: response.state,
source: "popup"
});
else if (response === null || response === void 0 ? void 0 : response.id_token) setResult({
id_token: response.id_token,
state: response.state,
source: "popup"
});
else setResult(null);
}).catch((err) => {
setResult(err);
});
});
return function loginWithPopup(_x6) {
return _ref8.apply(this, arguments);
};
}(),
checkSession,
logout,
fetchOpenIDConfiguration: () => client.fetchOpenIDConfiguration(),
buildAuthorizeUrl,
initializePAR,
generatePKCE: function() {
var _ref9 = _asyncToGenerator(function* () {
if (responseType !== "token" || completionStrategy !== "client") return;
return yield generatePKCE();
});
return function generatePKCE() {
return _ref9.apply(this, arguments);
};
}(),
buildOptions,
handleResponse,
responseType,
completionStrategy,
result,
claims,
domain: client.domain,
redirectUri: defaultRedirectUri(props.redirectUri),
action,
message,
pkce,
store: pkceStore,
isLoading,
isInitializing,
acrValues: configuration ? filterAcrValues(configuration.acr_values_supported) : void 0,
client,
uiLocales,
loginHint
};
}, [
client,
props.redirectUri,
responseType,
completionStrategy,
result,
claims,
action,
message,
pkce,
props.state,
props.prompt,
isLoading,
isInitializing,
handleResponse,
logout,
configuration,
uiLocales,
checkSession,
loginHint
]);
useEffect(() => {
setIsInitializing(false);
if (!client.redirect.hasMatch()) {
refreshPKCE();
return;
}
let isSubscribed = true;
setIsLoading(true);
const params = parseAuthorizeResponseFromLocation(window.location);
if (params.code && responseType === "code") {
setIsLoading(false);
setResult({
code: params.code,
source: "redirect",
state: params.state
});
refreshPKCE();
return;
}
_asyncToGenerator(function* () {
yield Promise.resolve();
if (!isSubscribed) return;
try {
const response = yield client.redirect.match();
if (!isSubscribed) return;
if (response === null || response === void 0 ? void 0 : response.code) setResult({
code: response.code,
source: "redirect",
state: response.state
});
else if (response === null || response === void 0 ? void 0 : response.id_token) {
setResult({
id_token: response.id_token,
source: "redirect",
state: response.state
});
sessionStore === null || sessionStore === void 0 || sessionStore.setItem(SESSION_KEY, response.id_token);
resetRedirectState(window);
} else setResult(null);
} catch (err) {
if (!isSubscribed) return;
if (err instanceof OAuth2Error$1) setResult(err);
else if (err instanceof Error) setResult(err);
else {
var _err$toString;
setResult(new Error((_err$toString = err === null || err === void 0 ? void 0 : err.toString()) !== null && _err$toString !== void 0 ? _err$toString : "Unknown error ocurred"));
}
} finally {
if (!isSubscribed) return;
setIsLoading(false);
refreshPKCE();
}
})();
return () => {
isSubscribed = false;
};
}, [props.pkce, responseType]);
useEffect(() => {
if (!sessionStore || claims) return;
if (!claims) {
const token = sessionStore.getItem(SESSION_KEY);
if (!token) return;
setResult({ id_token: token });
return;
}
}, [sessionStore, claims]);
useEffect(() => {
if (!claims) return;
if (!sessionStore) return;
const interval = setInterval(() => {
const now = Date.now();
if (claims.exp < now / 1e3) {
setResult(null);
sessionStore === null || sessionStore === void 0 || sessionStore.removeItem(SESSION_KEY);
return;
}
}, 5e3);
return () => clearInterval(interval);
}, [
sessionStore,
claims,
result
]);
/**
* Fresh page load SSO check
*/
useEffect(() => {
setIsInitializing(false);
if (!sessionStore) return;
if (client.redirect.hasMatch()) return;
if (sessionStore.getItem(SESSION_KEY)) return;
let isSubscribed = true;
setIsLoading(true);
checkSession().catch((err) => {
console.error("session silent check error", err);
}).finally(() => {
if (isSubscribed) setIsLoading(false);
});
return () => {
isSubscribed = false;
};
}, [sessionStore, client]);
return /* @__PURE__ */ jsx(CriiptoVerifyContext.Provider, {
value: context,
children: props.children
});
};
function resetRedirectState(window) {
const url = new URL(window.location.href);
url.searchParams.delete("code");
url.searchParams.delete("state");
window.history.replaceState({}, window.document.title, url.pathname + url.search);
}
//#endregion
//#region src/device.ts
function getUserAgent(userAgent) {
if (!userAgent) return null;
return UAParser(userAgent);
}
//#endregion
//#region src/components/SEBankIDSameDeviceButton/usePoll.ts
function usePoll$1({ shouldPoll, pollUrl, onComplete, onError }) {
useEffect(() => {
if (!shouldPoll) return;
let isSubscribed = true;
const poll = function() {
var _ref = _asyncToGenerator(function* () {
if (!isSubscribed) return;
const response = yield fetch(pollUrl);
if (response.status === 202) {
setTimeout(poll, 1e3);
return;
} else if (response.status >= 400) {
if (!isSubscribed) return;
onError(yield response.text());
return;
} else {
if (!isSubscribed) return;
const { targetUrl } = yield response.json();
onComplete(targetUrl);
return;
}
});
return function poll() {
return _ref.apply(this, arguments);
};
}();
setTimeout(poll, 1e3);
return () => {
isSubscribed = false;
};
}, [shouldPoll, pollUrl]);
}
//#endregion
//#region src/components/SEBankIDSameDeviceButton/Poll.tsx
function SEBankIDSameDevicePoll(props) {
const { links, onError, onComplete, onInitiate } = props;
const [initiated, setInitiated] = useState(false);
const { domain } = useContext(CriiptoVerifyContext);
usePoll$1(_objectSpread2(_objectSpread2({}, props), {}, {
shouldPoll: initiated,
pollUrl: links.pollUrl
}));
const handleInitiate = () => {
onInitiate();
setInitiated(true);
};
return React.cloneElement(props.children, _objectSpread2(_objectSpread2({}, props.children.props), {}, { onClick: handleInitiate }));
}
//#endregion
//#region src/hooks/usePageVisibility.ts
function usePageVisibility(onVisible, deps = []) {
const visibilityState = useRef(document.visibilityState);
const [state, setState] = useState(visibilityState.current);
useEffect(() => {
document.addEventListener("visibilitychange", _handleVisibilityChange);
return () => {
document.removeEventListener("visibilitychange", _handleVisibilityChange);
};
}, deps);
const _handleVisibilityChange = () => {
const nextState = document.visibilityState;
if (visibilityState.current === "hidden" && nextState === "visible") {
if (onVisible) onVisible();
}
visibilityState.current = nextState;
setState(visibilityState.current);
};
return state;
}
//#endregion
//#region src/components/SEBankIDSameDeviceButton/Foreground.tsx
function SEBankIDSameDeviceForeground(props) {
const { links, onInitiate, onLog } = props;
const [initiated, setInitiated] = useState(false);
const [result, setResult] = useState(null);
const onComplete = useCallback((completeUrl) => setResult({ result: completeUrl }), []);
const onError = useCallback((error) => setResult({ error }), []);
const visibility = usePageVisibility(() => {
onLog("ForegroundStrategy", "onForeground", initiated.toString());
}, [initiated]);
useEffect(() => {
if (result && visibility === "visible") {
if ("result" in result) props.onComplete(result.result);
else if ("error" in result) props.onError(result.error);
setResult(null);
}
}, [result, visibility]);
usePoll$1({
shouldPoll: initiated,
pollUrl: links.pollUrl,
onComplete,
onError
});
const handleInitiate = () => {
onLog("ForegroundStrategy", "handleInitiate");
onInitiate();
setInitiated(true);
};
return React.cloneElement(props.children, _objectSpread2(_objectSpread2({}, props.children.props), {}, { onClick: handleInitiate }));
}
//#endregion
//#region src/components/SEBankIDSameDeviceButton/shared.ts
const STATE_KEY = "@criipto/verify-react:sebankid:state";
const stateStore = (() => {
const sessionStorage = trySessionStorage();
if (sessionStorage === null) {
console.warn("Creating memory store for PKCE values as no sessionStorage is available. Authentication may be broken.");
return createMemoryStorage();
}
return sessionStorage;
})();
function hydrateState() {
const rawState = stateStore.getItem(STATE_KEY);
if (rawState) return JSON.parse(rawState);
}
const autoHydratedState = hydrateState();
function clearState() {
stateStore.removeItem(STATE_KEY);
}
function saveState(input) {
stateStore.setItem(STATE_KEY, JSON.stringify(input));
}
//#endregion
//#region src/components/SEBankIDSameDeviceButton/Reload.tsx
function SEBankIDSameDeviceReload(props) {
const { links, onError, onComplete, onInitiate, onLog, pkce, redirectUri } = props;
const handleInitiate = () => {
onLog("ReloadStrategy", "handleInitiate");
saveState({
links,
redirectUri,
pkce
});
onInitiate();
};
useEffect(() => {
const hydratedState = hydrateState();
if (!hydratedState) return;
clearState();
onComplete(hydratedState.links.completeUrl);
}, []);
return React.cloneElement(props.children, _objectSpread2(_objectSpread2({}, props.children.props), {}, { onClick: handleInitiate }));
}
//#endregion
//#region src/components/SEBankIDQRCode/logo@2x.png
var logo_2x_default = "data:image/png;base64,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";
//#endregion
//#region src/components/SEBankIDQRCode.tsx
function searchParamsToPOJO$1(input) {
return Array.from(input.keys()).reduce((memo, key) => {
memo[key] = input.get(key);
return memo;
}, {});
}
function SEBankIDQrCode(props) {
var _ref, _props$language, _window$innerHeight, _wrapperRef$current, _wrapperRef$current2, _props$qrMargin;
const wrapperRef = useRef(null);
const { buildAuthorizeUrl, completionStrategy, handleResponse, generatePKCE, redirectUri: defaultRedirectURi, uiLocales } = useContext(CriiptoVerifyContext);
const language = (_ref = (_props$language = props.language) !== null && _props$language !== void 0 ? _props$language : uiLocales) !== null && _ref !== void 0 ? _ref : "en";
const redirectUri = props.redirectUri || defaultRedirectURi;
const [qrCode, setQrCode] = useState(null);
const [pollUrl, setPollUrl] = useState(null);
const [error, setError] = useState(null);
const [pkce, setPKCE] = useState(void 0);
const [isCompleting, setCompleting] = useState(false);
const [fullscreen, setFullscreen] = useState(false);
const refresh = useCallback(_asyncToGenerator(function* () {
setError(null);
setQrCode(null);
setPollUrl(null);
setPKCE(void 0);
const pkce = yield generatePKCE();
buildAuthorizeUrl({
acrValues: "urn:grn:authn:se:bankid:another-device:qr",
responseMode: "json",
pkce,
redirectUri,
prompt: "login"
}).then((url) => {
return fetch(url).then((response) => response.json());
}).then((response) => {
setPKCE(pkce);
setQrCode(response.initialQrCode);
setPollUrl(response.pollUrl);
}).catch(console.error);
}), [buildAuthorizeUrl, redirectUri]);
useEffect(() => {
refresh();
}, [refresh]);
const handleRetry = () => {
setCompleting(false);
refresh();
};
const handleError = useCallback((error) => {
if (error === "Collect failed: startFailed" || error === "\"Collect failed: startFailed\"") {
handleRetry();
return;
}
setError(new Error(error));
handleResponse(new Error(error), {
pkce,
redirectUri,
source: "SEBankIDQrCode"
});
}, [pkce, redirectUri]);
const handleComplete = useCallback(function() {
var _ref2 = _asyncToGenerator(function* (completeUrl) {
setCompleting(true);
const required = { pkce };
const parsed = yield parseCompleteUrl(completeUrl);
if (parsed instanceof Error) return handleError(parsed.message);
const { location, response } = parsed;
if (completionStrategy === "openidprovider") {
window.location.href = location;
return;
}
yield handleResponse(response, {
pkce: required.pkce,
redirectUri,
source: "SEBankIDQrCode"
});
});
return function(_x) {
return _ref2.apply(this, arguments);
};
}(), [completionStrategy, pkce]);
/**
* Render QR codes
*/
const qrDataURL = useDraw(qrCode, {
width: fullscreen ? (_window$innerHeight = window.innerHeight) !== null && _window$innerHeight !== void 0 ? _window$innerHeight : (_wrapperRef$current = wrapperRef.current) === null || _wrapperRef$current === void 0 ? void 0 : _wrapperRef$current.offsetWidth : (_wrapperRef$current2 = wrapperRef.current) === null || _wrapperRef$current2 === void 0 ? void 0 : _wrapperRef$current2.offsetWidth,
qrMargin: (_props$qrMargin = props.qrMargin) !== null && _props$qrMargin !== void 0 ? _props$qrMargin : fullscreen ? 2 : void 0
});
/**
* Poll for response
*/
usePoll(pollUrl, {
enabled: !isCompleting,
onQrCode: setQrCode,
onComplete: handleComplete,
onError: handleError
});
const i18n = getI18n(language);
const imageElement = /* @__PURE__ */ jsx("button", {
"aria-label": i18n.thisIsTheQR,
ref: wrapperRef,
className: "criipto-se-bankid-qr-canvas",
onClick: () => setFullscreen((val) => !val),
children: qrDataURL ? /* @__PURE__ */ jsx("img", { src: qrDataURL }) : null
});
const qrElement = /* @__PURE__ */ jsxs("div", {
className: "criipto-se-bankid-qr",
children: [/* @__PURE__ */ jsxs("aside", {
className: "criipto-se-bankid-qr--help-text",
children: [isCompleting ? i18n.completingLogin : i18n.openAndScan, /* @__PURE__ */ jsx("img", { src: logo_2x_default })]
}), imageElement]
});
if (!qrCode && props.fallback) return props.fallback;
if (props.children) return props.children({
qrElement,
imageElement,
error,
isCompleting,
retry: () => handleRetry(),
fullscreen
});
if (fullscreen) return /* @__PURE__ */ jsx("dialog", {
className: "criipto-se-bankid-qr-fullscreen",
open: true,
children: imageElement
});
return qrElement;
}
SEBankIDQrCode.acr_values = "urn:grn:authn:se:bankid:another-device:qr";
function useDraw(qrCode, options) {
const { width, qrMargin } = options;
const [dataURL, setDataURL] = useState(null);
useEffect(() => {
if (!qrCode) return;
let isSubscribed = true;
_asyncToGenerator(function* () {
const qrImage = yield QRCode$1.toDataURL(qrCode, {
errorCorrectionLevel: "low",
scale: 10,
width,
margin: qrMargin !== null && qrMargin !== void 0 ? qrMargin : 4
});
if (!isSubscribed) return;
setDataURL(qrImage);
})();
return () => {
isSubscribed = false;
};
}, [
qrCode,
qrMargin,
width
]);
return dataURL;
}
function usePoll(pollUrl, options) {
const { onQrCode, onComplete, onError, enabled } = options;
useEffect(() => {
if (!pollUrl) return;
if (!enabled) return;
const delay = 2500;
let timeout;
let isSubscribed = true;
const poll = function() {
var _ref3 = _asyncToGenerator(function* () {
if (!isSubscribed) return;
const response = yield fetch(pollUrl);
if (!isSubscribed) return;
if (response.status < 400) {
const payload = yield response.json();
if (payload.qrCode) onQrCode(payload.qrCode);
if (payload.targetUrl) {
onComplete(payload.targetUrl);
return;
}
} else onError(yield response.text());
if (response.status === 202) timeout = setTimeout(poll, delay);
});
return function poll() {
return _ref3.apply(this, arguments);
};
}();
timeout = setTimeout(poll, delay);
return () => {
isSubscribed = false;
clearTimeout(timeout);
};
}, [
pollUrl,
onQrCode,
onComplete,
onError,
enabled
]);
}
function parseCompleteUrl(_x2) {
return _parseCompleteUrl.apply(this, arguments);
}
function _parseCompleteUrl() {
_parseCompleteUrl = _asyncToGenerator(function* (completeUrl) {
/**
* Handle verify response inconsistencies
*/
if (completeUrl.includes("error=")) return {
location: completeUrl,
response: searchParamsToPOJO$1(new URL(completeUrl).searchParams)
};
const completeResponse = yield fetch(completeUrl);
if (completeResponse.status >= 400) return new Error(yield completeResponse.text());
const { location } = yield completeResponse.json();
return {
location,
response: searchParamsToPOJO$1(new URL(location).searchParams)
};
});
return _parseCompleteUrl.apply(this, arguments);
}
const AuthButtonGroupContext = createContext({
multiple: false,
acrValues: [],
disabled: false,
setDisabled: () => {}
});
function AuthButtonGroup(props) {
const acrValues = React.Children.toArray(props.children).flatMap((child) => {
if (!child || typeof child !== "object") return [];
if ("type" in child) {
if (child.type === AuthMethodButtonContainer) {
const props = child.props;
return props.acrValue ? [props.acrValue] : [];
}
if (child.type === AuthMethodButtonComponent) {
const props = child.props;
return props.acrValue ? [props.acrValue] : [];
}
if (child.type === SEBankIDQrCode) return ["urn:grn:authn:se:bankid:another-device:qr"];
}
return [];
});
const [disabled, setDisabled] = useState(false);
const context = {
multiple: acrValues.length > 1,
acrValues,
disabled,
setDisabled
};
return /* @__PURE__ */ jsx(AuthButtonGroupContext.Provider, {
value: context,
children: props.children
});
}
//#endregion
//#region src/components/Spinner/Spinner.tsx
function Spinner() {
return /* @__PURE__ */ jsx("div", { className: "criipto-eid-loader" });
}
//#endregion
//#region src/components/SEBankIDSameDeviceButton.tsx
function searchParamsToPOJO(input) {
return Array.from(input.keys()).reduce((memo, key) => {
memo[key] = input.get(key);
return memo;
}, {});
}
function determineStrategy(input, loginHint) {
var _userAgent$browser$na;
const userAgent = getUserAgent(input);
const mobileOS = (userAgent === null || userAgent === void 0 ? void 0 : userAgent.os.name) === "iOS" ? "iOS" : (userAgent === null || userAgent === void 0 ? void 0 : userAgent.os.name) === "Android" ? "android" : (userAgent === null || userAgent === void 0 ? void 0 : userAgent.browser.name) === "Samsung Internet" ? "android" : null;
const iOSSafari = mobileOS === "iOS" && (userAgent === null || userAgent === void 0 || (_userAgent$browser$na = userAgent.browser.name) === null || _userAgent$browser$na === void 0 ? void 0 : _userAgent$browser$na.includes("Safari")) ? true : false;
const androidChrome = mobileOS === "android" && (userAgent === null || userAgent === void 0 ? void 0 : userAgent.browser.name) === "Mobile Chrome" ? true : false;
const redirect = iOSSafari && !(loginHint === null || loginHint === void 0 ? void 0 : loginHint.includes("appswitch:resumeUrl:disable"));
return {
resume: mobileOS ? iOSSafari && redirect ? "Reload" : "Foreground" : "Poll",
linkType: mobileOS === "iOS" || androidChrome ? "universal" : "scheme",
redirect
};
}
var NotDoneError = class extends Error {
constructor(message) {
super(message);
this.name = "NotDoneError";
}
};
function fetchComplete(_x) {
return _fetchComplete.apply(this, arguments);
}
function _fetchComplete() {
_fetchComplete = _asyncToGenerator(function* (completeUrl) {
const completeResponse = yield fetch(completeUrl);
if (completeResponse.status >= 400) {
const errorMessage = yield completeResponse.text();
if (errorMessage.includes("Native-app driven authentication is not done")) return new NotDoneError(errorMessage);
return new Error(errorMessage);
}
const { location } = yield completeResponse.json();
return { location };
});
return _fetchComplete.apply(this, arguments);
}
function SEBankIDSameDeviceButton(props) {
var _autoHydratedState$li, _autoHydratedState$pk;
const { loginHint } = useContext(CriiptoVerifyContext);
const group = useContext(AuthButtonGroupContext);
const rawUserAgent = typeof navigator !== "undefined" ? navigator.userAgent : props.userAgent;
const strategy = useMemo(() => determineStrategy(rawUserAgent, loginHint), [rawUserAgent, loginHint]);
const [href, setHref] = useState();
const [links, setLinks] = useState((_autoHydratedState$li = autoHydratedState === n