import { IgApiClient , IgCheckpointError , IgLoginTwoFactorRequiredError , } from 'instagram-private-api' ; import { Config } from './core/config' ; import { User } from './types' ; import inquirer from 'inquirer' ; import fs from 'fs' ; import logger from './core/logging' ; interface sessionFile { cookie : any ; user : any ; seed : string ; restore : boolean ; } function parseSession ( filepath ) { let cookie = null ; let user = null ; let seed = null ; let restore = false ; if ( fs . existsSync ( filepath ) ) { const content = fs . readFileSync ( filepath , 'utf-8' ) ; const data = JSON . parse ( content ) ; cookie = data . cookie ; seed = data . seed ; user = data . user ; restore = true ; } const config = { cookie , user , seed , restore , } ; return config ; } function restore ( config ) { const additionalConfig = parseSession ( config . sessionPath ) ; config . restore = additionalConfig . restore ; config . cookie = additionalConfig . cookie ; config . seed = additionalConfig . seed || config . seed ; config . user = additionalConfig . user ; } async function solveChallenge ( client ) { await client . challenge . auto ( true ) ; const { code } = await inquirer . prompt ( [ { type : 'input' , name : 'code' , message : 'Enter sms / email code:' , } ] ) ; const res = await client . challenge . sendSecurityCode ( code ) ; return res . logged_in_user ! ; } async function twoFactorLogin ( client , config , err ) { const twoFactorIdentifier = err . response . body . two_factor_info . two_factor_identifier ; if ( ! twoFactorIdentifier ) { throw 'Unable to login, no 2fa identifier found' ; } const { code } = await inquirer . prompt ( [ { type : 'input' , name : 'code' , message : 'Enter sms code:' , } , ] ) ; return await client . account . twoFactorLogin ( { username : config . username , verificationCode : code , twoFactorIdentifier , verificationMethod : '1' , trustThisDevice : '1' , } ) ; } async function saveSession ( client , config ) { const cookie = await client . state . serializeCookieJar ( ) ; const { sessionPath , user , seed } = config ; fs . writeFile ( sessionPath , JSON . stringify ( { cookie , seed , user } ) , 'utf-8' , err => err ? logger . error ( err ) : void 0 ) ; logger . info ( 'session saved' ) ; } async function login ( client , config ) { if ( ! config . reset ) restore ( config ) ; client . state . generateDevice ( config . seed ) ; if ( config . restore ) { await client . state . deserializeCookieJar ( config . cookie ) ; try { const tl = client . feed . timeline ( 'warm_start_fetch' ) ; await tl . items ( ) ; logger . info ( 'session restored' ) ; return config . user ; } catch { logger . info ( 'session expired, going for relogin' ) ; } } logger . info ( `logging in with user: ${ config . username } ...` ) ; await client . simulate . preLoginFlow ( ) ; let user = null ; try { user = await client . account . login ( config . username , config . password ) ; } catch ( e ) { if ( e instanceof IgCheckpointError ) { user = await solveChallenge ( client ) ; } else if ( e instanceof IgLoginTwoFactorRequiredError ) { user = await twoFactorLogin ( client , config , e ) ; } } await client . simulate . postLoginFlow ( ) ; config . user = user ; logger . info ( `user: ${ config . username } logged in successfully` ) ; await saveSession ( client , config ) ; return user ! ; } export default login ;