From ce7b573fe35b7951eb608a9436974405efd15f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Trevi=C3=B1o?= Date: Sun, 4 Nov 2018 21:15:50 +0100 Subject: [PATCH] Refactor to serversetup --- app-cli/api/LoginApi.js | 54 ++- app-cli/api/MainApi.js | 81 +++- app-cli/api/SystemApi.js | 87 +++++ app-cli/captainduckduck.js | 32 +- app-cli/lib/login.js | 5 +- app-cli/lib/serversetup.js | 563 +++++++--------------------- app-cli/utils/constants.js | 4 +- app-cli/utils/fileHandler.js | 178 --------- app-cli/utils/loginHandler.js | 211 ----------- app-cli/utils/messageHandler.js | 18 +- app-cli/utils/validationsHandler.js | 17 +- 11 files changed, 406 insertions(+), 844 deletions(-) create mode 100644 app-cli/api/SystemApi.js delete mode 100644 app-cli/utils/fileHandler.js delete mode 100644 app-cli/utils/loginHandler.js diff --git a/app-cli/api/LoginApi.js b/app-cli/api/LoginApi.js index 57d1cd8..0a4ec4a 100644 --- a/app-cli/api/LoginApi.js +++ b/app-cli/api/LoginApi.js @@ -1,9 +1,59 @@ const MainApi = require("./MainApi") +const SystemApi = require("./SystemApi") +const { DEFAULT_PASSWORD } = require("../utils/constants") class LoginApi { - loginMachine(url, password) { + constructor() { + this.token = "" + + this.oldPassword = DEFAULT_PASSWORD + } + + setOldPassword(newPassword) { + this.oldPassword = newPassword + } + + setToken(newToken) { + this.token = newToken + } + + async loginMachine(baseUrl, password) { try { - return MainApi.post(url, { password }) + const data = await MainApi.post(`${baseUrl}/api/v1/login`, { password }) + const dataAsObject = JSON.parse(data) + + if (dataAsObject) { + this.setToken(dataAsObject.token) + } + + return data + } catch (e) { + throw e + } + } + + async changePass(baseUrl, newPassword) { + try { + const customOptions = { + headers: { + "x-captain-auth": LoginApi.token + } + } + const form = { + oldPassword: this.oldPassword, + newPassword + } + const data = await MainApi.post( + `${baseUrl}/api/v1/user/changepassword/`, + form, + customOptions + ) + + this.setToken(data.token) + + SystemApi.setIpAddressOfServer(baseUrl) + + return data } catch (e) { throw e } diff --git a/app-cli/api/MainApi.js b/app-cli/api/MainApi.js index 630e179..d60f8fe 100644 --- a/app-cli/api/MainApi.js +++ b/app-cli/api/MainApi.js @@ -1,33 +1,84 @@ const Request = require("request-promise") class MainApi { - get(url, config) { - return Request.get(url) - } - - post(url, form, config) { - const options = { - url, + constructor() { + this.sharedOptions = { headers: { "x-namespace": "captain" - }, + } + } + } + + _buildOptions(options) { + if (!options) return this.sharedOptions + + if (options.headers) { + options.headers = Object.assign( + {}, + this.sharedOptions.headers, + options.headers + ) + } + + return Object.assign({}, this.sharedOptions, options) + } + + get(url, options) { + const overrideOptions = this._buildOptions(options) + const optionsToSend = { + ...overrideOptions, + url, + method: "GET" + } + + return Request(optionsToSend) + } + + post(url, form, options) { + const overrideOptions = this._buildOptions(options) + const optionsToSend = { + ...overrideOptions, + url, method: "POST", form } - return Request(options) + return Request(optionsToSend) } - put(url, data, config) { - return Request.put(url, data) + put(url, form, options) { + const overrideOptions = this._buildOptions(options) + const optionsToSend = { + ...overrideOptions, + url, + method: "PUT", + form + } + + return Request(optionsToSend) } - patch(url, data, config) { - return Request.patch(url, data) + patch(url, form, options) { + const overrideOptions = this._buildOptions(options) + const optionsToSend = { + ...overrideOptions, + url, + method: "PATCH", + form + } + + return Request(optionsToSend) } - delete(url, data, config) { - return Request.delete(url) + delete(url, options) { + const overrideOptions = this._buildOptions(options) + const optionsToSend = { + ...overrideOptions, + url, + method: "DELETE" + } + + return Request(optionsToSend) } } diff --git a/app-cli/api/SystemApi.js b/app-cli/api/SystemApi.js new file mode 100644 index 0000000..5eed530 --- /dev/null +++ b/app-cli/api/SystemApi.js @@ -0,0 +1,87 @@ +const MainApi = require("./MainApi") +const LoginApi = require("./LoginApi") +// const spinnerUtil = require("../../utils/spinner") + +class SystemApi { + constructor() { + this.ipAddressOfServer = "" + + this.customDomainFromUser = "" + + this.newPasswordFirstTry = "" + } + + setCustomDomainFromUser(newCustomDomainFromUser) { + this.customDomainFromUser = newCustomDomainFromUser + } + + setIpAddressOfServer(newIpAddress) { + this.ipAddressOfServer = newIpAddress.trim() + } + + async setCustomDomain(baseUrl, rootDomain) { + try { + const customOptions = { + headers: { + "x-captain-auth": LoginApi.token + } + } + const data = await MainApi.post( + `${baseUrl}/api/v1/user/system/changerootdomain/`, + { + rootDomain + }, + customOptions + ) + + return data + } catch (e) { + throw e + } + } + + async enableHttps(baseUrl, emailAddress) { + const customOptions = { + headers: { + "x-captain-auth": LoginApi.token + } + } + + try { + const data = await MainApi.post( + `${baseUrl}/api/v1/user/system/enablessl/`, + { + emailAddress + }, + customOptions + ) + + return data + } catch (e) { + throw e + } + } + + async forceHttps(baseUrl, isEnabled = true) { + try { + const customOptions = { + headers: { + "x-captain-auth": LoginApi.token + } + } + const data = await MainApi.post( + `${baseUrl}/api/v1/user/system/forcessl/`, + { + isEnabled + }, + customOptions + ) + + return data + } catch (e) { + throw e + } + } +} + +module.exports = new SystemApi() diff --git a/app-cli/captainduckduck.js b/app-cli/captainduckduck.js index cd62b73..f11c9f8 100755 --- a/app-cli/captainduckduck.js +++ b/app-cli/captainduckduck.js @@ -8,24 +8,23 @@ const program = require("commander") updateNotifier({ pkg: packagejson }).notify({ isGlobal: true }) // Command actions -const list = require("./lib/list") -const logout = require("./lib/logout") +const serversetup = require("./lib/serversetup") const login = require("./lib/login") +const logout = require("./lib/logout") +const list = require("./lib/list") +// const deploy = require("./lib/deploy") // Setup program.version(packagejson.version).description(packagejson.description) -program - .command( - "serversetup", - "Performs necessary actions and prepares your Captain server." - ) - .command( - "deploy", - "Deploy your app (current directory) to a specific Captain machine. You'll be prompted to choose your Captain machine." - ) - // Commands +program + .command("serversetup") + .description("Performs necessary actions and prepares your Captain server.") + .action(() => { + serversetup() + }) + program .command("login") .description( @@ -49,6 +48,15 @@ program list() }) +program + .command("deploy") + .description( + "Deploy your app (current directory) to a specific Captain machine. You'll be prompted to choose your Captain machine." + ) + .action(() => { + // deploy() + }) + // Error on unknown commands program.on("command:*", () => { const wrongCommands = program.args.join(" ") diff --git a/app-cli/lib/login.js b/app-cli/lib/login.js index ef5c822..b388bcc 100644 --- a/app-cli/lib/login.js +++ b/app-cli/lib/login.js @@ -88,10 +88,7 @@ function login() { const baseUrl = `${handleHttp}${cleanUpUrl(captainAddress)}` try { - const data = await LoginApi.loginMachine( - `${baseUrl}/api/v1/login`, - captainPassword - ) + const data = await LoginApi.loginMachine(baseUrl, captainPassword) const response = JSON.parse(data) // TODO - This status should be 200 maybe? diff --git a/app-cli/lib/serversetup.js b/app-cli/lib/serversetup.js index 5b01350..ceb1899 100644 --- a/app-cli/lib/serversetup.js +++ b/app-cli/lib/serversetup.js @@ -1,218 +1,18 @@ -const program = require("commander") -const chalk = require("chalk") +const MachineHelper = require("../helpers/MachineHelper") +const SystemApi = require("../api/SystemApi") +const LoginApi = require("../api/LoginApi") const inquirer = require("inquirer") -const configstore = require("configstore") -const request = require("request") -const spinnerUtil = require("./utils/spinner") -const packagejson = require("./package.json") -const configs = new configstore(packagejson.name, { - captainMachines: [] -}) - -program.description("Easy setup for your Captain server.").parse(process.argv) - -if (program.args.length) { - console.error(chalk.red("Unrecognized commands:")) - - program.args.forEach(function(arg) { - console.log(chalk.red(arg)) - }) - - console.error(chalk.red("This command does not require any options. ")) - - process.exit(1) -} - -function findDefaultCaptainName() { - const machines = configs.get("captainMachines") - let currentSuffix = machines.length + 1 - - function getCaptainFullName(suffix) { - if (suffix < 10) { - suffix = "0" + suffix - } - - return "captain-" + suffix - } - - function isSuffixValid(suffixNumber) { - for (let i = 0; i < machines.length; i++) { - const m = machines[i] - - if (m.name === getCaptainFullName(suffixNumber)) { - return false - } - } - - return true - } - - while (!isSuffixValid(currentSuffix)) { - currentSuffix++ - } - - return getCaptainFullName(currentSuffix) -} - -function isIpAddress(ipaddress) { - if ( - /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( - ipaddress - ) - ) { - return true - } - - return false -} - -console.log("\nSetup your Captain server\n") - -const SAMPLE_IP = "123.123.123.123" -let authTokenFromLogin = null -let ipAddressOfServer = null -let customDomainFromUser = null -let newPasswordFirstTry = null -let oldPassword = "captain42" - -function setCustomDomain(baseApiUrl, customDomain) { - return apiEndpointWithLoading("Changing Domain...")( - "POST", - baseApiUrl, - "/api/v1/user/system/changerootdomain/", - { - rootDomain: customDomain - } - ) -} - -function enableHttps(baseApiUrl, emailAddress) { - return apiEndpointWithLoading("Enabling SSL...")( - "POST", - baseApiUrl, - "/api/v1/user/system/enablessl/", - { - emailAddress: emailAddress - } - ) -} - -function changePass(baseApiUrl, newPass) { - return apiEndpointWithLoading("Changing Password...")( - "POST", - baseApiUrl, - "/api/v1/user/changepassword/", - { - oldPassword: oldPassword, - newPassword: newPass - } - ) -} - -function forceHttps(baseApiUrl) { - return apiEndpointWithLoading("Forcing SSL...")( - "POST", - baseApiUrl, - "/api/v1/user/system/forcessl/", - { - isEnabled: true - } - ) -} - -// returns promise that resolves to auth token -// rejects with ErrorCode or null -function login(baseApiUrl, password) { - return apiEndpointWithLoading("Login...")( - "POST", - baseApiUrl, - "/api/v1/login", - { - password: password - } - ).then(function(data) { - return data.token - }) -} - -function apiEndpointWithLoading(message) { - return (method, baseApiUrl, endpoint, dataToSend) => { - return apiEndpoint(method, baseApiUrl, endpoint, dataToSend, message) - } -} - -function apiEndpoint(method, baseApiUrl, endpoint, dataToSend, message) { - const options = { - url: baseApiUrl + endpoint, - headers: { - "x-namespace": "captain", - "x-captain-auth": authTokenFromLogin - }, - method: method, - form: dataToSend - } - - return new Promise(function(res, rej) { - let spinner - - if (message) { - spinner = spinnerUtil.start(message) - } - - var callback = function(error, response, body) { - try { - if (!error && response.statusCode === 200) { - const data = JSON.parse(body) - - if (data.status !== 100) { - if (spinner) { - spinnerUtil.fail(spinner) - } - - rej(data) - - return - } - - if (spinner) { - spinnerUtil.succeed(spinner) - } - - res(data) - - return - } - - if (error) { - throw new Error(error) - } - - throw new Error( - response ? JSON.stringify(response, null, 2) : "Response NULL" - ) - } catch (error) { - if (spinner) { - spinnerUtil.fail(spinner) - } - - console.error( - chalk.red( - `Something bad happened. Cannot connect to "${baseApiUrl} ${endpoint}"` - ) - ) - - const errorMessage = error.message ? error.message : error - - console.error(`${chalk.red(errorMessage)}\n`) - - process.exit(0) - } - } - - request(options, callback) - }) -} - +const { findDefaultCaptainName } = require("../utils/loginHelpers") +const { isIpAddress } = require("../utils/validationsHandler") +const { SAMPLE_IP, DEFAULT_PASSWORD } = require("../utils/constants") +const { + printMessage, + printErrorAndExit, + printError, + printMessageAndExit, + errorHandler +} = require("../utils/messageHandler") +let newPasswordFirstTry = undefined const questions = [ { type: "list", @@ -222,24 +22,18 @@ const questions = [ "\nmkdir /captain && docker run -v /var/run/docker.sock:/var/run/docker.sock dockersaturn/captainduckduck ?", default: "Yes", choices: ["Yes", "No"], - filter: function(value) { - return new Promise(function(res, rej) { - if (value === "Yes") { - res(true) + filter: value => { + const answerFromUser = value.trim() - return - } + if (answerFromUser === "Yes") return answerFromUser - console.log( - "\n\nCannot start the setup process if Captain is not installed." - ) + printMessage( + "\n\nCannot start the setup process if Captain is not installed." + ) - console.log( - "Please read tutorial on CaptainDuckDuck.com\n to learn how to install CaptainDuckDuck on a server.\n" - ) - - process.exit(0) - }) + printMessageAndExit( + "Please read tutorial on CaptainDuckDuck.com to learn how to install CaptainDuckDuck on a server." + ) } }, { @@ -247,88 +41,50 @@ const questions = [ default: SAMPLE_IP, name: "captainAddress", message: "Enter IP address of your captain server:", - filter: function(value) { - return new Promise(function(res, rej) { - if (value === SAMPLE_IP) { - rej("Enter a valid IP Address") + filter: async value => { + const ipFromUser = value.trim() - return - } + if (ipFromUser === SAMPLE_IP || !isIpAddress(ipFromUser)) { + printErrorAndExit(`\nThis is an invalid IP Address: ${ipFromUser}`) + } - if (!isIpAddress(value.trim())) { - rej("This is an invalid IP Address: " + value) + try { + // login using captain42. and set the ipAddressToServer + const data = await LoginApi.loginMachine( + `http://${ipFromUser}:3000`, + DEFAULT_PASSWORD + ) - return - } + SystemApi.setIpAddressOfServer(ipFromUser) - ipAddressOfServer = value.trim() - - //login using captain42. - - return login("http://" + ipAddressOfServer + ":3000", oldPassword) - .then(function(authTokenFetched) { - authTokenFromLogin = authTokenFetched - - res(ipAddressOfServer) - }) - .catch(function(error) { - // if error is anything but password wrong, exit here... - if (error.status == 1105) { - authTokenFromLogin = null - - res(ipAddressOfServer) - - return - } - - console.log("") - - if (error.status) { - console.log(chalk.red(`Error: ${error.status}`)) - - console.log(chalk.red(`Error: ${error.description}`)) - } else { - console.log(chalk.red(`Error: ${error}`)) - } - - process.exit(0) - }) - }) + // All went well + if (data) return ipFromUser + } catch (e) { + errorHandler(e) + } } }, { type: "password", name: "captainOriginalPassword", message: "Enter your current password:", - when: function() { - return !authTokenFromLogin - }, - filter: function(value) { - return new Promise(function(res, rej) { - console.log("") + when: () => !LoginApi.token, + filter: async value => { + try { + const captainPasswordFromUser = value.trim() + const data = await LoginApi.loginMachine( + `http://${SystemApi.ipAddressOfServer}:3000`, + captainPasswordFromUser + ) - return login("http://" + ipAddressOfServer + ":3000", value) - .then(function(authTokenFetched) { - authTokenFromLogin = authTokenFetched + if (data) { + SystemApi.setIpAddressOfServer(captainPasswordFromUser) - oldPassword = value - - res(value) - }) - .catch(function(error) { - console.log("") - - if (error.status) { - console.log(chalk.red("Error: " + error.status)) - - console.log(chalk.red("Error: " + error.description)) - } else { - console.log(chalk.red("Error: " + error)) - } - - process.exit(0) - }) - }) + LoginApi.setOldPassword(captainPasswordFromUser) + } + } catch (e) { + errorHandler(e) + } } }, { @@ -338,136 +94,103 @@ const questions = [ "Enter a root domain for this Captain server. For example, enter test.yourdomain.com if you" + " setup your DNS to point *.test.yourdomain.com to ip address of your server" + ": ", - filter: function(value) { - return new Promise(function(res, rej) { - value = value.trim() + filter: async value => { + try { + const captainRootDomainFromUser = value.trim() + const data = await SystemApi.setCustomDomain( + `http://${SystemApi.ipAddressOfServer}:3000`, + captainRootDomainFromUser + ) - customDomainFromUser = "captain." + value + if (data) { + const newCustomDomainFromUser = `captain.${captainRootDomainFromUser}` - return setCustomDomain("http://" + ipAddressOfServer + ":3000", value) - .then(function() { - res(customDomainFromUser) - }) - .catch(function(error) { - if (error.status) { - console.log(chalk.red(`Error: ${error.status}`)) + SystemApi.setCustomDomainFromUser(newCustomDomainFromUser) - console.log(chalk.red(`Error: ${error.description}`)) - } else { - console.log(chalk.red(`Error: ${error}`)) - } - - process.exit(0) - }) - }) + return captainRootDomainFromUser + } + } catch (e) { + errorHandler(e) + } } }, { type: "input", name: "emailAddress", message: "Enter your 'valid' email address to enable HTTPS: ", - filter: function(value) { - return new Promise(function(res, rej) { - console.log("") + filter: async value => { + try { + const emailAddressFromUser = value.trim() + const { customDomainFromUser } = SystemApi - value = value.trim() + await SystemApi.enableHttps( + `http://${customDomainFromUser}`, + emailAddressFromUser + ) - return enableHttps("http://" + customDomainFromUser, value) - .then(function() { - return forceHttps("https://" + customDomainFromUser) - }) - .then(function() { - res(value) - }) - .catch(function(error) { - console.log("") + const data = await SystemApi.forceHttps( + `https://${customDomainFromUser}` + ) - if (error.status) { - console.log(chalk.red(`Error: ${error.status}`)) - - console.log(chalk.red(`Error: ${error.description}`)) - } else { - console.log(chalk.red(`Error: ${error}`)) - } - - process.exit(0) - }) - }) + if (data) return emailAddressFromUser + } catch (e) { + errorHandler(e) + } } }, { type: "password", name: "newPasswordFirstTry", message: "Enter a new password:", - filter: function(value) { - return new Promise(function(res, rej) { - newPasswordFirstTry = value + filter: value => { + newPasswordFirstTry = value - res(value) - }) + return value } }, { type: "password", name: "newPassword", message: "Enter a new password:", - filter: function(value) { - return new Promise(function(res, rej) { - if (newPasswordFirstTry !== value) { - rej("Passwords do not match") - //process.exit(0); + filter: async value => { + const { customDomainFromUser } = SystemApi - return + try { + const confirmPasswordValueFromUser = value + const machineUrl = `https://${customDomainFromUser}` + + if (newPasswordFirstTry !== confirmPasswordValueFromUser) { + printErrorAndExit("Passwords do not match") } - return changePass("https://" + customDomainFromUser, value) - .then(function() { - return login("https://" + customDomainFromUser, value) - }) - .then(function(token) { - authTokenFromLogin = token + const changePassData = await LoginApi.changePass( + machineUrl, + confirmPasswordValueFromUser + ) - res(value) - }) - .catch(function(error) { - console.log("") + if (changePassData) { + const loginData = await LoginApi.login( + machineUrl, + confirmPasswordValueFromUser + ) - if (error.status) { - console.log(chalk.red(`Error: ${error.status}`)) + if (loginData) return + } + } catch (e) { + printError( + "\nIMPORTANT!! Server setup is completed by password is not changed." + ) - console.log(chalk.red(`Error: ${error.description}`)) - } else { - console.log(chalk.red(`Error: ${error}`)) - } + printError("\nYou CANNOT use serversetup anymore. To continue:") - console.log( - chalk.red( - "\nIMPORTANT!! Server setup is completed by password is not changed." - ) - ) + printError( + `\n- Go to https://${customDomainFromUser} login with default password and change the password in settings.` + ) - console.log( - chalk.red("You CANNOT use serversetup anymore. To continue: ") - ) - - console.log( - chalk.red( - "- Go to https://" + - customDomainFromUser + - " login with default password and change the password in settings." - ) - ) - - console.log( - chalk.red( - "- In terminal (here), type captainduckduck login and enter this as your root domain: " + - customDomainFromUser - ) - ) - - process.exit(0) - }) - }) + printErrorAndExit( + `\n- In terminal (here), type captainduckduck login and enter this as your root domain: ${customDomainFromUser}` + ) + } } }, { @@ -475,14 +198,14 @@ const questions = [ name: "captainName", message: "Enter a name for this Captain machine:", default: findDefaultCaptainName(), - validate: function(value) { - const machines = configs.get("captainMachines") + validate: value => { + const newMachineName = value.trim() - for (let i = 0; i < machines.length; i++) { - if (machines[i].name === value) { - return `${value} already exist. If you want to replace the existing entry, you have to first use command, and then re-login.` - } - } + MachineHelper.machines.map( + machine => + machine.name === newMachineName && + `${newMachineName} already exist. If you want to replace the existing entry, you have to first use command, and then re-login.` + ) if (value.match(/^[-\d\w]+$/i)) { return true @@ -493,22 +216,26 @@ const questions = [ } ] -inquirer.prompt(questions).then(function(answers) { - var captainAddress = "https://" + customDomainFromUser +function serversetup() { + printMessage("\nSetup your Captain server\n") - const machines = configs.get("captainMachines") + inquirer.prompt(questions).then(answers => { + var captainAddress = `https://${SystemApi.customDomainFromUser}` - machines.push({ - authToken: authTokenFromLogin, - baseUrl: captainAddress, - name: answers.captainName + const newMachine = { + authToken: LoginApi.token, + baseUrl: captainAddress, + name: answers.captainName + } + + MachineHelper.addMachine(newMachine) + + printMessage(`\n\nCaptain is available at ${captainAddress}`) + + printMessage( + "\nFor more details and docs see http://www.captainduckduck.com\n\n" + ) }) +} - configs.set("captainMachines", machines) - - console.log(`\n\nCaptain is available at ${captainAddress}`) - - console.log( - "\nFor more details and docs see http://www.captainduckduck.com\n\n" - ) -}) +module.exports = serversetup diff --git a/app-cli/utils/constants.js b/app-cli/utils/constants.js index 0c5224c..5862009 100644 --- a/app-cli/utils/constants.js +++ b/app-cli/utils/constants.js @@ -1,3 +1,5 @@ const SAMPLE_DOMAIN = "captain.captainroot.yourdomain.com" +const SAMPLE_IP = "123.123.123.123" +const DEFAULT_PASSWORD = "captain42" -module.exports = { SAMPLE_DOMAIN } +module.exports = { SAMPLE_DOMAIN, SAMPLE_IP, DEFAULT_PASSWORD } diff --git a/app-cli/utils/fileHandler.js b/app-cli/utils/fileHandler.js deleted file mode 100644 index 1358c6a..0000000 --- a/app-cli/utils/fileHandler.js +++ /dev/null @@ -1,178 +0,0 @@ -const fs = require("fs-extra") -const chalk = require("chalk") -const request = require("request") -const ProgressBar = require("progress") -const ora = require("ora") -const configstore = require("configstore") -const packagejson = require("./package.json") -const { requestLogin } = require("./utils/loginHandler") -const configs = new configstore(packagejson.name, { - captainMachines: [], - apps: [] -}) - -function sendFileToCaptain( - machineToDeploy, - zipFileFullPath, - appName, - gitHash, - branchToPush -) { - console.log("Uploading file to " + machineToDeploy.baseUrl) - - const fileSize = fs.statSync(zipFileFullPath).size - const fileStream = fs.createReadStream(zipFileFullPath) - const barOpts = { - width: 20, - total: fileSize, - clear: true - } - const bar = new ProgressBar( - " uploading [:bar] :percent (ETA :etas)", - barOpts - ) - - fileStream.on("data", function(chunk) { - bar.tick(chunk.length) - }) - - let spinner - - fileStream.on("end", function() { - console.log(" ") - - console.log("This might take several minutes. PLEASE BE PATIENT...") - - spinner = ora("Building your source code...").start() - - spinner.color = "yellow" - }) - - const options = { - url: - machineToDeploy.baseUrl + - "/api/v1/user/appData/" + - appName + - "/?detached=1", - headers: { - "x-namespace": "captain", - "x-captain-auth": machineToDeploy.authToken - }, - method: "POST", - formData: { - sourceFile: fileStream, - gitHash: gitHash - } - } - - function callback(error, response, body) { - if (spinner) { - spinner.stop() - } - - if (fs.pathExistsSync(zipFileFullPath) && !getSuppliedTarFile()) { - fs.removeSync(zipFileFullPath) - } - - try { - if (!error && response.statusCode === 200) { - const data = JSON.parse(body) - - if (data.status === 1106) { - // expired token - requestLogin( - machineToDeploy.name, - machineToDeploy.baseUrl, - function callback(machineToDeployNew) { - deployTo(machineToDeployNew, branchToPush, appName) - } - ) - - return - } - - if (data.status !== 100 && data.status !== 101) { - throw new Error(JSON.stringify(data, null, 2)) - } - - savePropForDirectory(APP_NAME, appName) - - savePropForDirectory(BRANCH_TO_PUSH, branchToPush) - - savePropForDirectory(MACHINE_TO_DEPLOY, machineToDeploy) - - if (data.status === 100) { - console.log(chalk.green("Deployed successfully: ") + appName) - console.log(" ") - } else if (data.status === 101) { - console.log(chalk.green("Building started: ") + appName) - console.log(" ") - - startFetchingBuildLogs(machineToDeploy, appName) - } - - return - } - - if (error) { - throw new Error(error) - } - - throw new Error( - response ? JSON.stringify(response, null, 2) : "Response NULL" - ) - } catch (error) { - console.error( - chalk.red('\nSomething bad happened. Cannot deploy "' + appName + '"\n') - ) - - if (error.message) { - try { - var errorObj = JSON.parse(error.message) - if (errorObj.status) { - console.error(chalk.red("\nError code: " + errorObj.status)) - console.error( - chalk.red("\nError message:\n\n " + errorObj.description) - ) - } else { - throw new Error("NOT API ERROR") - } - } catch (ignoreError) { - console.error(chalk.red(error.message)) - } - } else { - console.error(chalk.red(error)) - } - console.log(" ") - } - } - - request(options, callback) -} - -// Sets default value for propType that is stored in a directory to propValue. -// Replaces saveAppForDirectory -function savePropForDirectory(propType, propValue) { - const apps = configs.get("apps") - - for (let i = 0; i < apps.length; i++) { - const app = apps[i] - - if (app.cwd === process.cwd()) { - app[propType] = propValue - - configs.set("apps", apps) - - return - } - } - - apps.push({ - cwd: process.cwd(), - [propType]: propValue - }) - - configs.set("apps", apps) -} - -module.exports = sendFileToCaptain diff --git a/app-cli/utils/loginHandler.js b/app-cli/utils/loginHandler.js deleted file mode 100644 index fa5c779..0000000 --- a/app-cli/utils/loginHandler.js +++ /dev/null @@ -1,211 +0,0 @@ -const inquirer = require("inquirer") -const chalk = require("chalk") -const request = require("request") -const configstore = require("configstore") -const packagejson = require("../package.json") -const configs = new configstore(packagejson.name, { - captainMachines: [] -}) - -function requestLogin(serverName, serverAddress, loginCallback) { - console.log("Your auth token is not valid anymore. Try to login again.") - - const questions = [ - { - type: "password", - name: "captainPassword", - message: "Please enter your password for " + serverAddress, - validate: function(value) { - if (value && value.trim()) { - return true - } - - return "Please enter your password for " + serverAddress - } - } - ] - - function updateAuthTokenInConfigStoreAndReturn(authToken) { - const machines = configs.get("captainMachines") - - for (let i = 0; i < machines.length; i++) { - if (machines[i].name === serverName) { - machines[i].authToken = authToken - - configs.set("captainMachines", machines) - - console.log("You are now logged back in to " + serverAddress) - - return machines[i] - } - } - } - - inquirer.prompt(questions).then(passwordAnswers => { - var { captainPassword } = passwordAnswers - - const options = { - url: serverAddress + "/api/v1/login", - headers: { - "x-namespace": "captain" - }, - method: "POST", - form: { - password: captainPassword - } - } - - function callback(error, response, body) { - try { - if (!error && response.statusCode === 200) { - const data = JSON.parse(body) - - if (data.status !== 100) { - throw new Error(JSON.stringify(data, null, 2)) - } - - var newMachineToDeploy = updateAuthTokenInConfigStoreAndReturn( - data.token - ) - - loginCallback(newMachineToDeploy) - - return - } - - if (error) { - throw new Error(error) - } - - throw new Error( - response ? JSON.stringify(response, null, 2) : "Response NULL" - ) - } catch (error) { - if (error.message) { - try { - var errorObj = JSON.parse(error.message) - - if (errorObj.status) { - console.error(chalk.red("\nError code: " + errorObj.status)) - - console.error( - chalk.red("\nError message:\n\n " + errorObj.description) - ) - } else { - throw new Error("NOT API ERROR") - } - } catch (ignoreError) { - console.error(chalk.red(error.message)) - } - } else { - console.error(chalk.red(error)) - } - - console.log(" ") - } - - process.exit(0) - } - - request(options, callback) - }) -} - -function requestLoginAuth(serverAddress, password, authCallback) { - const options = { - url: serverAddress + "/api/v1/login", - headers: { - "x-namespace": "captain" - }, - method: "POST", - form: { - password: password - } - } - - function callback(error, response, body) { - try { - if (!error && response.statusCode === 200) { - const data = JSON.parse(body) - - if (data.status !== 100) { - throw new Error(JSON.stringify(data, null, 2)) - } - - authCallback(data.token) - - return - } - - if (error) { - throw new Error(error) - } - - throw new Error( - response ? JSON.stringify(response, null, 2) : "Response NULL" - ) - } catch (error) { - if (error.message) { - try { - var errorObj = JSON.parse(error.message) - - if (errorObj.status) { - console.error(chalk.red("\nError code: " + errorObj.status)) - - console.error( - chalk.red("\nError message:\n\n " + errorObj.description) - ) - } else { - throw new Error("NOT API ERROR") - } - } catch (ignoreError) { - console.error(chalk.red(error.message)) - } - } else { - console.error(chalk.red(error)) - } - - console.log(" ") - } - - process.exit(0) - } - - request(options, callback) -} - -function isAuthTokenValid(machineToDeploy, appName, isAuthTokenValidCallback) { - const options = { - url: machineToDeploy.baseUrl + "/api/v1/user/appDefinitions/", - headers: { - "x-namespace": "captain", - "x-captain-auth": machineToDeploy.authToken - }, - method: "GET" - } - - function callback(error, response, body) { - try { - if (!error && response.statusCode === 200) { - const data = JSON.parse(body) - - if (data.status === 1106 || data.status === 1105) { - isAuthTokenValidCallback(false) - } else { - isAuthTokenValidCallback(true) - } - } - } catch (error) { - // This is just a sanity check. We only fire FALSE (i.e. expired) if we know it's expired or password is wrong - isAuthTokenValidCallback(true) - } - } - - request(options, callback) -} - -module.exports = { - requestLogin, - requestLoginAuth, - isAuthTokenValid -} diff --git a/app-cli/utils/messageHandler.js b/app-cli/utils/messageHandler.js index 9ae72ec..f681a14 100644 --- a/app-cli/utils/messageHandler.js +++ b/app-cli/utils/messageHandler.js @@ -4,6 +4,12 @@ function printMessage(message) { console.log(message) } +function printMessageAndExit(message) { + console.log(message) + + process.exit(0) +} + function printGreenMessage(message) { console.log(`${chalk.green(message)}`) } @@ -18,9 +24,19 @@ function printErrorAndExit(error) { process.exit(0) } +function errorHandler(error) { + if (error.status) { + printErrorAndExit(`\nError: ${error.status}\nError: ${error.description}`) + } else { + printErrorAndExit(`\nError: ${error}`) + } +} + module.exports = { printMessage, + printMessageAndExit, printErrorAndExit, printError, - printGreenMessage + printGreenMessage, + errorHandler } diff --git a/app-cli/utils/validationsHandler.js b/app-cli/utils/validationsHandler.js index 032770f..90a984f 100644 --- a/app-cli/utils/validationsHandler.js +++ b/app-cli/utils/validationsHandler.js @@ -1,5 +1,5 @@ const fs = require("fs-extra") -const { printErrorAndExit } = require("./errorHandler") +const { printErrorAndExit } = require("./messageHandler") function validateIsGitRepository() { const gitFolderExists = fs.pathExistsSync("./.git") @@ -21,7 +21,20 @@ function validateDefinitionFile() { } } +function isIpAddress(ipaddress) { + if ( + /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test( + ipaddress + ) + ) { + return true + } + + return false +} + module.exports = { validateIsGitRepository, - validateDefinitionFile + validateDefinitionFile, + isIpAddress }