diff --git a/package.json b/package.json index 5a9c0e8..78c9e3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@circle-fin/w3s-pw-web-sdk", - "version": "1.0.13", + "version": "1.0.18", "description": "Javascript/Typescript SDK for Circle Programmable Wallets", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/index.ts b/src/index.ts index 4db745f..235976b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,20 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { getApps, initializeApp } from 'firebase/app' +import { + OAuthProvider, + getAuth, + getRedirectResult, + signInWithRedirect, +} from 'firebase/auth' +import { decode } from 'jsonwebtoken' +import { v4 as uuidv4 } from 'uuid' + +import { SocialLoginProvider } from './types' + import type { AppSettings, Authentication, Challenge, ChallengeCompleteCallback, + Configs, CustomLinks, DeviceInfo, Localizations, + LoginCompleteCallback, PostMessageEvent, Resources, SecurityQuestion, - SsoSettings, ThemeColor, } from './types' +import type { FirebaseApp } from 'firebase/app' +import type { UserCredential } from 'firebase/auth' +import type { JwtPayload } from 'jsonwebtoken' const packageInfo = require('../package.json') as { version: string } @@ -34,8 +50,7 @@ export class W3SSdk { private static instance: W3SSdk | null = null private readonly iframe: HTMLIFrameElement private readonly window: Window = window - private appSettings?: AppSettings - private auth?: Authentication + private configs?: Configs private challenge?: Challenge private securityQuestions?: SecurityQuestion[] | null private securityQuestionsRequiredCount = 2 @@ -44,12 +59,19 @@ export class W3SSdk { private themeColor?: ThemeColor private resources?: Resources private customLinks?: CustomLinks - private ssoSettings?: SsoSettings private deviceInfo?: DeviceInfo + private socialLoginToken?: string | null + private socialLoginProvider?: SocialLoginProvider + private firebaseApp?: FirebaseApp + /** * Callback function that is called when the challenge is completed. */ private onComplete?: ChallengeCompleteCallback + /** + * Callback function that is called when the page is redirected back from the social login provider and receives the verification result. + */ + private onLoginComplete?: LoginCompleteCallback private shouldCloseModalOnForgotPin = false /** * Callback function that is called when the user clicks the forgot pin button. @@ -64,54 +86,50 @@ export class W3SSdk { * Promise that is rejected when the device ID is not received. */ private rejectDeviceIdPromise?: (reason: string) => void + /** + * Callback function that is called when the user clicks the resend OTP email button. + */ + private onResendOtpEmail?: () => void - constructor() { - const version = packageInfo.version - + constructor(configs?: Configs, onLoginComplete?: LoginCompleteCallback) { if (W3SSdk.instance != null) { - this.iframe = W3SSdk.instance.iframe - this.deviceInfo = { - model: 'Web', - version, - } + this.setupInstance(configs, onLoginComplete) return W3SSdk.instance } this.iframe = document.createElement('iframe') - this.deviceInfo = { - model: 'Web', - version, - } - + this.setupInstance(configs, onLoginComplete) W3SSdk.instance = this } /** - * Executes the challenge. - * @param challengeId - Challenge ID. - * @param onCompleted - Callback function that is called when the challenge is completed. + * Sets the application settings. + * @param appSettings - Application settings. */ - execute(challengeId: string, onCompleted?: ChallengeCompleteCallback): void { - this.subscribeMessage() - this.setChallenge({ challengeId }) - this.exec(onCompleted) + setAppSettings(appSettings: AppSettings): void { + if (this.configs) { + this.configs.appSettings = appSettings + } } /** - * Executes the challenge with userSecret. This is used for SSO challenges. - * @param challengeId - Challenge ID. - * @param userSecret - User secret. - * @param onCompleted - Callback function that is called when the challenge is completed. + * Sets the authentication information. + * @param auth - Authentication information. */ - executeWithUserSecret( - challengeId: string, - userSecret: string, - onCompleted?: ChallengeCompleteCallback - ) { - this.subscribeMessage() - this.setChallenge({ challengeId, userSecret }) - this.exec(onCompleted, !this.ssoSettings?.disableConfirmationUI) + setAuthentication(auth: Authentication): void { + if (this.configs) { + this.configs.authentication = auth + } + } + + /** + * Updates the configurations. + * @param configs - Configurations. + * @param onLoginComplete - Callback function that is called when the page is redirected back from the social login provider and receives the verification result. + */ + updateConfigs(configs?: Configs, onLoginComplete?: LoginCompleteCallback) { + this.setupInstance(configs, onLoginComplete ?? this.onLoginComplete) } /** @@ -137,19 +155,56 @@ export class W3SSdk { } /** - * Sets the application settings. - * @param appSettings - Application settings. + * Performs social login. + * @param provider - Social login provider. */ - setAppSettings(appSettings: AppSettings): void { - this.appSettings = appSettings + performLogin(provider: SocialLoginProvider): void { + if (provider === SocialLoginProvider.GOOGLE) { + this.performGoogleLogin() + } else if (provider === SocialLoginProvider.FACEBOOK) { + this.performFacebookLogin() + } else if (provider === SocialLoginProvider.APPLE) { + this.performAppleLogin() + } else { + void this.onLoginComplete?.( + { + code: 155140, + message: 'Invalid social login provider', + }, + undefined + ) + } } /** - * Sets the authentication information. - * @param auth - Authentication information. + * Executes email OTP verification. */ - setAuthentication(auth: Authentication): void { - this.auth = auth + verifyOtp() { + this.subscribeMessage() + this.appendIframe(true, 'sso/verify-email') + + setTimeout(() => { + if (!this.receivedResponseFromService) { + void this.onComplete?.( + { + code: 155706, + message: 'Network error', + }, + undefined + ) + } + }, 1000 * 10) + } + + /** + * Executes the challenge. + * @param challengeId - Challenge ID. + * @param onCompleted - Callback function that is called when the challenge is completed. + */ + execute(challengeId: string, onCompleted?: ChallengeCompleteCallback): void { + this.subscribeMessage() + this.setChallenge({ challengeId }) + this.exec(onCompleted, false) } /** @@ -205,14 +260,6 @@ export class W3SSdk { this.customLinks = customLinks } - /** - * Sets the SSO settings. - * @param ssoSettings - SSO settings. - */ - setSsoSettings(ssoSettings: SsoSettings): void { - this.ssoSettings = ssoSettings - } - /** * Sets the callback function that is called when the user clicks the forgot pin button. * @param onForgotPin - Callback function that is called when the user clicks the forgot pin button. @@ -233,6 +280,39 @@ export class W3SSdk { } } + /** + * Sets the callback function that is called when the user clicks the resend OTP email button. + * @param onResendOtpEmail - Callback function that is called when the user clicks the resend OTP email button. + */ + setOnResendOtpEmail(onResendOtpEmail: () => void): void { + this.onResendOtpEmail = onResendOtpEmail + } + + /** + * Sets up the instance. + * @param configs - Configurations. + * @param onLoginComplete - Callback function that is called when the page is redirected back from the social login provider and receives the verification result. + */ + private setupInstance( + configs?: Configs, + onLoginComplete?: LoginCompleteCallback + ) { + if (configs?.socialLoginConfigs?.apple && getApps().length === 0) { + this.firebaseApp = initializeApp(configs.socialLoginConfigs.apple) + } else if (getApps().length !== 0) { + this.firebaseApp = getApps()[0] + } + + this.onLoginComplete = onLoginComplete + this.configs = configs + this.deviceInfo = { + model: 'Web', + version: packageInfo.version, + } + + void this.execSocialLoginStatusCheck() + } + /** * Sets the challenge. * @param challenge - Challenge. @@ -291,6 +371,333 @@ export class W3SSdk { }, 1000 * 10) } + private performAppleLogin() { + if (!this.firebaseApp) { + void this.onLoginComplete?.( + { + code: 155140, + message: 'Please provide the Apple social login configurations.', + }, + undefined + ) + + return + } + + this.saveOAuthInfo(SocialLoginProvider.APPLE) + const provider = new OAuthProvider('apple.com') + const auth = getAuth(this.firebaseApp) + + void signInWithRedirect(auth, provider) + } + + private performFacebookLogin() { + if (!this?.configs?.socialLoginConfigs?.facebook) { + void this.onLoginComplete?.( + { + code: 155140, + message: 'Please provide the Facebook social login configurations.', + }, + undefined + ) + + return + } + + const { appId, redirectUri } = this.configs.socialLoginConfigs.facebook + + const { url = '', state = '' } = + this.generateOauthUrlWithParams( + SocialLoginProvider.FACEBOOK, + appId, + redirectUri + ) || {} + + this.saveOAuthInfo(SocialLoginProvider.FACEBOOK, state) + this.window.location.href = url + } + + private performGoogleLogin() { + if (!this.configs?.socialLoginConfigs?.google) { + void this.onLoginComplete?.( + { + code: 155140, + message: 'Please provide the Google social login configurations.', + }, + undefined + ) + + return + } + + const { clientId, redirectUri } = this.configs.socialLoginConfigs.google + + const { + url = '', + state = '', + nonce = '', + } = this.generateOauthUrlWithParams( + SocialLoginProvider.GOOGLE, + clientId, + redirectUri + ) || {} + + this.saveOAuthInfo(SocialLoginProvider.GOOGLE, state, nonce) + this.window.location.href = url + } + + /** + * Generates the OAuth URL with the necessary parameters. + * @param provider - Social login provider. + * @param id - Client ID or Application ID. + * @param redirectUri - Redirect URI. + * @returns OAuth URL with the necessary parameters. + */ + private generateOauthUrlWithParams( + provider: SocialLoginProvider, + id: string, + redirectUri: string + ): + | { + url: string + state: string + nonce?: string + } + | undefined { + const state = uuidv4() + + if (provider === SocialLoginProvider.GOOGLE) { + const scope = encodeURIComponent( + 'openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email' + ) + const responseType = encodeURIComponent('id_token token') + const nonce = uuidv4() + + return { + url: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${id}&redirect_uri=${encodeURIComponent( + redirectUri + )}&scope=${scope}&state=${state}&response_type=${responseType}&nonce=${nonce}`, + state, + nonce, + } + } else if (provider === SocialLoginProvider.FACEBOOK) { + const scope = encodeURIComponent('email') + + return { + url: `https://www.facebook.com/v13.0/dialog/oauth?client_id=${id}&redirect_uri=${encodeURIComponent( + redirectUri + )}&scope=${scope}&state=${state}&response_type=token`, + state, + } + } + } + /** + * Executes the social login status check before sending the token to the verification service. + */ + private async execSocialLoginStatusCheck(): Promise { + const socialLoginProvider = this.window.localStorage.getItem( + 'socialLoginProvider' + ) as SocialLoginProvider + + if (socialLoginProvider === SocialLoginProvider.APPLE) { + await this.handleAppleLoginResponse() + } else if (this.isValidHash(this.window.location.hash)) { + this.handleHashLoginResponse(socialLoginProvider) + } + } + + /** + * Handles the Apple login response. + * @returns Promise. + */ + private async handleAppleLoginResponse(): Promise { + const auth = getAuth(this.firebaseApp) + + try { + const result = await getRedirectResult(auth) + + if (!result || !this.extractTokenFromResultAndSave(result)) { + return + } + + // Send the token to the verification service and reset the social login provider + this.verifyTokenViaService() + this.window.localStorage.setItem('socialLoginProvider', '') + } catch (error) { + this.handleLoginFailure() + } + } + + /** + * Handles the hash login responses. + * @param socialLoginProvider - Social login provider. + */ + private handleHashLoginResponse( + socialLoginProvider: SocialLoginProvider + ): void { + const hashParams = new URLSearchParams(window.location.hash.slice(1)) + + if (socialLoginProvider === SocialLoginProvider.GOOGLE) { + this.handleGoogleLogin(hashParams) + } else if (socialLoginProvider === SocialLoginProvider.FACEBOOK) { + this.handleFacebookLogin(hashParams) + } + + // Send the token to the verification service + this.verifyTokenViaService() + + // Clear the hash + history.replaceState(null, '', window.location.href.split('#')[0]) + } + + private handleGoogleLogin(hashParams: URLSearchParams): void { + if ( + this.isLoginStateValid(hashParams) && + this.isLoginNonceValid(hashParams) + ) { + this.socialLoginToken = hashParams.get('id_token') + this.socialLoginProvider = SocialLoginProvider.GOOGLE + } + } + + private handleFacebookLogin(hashParams: URLSearchParams): void { + if (this.isLoginStateValid(hashParams)) { + this.socialLoginToken = hashParams.get('access_token') + this.socialLoginProvider = SocialLoginProvider.FACEBOOK + } + } + + private isLoginStateValid(hashParams: URLSearchParams): boolean { + return this.checkSocialLoginState(hashParams) + } + + private isLoginNonceValid(hashParams: URLSearchParams): boolean { + return this.checkSocialLoginNonce(hashParams) + } + + private isValidHash(hash: string): boolean { + const validHashPattern = + /^#(?:[a-zA-Z0-9-_.%]+=[^&]*&)*[a-zA-Z0-9-_.%]+=[^&]*$/ + + return validHashPattern.test(hash) + } + + private extractTokenFromResultAndSave(result: UserCredential): boolean { + const credential = OAuthProvider.credentialFromResult(result) + + if (credential && credential.idToken) { + this.socialLoginToken = credential.idToken + this.socialLoginProvider = SocialLoginProvider.APPLE + return true + } + + return false + } + + private handleLoginFailure(): void { + void this.onLoginComplete?.( + { + code: 155140, + message: 'Failed to validate the idToken / accessToken', + }, + undefined + ) + } + + private verifyTokenViaService(): void { + this.subscribeMessage() + this.appendIframe(false, 'sso/verify-token') + + setTimeout(() => { + if (!this.receivedResponseFromService) { + void this.onComplete?.( + { + code: 155706, + message: 'Network error', + }, + undefined + ) + } + }, 1000 * 10) + } + + /** + * Saves the OAuth information to the local storage in order to check the state and nonce value later. + * @param provider - Social login provider. + * @param state - State value. + * @param nonce - Nonce value. + */ + private saveOAuthInfo( + provider: SocialLoginProvider, + state?: string, + nonce?: string + ): void { + this.window.localStorage.setItem('socialLoginProvider', provider) + this.window.localStorage.setItem('state', state ?? '') + this.window.localStorage.setItem('nonce', nonce ?? '') + } + + /** + * Checks the state value from the social login response. + * @param hashParams - Hash parameters. + * @returns Indicates whether the state value is valid. + */ + private checkSocialLoginState(hashParams: URLSearchParams) { + const state = hashParams.get('state') + const storedState = this.window.localStorage.getItem('state') + + if (!storedState || state !== storedState) { + void this.onLoginComplete?.( + { + code: 155140, + message: 'Failed to validate the idToken / accessToken', + }, + undefined + ) + + return false + } + + return true + } + + /** + * Checks the nonce value from the social login response. Only id token is going to have nonce value. + * @param hashParams - Hash parameters. + * @returns Indicates whether the nonce value is valid. + */ + private checkSocialLoginNonce(hashParams: URLSearchParams): boolean { + const token = hashParams.get('id_token') + const decodedToken = decode(token || '') + + const errorPayload = { + code: 155140, + message: 'Failed to validate the idToken/ accessToken', + } + + if (decodedToken === null) { + void this.onLoginComplete?.(errorPayload, undefined) + + return false + } + + try { + const storedNonce = this.window.localStorage.getItem('nonce') + + if (!storedNonce || (decodedToken as JwtPayload)?.nonce !== storedNonce) { + void this.onLoginComplete?.(errorPayload, undefined) + + return false + } + } catch { + void this.onLoginComplete?.(errorPayload, undefined) + + return false + } + + return true + } + /** * Handles the postMessage event. * @param event - PostMessageEvent. @@ -308,8 +715,8 @@ export class W3SSdk { iframe?.contentWindow?.postMessage( { w3s: { - appSettings: this.appSettings, - auth: this.auth, + appSettings: this.configs?.appSettings, + auth: this.configs?.authentication, challenge: this.challenge, customizations: { securityQuestions: { @@ -321,9 +728,21 @@ export class W3SSdk { localizations: this.localizations, resources: this.resources, customLinks: this.customLinks, - ssoSettings: this.ssoSettings, }, deviceInfo: this.deviceInfo, + ssoVerification: { + token: this.socialLoginToken, + deviceToken: this.configs?.socialLoginConfigs?.deviceToken, + deviceEncryptionKey: + this.configs?.socialLoginConfigs?.deviceEncryptionKey, + socialLoginProvider: this.socialLoginProvider, + }, + emailVerification: { + deviceToken: this.configs?.socialLoginConfigs?.deviceToken, + deviceEncryptionKey: + this.configs?.socialLoginConfigs?.deviceEncryptionKey, + otpToken: this.configs?.socialLoginConfigs?.otpToken, + }, }, }, this.serviceUrl @@ -342,6 +761,38 @@ export class W3SSdk { this.closeModal() this.unSubscribeMessage() + } else if (event.data?.showUi) { + this.iframe.width = '100%' + this.iframe.height = '100%' + this.iframe.style.zIndex = '2147483647' + this.iframe.style.position = 'fixed' + this.iframe.style.top = '50%' + this.iframe.style.left = '50%' + this.iframe.style.transform = 'translate(-50%, -50%)' + this.iframe.style.display = '' + } else if (event.data?.onSocialLoginVerified) { + void this.onLoginComplete?.( + event.data.onSocialLoginVerified.error, + event.data.onSocialLoginVerified.result + ) + + this.closeModal() + this.unSubscribeMessage() + } else if (event.data?.onEmailLoginVerified) { + void this.onLoginComplete?.( + event.data.onEmailLoginVerified.error, + event.data.onEmailLoginVerified.result + ) + + if ( + event.data.onEmailLoginVerified.result && + !event.data.onEmailLoginVerified.error + ) { + this.unSubscribeMessage() + this.closeModal() + } + } else if (event.data?.onResendOtpEmail) { + this.onResendOtpEmail?.() } else if (event.data?.onError) { void this.onComplete?.(event.data?.error, undefined) } else if (event.data?.onClose) { diff --git a/src/types.ts b/src/types.ts index 76ae502..e22bbfa 100644 --- a/src/types.ts +++ b/src/types.ts @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +import type { FirebaseOptions } from 'firebase/app' + // Enums /** * ChallengeType. @@ -67,6 +69,7 @@ export enum ErrorCode { invalidPartnerId = 13, invalidMessage = 14, invalidPhone = 15, + userAlreadyExisted = 155101, userNotFound = 155102, userTokenNotFound = 155103, @@ -87,6 +90,24 @@ export enum ErrorCode { invalidEncryptionKey = 155118, userPinLocked = 155119, securityAnswersLocked = 155120, + + userOTPTokenExpiredError = 155130, + userOTPTokenInvalidError = 155131, + userOTPNotFoundError = 155132, + userOTPInvalidError = 155133, + userOTPNotMatchError = 155134, + userEmailInvalidError = 155135, + userEmailMismatchError = 155136, + deviceIDInvalidError = 155137, + emailSendingFailedError = 155138, + socialLoginTokenExpiredError = 155139, + socialLoginProviderAppIDNotMatchError = 155140, + userOTPIsLockedError = 155141, + userOTPSendCountsOverLimitError = 155142, + deviceTokenExpiredError = 155143, + deviceTokenInvalidError = 155144, + deviceTokenNotFoundError = 155145, + notEnoughFunds = 155201, notEnoughBalance = 155202, exceedWithdrawLimit = 155203, @@ -111,6 +132,7 @@ export enum ErrorCode { maxWalletLimitReached = 155502, walletSetIdMutuallyExclusive = 155503, metadataUnmatched = 155504, + userCanceled = 155701, launchUiFailed = 155702, pinCodeNotMatched = 155703, @@ -126,15 +148,15 @@ export enum ErrorCode { biometricsUserLockoutPermanent = 155714, biometricsUserNotAllowPermission = 155715, biometricsInternalError = 155716, + userSecretMissing = 155717, + invalidUserSecret = 155718, + userTokenMismatch = 155719, + walletIdNotFound = 156001, tokenIdNotFound = 156002, transactionIdNotFound = 156003, entityCredentialNotFound = 156004, walletSetIdNotFound = 156005, - - userSecretMissing = 155717, - invalidUserSecret = 155718, - userTokenMismatch = 155719, } // Settings and Authentication @@ -156,6 +178,70 @@ export interface Authentication { encryptionKey: string } +/** + * Social Login Provider. + */ +export enum SocialLoginProvider { + APPLE = 'Apple', + FACEBOOK = 'Facebook', + GOOGLE = 'Google', +} + +/** + * Social Login configurations, including Google, Facebook, and Apple. + */ +export interface SocialLoginConfigs { + google?: + | { + /** + * Google client ID. + */ + clientId: string + /** + * Google redirect URI. + */ + redirectUri: string + } + | undefined + facebook?: + | { + /** + * Facebook app ID. + */ + appId: string + /** + * Facebook redirect URI. + */ + redirectUri: string + } + | undefined + /** + * We use firebase for Apple login. You can provide the firebase configuration here. + */ + apple?: FirebaseOptions | undefined + deviceToken: string + deviceEncryptionKey: string + otpToken?: string +} + +/** + * Configuration settings for the SDK. + */ +export interface Configs { + /** + * Application settings. + */ + appSettings: AppSettings + /** + * Authentication settings. + */ + authentication?: Authentication + /** + * Social login configurations. + */ + socialLoginConfigs?: SocialLoginConfigs +} + // Challenge Related export interface Challenge { /** @@ -246,6 +332,36 @@ export interface SignTransactionResult extends ChallengeResult { } } +/** + * Result for oauth login. + */ +export interface OAuthInfo { + provider: SocialLoginProvider + scope?: string[] + ssoUserUUID?: string + ssoUserInfo?: { + email?: string + name?: string + phone?: string + } +} + +/** + * Social login result. + */ +export interface SocialLoginResult { + userToken: string + encryptionKey: string + refreshToken: string + oAuthInfo: OAuthInfo +} + +/** + * Email login result. + */ +export interface EmailLoginResult + extends Omit {} + export interface SecurityQuestion { /** * Custom security question. @@ -278,14 +394,29 @@ export type ChallengeCompleteCallback = ( | undefined ) => Promise | void +export type LoginCompleteCallback = ( + error: Error | undefined, + result: SocialLoginResult | EmailLoginResult | undefined +) => Promise | void + export interface PostMessageEvent extends MessageEvent { data: { onFrameReady?: boolean onComplete?: boolean onForgotPin?: boolean onLearnMore?: boolean + onResendOtpEmail?: boolean onError?: boolean onClose?: boolean + showUi?: boolean + onSocialLoginVerified?: { + error: Error | undefined + result: SocialLoginResult | undefined + } + onEmailLoginVerified?: { + error: Error | undefined + result: EmailLoginResult | undefined + } deviceId?: string error?: Error result?: ChallengeResult | SignMessageResult | SignTransactionResult @@ -296,6 +427,9 @@ export interface Common { continue?: string showPin?: string hidePin?: string + confirm?: string + sign?: string + retry?: string } export interface ConfirmPincode { @@ -356,6 +490,103 @@ export interface SecuritySummary { question?: string } +export interface SsoConfirm { + title?: string + headline?: string +} + +export interface TransactionRequest { + title?: string + subtitle?: string + + mainCurrency?: { + amount?: string | number + symbol?: string + } + exchangeValue?: { + amount?: string | number + symbol?: string + } + + fromLabel?: string + from?: string + toLabel?: string + to?: string[] + + networkFeeLabel?: string + networkFeeTip?: string + networkFee?: string + exchangeNetworkFee?: string + + totalLabel?: string + total?: string[] + exchangeTotalValue?: string + + rawTxDescription?: string + rawTx?: string +} + +export interface ContractInteraction { + title?: string + subtitle?: string + + mainCurrency?: { + amount?: string | number + symbol?: string + } + exchangeValue?: { + amount?: string | number + symbol?: string + } + + fromLabel?: string + from?: string + contractAddressLabel?: string + contractInfo?: string[] + + networkFeeLabel?: string + networkFeeTip?: string + networkFee?: string + exchangeNetworkFee?: string + + totalLabel?: string + total?: string[] + exchangeTotalValue?: string + + dataDetails?: { + dataDetailsLabel?: string + callData?: { + callDataLabel?: string + data?: string + } + abiInfo?: { + functionNameLabel?: string + functionName?: string + parametersLabel?: string + parameters?: string[] + } + } +} + +export interface SignatureRequest { + title?: string + contractName?: string + contractUrl?: string + + subtitle?: string + + descriptionLabel?: string + description?: string +} + +export interface EmailOtp { + title?: string + subtitle?: string + + resendHint?: string + resend?: string +} + export interface Localizations { common?: Common confirmInitPincode?: ConfirmPincode @@ -368,6 +599,11 @@ export interface Localizations { securityIntros?: SecurityIntros securityQuestions?: SecurityQuestions securitySummary?: SecuritySummary + ssoConfirm?: SsoConfirm + transactionRequest?: TransactionRequest + contractInteraction?: ContractInteraction + signatureRequest?: SignatureRequest + emailOtp?: EmailOtp } export interface ThemeColor { @@ -423,6 +659,26 @@ export interface ThemeColor { * Text input placeholder color, e.g. '#808080' or 'grey'. */ textPlaceholder?: string + /** + * Text color for contraction interaction collapsible toggle label text, e.g. '#000000' or 'black'. + */ + textDetailToggle?: string + /** + * Text color for interactive text, e.g. '#000000' or 'black'. + */ + textInteractive?: string + /** + * Container background color for interactive text, e.g. '#FFFFFF' or 'white'. + */ + interactiveBg?: string + /** + * Text color for tooltip content text, e.g. '#000000' or 'black'. + */ + tooltipText?: string + /** + * Background color for tooltip content, e.g. '#FFFFFF' or 'white'. + */ + tooltipBg?: string /** * Fill color for pincode input dot, e.g. '#FFFFFF' or 'white'. */ @@ -575,7 +831,7 @@ export interface Resources { */ securityIntroMain?: string /* - * Arrow icon for the dropdown. + * Arrow icon for the dropdown and collapsible section. */ dropdownArrow?: string /* @@ -590,6 +846,22 @@ export interface Resources { * Error icon for form validation. */ errorInfo?: string + /** + * Token icon for the transaction request page. + */ + transactionTokenIcon?: string + /** + * DApp icon for customization for the sign message page. + */ + dAppIcon?: string + /** + * Tooltip icon for customization. + */ + tipIcon?: string + /** + * Email icon for customization. + */ + emailIcon?: string /** * Font-family for customization. * E.g. \{ name: 'Edu TAS Beginner', url: 'https://fonts.googleapis.com/css2?family=Edu+TAS+Beginner:wght@400;500;600;700&display=swap' \}. @@ -606,10 +878,3 @@ export interface CustomLinks { */ learnMoreUrl?: string } - -export interface SsoSettings { - /** - * Controls whether the SSO UI is disabled. - */ - disableConfirmationUI?: boolean -}