import { Long } from 'bson' ; import { WebClient , createWebClient , RequestForm , RequestHeader , DataWebRequest } from './web-client' ; import { DefaultConfiguration , OAuthLoginConfig } from '../config' ; import { OAuthCredential } from '../oauth' ; import { AsyncCommandResult , DefaultRes , KnownDataStatusCode } from '../request' ; import { fillAHeader , fillBaseHeader , getUserAgent } from './header-util' ; import { AccessDataStruct , structToLoginData } from './struct' ; import { Win32XVCProvider , XVCProvider } from './xvc' ; /**
 * Login data
 */ export interface LoginData extends OAuthCredential { /**
     * User id
     */ userId : Long ; /**
     * Country iso
     */ countryIso : string ; /**
     * Country code
     */ countryCode : string ; /**
     * Account id
     */ accountId : number ; /**
     * Login server time
     */ serverTime : number ; /**
     * true if user data should be reset
     */ resetUserData : boolean ; /**
     * Story URL
     */ storyURL : string ; /**
     * OAuth token type
     */ tokenType : string ; /**
     * Auto login account id
     */ autoLoginAccountId : string ; /**
     * Displayed account id
     */ displayAccountId : string ; /**
     * Main device agent
     */ mainDeviceAgentName : string ; /**
     * Main device app version
     */ mainDeviceAppVersion : string ; } export interface LoginForm { email : string ; password : string ; } export interface TokenLoginForm extends LoginForm { autowithlock : boolean ; } /**
 * Status code for auth client results
 */ export enum KnownAuthStatusCode { INVALID_PHONE_NUMBER = 1 , SUCCESS_WITH_ACCOUNT = 10 , SUCCESS_WITH_DEVICE_CHANGED = 11 , MISMATCH_PASSWORD = 12 , EXCEED_LOGIN_LIMIT = 13 , MISMATCH_PHONE_NUMBER = 14 , EXCEED_PHONE_NUMBER_CHECK_LIMIT = 15 , NOT_EXIST_ACCOUNT = 16 , NEED_CHECK_PHONE_NUMBER = 20 , NEED_CHECK_QUIZ = 25 , DORMANT_ACCOUNT = 26 , RESTRICTED_ACCOUNT = 27 , LOGIN_FAILED = 30 , NOT_VERIFIED_EMAIL = 31 , MOBILE_UNREGISTERED = 32 , UNKNOWN_PHONE_NUMBER = 99 , SUCCESS_SAME_USER = 100 , SUCCESS_SAME_USER_BY_MIGRATION = 101 , TOO_MANY_REQUEST_A_DAY = - 20 , TOO_MANY_REQUEST_AT_A_TIME = - 30 , MISMATCH_PASSCODE = - 31 , EXCEED_DAILY_REQUEST_LIMIT = - 32 , EXCEED_DAILY_REQUEST_LIMIT_VOICECALL = - 33 , EXCEED_DAILY_REQUEST_LIMIT_WITHOUT_TOKEN = - 34 , DEVICE_NOT_REGISTERED = - 100 , ANOTHER_LOGON = - 101 , DEVICE_REGISTER_FAILED = - 102 , INVALID_DEVICE_REGISTER = - 110 , INVALID_PASSCODE = - 111 , PASSCODE_REQUEST_FAILED = - 112 , NEED_TERMS_AGREE = - 126 , DENIED_DEVICE_MODEL = - 132 , RESET_STEP = - 940 , NEED_PROTECTOR_AGREE = - 991 , ACCOUNT_RESTRICTED = - 997 , INVALID_STAGE_ERROR = - 998 , UPGRADE_REQUIRED = - 999 , VOICE_CALL_ONLY = - 10002 , ACCESSIBILITY_ARS_ONLY = - 10003 , MIGRATION_FAILURE = - 100001 , INVAILD_TOKEN = - 100002 , UNDEFINED = - 999999 } /**
 * Provides default pc login api which can obtain OAuthCredential
 */ export class AuthApiClient { private _client : DataWebRequest ; constructor ( client , private _name , private _deviceUUID , public config , public xvcProvider ) { this . _client = new DataWebRequest ( client ) ; } get name ( ) : string { return this . _name ; } get deviceUUID ( ) : string { return this . _deviceUUID ; } private async createAuthHeader ( form ) { const header = { } ; fillBaseHeader ( header , this . config ) ; fillAHeader ( header , this . config ) ; const userAgent = getUserAgent ( this . config ) ; header [ 'User-Agent' ] = userAgent ; header [ 'X-VC' ] = await this . calculateXVCKey ( this . deviceUUID , userAgent , form . email ) ; return header ; } private fillAuthForm ( form ) { form [ 'device_uuid' ] = this . _deviceUUID ; form [ 'device_name' ] = this . _name ; if ( this . config . deviceModel ) { form [ 'model_name' ] = this . config . deviceModel ; } return form ; } param { LoginForm } form param { boolean } forced async login ( form , forced = false ) { const res = await this . _client . requestData ( 'POST' , this . getApiPath ( 'login.json' ) , this . fillAuthForm ( { ... form , forced } ) , await this . createAuthHeader ( form ) ) ; if ( res . status !== KnownDataStatusCode . SUCCESS ) return { status : res . status , success : false } ; return { status : res . status , success : true , result : structToLoginData ( res as DefaultRes & AccessDataStruct , this . _deviceUUID ) , } ; } param { TokenLoginForm } form param { boolean } forced async loginToken ( form , forced = false ) { const res = await this . _client . requestData ( 'POST' , this . getApiPath ( 'login.json' ) , this . fillAuthForm ( { ... form , auto_login : true , forced } ) , await this . createAuthHeader ( form ) ) ; if ( res . status !== KnownDataStatusCode . SUCCESS ) return { status : res . status , success : false } ; return { status : res . status , success : true , result : structToLoginData ( res as DefaultRes & AccessDataStruct , this . _deviceUUID ) , } ; } param { LoginForm } form async requestPasscode ( form ) { const res = await this . _client . requestData ( 'POST' , this . getApiPath ( 'request_passcode.json' ) , this . fillAuthForm ( { ... form } ) , await this . createAuthHeader ( form ) ) ; return { status : res . status , success : res . status === KnownDataStatusCode . SUCCESS } ; } param { LoginForm } form param { string } passcode param { boolean } permanent async registerDevice ( form , passcode , permanent = true ) { const res = await this . _client . requestData ( 'POST' , this . getApiPath ( 'register_device.json' ) , this . fillAuthForm ( { ... form , passcode , permanent } ) , await this . createAuthHeader ( form ) ) ; return { status : res . status , success : res . status === KnownDataStatusCode . SUCCESS } ; } private async calculateXVCKey ( deviceUUID , userAgent , email ) { return ( await this . xvcProvider . toFullXVCKey ( deviceUUID , userAgent , email ) ) . substring ( 0 , 16 ) ; } private getApiPath ( api ) { return `${ this . config . agent }/account/${ api }` ; } param { string } name param { string } deviceUUID param { Partial < OAuthLoginConfig > } config param { XVCProvider } xvcProvider static async create ( name , deviceUUID , config = { } , xvcProvider ? ) { return new AuthApiClient ( await createWebClient ( 'https' , 'katalk.kakao.com' ) , name , deviceUUID , Object . assign ( { ... DefaultConfiguration } , config ) , xvcProvider ? xvcProvider : Win32XVCProvider ) ; } }