1"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[392],{60392:(e,i,a)=>{a.d(i,{authService:()=>v});var t=a(24571),r=a(87777),l=a(71931),n=a(76458),s=a(18654);let o="loginTrackedAt";function c(e){try{let i=sessionStorage.getItem(`${o}:${e}`);if(!i)return!1;return Date.now()-Number(i)<9e4}catch{return!1}}class d{static instance;deviceFingerprint=null;inFlightByUser=new Map;constructor(){this.generateDeviceFingerprint()}static getInstance(){return d.instance||(d.instance=new d),d.instance}generateDeviceFingerprint(){let e=document.createElement("canvas"),i=e.getContext("2d");i&&(i.textBaseline="top",i.font="14px Arial",i.fillText("Device fingerprint",2,2));let a=[navigator.userAgent,navigator.language,screen.width+"x"+screen.height,new Date().getTimezoneOffset(),e.toDataURL()].join("|");this.deviceFingerprint=btoa(a).substring(0,32)}async getLocationInfo(){let e=Intl.DateTimeFormat().resolvedOptions().timeZone,i=navigator.language,a=Intl.Locale?new Intl.Locale(i).region:"æªç¥";return`æå: ${e}, èªè¨: ${i}, å°å: ${a}`}async getIPAddress(){return"æªç¥ IP"}async checkIfNewDevice(e){if(!this.deviceFingerprint||!n.db)return!0;try{let i=(0,t.rJ)(n.db,"userLoginLogs");return(await (0,t.GG)((0,t.P)(i,(0,t._M)("userId","==",e),(0,t._M)("deviceFingerprint","==",this.deviceFingerprint),(0,t.AB)(1)))).empty}catch(e){return!0}}async checkIfNewLocation(e,i){if(!n.db)return!0;try{let a=(0,t.rJ)(n.db,"userLoginLogs");for(let r of(await (0,t.GG)((0,t.P)(a,(0,t._M)("userId","==",e),(0,t.AB)(10)))).docs)if(r.data().location===i)return!1;return!0}catch(e){return!0}}async trackLogin(e,i){if(!n.db||!e)return;if(!i?.force&&c(e))return void(0,s.fH)("[loginTracker] skip duplicate trackLogin",{userId:e});let a=this.inFlightByUser.get(e);if(a)return(0,s.fH)("[loginTracker] join in-flight trackLogin",{userId:e}),a;let t=this.writeLoginLog(e,i);this.inFlightByUser.set(e,t);try{await t}finally{this.inFlightByUser.delete(e)}}async writeLoginLog(e,i){if(n.db&&!(!i?.force&&c(e))){try{sessionStorage.setItem(`${o}:${e}`,String(Date.now()))}catch{}try{let i=await this.getLocationInfo(),a=await this.getIPAddress(),[r,l]=await Promise.all([this.checkIfNewDevice(e),this.checkIfNewLocation(e,i)]),o={userId:e,timestamp:(0,t.serverTimestamp)(),deviceInfo:navigator.userAgent,location:i,ipAddress:a,isNewDevice:r,isNewLocation:l,userAgent:navigator.userAgent,platform:navigator.platform,language:navigator.language,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone};this.deviceFingerprint&&(o.deviceFingerprint=this.deviceFingerprint),await (0,t.gS)((0,t.rJ)(n.db,"userLoginLogs"),o),(0,s.fH)("[loginTracker] userLoginLogs written",{userId:e,isNewDevice:r,isNewLocation:l})}catch(i){if(i?.code==="already-exists")return void(0,s.fH)("[loginTracker] userLoginLogs already written (retry collision)",{userId:e});throw(0,s.vV)("[loginTracker] trackLogin failed",i),i}}}}let u=d.getInstance();var m=a(47026),h=a(48716);function g(){if(n.functions)return n.functions;try{let e=(0,r.Sx)();return(0,l.getFunctions)(e,"asia-east1")}catch{return}}class f{defaultConfig={autoRedirect:!0,defaultRedirectPath:"/dashboard",trackLogin:!0,refreshExchangeRates:!0};async handleAuthSuccess(e,i,a){(0,s.MD)("[AuthService] handleAuthSuccess 被å¼å«",{uid:e?.uid,hasCredential:!!i,credentialKeys:i?Object.keys(i).filter(e=>e.includes("line")||e.includes("Line")||"_lineEmail"===e||"_tokenResponse"===e):[]});let t={...this.defaultConfig,...a};try{if(await this.syncUserDataToFirestore(e,i),t.trackLogin)try{await u.trackLogin(e.uid)}catch(e){(0,s.vV)("è¨éç»å
¥æ´»å失æ:",e)}if(t.refreshExchangeRates)try{await (0,m.ME)()}catch(e){(0,s.vV)("æ´æ°å¯ç失æ:",e)}(0,h.setLoginState)(),(0,h.clearLogoutState)(),(0,h.clearOAuthRedirectState)()}catch(e){(0,s.vV)("èçç»å
¥æåé輯æç¼çé¯èª¤:",e)}}static isEmailAlreadyInUseError(e){let i=e?.code,a=e?.message??"";return"functions/already-exists"===i||"already-exists"===i||a.includes("æ¤é»åéµä»¶å·²è¢«ä½¿ç¨")}async syncUserDataToFirestore(e,i){if((0,s.MD)("[AuthService] syncUserDataToFirestore 被å¼å«",{uid:e?.uid,hasCredential:!!i}),!n.db){(0,s.vV)("Firestore å°æªåå§å"),(0,s.MD)("[AuthService] æ©æé¢éï¼db çºç©º");return}try{await e.getIdToken(!0);let a=(0,t.doc)(n.db,n.USERS,e.uid),r=await (0,t.getDoc)(a),o={uid:e.uid,email:e.email,displayName:e.displayName,photoURL:e.ph
1otoURL,emailVerified:e.emailVerified,providerData:e.providerData.map(e=>({providerId:e.providerId,uid:e.uid,displayName:e.displayName,email:e.email,photoURL:e.photoURL})),lastSignInTime:e.metadata.lastSignInTime,creationTime:e.metadata.creationTime,updatedAt:(0,t.serverTimestamp)()};if((0,s.MD)("[AuthService] syncUserDataToFirestore éå§",{uid:e.uid,hasCredential:!!i,userEmail:e.email,credentialLineEmail:i?._lineEmail??"(ç¡)"}),(0,s.fH)("[AuthService] syncUserDataToFirestore éå§",{uid:e.uid,hasCredential:!!i,userEmail:e.email,credentialLineEmail:i?._lineEmail||"none"}),!o.email&&i&&e.providerData.some(e=>e.providerId===n.OIDC_LINE_PROVIDER_ID||e.providerId?.startsWith("oidc")))try{if((0,s.fH)("[AuthService] èç LINE ç»å
¥ç Email åå¾",{uid:e.uid,hasProviderData:e.providerData.length>0}),(0,s.MD)("[AuthService] éå§èç LINE ç»å
¥ç Email åå¾",{uid:e.uid,hasCredential:!!i,hasLineEmail:!!i?._lineEmail,credentialLineEmail:i?._lineEmail||"none"}),i?._lineEmail)o.email=i._lineEmail,(0,s.MD)("[AuthService] â
å¾ credential._lineEmail åå¾ Email",{uid:e.uid,email:o.email}),(0,s.fH)("[AuthService] â
å¾ credential._lineEmail åå¾ Email",{uid:e.uid,email:o.email});else{(0,s.MD)("[AuthService] credential._lineEmail ä¸åå¨ï¼åè©¦å¾ ID Token è§£æ");try{let a=i?._tokenResponse,t=a?.oauthIdToken||a?.idToken;if((0,s.MD)("[AuthService] æª¢æ¥ credential ä¸ç ID Token",{hasTokenResponse:!!a,hasOauthIdToken:!!a?.oauthIdToken,hasIdToken:!!a?.idToken,lineIdTokenLength:t?.length||0}),t){let i=t.split(".");if(3===i.length){let a=i[1].replace(/-/g,"+").replace(/_/g,"/"),t=a+"=".repeat((4-a.length%4)%4),r=JSON.parse(atob(t));(0,s.MD)("[AuthService] ID Token payload è§£æçµæ:",{payloadKeys:Object.keys(r||{}),hasEmail:"email"in(r||{}),email:r?.email}),r.email?(o.email=r.email,void 0!==r.email_verified&&(o.emailVerified=r.email_verified),(0,s.MD)("[AuthService] â
å¾ credential ID Token è§£æåå¾ Email",{uid:e.uid,email:o.email}),(0,s.fH)("[AuthService] â
å¾ credential ID Token è§£æåå¾ Email",{uid:e.uid,email:o.email})):((0,s.MD)("[AuthService] credential ID Token payload 䏿²æ email",{payloadKeys:Object.keys(r||{})}),(0,s.vV)("[AuthService] credential ID Token payload 䏿²æ email",{payloadKeys:Object.keys(r||{})}))}}else(0,s.MD)("[AuthService] credential 䏿²ææ¾å° ID Token",{hasTokenResponse:!!a,tokenResponseKeys:a?Object.keys(a):[]}),(0,s.vV)("[AuthService] credential 䏿²ææ¾å° ID Token",{hasTokenResponse:!!a,tokenResponseKeys:a?Object.keys(a):[]})}catch(e){(0,s.MD)("[AuthService] è§£æ credential ID Token 失æ",e),(0,s.vV)("[AuthService] è§£æ credential ID Token 失æ:",e)}}o.email?((0,s.MD)("[AuthService] â
LINE ç»å
¥ Email 已寫å
¥ userData",{uid:e.uid,email:o.email}),(0,s.fH)("[AuthService] â
LINE ç»å
¥ Email å徿å",{uid:e.uid,email:o.email,emailVerified:o.emailVerified})):(0,s.vV)("[AuthService] â ï¸ LINE ç»å
¥ç¨æ¶ç¼ºå° Email",{uid:e.uid,displayName:e.displayName,providerData:e.providerData})}catch(e){(0,s.vV)("[AuthService] èç LINE ç»å
¥ Email æç¼çé¯èª¤:",e)}if((0,s.MD)("[AuthService] sync 忝å",{uid:e.uid,userDocExists:r.exists(),userDataEmail:o.email??"(null)"}),r.exists()){let i=o.email&&"string"==typeof o.email&&""!==o.email.trim();if(i){let i=g();if(i)try{(0,s.MD)("[AuthService] ç¾æç¨æ¶æ emailï¼å¼å« initializeUserProfile callable",{uid:e.uid,email:o.email});let a=(0,l.httpsCallable)(i,"initializeUserProfile");await a({email:o.email,name:e.displayName||void 0}),(0,s.MD)("[AuthService] â
initializeUserProfile callable æåï¼ç¾æç¨æ¶ï¼",{uid:e.uid,email:o.email}),(0,s.fH)("[AuthService] â
å·²éé initializeUserProfile callable 寫å
¥/åä½µ emailï¼ç¾æç¨æ¶ï¼",{uid:e.uid,email:o.email})}catch(i){(0,s.MD)("[AuthService] initializeUserProfile callable 失æï¼ç¾æç¨æ¶ï¼",i),f.isEmailAlreadyInUseError(i)?(0,s.fH)("[AuthService] æ¤ email 已被å
¶ä»å¸³è使ç¨ï¼è·³é寫å
¥ emailï¼ç»å
¥æµç¨ç
§å¸¸ç¹¼çº",{uid:e.uid,email:o.email}):(0,s.vV)("[AuthService] ç¾æç¨æ¶èª¿ç¨ initializeUserProfile 寫å
¥ email 失æ:",i)}else(0,s.MD)("[AuthService] ç¡æ³åå¾ Functions 實ä¾ï¼ç¡æ³å¼å« initializeUserProfileï¼ç¾æç¨æ¶ï¼")}let n=r.data(),c={...o};i?c.email=o.email:delete c.email,n?.emailVerified!==o.emailVerified&&(c.emailVerified=o.emailVerified),("string"==typeof n?.name?n.name.trim():"")?delete c.name:"string"==typeof e.displayName&&e.displayName.trim()&&(c.name=e.displayName.trim().slice(0,80)),await (0,t.setDoc)(a,c,{merge:!0})}else{if(o.email){let i=g();if(i)try{(0,s.MD)("[AuthService] æ°ç¨æ¶æ emailï¼å¼å« initializeUserProfile callable",{uid:e.uid,email:o.email});let a=(0,l.httpsCallable)(i,"initializeUserProfile");await a({email:o.email,name:e.displayName||void 0}),(0,s.MD)("[AuthService] â
initializeUserProfile callable æåï¼æ°ç¨æ¶ï¼",{uid:e.uid,email:o.email}),(0,s.fH)("[AuthService] â
å·²éé initializeUserProfile callable å»ºç« users æä»¶ï¼å« emailï¼",{uid:e.uid,email:o.email});return}catch(i){(0,s.MD)("[AuthService] initializeUserProfile callable 失æï¼æ°ç¨æ¶ï¼",i),f.isEmailAlreadyInUseError(i)?(0,s.fH)("[AuthService] æ¤ email 已被å
¶ä»å¸³è使ç¨ï¼è·³é寫å
¥ï¼æ¹ç± Gen2 觸ç¼å¨å»ºç« users æä»¶",{uid:e.uid}):(0,s.vV)("[AuthService] èª¿ç¨ initializeUserProfile callable 失æ:",i)}else(0,s.MD)("[AuthService] ç¡æ³åå¾ Functions 實ä¾ï¼ç¡æ³å¼å« initializeUserProfileï¼æ°ç¨æ¶ï¼"),(0,s.vV)("[AuthService] functions æªåå§åï¼ç¡æ³å¼å« initializeUserProfile");(0,s.fH)("[AuthService] æ¹çºçå¾
Gen2 觸ç¼å¨å»ºç« users æä»¶",{uid:e.uid})}o.email||(0,s.fH)("[AuthService] æ°ç¨æ¶ç¡ emailï¼çå¾
Gen2 觸ç¼å¨å»ºç« users æä»¶",{uid:e.uid,providerIds:e.providerData.map(e=>e.providerId)});for(let i=0;i<10;i++){if((await (0,t.getDoc)(a)).exists())return void(0,s.fH)("[AuthService] Gen2 觸ç¼å¨å·²å»ºç«
1 users æä»¶",{uid:e.uid});await new Promise(e=>setTimeout(e,500))}(0,s.fH)("[AuthService] â ï¸ Gen2 觸ç¼å¨å°æªå»ºç« users æä»¶ï¼é¾æï¼ï¼useUserProfileLoader å°èç",{uid:e.uid});return}}catch(e){(0,s.vV)("åæ¥ä½¿ç¨è
è³æå° Firestore 失æ:",e.message)}}getRedirectPath(e){let i=localStorage.getItem("lineLoginReturnUrl");return i?(localStorage.removeItem("lineLoginReturnUrl"),i):e||this.defaultConfig.defaultRedirectPath}clearLoginFlags(){try{let{clearLoginState:e,clearOAuthRedirectState:i}=a(48716);e(),i(),sessionStorage.removeItem("lineLoginSuccess")}catch(e){}}}let v=new f}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.