UNPKG

node-red-contrib-smartnora

Version:

Google Smart Home integration via Smart Nora https://smart-nora.eu/

100 lines (99 loc) 4.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FirebaseConnection = void 0; const app_1 = require("firebase/app"); const auth_1 = require("firebase/auth"); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const __1 = require(".."); const config_1 = require("../config"); const fetch_1 = require("./fetch"); const async_commands_registry_1 = require("./async-commands.registry"); const local_execution_1 = require("./local-execution"); const sync_1 = require("./sync"); class FirebaseConnection { static withLogger(logger) { var _a; (_a = this.logger) !== null && _a !== void 0 ? _a : (this.logger = logger); local_execution_1.LocalExecution.withLogger(logger); async_commands_registry_1.AsyncCommandsRegistry.withLogger(logger); return this; } static fromConfig(config, ctx) { const key = (0, __1.getHash)(`${config.email}:${config.group}`); let cached = this.configs[key]; if (!cached) { cached = this.configs[key] = this.getAppFromConfig(config) .pipe((0, operators_1.map)(app => new sync_1.FirebaseSync(app, config.group, this.logger)), (0, operators_1.retry)({ delay: err => { var _a, _b; const seconds = Math.round(Math.random() * 120) / 2 + 30; (_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`nora: ${err}`); (_b = this.logger) === null || _b === void 0 ? void 0 : _b.warn(`nora: trying again in ${seconds} sec`); return (0, rxjs_1.timer)(seconds * 1000); } }), (0, operators_1.finalize)(() => delete this.configs[key]), (0, __1.publishReplayRefCountWithDelay)(5000)); } return cached.pipe((0, operators_1.switchMap)(connection => (0, rxjs_1.merge)(connection.connected$.pipe((0, operators_1.tap)(ctx.connected$), (0, operators_1.ignoreElements)()), (0, rxjs_1.of)(connection)))); } static getAppFromConfig(config) { const key = (0, __1.getHash)(`${config.email}`); let cached = this.apps[key]; if (!cached) { cached = this.apps[key] = this.createFirebaseApp().pipe((0, operators_1.switchMap)(async (app) => { var _a, _b; const result = await this.authenticate(app, config); (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`nora: authenticated, uid: ${(_b = result.user) === null || _b === void 0 ? void 0 : _b.uid}`); return app; }), (0, operators_1.finalize)(() => delete this.apps[key]), (0, __1.publishReplayRefCountWithDelay)(5000)); } return cached; } static async authenticate(app, config) { var _a, _b, _c; const auth = (0, auth_1.getAuth)(app); if ((_a = config.password) === null || _a === void 0 ? void 0 : _a.length) { return await (0, auth_1.signInWithEmailAndPassword)(auth, config.email, config.password); } else if ((_b = config.sso) === null || _b === void 0 ? void 0 : _b.length) { const customToken = await this.exchangeToken(config.sso); return await (0, auth_1.signInWithCustomToken)(auth, customToken); } else { (_c = this.logger) === null || _c === void 0 ? void 0 : _c.error('nora: invalid auth config; not retrying'); return (0, rxjs_1.firstValueFrom)(rxjs_1.NEVER); } } static async exchangeToken(ssoToken) { var _a; const url = `${config_1.API_ENDPOINT}/sso/exchange`; const response = await (0, fetch_1.fetch)(url, { method: 'POST', headers: { 'user-agent': config_1.USER_AGENT, }, body: { token: ssoToken }, }); if (response.status === 200) { const { token } = await response.json(); return token; } if (response.status === 400) { (_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`nora: invalid sso token; not retrying - ${await response.text()}`); return (0, rxjs_1.firstValueFrom)(rxjs_1.NEVER); } throw new __1.HttpError(response.status, await response.text()); } static createFirebaseApp() { return new rxjs_1.Observable(observer => { const app = (0, app_1.initializeApp)(config_1.FIREBASE_CONFIG, `app-${new Date().getTime()}`); observer.next(app); return () => (0, app_1.deleteApp)(app); }); } } exports.FirebaseConnection = FirebaseConnection; FirebaseConnection.configs = {}; FirebaseConnection.apps = {};