UNPKG

botpress

Version:

The world's first CMS for bots. Easily create, manage and extend chatbots.

299 lines (234 loc) 8.98 kB
'use strict'; var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _bluebird = require('bluebird'); var _bluebird2 = _interopRequireDefault(_bluebird); var _prompt = require('prompt'); var _prompt2 = _interopRequireDefault(_prompt); var _chalk = require('chalk'); var _chalk2 = _interopRequireDefault(_chalk); var _validUrl = require('valid-url'); var _validUrl2 = _interopRequireDefault(_validUrl); var _axios = require('axios'); var _axios2 = _interopRequireDefault(_axios); var _promptConfirm = require('prompt-confirm'); var _promptConfirm2 = _interopRequireDefault(_promptConfirm); var _mkdirp = require('mkdirp'); var _mkdirp2 = _interopRequireDefault(_mkdirp); var _os = require('os'); var _os2 = _interopRequireDefault(_os); var _get = require('lodash/get'); var _get2 = _interopRequireDefault(_get); var _util = require('../util'); var _util2 = _interopRequireDefault(_util); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new _bluebird2.default(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return _bluebird2.default.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } const AUTH_FILE = '.auth.json'; // TODO: this part replicates `start.js`, refactor later const getDataDir = () => { const projectPath = _path2.default.resolve('.'); const botfile = _path2.default.join(projectPath, 'botfile.js'); if (!_fs2.default.existsSync(botfile)) { _util2.default.print.error(`(fatal) No ${_chalk2.default.bold('botfile.js')} file found at: ` + botfile); process.exit(1); } const bf = require(botfile); return _util2.default.getDataLocation(bf.dataDir, projectPath); }; const getCloudAuthFile = () => _path2.default.join(_os2.default.homedir(), '.botpress', AUTH_FILE); const getAuthFile = () => _path2.default.join(getDataDir(), AUTH_FILE); const readJsonFile = file => { try { const json = _fs2.default.readFileSync(file, 'utf-8'); return JSON.parse(json); } catch (err) { if (err.code !== 'ENOENT') { _util2.default.print.warn(err.message || 'Unknown error', `while reading ${file}.`); } } return {}; }; const writeJsonFile = (file, content) => { _mkdirp2.default.sync(_path2.default.dirname(file)); _fs2.default.writeFileSync(file, JSON.stringify(content, null, 2)); }; const readBotAuth = () => readJsonFile(getAuthFile()); const readCloudAuth = () => readJsonFile(getCloudAuthFile()); const writeBotAuth = auth => writeJsonFile(getAuthFile(), auth); const writeCloudAuth = auth => writeJsonFile(getCloudAuthFile(), auth); const AUTH_DISABLED = '[AUTH DISABLED]'; const refreshToken = (() => { var _ref = _asyncToGenerator(function* (botUrl) { const auth = readBotAuth(); const token = auth[botUrl]; // this method is only called if the auth is enabled // in which case it doesn't make sense even to try refreshing the fake token // we might have saved before when the auth was disabled on this server if (!token || token === AUTH_DISABLED) { return; } try { const response = yield _axios2.default.request({ url: `${botUrl}/api/auth/refresh_token`, method: 'POST', headers: { Authorization: `Bearer ${token}` } }); return response.data; } catch (err) { return null; } }); return function refreshToken(_x) { return _ref.apply(this, arguments); }; })(); const doRootLogin = (() => { var _ref2 = _asyncToGenerator(function* (botUrl) { // try refreshing token before attempting the new login const token = yield refreshToken(botUrl); if (token) { return { token, kind: 'refresh' }; } const schema = { properties: { user: { description: _chalk2.default.white('User:'), required: true }, password: { description: _chalk2.default.white('Password:'), hidden: true, required: true } } }; _prompt2.default.message = ''; _prompt2.default.delimiter = ''; _prompt2.default.start(); const { user, password } = yield _bluebird2.default.fromCallback(function (cb) { return _prompt2.default.get(schema, cb); }); const result = yield _axios2.default.post(`${botUrl}/api/login`, { user, password }); if (result.data.success) { return { token: result.data.token, kind: 'login' }; } throw new Error(result.data.reason); }); return function doRootLogin(_x2) { return _ref2.apply(this, arguments); }; })(); const doCloudLogin = (() => { var _ref3 = _asyncToGenerator(function* (botUrl, botInfo) { const userAuthUrl = `${botInfo.endpoint}/me/cli`; const loginUrl = `${botInfo.endpoint}/api/login/bot/${botInfo.botId}/${botInfo.botEnv}`; const cloudAuth = readCloudAuth(); if (!cloudAuth[botInfo.endpoint]) { const schema = { properties: { token: { description: _chalk2.default.white('API Token:'), required: true } } }; _prompt2.default.message = `You need to authenticate using Botpress Cloud for this bot.\r\nPlease visit ${userAuthUrl} and copy/paste your API token here.\r\n`; _prompt2.default.delimiter = ''; _prompt2.default.start(); const { token: apiToken } = yield _bluebird2.default.fromCallback(function (cb) { return _prompt2.default.get(schema, cb); }); if (!apiToken.startsWith('cli__')) { throw new Error('Invalid API Token, expected token starting with "cli__"'); } cloudAuth[botInfo.endpoint] = apiToken; writeCloudAuth(cloudAuth); } try { const authorization = `Bearer ${cloudAuth[botInfo.endpoint]}`; const { data } = yield _axios2.default.get(loginUrl, { headers: { authorization } }); return { token: (0, _get2.default)(data, 'payload.token'), kind: 'refresh' }; } catch (err) { delete cloudAuth[botInfo.endpoint]; writeCloudAuth(cloudAuth); const msg = (0, _get2.default)(err, 'response.data.message') || err.message; throw new Error('Could not authenticate to bot using Botpress Cloud, please try again. (' + msg + ')'); } }); return function doCloudLogin(_x3, _x4) { return _ref3.apply(this, arguments); }; })(); const doLogin = (() => { var _ref4 = _asyncToGenerator(function* (botUrl) { const res = yield _axios2.default.get(`${botUrl}/api/auth/info`); const data = res.data || {}; if (!data.type === 'none') { return { token: AUTH_DISABLED, kind: 'no-auth' }; } else if (data.type === 'cloud') { return doCloudLogin(botUrl, data); } else if (data.type === 'root') { return doRootLogin(botUrl); } else { throw new Error('Unknown login type: ' + data.type); } }); return function doLogin(_x5) { return _ref4.apply(this, arguments); }; })(); exports.login = (() => { var _ref5 = _asyncToGenerator(function* (botUrl) { botUrl = botUrl.replace(/\/+$/, ''); if (!_validUrl2.default.isUri(botUrl)) { _util2.default.print.error(`Doesn't look like valid URL: ${botUrl}`); return; } try { const { token, kind } = yield doLogin(botUrl); const auth = readBotAuth(); auth[botUrl] = token; writeBotAuth(auth); if (kind === 'login') { _util2.default.print.success(`Logged in successfully. Auth token saved in ${getAuthFile()}.`); } else if (kind === 'refresh') { _util2.default.print.success(`Auth token refreshed and saved in ${getAuthFile()}.`); } else if (kind === 'no-auth') { _util2.default.print.info(`Auth is disabled at ${botUrl}, no need to login.`); } return token; } catch (err) { _util2.default.print.error(err.message || 'Unknown'); return; } }); return function (_x6) { return _ref5.apply(this, arguments); }; })(); exports.logout = botUrl => { if (!botUrl) { new _promptConfirm2.default("You're about to delete all saved auth tokens in the current folder. Are you sure?").run().then(answer => { if (!answer) { return; } writeBotAuth({}); writeCloudAuth({}); }); return; } botUrl = botUrl.replace(/\/+$/, ''); const auth = readBotAuth(); if (!auth[botUrl]) { _util2.default.print.warn(`No saved token for ${botUrl}, nothing to do.`); return; } delete auth[botUrl]; writeBotAuth(auth); _util2.default.print.success('Logged out successfully.'); }; //# sourceMappingURL=auth.js.map