baqend
Version:
Baqend JavaScript SDK
386 lines • 32.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getApps = exports.whoami = exports.listApps = exports.openDashboard = exports.openApp = exports.persistLogin = exports.logout = exports.login = exports.register = void 0;
const open_1 = __importDefault(require("open"));
const crypto_1 = __importDefault(require("crypto"));
const http_1 = require("http");
const os_1 = __importDefault(require("os"));
const inquirer_1 = __importDefault(require("inquirer"));
const baqend_1 = require("baqend");
const helper = __importStar(require("./helper"));
const helper_1 = require("./helper");
const { TokenStorage } = baqend_1.intersection;
const { UserFactory } = baqend_1.binding;
const fileName = `${os_1.default.homedir()}/.baqend`;
const algorithm = 'aes-256-ctr';
const PROFILE_DEFAULT_KEY = 'N2Ki=za[8iy4ff4jYn/3,y;';
const bbqHost = 'bbq';
function getAppInfo(args) {
const isCustomHost = args.app && /^https?:\/\//.test(args.app);
return {
isCustomHost: !!isCustomHost,
host: isCustomHost ? args.app : bbqHost,
app: isCustomHost ? null : args.app,
};
}
function getArgsCredentials(args) {
if (args.username && args.password) {
return {
username: args.username,
password: args.password,
};
}
if (args.token) {
return { token: args.token };
}
return null;
}
function getEnvCredentials() {
const token = process.env.BAQEND_TOKEN || process.env.BAT;
if (token) {
return { token };
}
return null;
}
function getProfileCredentials(appInfo) {
return readProfileFile().then((json) => {
const credentials = json[appInfo.host];
if (!credentials) {
return null;
}
if ('password' in credentials) {
console.log('Storing username/password in the baqend profile will not be supported in future version.');
console.log('Logout and login again to fix this issue.');
credentials.password = decrypt(credentials.password);
}
if ('token' in credentials) {
const { createdAt, expireAt } = TokenStorage.parse(credentials.token);
// validate token expiration
if (createdAt + (24 * 60 * 60 * 1000) < Date.now()) {
return null;
}
}
return credentials;
}).catch(() => null);
}
function getLocalCredentials(appInfo) {
if (appInfo.isCustomHost) {
return { username: 'root', password: 'root' };
}
return null;
}
function getInputCredentials(appInfo, authProvider, showLoginInfo) {
return __awaiter(this, void 0, void 0, function* () {
if (!process.stdout.isTTY) {
throw new Error('Can\'t interactive login into baqend, no tty session was detected.');
}
if (showLoginInfo) {
console.log('Baqend Login is required. You can skip this step by saving the Login credentials with "baqend login or baqend sso"');
}
const options = ['password', 'google', 'facebook', 'github'];
let result = authProvider || 'password';
if (!appInfo.isCustomHost && options.length > 1 && !authProvider) {
const responses = yield inquirer_1.default.prompt([{
name: 'loginType',
message: 'Choose how you want to login:',
type: 'list',
default: 'google',
choices: options.map((op) => ({ name: op })),
}]);
result = responses.loginType;
}
if (!result) {
throw new Error('No valid login option was chosen.');
}
if (result === 'password') {
return readInputCredentials(appInfo);
}
return requestSSOCredentials(appInfo, result);
});
}
function requestSSOCredentials(appInfo, oAuthProvider, oAuthOptions = {}) {
// TODO: current workaround until our server pass this ids to the client dynamically
const clientIds = {
facebook: '976707865723719',
google: '586076830320-0el1jebupjvbcmqf95vfaqjq7gbs0bdh.apps.googleusercontent.com',
gitHub: '1311e3415ab415fda705',
};
return appConnect(appInfo)
.then((db) => {
const host = '127.0.0.1';
const port = 9876;
const provider = oAuthProvider.toLowerCase();
return Promise.all([
oAuthHandler(host, port),
db.loginWithOAuth(oAuthProvider, Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, UserFactory.DefaultOptions[provider] || {}), (clientIds[provider] && { clientId: clientIds[provider] })), { open: open_1.default }), oAuthOptions), { redirect: `http://${host}:${port}` })),
]).then(([credentials, windowProcess]) => {
windowProcess.kill('SIGHUP'); // seems not working on every platform
return credentials;
});
});
}
function oAuthHandler(host, port) {
return __awaiter(this, void 0, void 0, function* () {
const htmlTemplate = yield (0, helper_1.readModuleFile)('./sso.html');
return new Promise((resolve, reject) => {
const server = (0, http_1.createServer)((req, res) => {
const url = new URL(req.url, `http://${host}:${port}`);
const errorMessage = url.searchParams.get('errorMessage');
let text = null;
if (errorMessage) {
reject(new Error(errorMessage));
text = `<h1>An error has occurred</h1><p>${errorMessage}</p>`;
}
else if (url.searchParams.has('token')) {
resolve({ token: url.searchParams.get('token') });
text = '<h1>Continue within the CLI</h1><p>You can close this window now.</p>';
}
if (text) {
// eslint-disable-next-line no-template-curly-in-string
const html = htmlTemplate.replace('${content}', text);
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(html);
setTimeout(() => {
server.close();
});
}
else {
res.writeHead(404);
res.end();
}
});
server.on('error', (err) => {
reject(err);
});
server.listen(port, host);
});
});
}
function getCredentials(appInfo, args) {
let providers = Promise.resolve(null)
.then((credentials) => credentials || getArgsCredentials(args))
.then((credentials) => credentials || getEnvCredentials())
.then((credentials) => credentials || getProfileCredentials(appInfo))
.then((credentials) => credentials || getLocalCredentials(appInfo));
if (!args.skipInput && process.stdout.isTTY) {
providers = providers
.then((credentials) => credentials || persistLogin(Object.assign(Object.assign({}, appInfo), args)));
}
return providers;
}
function register(args) {
const appInfo = getAppInfo(args);
return getInputCredentials(appInfo, args.auth)
.then((credentials) => appConnect(appInfo)
.then((db) => {
if ('token' in credentials) {
return db.User.loginWithToken(credentials.token).then(() => db);
}
return db.User.register(credentials.username, credentials.password).then(() => db);
})
.then((db) => Promise.all([
getDefaultApp(db).then((name) => console.log(`Your app name is ${name}`)),
saveCredentials(appInfo, { token: db.token }),
])));
}
exports.register = register;
function connect(args) {
const appInfo = getAppInfo(args);
return getCredentials(appInfo, args)
.then((credentials) => {
if (!credentials)
throw new Error('Login information are missing. Login with baqend login or pass a baqend token via BAQEND_TOKEN environment variable');
return appConnect(appInfo, credentials);
});
}
function appConnect(appInfo, credentials) {
// do not use the global token storage here, to prevent login collisions on the bbq app
const factory = new baqend_1.EntityManagerFactory({ host: appInfo.host, secure: true, tokenStorageFactory: TokenStorage });
return factory.createEntityManager(true).ready().then((db) => {
if (!credentials)
return db;
if ('token' in credentials) {
return db.User.loginWithToken(credentials.token)
.then((me) => {
if (me) {
return db;
}
throw new Error('Login with Baqend token failed.');
});
}
return db.User.login(credentials.username, credentials.password).then(() => db);
});
}
function login(args) {
const appInfo = getAppInfo(args);
return connect(args)
.then((db) => {
if (appInfo.isCustomHost) {
return db;
}
if (appInfo.app) {
return bbqAppLogin(db, appInfo.app);
}
return getDefaultApp(db).then((appName) => bbqAppLogin(db, appName));
}).catch((e) => {
// if the login failed try to directly login into the app
if (appInfo.app && !appInfo.isCustomHost) {
return login(Object.assign(Object.assign({}, args), { app: `https://${appInfo.app}.app.baqend.com/v1` }));
}
throw e;
});
}
exports.login = login;
function bbqAppLogin(db, appName) {
return __awaiter(this, void 0, void 0, function* () {
const { token } = yield db.modules.get('token', { app: appName });
return appConnect({ host: appName, isCustomHost: false, app: appName }, { token });
});
}
function logout(args) {
const appInfo = getAppInfo(args);
return readProfileFile().then((json) => {
// eslint-disable-next-line no-param-reassign
delete json[appInfo.host];
return writeProfileFile(json);
});
}
exports.logout = logout;
function persistLogin(args) {
return __awaiter(this, void 0, void 0, function* () {
const appInfo = getAppInfo(args);
let credentials = getArgsCredentials(args);
if (!credentials) {
credentials = yield getInputCredentials(appInfo, args.auth, false);
}
const db = yield appConnect(appInfo, credentials);
const tokenCredentials = 'token' in credentials ? credentials : { token: db.token };
yield saveCredentials(appInfo, tokenCredentials);
return tokenCredentials;
});
}
exports.persistLogin = persistLogin;
function openApp(app) {
if (app) {
return (0, open_1.default)(`https://${app}.app.baqend.com`);
}
return login({}).then((db) => {
(0, open_1.default)(`https://${db.connection.host}`);
});
}
exports.openApp = openApp;
function openDashboard(args) {
return connect(args).then((db) => {
(0, open_1.default)(`https://dashboard.baqend.com/login?token=${db.token}`);
}).catch(() => {
(0, open_1.default)('https://dashboard.baqend.com');
});
}
exports.openDashboard = openDashboard;
function listApps(args) {
return __awaiter(this, void 0, void 0, function* () {
const db = yield connect(args);
let apps = yield getApps(db);
apps = apps.sort();
apps.forEach((app) => console.log(app));
});
}
exports.listApps = listApps;
function whoami(args) {
return connect(Object.assign({ skipInput: true }, args))
.then((db) => console.log(db.User.me.username), () => console.log('You are not logged in.'));
}
exports.whoami = whoami;
function getApps(db) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
let query = db.App.find()
.eq('status', 'running');
if ((_b = (_a = db.User.me) === null || _a === void 0 ? void 0 : _a.username) === null || _b === void 0 ? void 0 : _b.endsWith('@baqend.com')) {
query = query.eq('owner', db.User.me);
}
return (yield query.resultList()).map((app) => app.name);
});
}
exports.getApps = getApps;
function getDefaultApp(db) {
return getApps(db).then((apps) => {
if (apps.length === 1) {
return apps[0];
}
throw new Error('Please add the name of your app as a parameter.');
});
}
function readInputCredentials(appInfo) {
return __awaiter(this, void 0, void 0, function* () {
return inquirer_1.default.prompt([
{ name: 'username', type: 'input', message: appInfo.isCustomHost ? 'Username:' : 'E-Mail:' },
{ name: 'password', type: 'password', message: 'Password:' },
]);
});
}
function decrypt(input) {
// This is legacy and we will remove support for the username / password storage in the profile file
// eslint-disable-next-line node/no-deprecated-api
const decipher = crypto_1.default.createDecipher(algorithm, PROFILE_DEFAULT_KEY);
let decrypted = decipher.update(input, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
function writeProfileFile(json) {
return helper.writeFile(fileName, JSON.stringify(json)).catch((e) => {
console.warn('Baqend Profile file can\'t be written', e);
throw e;
});
}
function readProfileFile() {
return (0, helper_1.isFile)(fileName).then((exists) => {
if (!exists) {
return {};
}
return (0, helper_1.readFile)(fileName, 'utf-8').then((data) => (data ? JSON.parse(data) : {}));
});
}
function saveCredentials(appInfo, credentials) {
return readProfileFile().then((json) => {
// eslint-disable-next-line no-param-reassign
json[appInfo.host] = Object.assign(Object.assign({}, json[appInfo.host]), credentials);
return writeProfileFile(json);
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWNjb3VudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImFjY291bnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxnREFBd0I7QUFFeEIsb0RBQTRCO0FBQzVCLCtCQUFvQztBQUNwQyw0Q0FBb0I7QUFDcEIsd0RBQWdDO0FBQ2hDLG1DQUVnQjtBQUNoQixpREFBbUM7QUFDbkMscUNBRWtCO0FBRWxCLE1BQU0sRUFBRSxZQUFZLEVBQUUsR0FBRyxxQkFBWSxDQUFDO0FBQ3RDLE1BQU0sRUFBRSxXQUFXLEVBQUUsR0FBRyxnQkFBTyxDQUFDO0FBRWhDLE1BQU0sUUFBUSxHQUFHLEdBQUcsWUFBRSxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUM7QUFDM0MsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDO0FBQ2hDLE1BQU0sbUJBQW1CLEdBQUcseUJBQXlCLENBQUM7QUFDdEQsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDO0FBa0N0QixTQUFTLFVBQVUsQ0FBQyxJQUFpQjtJQUNuQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxJQUFJLGNBQWMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRS9ELE9BQU87UUFDTCxZQUFZLEVBQUUsQ0FBQyxDQUFDLFlBQVk7UUFDNUIsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUksQ0FBQyxDQUFDLENBQUMsT0FBTztRQUN4QyxHQUFHLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFJO0tBQ3JDLENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxrQkFBa0IsQ0FBQyxJQUFpQjtJQUMzQyxJQUFJLElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRTtRQUNsQyxPQUFPO1lBQ0wsUUFBUSxFQUFFLElB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