@imtbl/auth 2.10.7-alpha.6 → 2.11.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +1 -1
- package/dist/browser/index.js +23 -23
- package/dist/node/index.cjs +42 -41
- package/dist/node/index.js +30 -30
- package/dist/types/Auth.d.ts +1 -1
- package/dist/types/errors.d.ts +2 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types.d.ts +2 -0
- package/jest.config.ts +27 -0
- package/jest.setup.js +4 -0
- package/package.json +14 -6
- package/src/Auth.test.ts +186 -0
- package/src/Auth.ts +22 -53
- package/src/errors.test.ts +21 -0
- package/src/errors.ts +7 -1
- package/src/index.ts +3 -1
- package/src/types.ts +2 -0
- package/tsconfig.eslint.json +6 -0
- package/tsconfig.json +4 -0
package/dist/node/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { UserManager, User, ErrorTimeout, ErrorResponse, InMemoryWebStorage, WebStorageStateStore } from 'oidc-client-ts';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { track, getDetail, Detail, trackFlow, trackError
|
|
2
|
+
import ve, { isAxiosError } from 'axios';
|
|
3
|
+
import X from 'jwt-decode';
|
|
4
|
+
import Ee from 'localforage';
|
|
5
|
+
import { track, identify, getDetail, Detail, trackFlow, trackError } from '@imtbl/metrics';
|
|
6
6
|
import { EventEmitter } from 'events';
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var L=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION="INVALID_CONFIGURATION",s.WALLET_CONNECTION_ERROR="WALLET_CONNECTION_ERROR",s.NOT_LOGGED_IN_ERROR="NOT_LOGGED_IN_ERROR",s.SILENT_LOGIN_ERROR="SILENT_LOGIN_ERROR",s.REFRESH_TOKEN_ERROR="REFRESH_TOKEN_ERROR",s.USER_REGISTRATION_ERROR="USER_REGISTRATION_ERROR",s.USER_NOT_REGISTERED_ERROR="USER_NOT_REGISTERED_ERROR",s.LOGOUT_ERROR="LOGOUT_ERROR",s.TRANSFER_ERROR="TRANSFER_ERROR",s.CREATE_ORDER_ERROR="CREATE_ORDER_ERROR",s.CANCEL_ORDER_ERROR="CANCEL_ORDER_ERROR",s.EXCHANGE_TRANSFER_ERROR="EXCHANGE_TRANSFER_ERROR",s.CREATE_TRADE_ERROR="CREATE_TRADE_ERROR",s.OPERATION_NOT_SUPPORTED_ERROR="OPERATION_NOT_SUPPORTED_ERROR",s.LINK_WALLET_ALREADY_LINKED_ERROR="LINK_WALLET_ALREADY_LINKED_ERROR",s.LINK_WALLET_MAX_WALLETS_LINKED_ERROR="LINK_WALLET_MAX_WALLETS_LINKED_ERROR",s.LINK_WALLET_VALIDATION_ERROR="LINK_WALLET_VALIDATION_ERROR",s.LINK_WALLET_DUPLICATE_NONCE_ERROR="LINK_WALLET_DUPLICATE_NONCE_ERROR",s.LINK_WALLET_GENERIC_ERROR="LINK_WALLET_GENERIC_ERROR",s.SERVICE_UNAVAILABLE_ERROR="SERVICE_UNAVAILABLE_ERROR",s.TRANSACTION_REJECTED="TRANSACTION_REJECTED",s))(L||{});function D(o){return typeof o=="object"&&o!==null&&"code"in o&&"message"in o}var p=class extends Error{type;constructor(e,t){super(e),this.type=t;}},g=async(o,e)=>{try{return await o()}catch(t){let r;throw t instanceof p&&t.type==="SERVICE_UNAVAILABLE_ERROR"?new p(t.message,t.type):(isAxiosError(t)&&t.response?.data&&D(t.response.data)?r=t.response.data.message:r=t.message,new p(r,e))}};var ee=(o,e,t)=>{let r=e.map(n=>!o[n]&&n).filter(n=>n).join(", ");if(r!==""){let n=`${r} cannot be null`;throw new p(n,"INVALID_CONFIGURATION")}},_=class{authenticationDomain;passportDomain;oidcConfiguration;crossSdkBridgeEnabled;popupOverlayOptions;constructor({authenticationDomain:e,passportDomain:t,crossSdkBridgeEnabled:r,popupOverlayOptions:n,...i}){ee(i,["clientId","redirectUri"]),this.oidcConfiguration=i,this.crossSdkBridgeEnabled=r||!1,this.popupOverlayOptions=n,this.authenticationDomain=e||"https://auth.immutable.com",this.passportDomain=t||"https://passport.immutable.com";}};var N=(e=>(e.ZKEVM="zkEvm",e))(N||{}),w=o=>!!o.zkEvm,S=(t=>(t.OptedIn="opted_in",t.Unsubscribed="unsubscribed",t))(S||{}),U=(t=>(t.LOGGED_OUT="loggedOut",t.LOGGED_IN="loggedIn",t))(U||{});var F="im_passport_embedded_login_prompt";var E="passport-overlay",R="passport-overlay-contents",P=`${E}-close`,I=`${E}-try-again`,H=`
|
|
9
9
|
<svg
|
|
10
10
|
viewBox="0 0 20 20"
|
|
11
11
|
fill="none"
|
|
@@ -17,7 +17,7 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
17
17
|
fill="#F3F3F3"
|
|
18
18
|
/>
|
|
19
19
|
</svg>
|
|
20
|
-
`,
|
|
20
|
+
`,V=`
|
|
21
21
|
<svg
|
|
22
22
|
viewBox="0 0 17 16"
|
|
23
23
|
fill="none"
|
|
@@ -31,7 +31,7 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
31
31
|
fill="#E01A3D"
|
|
32
32
|
/>
|
|
33
33
|
</svg>
|
|
34
|
-
`,
|
|
34
|
+
`,b=`
|
|
35
35
|
<svg
|
|
36
36
|
style="
|
|
37
37
|
max-width: 123px !important;
|
|
@@ -214,9 +214,9 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
214
214
|
</clipPath>
|
|
215
215
|
</defs>
|
|
216
216
|
</svg>
|
|
217
|
-
`;var
|
|
217
|
+
`;var te=()=>`
|
|
218
218
|
<button
|
|
219
|
-
id="${
|
|
219
|
+
id="${P}"
|
|
220
220
|
style="
|
|
221
221
|
background: #f3f3f326 !important;
|
|
222
222
|
border: none !important;
|
|
@@ -232,9 +232,9 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
232
232
|
justify-content: center !important;
|
|
233
233
|
"
|
|
234
234
|
>
|
|
235
|
-
${
|
|
235
|
+
${H}
|
|
236
236
|
</button>
|
|
237
|
-
`,
|
|
237
|
+
`,G=()=>`
|
|
238
238
|
<button
|
|
239
239
|
id="${I}"
|
|
240
240
|
style="
|
|
@@ -251,8 +251,8 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
251
251
|
>
|
|
252
252
|
Try again
|
|
253
253
|
</button>
|
|
254
|
-
`,
|
|
255
|
-
${
|
|
254
|
+
`,re=()=>`
|
|
255
|
+
${b}
|
|
256
256
|
<div
|
|
257
257
|
style="
|
|
258
258
|
color: #e01a3d !important;
|
|
@@ -262,7 +262,7 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
262
262
|
margin-bottom: 10px !important;
|
|
263
263
|
"
|
|
264
264
|
>
|
|
265
|
-
${
|
|
265
|
+
${V}
|
|
266
266
|
Pop-up blocked
|
|
267
267
|
</div>
|
|
268
268
|
<p style="
|
|
@@ -275,9 +275,9 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
275
275
|
If the problem continues, adjust your<br />
|
|
276
276
|
browser settings.
|
|
277
277
|
</p>
|
|
278
|
-
${
|
|
279
|
-
`,
|
|
280
|
-
${
|
|
278
|
+
${G()}
|
|
279
|
+
`,ne=()=>`
|
|
280
|
+
${b}
|
|
281
281
|
<p style="
|
|
282
282
|
color: #b6b6b6 !important;
|
|
283
283
|
text-align: center !important;
|
|
@@ -286,10 +286,10 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
286
286
|
>
|
|
287
287
|
Secure pop-up not showing?<br />We'll help you re-launch
|
|
288
288
|
</p>
|
|
289
|
-
${
|
|
290
|
-
`,
|
|
289
|
+
${G()}
|
|
290
|
+
`,B=o=>`
|
|
291
291
|
<div
|
|
292
|
-
id="${
|
|
292
|
+
id="${E}"
|
|
293
293
|
style="
|
|
294
294
|
position: fixed !important;
|
|
295
295
|
top: 0 !important;
|
|
@@ -312,9 +312,9 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
312
312
|
z-index: 2147483647 !important;
|
|
313
313
|
"
|
|
314
314
|
>
|
|
315
|
-
${
|
|
315
|
+
${te()}
|
|
316
316
|
<div
|
|
317
|
-
id="${
|
|
317
|
+
id="${R}"
|
|
318
318
|
style="
|
|
319
319
|
display: flex !important;
|
|
320
320
|
flex-direction: column !important;
|
|
@@ -322,12 +322,12 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
322
322
|
max-width: 400px !important;
|
|
323
323
|
"
|
|
324
324
|
>
|
|
325
|
-
${
|
|
325
|
+
${o??""}
|
|
326
326
|
</div>
|
|
327
327
|
</div>
|
|
328
|
-
`,
|
|
328
|
+
`,Z=()=>`
|
|
329
329
|
<div
|
|
330
|
-
id="${
|
|
330
|
+
id="${E}"
|
|
331
331
|
style="
|
|
332
332
|
position: fixed;
|
|
333
333
|
top: 0;
|
|
@@ -345,7 +345,7 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
345
345
|
"
|
|
346
346
|
>
|
|
347
347
|
<div
|
|
348
|
-
id="${
|
|
348
|
+
id="${R}"
|
|
349
349
|
style="
|
|
350
350
|
display: flex;
|
|
351
351
|
flex-direction: column;
|
|
@@ -354,7 +354,7 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
354
354
|
"
|
|
355
355
|
/>
|
|
356
356
|
</div>
|
|
357
|
-
`;function
|
|
357
|
+
`;function A({id:o,href:e,rel:t,crossOrigin:r}){let n=`${E}-${o}`;if(!document.getElementById(n)){let i=document.createElement("link");i.id=n,i.href=e,t&&(i.rel=t),r&&(i.crossOrigin=r),document.head.appendChild(i);}}var K=()=>B(re()),W=()=>B(ne());var m=class{static overlay;static onCloseListener;static closeButton;static remove(){this.onCloseListener&&this.closeButton?.removeEventListener?.("click",this.onCloseListener),this.overlay?.remove(),this.closeButton=void 0,this.onCloseListener=void 0,this.overlay=void 0;}static appendOverlay(e,t){if(!this.overlay){let r=document.createElement("div");r.innerHTML=Z(),document.body.insertAdjacentElement("beforeend",r);let n=document.querySelector(`#${R}`);n&&n.appendChild(e),r.addEventListener("click",t),this.overlay=r;}}};var se=660,ae=440,le="16px",$="passport-embedded-login-keyframes",Y="passport-embedded-login-iframe",O=class o{config;constructor(e){this.config=e;}getHref=()=>`${this.config.authenticationDomain}/im-embedded-login-prompt?client_id=${this.config.oidcConfiguration.clientId}&rid=${getDetail(Detail.RUNTIME_ID)}`;static appendIFrameStylesIfNeeded=()=>{if(document.getElementById($))return;let e=document.createElement("style");e.id=$,e.textContent=`
|
|
358
358
|
@keyframes passportEmbeddedLoginPromptPopBounceIn {
|
|
359
359
|
0% {
|
|
360
360
|
opacity: 0.5;
|
|
@@ -373,7 +373,7 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
373
373
|
}
|
|
374
374
|
|
|
375
375
|
@media (max-height: 400px) {
|
|
376
|
-
#${
|
|
376
|
+
#${Y} {
|
|
377
377
|
width: 100% !important;
|
|
378
378
|
max-width: none !important;
|
|
379
379
|
}
|
|
@@ -387,6 +387,6 @@ var P=(s=>(s.AUTHENTICATION_ERROR="AUTHENTICATION_ERROR",s.INVALID_CONFIGURATION
|
|
|
387
387
|
opacity: 1;
|
|
388
388
|
}
|
|
389
389
|
}
|
|
390
|
-
`,document.head.appendChild(e);};getEmbeddedLoginIFrame=()=>{let e=document.createElement("iframe");return e.id=z,e.src=this.getHref(),e.style.height="100vh",e.style.width="100vw",e.style.maxHeight=`${le}px`,e.style.maxWidth=`${de}px`,e.style.borderRadius=ce,e.style.opacity="0",e.style.transform="scale(0.6)",e.style.animation="passportEmbeddedLoginPromptPopBounceIn 1s ease forwards",n.appendIFrameStylesIfNeeded(),e};displayEmbeddedLoginPrompt(){return new Promise((e,t)=>{let r=this.getEmbeddedLoginIFrame(),i=({data:o,origin:d})=>{if(!(d!==this.config.authenticationDomain||o.eventType!==H))switch(o.messageType){case"login_method_selected":{let l=o.payload;window.removeEventListener("message",i),u.remove(),e(l);break}case"login_prompt_error":{window.removeEventListener("message",i),u.remove(),t(new Error("Error during embedded login prompt",{cause:o.payload}));break}case"login_prompt_closed":{window.removeEventListener("message",i),u.remove(),t(new Error("Popup closed by user"));break}default:window.removeEventListener("message",i),u.remove(),t(new Error(`Unsupported message type: ${o.messageType}`));break}};window.addEventListener("message",i),u.appendOverlay(r,()=>{window.removeEventListener("message",i),u.remove(),t(new Error("Popup closed by user"));});})}};var C=class{emitter=new EventEmitter;emit(e,...t){this.emitter.emit(e,...t);}on(e,t){this.emitter.on(e,t);}removeListener(e,t){this.emitter.removeListener(e,t);}};var p=async(n,e,t=!0,r=!0)=>{let i=trackFlow("passport",e,t);try{return await n(i)}catch(o){throw o instanceof Error?trackError("passport",e,o,{flowId:i.details.flowId}):i.addEvent("errored"),o}finally{r&&i.addEvent("End");}};var j="pkce_state",Q="pkce_verifier",fe=3600,v=class{isTokenValid(e){try{let r=J(e).exp??0,i=Date.now()/1e3+fe;return r>i}catch{return !1}}savePKCEData(e){localStorage.setItem(j,e.state),localStorage.setItem(Q,e.verifier);}getPKCEData(){let e=localStorage.getItem(j),t=localStorage.getItem(Q);return e&&t?{state:e,verifier:t}:null}};var Ee=(...n)=>{if(typeof process>"u")return;process?.env?.JEST_WORKER_ID===void 0&&console.warn(...n);},_={warn:Ee};function q(n){try{let e=J(n),t=Math.floor(Date.now()/1e3);return e.exp?e.exp<=t+30:!0}catch{return !0}}function X(n){let{id_token:e,access_token:t}=n;return !t||!e?!0:q(t)||q(e)}var T=class{disableGenericPopupOverlay;disableBlockedPopupOverlay;overlay;isBlockedOverlay;tryAgainListener;onCloseListener;constructor(e,t=!1){this.disableBlockedPopupOverlay=e.disableBlockedPopupOverlay||!1,this.disableGenericPopupOverlay=e.disableGenericPopupOverlay||!1,this.isBlockedOverlay=t;}append(e,t){this.shouldAppendOverlay()&&(this.appendOverlay(),this.updateTryAgainButton(e),this.updateCloseButton(t));}update(e){this.updateTryAgainButton(e);}remove(){this.overlay&&this.overlay.remove();}shouldAppendOverlay(){return !(this.disableGenericPopupOverlay&&this.disableBlockedPopupOverlay||this.disableGenericPopupOverlay&&!this.isBlockedOverlay||this.disableBlockedPopupOverlay&&this.isBlockedOverlay)}appendOverlay(){if(!this.overlay){k({id:"link-googleapis",href:"https://fonts.googleapis.com"}),k({id:"link-gstatic",href:"https://fonts.gstatic.com",crossOrigin:"anonymous"}),k({id:"link-roboto",href:"https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap",rel:"stylesheet"});let t=document.createElement("div");t.innerHTML=this.isBlockedOverlay?$():W(),document.body.insertAdjacentElement("beforeend",t),this.overlay=t;}}updateTryAgainButton(e){let t=document.getElementById(I);t&&(this.tryAgainListener&&t.removeEventListener("click",this.tryAgainListener),this.tryAgainListener=e,t.addEventListener("click",e));}updateCloseButton(e){let t=document.getElementById(L);t&&(this.onCloseListener&&t.removeEventListener("click",this.onCloseListener),this.onCloseListener=e,t.addEventListener("click",e));}};var w=class{storage;constructor(e,t){this.storage=Ce.createInstance({name:e,driver:t});}get length(){return this.storage.length()}clear(){return this.storage.clear()}getItem(e){return this.storage.getItem(e)}key(e){return this.storage.key(e)}async removeItem(e){await this.storage.removeItem(e);}async setItem(e,t){await this.storage.setItem(e,t);}};var Ue=500,be={headers:{"Content-Type":"application/x-www-form-urlencoded"}},xe="/v2/logout",Me="/im-logged-out",De="/authorize",Ne=n=>n?Me:xe,Se=n=>{let{authenticationDomain:e,oidcConfiguration:t}=n,r;n.crossSdkBridgeEnabled?r=new w("ImmutableSDKPassport",Ce.INDEXEDDB):typeof window<"u"?r=window.localStorage:r=new InMemoryWebStorage;let i=new WebStorageStateStore({store:r}),o=new URL(Ne(n.crossSdkBridgeEnabled),e.replace(/^(?:https?:\/\/)?(.*)/,"https://$1"));return o.searchParams.set("client_id",t.clientId),t.logoutRedirectUri&&o.searchParams.set("returnTo",t.logoutRedirectUri),{authority:e,redirect_uri:t.redirectUri,popup_redirect_uri:t.popupRedirectUri||t.redirectUri,client_id:t.clientId,metadata:{authorization_endpoint:`${e}/authorize`,token_endpoint:`${e}/oauth/token`,userinfo_endpoint:`${e}/userinfo`,end_session_endpoint:o.toString(),revocation_endpoint:`${e}/oauth/revoke`},automaticSilentRenew:!1,scope:t.scope,userStore:i,revokeTokenTypes:["refresh_token"],extraQueryParams:{...t.audience?{audience:t.audience}:{}}}};function M(n){return btoa(String.fromCharCode(...new Uint8Array(n))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function Fe(n){let t=new TextEncoder().encode(n);return window.crypto.subtle.digest("SHA-256",t)}var D=class n{config;userManager;deviceCredentialsManager;embeddedLoginPrompt;logoutMode;refreshingPromise=null;eventEmitter;constructor(e){this.config=new R(e),this.embeddedLoginPrompt=new y(this.config),this.userManager=new UserManager(Se(this.config)),this.deviceCredentialsManager=new v,this.logoutMode=this.config.oidcConfiguration.logoutMode||"redirect",this.eventEmitter=new C,track("passport","initialise");}async login(e){return p(async()=>{let{useCachedSession:t=!1,useSilentLogin:r}=e||{},i=null;try{i=await this.getUserInternal();}catch(o){if(o instanceof Error&&!o.message.includes("Unknown or invalid refresh token")&&trackError("passport","login",o),t)throw o;_.warn("Failed to retrieve a cached user session",o);}if(!i&&r)i=await this.forceUserRefreshInternal();else if(!i&&!t){if(e?.useRedirectFlow)return await this.loginWithRedirectInternal(e?.directLoginOptions),null;i=await this.loginWithPopup(e?.directLoginOptions);}return i&&(this.eventEmitter.emit("loggedIn",i),identify({passportId:i.profile.sub})),i},"login")}async loginWithRedirect(e){await this.loginWithRedirectInternal(e);}async loginCallback(){return p(async()=>{let e=await this.loginCallbackInternal();return e&&(this.eventEmitter.emit("loggedIn",e),identify({passportId:e.profile.sub})),e},"loginCallback")}async logout(){await p(async()=>{await this.logoutInternal(),this.eventEmitter.emit("loggedOut");},"logout");}async getUser(){return p(async()=>this.getUserInternal(),"getUserInfo",!1)}async getUserOrLogin(){let e=null;try{e=await this.getUserInternal();}catch(t){_.warn("Failed to retrieve a cached user session",t);}return e||this.loginWithPopup()}async getUserZkEvm(){return this.getUserZkEvmInternal()}async getIdToken(){return p(async()=>(await this.getUserInternal())?.idToken,"getIdToken",!1)}async getAccessToken(){return p(async()=>(await this.getUserInternal())?.accessToken,"getAccessToken",!1,!1)}async isLoggedIn(){return await this.getUser()!==null}async forceUserRefresh(){return this.forceUserRefreshInternal()}forceUserRefreshInBackground(){this.forceUserRefreshInBackgroundInternal();}async loginWithPKCEFlow(e,t){return p(async()=>this.getPKCEAuthorizationUrl(e,t),"loginWithPKCEFlow")}async loginWithPKCEFlowCallback(e,t){return p(async()=>{let r=await this.loginWithPKCEFlowCallbackInternal(e,t);return this.eventEmitter.emit("loggedIn",r),identify({passportId:r.profile.sub}),r},"loginWithPKCEFlowCallback")}async storeTokens(e){return p(async()=>{let t=await this.storeTokensInternal(e);return this.eventEmitter.emit("loggedIn",t),identify({passportId:t.profile.sub}),t},"storeTokens")}async getLogoutUrl(){return p(async()=>(await this.userManager.removeUser(),this.eventEmitter.emit("loggedOut"),await this.getLogoutUrlInternal()||void 0),"getLogoutUrl")}async logoutSilentCallback(e){return p(()=>this.userManager.signoutSilentCallback(e),"logoutSilentCallback")}getConfig(){return this.config}async getClientId(){return this.config.oidcConfiguration.clientId}buildExtraQueryParams(e,t){let r={...this.userManager.settings?.extraQueryParams??{},rid:getDetail(Detail.RUNTIME_ID)||"",third_party_a_id:""};if(e){if(e.directLoginMethod==="email"){let i=e.email;i&&(r.direct=e.directLoginMethod,r.email=i);}else r.direct=e.directLoginMethod;e.marketingConsentStatus&&(r.marketingConsent=e.marketingConsentStatus);}return t&&(r.im_passport_trace_id=t),r}async loginWithRedirectInternal(e){await this.userManager.clearStaleState(),await f(async()=>{let t=this.buildExtraQueryParams(e);await this.userManager.signinRedirect({extraQueryParams:t});},"AUTHENTICATION_ERROR");}async loginWithPopup(e){return f(async()=>{let t,r;if(e)t=e;else if(!this.config.popupOverlayOptions?.disableHeadlessLoginPromptOverlay){let{imPassportTraceId:d,...l}=await this.embeddedLoginPrompt.displayEmbeddedLoginPrompt();t=l,r=d;}let i=window.crypto.randomUUID(),o=async()=>{let d=this.buildExtraQueryParams(t,r),l=this.userManager.signinPopup({extraQueryParams:d,popupWindowFeatures:{width:410,height:450},popupWindowTarget:i}),c=window.open("",i);if(c){let E=new Promise((a,g)=>{let N=setInterval(()=>{c.closed&&(clearInterval(N),g(new Error("Popup closed by user")));},Ue);l.finally(()=>{clearInterval(N),c.close();});});return Promise.race([l,E])}return l};return new Promise((d,l)=>{o().then(c=>d(n.mapOidcUserToDomainModel(c))).catch(c=>{if(!(c instanceof Error)||c.message!=="Attempted to navigate on a disposed window"){l(c);return}let E=!1,a=new T(this.config.popupOverlayOptions||{},!0);a.append(async()=>{try{if(E)window.open("",i);else {E=!0;let g=await o();a.remove(),d(n.mapOidcUserToDomainModel(g));}}catch(g){a.remove(),l(g);}},()=>{a.remove(),l(new Error("Popup closed by user"));});});})},"AUTHENTICATION_ERROR")}static mapOidcUserToDomainModel=e=>{let t;e.id_token&&(t=J(e.id_token)?.passport);let r={expired:e.expired,idToken:e.id_token,accessToken:e.access_token,refreshToken:e.refresh_token,profile:{sub:e.profile.sub,email:e.profile.email,nickname:e.profile.nickname}};return t?.zkevm_eth_address&&t?.zkevm_user_admin_address&&(r.zkEvm={ethAddress:t.zkevm_eth_address,userAdminAddress:t.zkevm_user_admin_address}),r};static mapDeviceTokenResponseToOidcUser=e=>{let t=J(e.id_token);return new User({id_token:e.id_token,access_token:e.access_token,refresh_token:e.refresh_token,token_type:e.token_type,profile:{sub:t.sub,iss:t.iss,aud:t.aud,exp:t.exp,iat:t.iat,email:t.email,nickname:t.nickname,passport:t.passport}})};static shouldUseSigninPopupCallback(){try{let r=`oidc.${new URLSearchParams(window.location.search).get("state")}`,i=localStorage.getItem(r);return JSON.parse(i||"{}")?.request_type==="si:p"}catch{return !1}}async loginCallbackInternal(){return f(async()=>{if(n.shouldUseSigninPopupCallback()){await this.userManager.signinPopupCallback(void 0,!0);return}let e=await this.userManager.signinCallback();if(e)return n.mapOidcUserToDomainModel(e)},"AUTHENTICATION_ERROR")}async getPKCEAuthorizationUrl(e,t){let r=M(window.crypto.getRandomValues(new Uint8Array(32))),i=M(await Fe(r)),o=M(window.crypto.getRandomValues(new Uint8Array(32))),{redirectUri:d,scope:l,audience:c,clientId:E}=this.config.oidcConfiguration;this.deviceCredentialsManager.savePKCEData({state:o,verifier:r});let a=new URL(De,this.config.authenticationDomain);if(a.searchParams.set("response_type","code"),a.searchParams.set("code_challenge",i),a.searchParams.set("code_challenge_method","S256"),a.searchParams.set("client_id",E),a.searchParams.set("redirect_uri",d),a.searchParams.set("state",o),l&&a.searchParams.set("scope",l),c&&a.searchParams.set("audience",c),e){if(e.directLoginMethod==="email"){let g=e.email;g&&(a.searchParams.set("direct",e.directLoginMethod),a.searchParams.set("email",g));}else a.searchParams.set("direct",e.directLoginMethod);e.marketingConsentStatus&&a.searchParams.set("marketingConsent",e.marketingConsentStatus);}return t&&a.searchParams.set("im_passport_trace_id",t),a.toString()}async loginWithPKCEFlowCallbackInternal(e,t){return f(async()=>{let r=this.deviceCredentialsManager.getPKCEData();if(!r)throw new Error("No code verifier or state for PKCE");if(t!==r.state)throw new Error("Provided state does not match stored state");let i=await this.getPKCEToken(e,r.verifier),o=n.mapDeviceTokenResponseToOidcUser(i),d=n.mapOidcUserToDomainModel(o);return await this.userManager.storeUser(o),d},"AUTHENTICATION_ERROR")}async getPKCEToken(e,t){return (await Pe.post(`${this.config.authenticationDomain}/oauth/token`,{client_id:this.config.oidcConfiguration.clientId,grant_type:"authorization_code",code_verifier:t,code:e,redirect_uri:this.config.oidcConfiguration.redirectUri},be)).data}async storeTokensInternal(e){return f(async()=>{let t=n.mapDeviceTokenResponseToOidcUser(e),r=n.mapOidcUserToDomainModel(t);return await this.userManager.storeUser(t),r},"AUTHENTICATION_ERROR")}async logoutInternal(){await f(async()=>{await this.userManager.revokeTokens(["refresh_token"]),this.logoutMode==="silent"?await this.userManager.signoutSilent():await this.userManager.signoutRedirect();},"LOGOUT_ERROR");}async getLogoutUrlInternal(){let e=this.userManager.settings?.metadata?.end_session_endpoint;return e||(_.warn("Failed to get logout URL"),null)}forceUserRefreshInBackgroundInternal(){this.refreshTokenAndUpdatePromise().catch(e=>{_.warn("Failed to refresh user token",e);});}async forceUserRefreshInternal(){return this.refreshTokenAndUpdatePromise().catch(e=>(_.warn("Failed to refresh user token",e),null))}async refreshTokenAndUpdatePromise(){return this.refreshingPromise?this.refreshingPromise:(this.refreshingPromise=new Promise((e,t)=>{(async()=>{try{let r=await this.userManager.signinSilent();if(r){e(n.mapOidcUserToDomainModel(r));return}e(null);}catch(r){let i="AUTHENTICATION_ERROR",o="Failed to refresh token",d=!0;if(r instanceof ErrorTimeout?(i="SILENT_LOGIN_ERROR",o=`${o}: ${r.message}`,d=!1):r instanceof ErrorResponse?(i="NOT_LOGGED_IN_ERROR",o=`${o}: ${r.message||r.error_description}`):r instanceof Error?o=`${o}: ${r.message}`:typeof r=="string"&&(o=`${o}: ${r}`),d)try{await this.userManager.removeUser();}catch(l){l instanceof Error&&(o=`${o}: Failed to remove user: ${l.message}`);}t(new m(o,i));}finally{this.refreshingPromise=null;}})();}),this.refreshingPromise)}async getUserInternal(e=t=>!0){if(this.refreshingPromise){let r=await this.refreshingPromise;return r&&e(r)?r:null}let t=await this.userManager.getUser();if(!t)return null;if(!X(t)){let r=n.mapOidcUserToDomainModel(t);if(r&&e(r))return r}if(t.refresh_token){let r=await this.refreshTokenAndUpdatePromise();if(r&&e(r))return r}return null}async getUserZkEvmInternal(){let e=await this.getUserInternal(U);if(!e)throw new Error("Failed to obtain a User with the required ZkEvm attributes");return e}};
|
|
390
|
+
`,document.head.appendChild(e);};getEmbeddedLoginIFrame=()=>{let e=document.createElement("iframe");return e.id=Y,e.src=this.getHref(),e.style.height="100vh",e.style.width="100vw",e.style.maxHeight=`${se}px`,e.style.maxWidth=`${ae}px`,e.style.borderRadius=le,e.style.opacity="0",e.style.transform="scale(0.6)",e.style.animation="passportEmbeddedLoginPromptPopBounceIn 1s ease forwards",o.appendIFrameStylesIfNeeded(),e};displayEmbeddedLoginPrompt(){return new Promise((e,t)=>{let r=this.getEmbeddedLoginIFrame(),n=({data:i,origin:l})=>{if(!(l!==this.config.authenticationDomain||i.eventType!==F))switch(i.messageType){case"login_method_selected":{let d=i.payload;window.removeEventListener("message",n),m.remove(),e(d);break}case"login_prompt_error":{window.removeEventListener("message",n),m.remove(),t(new Error("Error during embedded login prompt",{cause:i.payload}));break}case"login_prompt_closed":{window.removeEventListener("message",n),m.remove(),t(new Error("Popup closed by user"));break}default:window.removeEventListener("message",n),m.remove(),t(new Error(`Unsupported message type: ${i.messageType}`));break}};window.addEventListener("message",n),m.appendOverlay(r,()=>{window.removeEventListener("message",n),m.remove(),t(new Error("Popup closed by user"));});})}};var h=class{emitter=new EventEmitter;emit(e,...t){this.emitter.emit(e,...t);}on(e,t){this.emitter.on(e,t);}removeListener(e,t){this.emitter.removeListener(e,t);}};var c=async(o,e,t=!0,r=!0)=>{let n=trackFlow("passport",e,t);try{return await o(n)}catch(i){throw i instanceof Error?trackError("passport",e,i,{flowId:n.details.flowId}):n.addEvent("errored"),i}finally{r&&n.addEvent("End");}};var z="pkce_state",j="pkce_verifier",ue=3600,y=class{isTokenValid(e){try{let r=X(e).exp??0,n=Date.now()/1e3+ue;return r>n}catch{return !1}}savePKCEData(e){localStorage.setItem(z,e.state),localStorage.setItem(j,e.verifier);}getPKCEData(){let e=localStorage.getItem(z),t=localStorage.getItem(j);return e&&t?{state:e,verifier:t}:null}};var ge=(...o)=>{if(typeof process>"u")return;process?.env?.JEST_WORKER_ID===void 0&&console.warn(...o);},C={warn:ge};function Q(o){try{let e=X(o),t=Math.floor(Date.now()/1e3);return e.exp?e.exp<=t+30:!0}catch{return !0}}function J(o){let{id_token:e,access_token:t}=o;return !t||!e?!0:Q(t)||Q(e)}var v=class{disableGenericPopupOverlay;disableBlockedPopupOverlay;overlay;isBlockedOverlay;tryAgainListener;onCloseListener;constructor(e,t=!1){this.disableBlockedPopupOverlay=e.disableBlockedPopupOverlay||!1,this.disableGenericPopupOverlay=e.disableGenericPopupOverlay||!1,this.isBlockedOverlay=t;}append(e,t){this.shouldAppendOverlay()&&(this.appendOverlay(),this.updateTryAgainButton(e),this.updateCloseButton(t));}update(e){this.updateTryAgainButton(e);}remove(){this.overlay&&this.overlay.remove();}shouldAppendOverlay(){return !(this.disableGenericPopupOverlay&&this.disableBlockedPopupOverlay||this.disableGenericPopupOverlay&&!this.isBlockedOverlay||this.disableBlockedPopupOverlay&&this.isBlockedOverlay)}appendOverlay(){if(!this.overlay){A({id:"link-googleapis",href:"https://fonts.googleapis.com"}),A({id:"link-gstatic",href:"https://fonts.gstatic.com",crossOrigin:"anonymous"}),A({id:"link-roboto",href:"https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap",rel:"stylesheet"});let t=document.createElement("div");t.innerHTML=this.isBlockedOverlay?K():W(),document.body.insertAdjacentElement("beforeend",t),this.overlay=t;}}updateTryAgainButton(e){let t=document.getElementById(I);t&&(this.tryAgainListener&&t.removeEventListener("click",this.tryAgainListener),this.tryAgainListener=e,t.addEventListener("click",e));}updateCloseButton(e){let t=document.getElementById(P);t&&(this.onCloseListener&&t.removeEventListener("click",this.onCloseListener),this.onCloseListener=e,t.addEventListener("click",e));}};var k=class{storage;constructor(e,t){this.storage=Ee.createInstance({name:e,driver:t});}get length(){return this.storage.length()}clear(){return this.storage.clear()}getItem(e){return this.storage.getItem(e)}key(e){return this.storage.key(e)}async removeItem(e){await this.storage.removeItem(e);}async setItem(e,t){await this.storage.setItem(e,t);}};var we={headers:{"Content-Type":"application/x-www-form-urlencoded"}},Ue="/v2/logout",be="/im-logged-out",xe="/authorize",Me=o=>o?be:Ue,De=o=>{let{authenticationDomain:e,oidcConfiguration:t}=o,r;o.crossSdkBridgeEnabled?r=new k("ImmutableSDKPassport",Ee.INDEXEDDB):typeof window<"u"?r=window.localStorage:r=new InMemoryWebStorage;let n=new WebStorageStateStore({store:r}),i=new URL(Me(o.crossSdkBridgeEnabled),e.replace(/^(?:https?:\/\/)?(.*)/,"https://$1"));return i.searchParams.set("client_id",t.clientId),t.logoutRedirectUri&&i.searchParams.set("returnTo",t.logoutRedirectUri),{authority:e,redirect_uri:t.redirectUri,popup_redirect_uri:t.popupRedirectUri||t.redirectUri,client_id:t.clientId,metadata:{authorization_endpoint:`${e}/authorize`,token_endpoint:`${e}/oauth/token`,userinfo_endpoint:`${e}/userinfo`,end_session_endpoint:i.toString(),revocation_endpoint:`${e}/oauth/revoke`},automaticSilentRenew:!1,scope:t.scope,userStore:n,revokeTokenTypes:["refresh_token"],extraQueryParams:{...t.audience?{audience:t.audience}:{}}}};function x(o){return btoa(String.fromCharCode(...new Uint8Array(o))).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function Ne(o){let t=new TextEncoder().encode(o);return window.crypto.subtle.digest("SHA-256",t)}var M=class o{config;userManager;deviceCredentialsManager;embeddedLoginPrompt;logoutMode;refreshingPromise=null;eventEmitter;constructor(e){this.config=new _(e),this.embeddedLoginPrompt=new O(this.config),this.userManager=new UserManager(De(this.config)),this.deviceCredentialsManager=new y,this.logoutMode=this.config.oidcConfiguration.logoutMode||"redirect",this.eventEmitter=new h,track("passport","initialise");}async login(e){return c(async()=>{let{useCachedSession:t=!1,useSilentLogin:r}=e||{},n=null;try{n=await this.getUserInternal();}catch(i){if(i instanceof Error&&!i.message.includes("Unknown or invalid refresh token")&&trackError("passport","login",i),t)throw i;C.warn("Failed to retrieve a cached user session",i);}if(!n&&r)n=await this.forceUserRefreshInternal();else if(!n&&!t){if(e?.useRedirectFlow)return await this.loginWithRedirectInternal(e?.directLoginOptions),null;n=await this.loginWithPopup(e?.directLoginOptions);}return n&&this.handleSuccessfulLogin(n),n},"login")}async loginWithRedirect(e){await this.loginWithRedirectInternal(e);}async loginCallback(){return c(async()=>{let e=await this.loginCallbackInternal();return e&&this.handleSuccessfulLogin(e),e},"loginCallback")}async logout(){await c(async()=>{await this.logoutInternal(),this.eventEmitter.emit("loggedOut");},"logout");}async getUser(){return this.getUserInternal()}async getUserOrLogin(){let e=null;try{e=await this.getUserInternal();}catch(r){C.warn("Failed to retrieve a cached user session",r);}if(e)return e;let t=await this.loginWithPopup();return this.handleSuccessfulLogin(t),t}async getUserZkEvm(){return this.getUserZkEvmInternal()}async getIdToken(){return c(async()=>(await this.getUserInternal())?.idToken,"getIdToken",!1)}async getAccessToken(){return c(async()=>(await this.getUserInternal())?.accessToken,"getAccessToken",!1,!1)}async isLoggedIn(){return await this.getUser()!==null}async forceUserRefresh(){return this.forceUserRefreshInternal()}forceUserRefreshInBackground(){this.forceUserRefreshInBackgroundInternal();}async loginWithPKCEFlow(e,t){return c(async()=>this.getPKCEAuthorizationUrl(e,t),"loginWithPKCEFlow")}async loginWithPKCEFlowCallback(e,t){return c(async()=>{let r=await this.loginWithPKCEFlowCallbackInternal(e,t);return this.handleSuccessfulLogin(r),r},"loginWithPKCEFlowCallback")}async storeTokens(e){return c(async()=>{let t=await this.storeTokensInternal(e);return this.handleSuccessfulLogin(t),t},"storeTokens")}async getLogoutUrl(){return c(async()=>(await this.userManager.removeUser(),this.eventEmitter.emit("loggedOut"),await this.getLogoutUrlInternal()||void 0),"getLogoutUrl")}async logoutSilentCallback(e){return c(()=>this.userManager.signoutSilentCallback(e),"logoutSilentCallback")}getConfig(){return this.config}async getClientId(){return this.config.oidcConfiguration.clientId}handleSuccessfulLogin(e){this.eventEmitter.emit("loggedIn",e),identify({passportId:e.profile.sub});}buildExtraQueryParams(e,t){let r={...this.userManager.settings?.extraQueryParams??{},rid:getDetail(Detail.RUNTIME_ID)||""};if(e){if(e.directLoginMethod==="email"){let n=e.email;n&&(r.direct=e.directLoginMethod,r.email=n);}else r.direct=e.directLoginMethod;e.marketingConsentStatus&&(r.marketingConsent=e.marketingConsentStatus);}return t&&(r.im_passport_trace_id=t),r}async loginWithRedirectInternal(e){await this.userManager.clearStaleState(),await g(async()=>{let t=this.buildExtraQueryParams(e);await this.userManager.signinRedirect({extraQueryParams:t});},"AUTHENTICATION_ERROR");}async loginWithPopup(e){return g(async()=>{let t,r;if(e)t=e;else if(!this.config.popupOverlayOptions?.disableHeadlessLoginPromptOverlay){let{imPassportTraceId:l,...d}=await this.embeddedLoginPrompt.displayEmbeddedLoginPrompt();t=d,r=l;}let n=window.crypto.randomUUID(),i=async()=>{let l=this.buildExtraQueryParams(t,r);return this.userManager.signinPopup({extraQueryParams:l,popupWindowFeatures:{width:410,height:450},popupWindowTarget:n})};return new Promise((l,d)=>{i().then(u=>l(o.mapOidcUserToDomainModel(u))).catch(u=>{if(!(u instanceof Error)||u.message!=="Attempted to navigate on a disposed window"){d(u);return}let T=!1,a=new v(this.config.popupOverlayOptions||{},!0);a.append(async()=>{try{if(T)window.open("",n);else {T=!0;let f=await i();a.remove(),l(o.mapOidcUserToDomainModel(f));}}catch(f){a.remove(),d(f);}},()=>{a.remove(),d(new Error("Popup closed by user"));});});})},"AUTHENTICATION_ERROR")}static mapOidcUserToDomainModel=e=>{let t,r;if(e.id_token){let i=X(e.id_token);t=i?.passport,i?.username&&(r=i?.username);}let n={expired:e.expired,idToken:e.id_token,accessToken:e.access_token,refreshToken:e.refresh_token,profile:{sub:e.profile.sub,email:e.profile.email,nickname:e.profile.nickname,username:r}};return t?.zkevm_eth_address&&t?.zkevm_user_admin_address&&(n.zkEvm={ethAddress:t.zkevm_eth_address,userAdminAddress:t.zkevm_user_admin_address}),n};static mapDeviceTokenResponseToOidcUser=e=>{let t=X(e.id_token);return new User({id_token:e.id_token,access_token:e.access_token,refresh_token:e.refresh_token,token_type:e.token_type,profile:{sub:t.sub,iss:t.iss,aud:t.aud,exp:t.exp,iat:t.iat,email:t.email,nickname:t.nickname,passport:t.passport,...t.username?{username:t.username}:{}}})};async loginCallbackInternal(){return g(async()=>{let e=await this.userManager.signinCallback();if(e)return o.mapOidcUserToDomainModel(e)},"AUTHENTICATION_ERROR")}async getPKCEAuthorizationUrl(e,t){let r=x(window.crypto.getRandomValues(new Uint8Array(32))),n=x(await Ne(r)),i=x(window.crypto.getRandomValues(new Uint8Array(32))),{redirectUri:l,scope:d,audience:u,clientId:T}=this.config.oidcConfiguration;this.deviceCredentialsManager.savePKCEData({state:i,verifier:r});let a=new URL(xe,this.config.authenticationDomain);if(a.searchParams.set("response_type","code"),a.searchParams.set("code_challenge",n),a.searchParams.set("code_challenge_method","S256"),a.searchParams.set("client_id",T),a.searchParams.set("redirect_uri",l),a.searchParams.set("state",i),d&&a.searchParams.set("scope",d),u&&a.searchParams.set("audience",u),e){if(e.directLoginMethod==="email"){let f=e.email;f&&(a.searchParams.set("direct",e.directLoginMethod),a.searchParams.set("email",f));}else a.searchParams.set("direct",e.directLoginMethod);e.marketingConsentStatus&&a.searchParams.set("marketingConsent",e.marketingConsentStatus);}return t&&a.searchParams.set("im_passport_trace_id",t),a.toString()}async loginWithPKCEFlowCallbackInternal(e,t){return g(async()=>{let r=this.deviceCredentialsManager.getPKCEData();if(!r)throw new Error("No code verifier or state for PKCE");if(t!==r.state)throw new Error("Provided state does not match stored state");let n=await this.getPKCEToken(e,r.verifier),i=o.mapDeviceTokenResponseToOidcUser(n),l=o.mapOidcUserToDomainModel(i);return await this.userManager.storeUser(i),l},"AUTHENTICATION_ERROR")}async getPKCEToken(e,t){return (await ve.post(`${this.config.authenticationDomain}/oauth/token`,{client_id:this.config.oidcConfiguration.clientId,grant_type:"authorization_code",code_verifier:t,code:e,redirect_uri:this.config.oidcConfiguration.redirectUri},we)).data}async storeTokensInternal(e){return g(async()=>{let t=o.mapDeviceTokenResponseToOidcUser(e),r=o.mapOidcUserToDomainModel(t);return await this.userManager.storeUser(t),r},"AUTHENTICATION_ERROR")}async logoutInternal(){await g(async()=>{await this.userManager.revokeTokens(["refresh_token"]),this.logoutMode==="silent"?await this.userManager.signoutSilent():await this.userManager.signoutRedirect();},"LOGOUT_ERROR");}async getLogoutUrlInternal(){let e=this.userManager.settings?.metadata?.end_session_endpoint;return e||(C.warn("Failed to get logout URL"),null)}forceUserRefreshInBackgroundInternal(){this.refreshTokenAndUpdatePromise().catch(e=>{C.warn("Failed to refresh user token",e);});}async forceUserRefreshInternal(){return this.refreshTokenAndUpdatePromise().catch(e=>(C.warn("Failed to refresh user token",e),null))}async refreshTokenAndUpdatePromise(){return this.refreshingPromise?this.refreshingPromise:(this.refreshingPromise=new Promise((e,t)=>{(async()=>{try{let r=await this.userManager.signinSilent();if(r){e(o.mapOidcUserToDomainModel(r));return}e(null);}catch(r){let n="AUTHENTICATION_ERROR",i="Failed to refresh token",l=!0;if(r instanceof ErrorTimeout?(n="SILENT_LOGIN_ERROR",i=`${i}: ${r.message}`,l=!1):r instanceof ErrorResponse?(n="NOT_LOGGED_IN_ERROR",i=`${i}: ${r.message||r.error_description}`):r instanceof Error?i=`${i}: ${r.message}`:typeof r=="string"&&(i=`${i}: ${r}`),l)try{await this.userManager.removeUser();}catch(d){d instanceof Error&&(i=`${i}: Failed to remove user: ${d.message}`);}t(new p(i,n));}finally{this.refreshingPromise=null;}})();}),this.refreshingPromise)}async getUserInternal(e=t=>!0){if(this.refreshingPromise){let r=await this.refreshingPromise;return r&&e(r)?r:null}let t=await this.userManager.getUser();if(!t)return null;if(!J(t)){let r=o.mapOidcUserToDomainModel(t);if(r&&e(r))return r}if(t.refresh_token){let r=await this.refreshTokenAndUpdatePromise();if(r&&e(r))return r}return null}async getUserZkEvmInternal(){let e=await this.getUserInternal(w);if(!e)throw new Error("Failed to obtain a User with the required ZkEvm attributes");return e}};
|
|
391
391
|
|
|
392
|
-
export {
|
|
392
|
+
export { M as Auth, _ as AuthConfiguration, U as AuthEvents, S as MarketingConsentStatus, p as PassportError, L as PassportErrorType, N as RollupType, h as TypedEventEmitter, D as isAPIError, w as isUserZkEvm, g as withPassportError };
|
package/dist/types/Auth.d.ts
CHANGED
|
@@ -145,12 +145,12 @@ export declare class Auth {
|
|
|
145
145
|
* @returns Promise that resolves with the client ID string
|
|
146
146
|
*/
|
|
147
147
|
getClientId(): Promise<string>;
|
|
148
|
+
private handleSuccessfulLogin;
|
|
148
149
|
private buildExtraQueryParams;
|
|
149
150
|
private loginWithRedirectInternal;
|
|
150
151
|
private loginWithPopup;
|
|
151
152
|
private static mapOidcUserToDomainModel;
|
|
152
153
|
private static mapDeviceTokenResponseToOidcUser;
|
|
153
|
-
private static shouldUseSigninPopupCallback;
|
|
154
154
|
private loginCallbackInternal;
|
|
155
155
|
private getPKCEAuthorizationUrl;
|
|
156
156
|
private loginWithPKCEFlowCallbackInternal;
|
package/dist/types/errors.d.ts
CHANGED
|
@@ -20,7 +20,8 @@ export declare enum PassportErrorType {
|
|
|
20
20
|
LINK_WALLET_VALIDATION_ERROR = "LINK_WALLET_VALIDATION_ERROR",
|
|
21
21
|
LINK_WALLET_DUPLICATE_NONCE_ERROR = "LINK_WALLET_DUPLICATE_NONCE_ERROR",
|
|
22
22
|
LINK_WALLET_GENERIC_ERROR = "LINK_WALLET_GENERIC_ERROR",
|
|
23
|
-
SERVICE_UNAVAILABLE_ERROR = "SERVICE_UNAVAILABLE_ERROR"
|
|
23
|
+
SERVICE_UNAVAILABLE_ERROR = "SERVICE_UNAVAILABLE_ERROR",
|
|
24
|
+
TRANSACTION_REJECTED = "TRANSACTION_REJECTED"
|
|
24
25
|
}
|
|
25
26
|
export declare function isAPIError(error: any): error is imx.APIError;
|
|
26
27
|
export declare class PassportError extends Error {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export { AuthConfiguration, type IAuthConfiguration } from './config';
|
|
|
3
3
|
export type { User, UserProfile, UserZkEvm, DirectLoginMethod, DirectLoginOptions, LoginOptions, DeviceTokenResponse, OidcConfiguration, AuthModuleConfiguration, PopupOverlayOptions, PassportMetadata, IdTokenPayload, PKCEData, AuthEventMap, } from './types';
|
|
4
4
|
export { isUserZkEvm, RollupType, MarketingConsentStatus, AuthEvents, } from './types';
|
|
5
5
|
export { default as TypedEventEmitter } from './utils/typedEventEmitter';
|
|
6
|
-
export { PassportError, PassportErrorType, withPassportError } from './errors';
|
|
6
|
+
export { PassportError, PassportErrorType, withPassportError, isAPIError, } from './errors';
|
package/dist/types/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type UserProfile = {
|
|
|
8
8
|
email?: string;
|
|
9
9
|
nickname?: string;
|
|
10
10
|
sub: string;
|
|
11
|
+
username?: string;
|
|
11
12
|
};
|
|
12
13
|
export declare enum RollupType {
|
|
13
14
|
ZKEVM = "zkEvm"
|
|
@@ -77,6 +78,7 @@ export type TokenPayload = {
|
|
|
77
78
|
};
|
|
78
79
|
export type IdTokenPayload = {
|
|
79
80
|
passport?: PassportMetadata;
|
|
81
|
+
username?: string;
|
|
80
82
|
email: string;
|
|
81
83
|
nickname: string;
|
|
82
84
|
aud: string;
|
package/jest.config.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Config } from 'jest';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
import { name } from './package.json';
|
|
4
|
+
|
|
5
|
+
const rootDirs = execSync(`pnpm --filter ${name}... exec pwd`)
|
|
6
|
+
.toString()
|
|
7
|
+
.split('\n')
|
|
8
|
+
.filter(Boolean)
|
|
9
|
+
.map((dir) => `${dir}/dist`);
|
|
10
|
+
|
|
11
|
+
const config: Config = {
|
|
12
|
+
clearMocks: true,
|
|
13
|
+
roots: ['<rootDir>/src', ...rootDirs],
|
|
14
|
+
coverageProvider: 'v8',
|
|
15
|
+
moduleDirectories: ['node_modules', 'src'],
|
|
16
|
+
moduleNameMapper: { '^@imtbl/(.*)$': '<rootDir>/../../node_modules/@imtbl/$1/src' },
|
|
17
|
+
testEnvironment: 'jsdom',
|
|
18
|
+
transform: {
|
|
19
|
+
'^.+\\.(t|j)sx?$': '@swc/jest',
|
|
20
|
+
},
|
|
21
|
+
transformIgnorePatterns: [],
|
|
22
|
+
restoreMocks: true,
|
|
23
|
+
setupFiles: ['<rootDir>/jest.setup.js'],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default config;
|
|
27
|
+
|
package/jest.setup.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imtbl/auth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.1-alpha.0",
|
|
4
4
|
"description": "Authentication SDK for Immutable",
|
|
5
5
|
"author": "Immutable",
|
|
6
6
|
"bugs": "https://github.com/immutable/ts-immutable-sdk/issues",
|
|
@@ -25,17 +25,24 @@
|
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@imtbl/config": "2.
|
|
29
|
-
"@imtbl/metrics": "2.
|
|
28
|
+
"@imtbl/config": "2.11.1-alpha.0",
|
|
29
|
+
"@imtbl/metrics": "2.11.1-alpha.0",
|
|
30
30
|
"axios": "^1.6.5",
|
|
31
31
|
"jwt-decode": "^3.1.2",
|
|
32
32
|
"localforage": "^1.10.0",
|
|
33
|
-
"oidc-client-ts": "3.
|
|
33
|
+
"oidc-client-ts": "3.4.1",
|
|
34
34
|
"uuid": "^9.0.1"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@imtbl/toolkit": "2.
|
|
37
|
+
"@imtbl/toolkit": "2.11.1-alpha.0",
|
|
38
|
+
"@swc/core": "^1.3.36",
|
|
39
|
+
"@swc/jest": "^0.2.37",
|
|
40
|
+
"@types/jest": "^29.5.12",
|
|
38
41
|
"@types/node": "^18.14.2",
|
|
42
|
+
"@jest/test-sequencer": "^29.7.0",
|
|
43
|
+
"jest": "^29.4.3",
|
|
44
|
+
"jest-environment-jsdom": "^29.4.3",
|
|
45
|
+
"ts-node": "^10.9.1",
|
|
39
46
|
"tsup": "^8.3.0",
|
|
40
47
|
"typescript": "^5.6.2"
|
|
41
48
|
},
|
|
@@ -50,6 +57,7 @@
|
|
|
50
57
|
"typegen": "tsc --customConditions default --emitDeclarationOnly --outDir dist/types",
|
|
51
58
|
"pack:root": "pnpm pack --pack-destination $(dirname $(pnpm root -w))",
|
|
52
59
|
"lint": "eslint ./src --ext .ts,.jsx,.tsx --max-warnings=0",
|
|
53
|
-
"typecheck": "tsc --customConditions default --noEmit --jsx preserve"
|
|
60
|
+
"typecheck": "tsc --customConditions default --noEmit --jsx preserve",
|
|
61
|
+
"test": "jest"
|
|
54
62
|
}
|
|
55
63
|
}
|
package/src/Auth.test.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { Auth } from './Auth';
|
|
2
|
+
import { AuthEvents, User } from './types';
|
|
3
|
+
import { withMetricsAsync } from './utils/metrics';
|
|
4
|
+
import jwt_decode from 'jwt-decode';
|
|
5
|
+
|
|
6
|
+
const trackFlowMock = jest.fn();
|
|
7
|
+
const trackErrorMock = jest.fn();
|
|
8
|
+
const identifyMock = jest.fn();
|
|
9
|
+
const trackMock = jest.fn();
|
|
10
|
+
const getDetailMock = jest.fn();
|
|
11
|
+
|
|
12
|
+
jest.mock('@imtbl/metrics', () => ({
|
|
13
|
+
Detail: { RUNTIME_ID: 'runtime-id' },
|
|
14
|
+
trackFlow: (...args: any[]) => trackFlowMock(...args),
|
|
15
|
+
trackError: (...args: any[]) => trackErrorMock(...args),
|
|
16
|
+
identify: (...args: any[]) => identifyMock(...args),
|
|
17
|
+
track: (...args: any[]) => trackMock(...args),
|
|
18
|
+
getDetail: (...args: any[]) => getDetailMock(...args),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
jest.mock('jwt-decode', () => jest.fn());
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
trackFlowMock.mockReset();
|
|
25
|
+
trackErrorMock.mockReset();
|
|
26
|
+
identifyMock.mockReset();
|
|
27
|
+
trackMock.mockReset();
|
|
28
|
+
getDetailMock.mockReset();
|
|
29
|
+
(jwt_decode as jest.Mock).mockReset();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('withMetricsAsync', () => {
|
|
33
|
+
it('resolves with function result and tracks flow', async () => {
|
|
34
|
+
const flow = {
|
|
35
|
+
addEvent: jest.fn(),
|
|
36
|
+
details: { flowId: 'flow-id' },
|
|
37
|
+
};
|
|
38
|
+
trackFlowMock.mockReturnValue(flow);
|
|
39
|
+
|
|
40
|
+
const result = await withMetricsAsync(async () => 'done', 'login');
|
|
41
|
+
|
|
42
|
+
expect(result).toEqual('done');
|
|
43
|
+
expect(trackFlowMock).toHaveBeenCalledWith('passport', 'login', true);
|
|
44
|
+
expect(flow.addEvent).toHaveBeenCalledWith('End');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('tracks error when function throws', async () => {
|
|
48
|
+
const flow = {
|
|
49
|
+
addEvent: jest.fn(),
|
|
50
|
+
details: { flowId: 'flow-id' },
|
|
51
|
+
};
|
|
52
|
+
trackFlowMock.mockReturnValue(flow);
|
|
53
|
+
const error = new Error('boom');
|
|
54
|
+
|
|
55
|
+
await expect(withMetricsAsync(async () => {
|
|
56
|
+
throw error;
|
|
57
|
+
}, 'login')).rejects.toThrow(error);
|
|
58
|
+
|
|
59
|
+
expect(trackErrorMock).toHaveBeenCalledWith('passport', 'login', error, { flowId: 'flow-id' });
|
|
60
|
+
expect(flow.addEvent).toHaveBeenCalledWith('End');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('does not fail when non-error is thrown', async () => {
|
|
64
|
+
const flow = {
|
|
65
|
+
addEvent: jest.fn(),
|
|
66
|
+
details: { flowId: 'flow-id' },
|
|
67
|
+
};
|
|
68
|
+
trackFlowMock.mockReturnValue(flow);
|
|
69
|
+
|
|
70
|
+
const nonError = { message: 'failure' };
|
|
71
|
+
await expect(withMetricsAsync(async () => {
|
|
72
|
+
throw nonError as unknown as Error;
|
|
73
|
+
}, 'login')).rejects.toBe(nonError);
|
|
74
|
+
|
|
75
|
+
expect(flow.addEvent).toHaveBeenCalledWith('errored');
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe('Auth', () => {
|
|
80
|
+
describe('getUserOrLogin', () => {
|
|
81
|
+
const createMockUser = (): User => ({
|
|
82
|
+
accessToken: 'access',
|
|
83
|
+
idToken: 'id',
|
|
84
|
+
refreshToken: 'refresh',
|
|
85
|
+
expired: false,
|
|
86
|
+
profile: {
|
|
87
|
+
sub: 'user-123',
|
|
88
|
+
email: 'test@example.com',
|
|
89
|
+
nickname: 'tester',
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('emits LOGGED_IN event and identifies user when login is required', async () => {
|
|
94
|
+
const auth = Object.create(Auth.prototype) as Auth;
|
|
95
|
+
const loginWithPopup = jest.fn().mockResolvedValue(createMockUser());
|
|
96
|
+
|
|
97
|
+
(auth as any).eventEmitter = { emit: jest.fn() };
|
|
98
|
+
(auth as any).getUserInternal = jest.fn().mockResolvedValue(null);
|
|
99
|
+
(auth as any).loginWithPopup = loginWithPopup;
|
|
100
|
+
|
|
101
|
+
const user = await auth.getUserOrLogin();
|
|
102
|
+
|
|
103
|
+
expect(loginWithPopup).toHaveBeenCalledTimes(1);
|
|
104
|
+
expect((auth as any).eventEmitter.emit).toHaveBeenCalledWith(AuthEvents.LOGGED_IN, user);
|
|
105
|
+
expect(identifyMock).toHaveBeenCalledWith({ passportId: user.profile.sub });
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('returns cached user without triggering login', async () => {
|
|
109
|
+
const auth = Object.create(Auth.prototype) as Auth;
|
|
110
|
+
const cachedUser = createMockUser();
|
|
111
|
+
|
|
112
|
+
(auth as any).eventEmitter = { emit: jest.fn() };
|
|
113
|
+
(auth as any).getUserInternal = jest.fn().mockResolvedValue(cachedUser);
|
|
114
|
+
(auth as any).loginWithPopup = jest.fn();
|
|
115
|
+
|
|
116
|
+
const user = await auth.getUserOrLogin();
|
|
117
|
+
|
|
118
|
+
expect(user).toBe(cachedUser);
|
|
119
|
+
expect((auth as any).loginWithPopup).not.toHaveBeenCalled();
|
|
120
|
+
expect((auth as any).eventEmitter.emit).not.toHaveBeenCalled();
|
|
121
|
+
expect(identifyMock).not.toHaveBeenCalled();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
describe('buildExtraQueryParams', () => {
|
|
126
|
+
it('omits third_party_a_id when no anonymous id is provided', () => {
|
|
127
|
+
const auth = Object.create(Auth.prototype) as Auth;
|
|
128
|
+
(auth as any).userManager = { settings: { extraQueryParams: {} } };
|
|
129
|
+
getDetailMock.mockReturnValue('runtime-id-value');
|
|
130
|
+
|
|
131
|
+
const params = (auth as any).buildExtraQueryParams();
|
|
132
|
+
|
|
133
|
+
expect(params.third_party_a_id).toBeUndefined();
|
|
134
|
+
expect(params.rid).toEqual('runtime-id-value');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe('username extraction', () => {
|
|
139
|
+
it('extracts username from id token when present', () => {
|
|
140
|
+
const mockOidcUser = {
|
|
141
|
+
id_token: 'token',
|
|
142
|
+
access_token: 'access',
|
|
143
|
+
refresh_token: 'refresh',
|
|
144
|
+
expired: false,
|
|
145
|
+
profile: { sub: 'user-123', email: 'test@example.com', nickname: 'tester' },
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
(jwt_decode as jest.Mock).mockReturnValue({
|
|
149
|
+
username: 'username123',
|
|
150
|
+
passport: undefined,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const result = (Auth as any).mapOidcUserToDomainModel(mockOidcUser);
|
|
154
|
+
|
|
155
|
+
expect(jwt_decode).toHaveBeenCalledWith('token');
|
|
156
|
+
expect(result.profile.username).toEqual('username123');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('maps username when creating OIDC user from device tokens', () => {
|
|
160
|
+
const tokenResponse = {
|
|
161
|
+
id_token: 'token',
|
|
162
|
+
access_token: 'access',
|
|
163
|
+
refresh_token: 'refresh',
|
|
164
|
+
token_type: 'Bearer',
|
|
165
|
+
expires_in: 3600,
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
(jwt_decode as jest.Mock).mockReturnValue({
|
|
169
|
+
sub: 'user-123',
|
|
170
|
+
iss: 'issuer',
|
|
171
|
+
aud: 'audience',
|
|
172
|
+
exp: 1,
|
|
173
|
+
iat: 0,
|
|
174
|
+
email: 'test@example.com',
|
|
175
|
+
nickname: 'tester',
|
|
176
|
+
username: 'username123',
|
|
177
|
+
passport: undefined,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const oidcUser = (Auth as any).mapDeviceTokenResponseToOidcUser(tokenResponse);
|
|
181
|
+
|
|
182
|
+
expect(jwt_decode).toHaveBeenCalledWith('token');
|
|
183
|
+
expect(oidcUser.profile.username).toEqual('username123');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|