UNPKG

golos-lib-js

Version:

Golos-js the JavaScript library with API for GOLOS blockchain

230 lines (228 loc) 6.52 kB
"use strict"; var _debug = _interopRequireDefault(require("debug")); var _config = _interopRequireDefault(require("../config")); var _ecc = require("../auth/ecc"); var _fetchEx = _interopRequireDefault(require("../utils/fetchEx")); var _keychain = require("./keychain"); var _misc = require("../utils/misc"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } let _apiHost; let _uiHost; let _clientId; let _oauthNode, _oauthChainId; const debug = (0, _debug.default)('golos:multiauth'); const AuthType = { OAUTH: 1, KEYCHAIN: 2 }; function apiHost() { if (_apiHost) return _apiHost; const KEY = 'oauth.host'; let host = _config.default.get(KEY); if (!host) throw new Error(KEY + ' is not set in golos.config'); if (!host.startsWith('http://') && !host.startsWith('https://')) host = 'https://' + host; try { _apiHost = new URL(host).origin; } catch (err) { throw new Error(KEY + ' cannot be parsed as URL: ' + host); } return _apiHost; } function uiHost() { if (_uiHost) return _uiHost; const KEY = 'oauth.ui_host'; let host = _config.default.get(KEY); if (!host) { _uiHost = apiHost(); return _uiHost; } if (!host.startsWith('http://') && !host.startsWith('https://')) host = 'https://' + host; try { _uiHost = new URL(host).origin; } catch (err) { throw new Error(KEY + ' cannot be parsed as URL: ' + host); } return _uiHost; } function clientId() { if (_clientId) return _clientId; const KEY = 'oauth.client'; let client = _config.default.get(KEY); if (!client) throw new Error(KEY + ' is not set in golos.config'); _clientId = client; return _clientId; } // Keychain only signs transactions, but not sends them // and we cannot use OAuth host if we are using KeyChain // so we should use our node to send them function setKeychainNodeIfCan() { const signedNode = _config.default.get('signed.websocket'); if (signedNode) { _oauthNode = _config.default.get('websocket'); _config.default.set('websocket', signedNode); } const signedCid = _config.default.get('signed.chain_id'); if (signedCid) { _oauthChainId = _config.default.get('chain_id'); _config.default.set('chain_id', signedCid); } } function switchBackToOAuth() { if (_oauthNode) { _config.default.set('websocket', _oauthNode); } if (_oauthChainId) { _config.default.set('chain_id', _oauthChainId); } } function _callApi(url, data) { let getHost = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : apiHost; let request = { method: data ? 'post' : 'get', credentials: 'include', headers: { Accept: 'application/json', 'Content-type': data ? 'application/json' : undefined }, body: data ? JSON.stringify(data) : undefined }; return (0, _fetchEx.default)(new URL(url, getHost()), request); } async function check() { const resKC = await (0, _keychain.kcLoggedIn)(); if (resKC.authorized) { setKeychainNodeIfCan(); return { ...resKC, authType: AuthType.KEYCHAIN }; } let res = await _callApi('/api/oauth/check/' + clientId()); res = await res.json(); return { ...res, authType: AuthType.OAUTH }; } async function checkReliable() { let onError = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined; let retry = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; let res = null; try { res = await check(); } catch (err) { if (onError && onError({ retry })) { throw err; } if (!onError) { if (retry > 10) { console.error('multiauth.check stopped retrying'); throw err; } console.error('multiauth.check error:', err, 'retrying...'); } await (0, _misc.delay)(3000); res = await checkReliable(onError, ++retry); } return res; } const waiters = new Set(); let waiterAutoInc = 0; const stopped = (id, onFail) => { if (!waiters.has(id)) { onFail(); return true; } return false; }; async function waitingLoop(id, onFinish, onFail) { let retries = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 180; let onRetry = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : undefined; if (!retries) { console.error('waiting for login is timeouted'); onFail(); return; } if (stopped(id, onFail)) return; const res = await checkReliable(); if (stopped(id, onFail)) return; if (res.authorized) { onFinish(res); } else { if (onRetry && onRetry({ retriesLeft: retries })) { onFail(); return; } debug('waiting for login...'); setTimeout(() => { waitingLoop(id, onFinish, onFail, --retries, onRetry); }, 1000); } } async function waitForLogin(onFinish, onFail) { let retries = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 180; let onRetry = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined; ++waiterAutoInc; waiters.clear(); waiters.add(waiterAutoInc); await waitingLoop(waiterAutoInc, onFinish, onFail, --retries, onRetry); } async function login() { let permissions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; let { type = AuthType.OAUTH, extraParams = '' } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; if (typeof document === 'undefined') { throw new Error('MultiAuth works only in browser environment (window should be defined)'); } if (type === AuthType.KEYCHAIN) { await (0, _keychain.assertKc)(); await (0, _keychain.kcLogin)(); return true; } return window.open(uiHost() + '/oauth/' + clientId() + '/' + permissions.join(',') + extraParams); } async function logout() { if (!(await (0, _keychain.kcLogout)())) { const res = await _callApi('/api/oauth/logout/' + clientId()); } else { switchBackToOAuth(); } } function _hashOps(operations) { let json = JSON.stringify(operations); const idHash = _ecc.hash.sha256(json, 'hex'); return idHash; } async function keychainInfo() { let info = { installed: false, loadingBroken: false }; try { info.installed = await (0, _keychain.waitForKc)(); } catch (err) { console.error(err); info.loadingBroken = true; } return info; } module.exports = { clientId, apiHost, uiHost, check, checkReliable, AuthType, login, waitForLogin, logout, keychainInfo, _callApi, _hashOps };