Files
alexis/lib/init.js
2023-08-01 12:47:58 +02:00

218 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict'
const os = require('os')
const fs = require('fs')
const path = require('path')
const homedir = require('homedir')
const Store = require('./store')
const phantomloader = require('./phantomloader')
const webserver = require('./webserver')
const Cookies = require('./cookies')
const Headers = require('./headers')
const Login = require('./login')
const proxy = require('./proxy')
// file & directory names
const DATA_DIR = '.alexis'
const PHANTOMFILE = os.platform() === 'win32' ? 'phantomjs.exe' : 'phantomjs'
// computes the data directory
const getDataDir = () => path.join(homedir(), DATA_DIR)
// checks if the data directory exists
const checkDataDirExists = () => fs.existsSync(getDataDir())
// creates the data directory
const createDataDir = () => fs.mkdirSync(getDataDir())
// checks if the PhantomJS binary exists
const checkPhantomExist = () => fs.existsSync(path.join(getDataDir(), PHANTOMFILE))
// checks if the given options are valid
const validateOptions = (options, verbose) => {
let missing = [];
['httpPort', 'email', 'pass'].forEach(option => {
if (!options[option]) missing.push(option)
})
if (verbose && missing.length > 0) return missing.join(', ')
if (missing.length > 0) return false
return true
}
// validate options
const optionsAreValid = (options = {}, invalidOptionsCb) => {
if (!options.interval) options.interval = 10
options.interval = options.interval * 1000
if(!validateOptions(options)) {
invalidOptionsCb()
return false
}
return true
}
// checks if data dir exists and creates it if not
const doCreateUserdataDirectory = (data_dir, logger) => {
if (!checkDataDirExists()) {
logger.log('SETUP', `Creating data directory: ${data_dir}`)
createDataDir()
}
}
// checks if Phantom is installed, downloads it if not
const mountPhantom = async (data_dir, logger) => {
if (!checkPhantomExist()) {
phantom_mounted = false
const phantom_path_name = path.join(data_dir, PHANTOMFILE)
logger.log('SETUP', 'Downloading Phantom')
return await Phantom.download(phantom_path_name, data_dir)
}
return true
}
// Initializing flow
const run = async (logger, options, invalidOptionsCb) => {
// helper variable to determine if cookies exist
let cookies_exist = false
// helper variable to determine if cookies are valid
let cookies_valid = false
// helper variable to determine if login did work
let login_success = false
// init store
let store = null
// device data store
let device_data = null
// init PhantomJS downlaoder
const Phantom = phantomloader(logger)
// cache data dir location
const data_dir = getDataDir()
// validate options
if (!optionsAreValid(options, invalidOptionsCb)) return false
// set up redux store
logger.log('SETUP', 'Creating in-memory store')
store = Store()
// check if data dir exists, else create
doCreateUserdataDirectory(data_dir, logger)
// checks if Phantom is installed, downloads it if not
const phantom_mounted = await mountPhantom(data_dir, logger)
// check if phantom is mounted
if (phantom_mounted !== true) {
logger.log('ERROR', 'Error with mounting Phantom')
return false
}
// everythings okay
logger.log('SETUP', 'Dependency check successful')
// cookie check
if (Cookies.checkJsonCookiesExist(data_dir) && Cookies.checkJsonCookiesExist(data_dir)) {
logger.log('SETUP', 'Cookies exist, trying to reuse them')
// validate existing cookies
try {
cookies_valid = await Cookies.validateCookie(data_dir)
device_data = cookies_valid[1]
cookies_valid = cookies_valid[0]
} catch (e) {
cookies_valid = false
}
// set flasg & log cookie state
if (cookies_valid) {
cookies_exist = true
login_success = true
logger.log('SETUP', 'Cookies valid, connection could be established')
} else {
cookies_exist = false
logger.log('SETUP', 'Cookies invalid, connection could not be established')
}
}
// create a new set of cookies by logging in
if (!cookies_exist) {
logger.log('SETUP', 'No cookies found or invalid, logging in to create a fresh pair')
try {
login_success = await Login.fetchInitialCookies(
Cookies.getJsonCookiePath(data_dir),
Cookies.getRawCookiePath(data_dir),
Headers.ua,
options.email,
options.pass,
path.join(data_dir, PHANTOMFILE),
)
} catch (error) {
console.log(error)
if (error === 'captcha') {
logger.log('ERROR', 'Login failed, we got a captcha notice. Please change your public IP and try again.')
} else {
logger.log('ERROR', 'Login failed, please check your credentials')
}
login_success = false
return false
}
// Login should´ve been successful, lets validate
logger.log('SETUP', 'Login successful')
// cookie check
if (Cookies.checkJsonCookiesExist(getDataDir()) && Cookies.checkJsonCookiesExist(getDataDir())) {
// validate existing cookies
try {
cookies_valid = await Cookies.validateCookie(getDataDir())
device_data = cookies_valid[1]
cookies_valid = cookies_valid[0]
} catch (e) {
cookies_valid = false
}
// set flasg & log cookie state
if (cookies_valid) {
logger.log('SETUP', 'Cookies valid, connection could be established')
} else {
logger.log('SETUP', 'Cookies invalid, connection could not be established')
return false
}
}
}
// set up proxy dialer
const Proxy = await proxy(logger, data_dir, store)
// initial fetch of data
logger.log('SETUP', 'Fetching initial data')
const initial_data = await Proxy.fetchAll()
logger.log('SETUP', 'Fetch finished')
// start webserver
logger.log('SETUP', 'Starting webserver')
try {
await webserver(logger, options.httpPort, store, Proxy)
} catch (error) {
logger.log('ERROR', `Problem starting webserver: ${error}`)
return false
}
// set up scheduler to periodically fetch data
logger.log('SETUP', `Setting up scheduler with interval: ${options.interval}ms`)
// display data about the echo devices we found
logger.log('ECHO', `Found ${device_data.devices.length} Device(s) connected with this account`)
device_data.devices.forEach(device => {
logger.log('ECHO', `---------------------------------`)
logger.log('ECHO', `Name: ${device.accountName}`)
logger.log('ECHO', `Id: ${device.deviceAccountId}`)
logger.log('ECHO', `Type: ${device.deviceFamily}`)
logger.log('ECHO', `Active: ${device.online}`)
logger.log('ECHO', `Mac Address: ${device.macAddress}`)
})
logger.log('ECHO', `---------------------------------`)
// setup done, system is ready to use
logger.log('SETUP', 'Setup finished. Ready to use. Have Fun!')
return true
}
module.exports = (logger) => {
return {
getDataDir,
checkDataDirExists,
createDataDir,
checkPhantomExist,
run: run.bind(this, logger)
}
}