UNPKG

homebridge-hilo

Version:

Plugin Homebridge (non officiel) pour la passerelle et les appareils Hilo de Hydro-Québec | Unofficial Homebridge plugin for Hydro-Québec Hilo bridge and devices

204 lines 7.84 kB
"use strict"; 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 () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.graphqlApi = exports.hiloApi = exports.getWsAccessToken = exports.getAccessToken = void 0; exports.negotiate = negotiate; exports.setupAutoRefreshToken = setupAutoRefreshToken; exports.execute = execute; const axios_1 = __importStar(require("axios")); const fs_1 = __importDefault(require("fs")); const jsonwebtoken_1 = require("jsonwebtoken"); const config_1 = require("./config"); const logger_1 = require("./logger"); const api_1 = require("./api"); let accessToken; let refreshToken; let wsAccessToken; const clientId = "1ca9f585-4a55-4085-8e30-9746a65fa561"; const authServer = "https://connexion.hiloenergie.com"; const renewTokens = async ({ newRefreshToken, newAccessToken, expiresIn, }) => { const configPath = (0, api_1.getApi)().user.configPath(); const config = JSON.parse(fs_1.default.readFileSync(configPath, "utf8")); const hilo = config.platforms.find((p) => p.platform === "Hilo"); hilo.refreshToken = newRefreshToken; fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 4)); accessToken = newAccessToken; refreshToken = newRefreshToken; await setupAutoRefreshToken(expiresIn); }; async function login() { (0, logger_1.getLogger)().debug("Logging in"); const config = (0, config_1.getConfig)(); const newRefreshToken = config.refreshToken; await renewTokens({ newRefreshToken, }); } async function refreshTokenRequest() { (0, logger_1.getLogger)().debug("Refreshing token"); const data = new URLSearchParams(); data.append("grant_type", "refresh_token"); data.append("client_id", clientId); data.append("refresh_token", refreshToken); data.append("scope", "openid https://HiloDirectoryB2C.onmicrosoft.com/hiloapis/user_impersonation offline_access"); data.append("redirect_uri", "https://my.home-assistant.io/redirect/oauth"); const response = await axios_1.default.post(`${authServer}/HiloDirectoryB2C.onmicrosoft.com/B2C_1A_SIGN_IN/oauth2/v2.0/token?p=b2c_1a_sign_in`, data); await renewTokens({ newAccessToken: response.data.access_token, newRefreshToken: response.data.refresh_token, expiresIn: response.data.expires_in, }); } const getAccessToken = () => accessToken || ""; exports.getAccessToken = getAccessToken; const getWsAccessToken = () => wsAccessToken || ""; exports.getWsAccessToken = getWsAccessToken; let wsRefreshTimer; async function negotiate() { (0, logger_1.getLogger)().debug("Negotiating websocket connection"); const response = await exports.hiloApi.post("/DeviceHub/negotiate", {}, { params: { negociateVersion: 1, }, }); wsAccessToken = response.data.accessToken; if (wsRefreshTimer) { clearTimeout(wsRefreshTimer); } const decoded = (0, jsonwebtoken_1.decode)(response.data.accessToken); const exp = decoded === null || decoded === void 0 ? void 0 : decoded.exp; // Refresh 5 minutes before expiration, fallback to 55 minutes if exp is unreadable const refreshIn = exp ? exp * 1000 - Date.now() - 5 * 60 * 1000 : 55 * 60 * 1000; (0, logger_1.getLogger)().debug(`WebSocket token refreshing in ${Math.round(refreshIn / 60000)} minutes`); wsRefreshTimer = setTimeout(async () => { (0, logger_1.getLogger)().debug("Refreshing websocket token"); try { await negotiate(); } catch (e) { (0, logger_1.getLogger)().error("Failed to refresh websocket token", e instanceof Error ? e.message : e); } }, Math.max(refreshIn, 60000)); return { accessToken: response.data.accessToken, url: response.data.url }; } async function setupAutoRefreshToken(expiresIn) { if (!expiresIn) { (0, logger_1.getLogger)().debug("Refreshing token"); try { await refreshTokenRequest(); } catch (e) { unableToLogin(e); } } else { (0, logger_1.getLogger)().debug("Setting up auto refresh token"); setTimeout(async () => { (0, logger_1.getLogger)().debug("Refreshing token automatically"); try { await refreshTokenRequest(); } catch (_e) { try { await login(); } catch (e) { unableToLogin(e); } } }, expiresIn * 1000 - 1000 * 60 * 5); // 5 minutes before expiration } } exports.hiloApi = axios_1.default.create({ baseURL: "https://api.hiloenergie.com", }); exports.graphqlApi = axios_1.default.create({ baseURL: "https://platform.hiloenergie.com", }); function execute(query, ...[variables]) { return exports.graphqlApi.post("/api/digital-twin/v3/graphql", { query: query.toString(), variables, }, { headers: { "Content-Type": "application/json", }, }); } const authInterceptor = async (config) => { if (!accessToken) { if (refreshToken) { try { await refreshTokenRequest(); } catch (_e) { try { await login(); } catch (e) { unableToLogin(e); } } } else { try { await login(); } catch (e) { unableToLogin(e); } } } config.headers = new axios_1.AxiosHeaders({ ...config.headers, "Ocp-Apim-Subscription-Key": "20eeaedcb86945afa3fe792cea89b8bf", Authorization: accessToken ? `Bearer ${accessToken}` : "", }); return config; }; exports.hiloApi.interceptors.request.use(authInterceptor); exports.graphqlApi.interceptors.request.use(authInterceptor); const unableToLogin = (e) => { var _a; const logger = (0, logger_1.getLogger)(); logger.error("Unable to login", axios_1.default.isAxiosError(e) ? (_a = e.response) === null || _a === void 0 ? void 0 : _a.data : e); logger.error("You can try to refresh your login credentials by using the 'Login with Hilo' button in the plugin configuration in homebridge UI"); }; //# sourceMappingURL=hiloApi.js.map