UNPKG

homebridge-nest-cam-ft

Version:

Nest cam plugin for homebridge: https://homebridge.io/

237 lines 10.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.nest_auth = exports.old_auth = exports.auth = exports.getRefreshToken = exports.generateToken = exports.getCameras = void 0; const axios_1 = __importDefault(require("axios")); const endpoints_1 = require("./endpoints"); const querystring_1 = __importDefault(require("querystring")); const CLIENT_ID = '733249279899-1gpkq9duqmdp55a7e5lft1pr2smumdla.apps.googleusercontent.com'; const CLIENT_ID_FT = '384529615266-57v6vaptkmhm64n9hn5dcmkr4at14p8j.apps.googleusercontent.com'; const APIKEY = 'AIzaSyAdkSIMNc51XGNEAYWasX9UOWkS5P6sZE4'; const APIKEY_FT = 'AIzaSyB0WNyJX2EQQujlknzTDD9jz7iVHK5Jn-U'; const TOKEN_URL = 'https://oauth2.googleapis.com/token'; const ISSUE_JWT_URL = 'https://nestauthproxyservice-pa.googleapis.com/v1/issue_jwt'; const NEST_AUTH_URL = 'https://webapi.camera.home.ft.nest.com/api/v1/login.login_nest'; const API_AUTH_FAIL_RETRY_DELAY_SECONDS = 15; const API_TIMEOUT_SECONDS = 10; const delay = function (time) { return new Promise((resolve) => setTimeout(resolve, time)); }; async function getCameras(config, log) { var _a; const endpoints = new endpoints_1.NestEndpoints((_a = config.options) === null || _a === void 0 ? void 0 : _a.fieldTest); let cameras = []; try { const response = await endpoints.sendRequest(config.access_token, endpoints.CAMERA_API_HOSTNAME, '/api/cameras.get_owned_and_member_of_with_properties', 'GET'); cameras = response.items; } catch (error) { if (log) { (0, endpoints_1.handleError)(log, error, 'Error fetching cameras'); } } return cameras; } exports.getCameras = getCameras; function generateToken(ft = false) { const data = { access_type: 'offline', response_type: 'code', scope: 'openid profile email https://www.googleapis.com/auth/nest-account', redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', client_id: ft ? CLIENT_ID_FT : CLIENT_ID, }; return `https://accounts.google.com/o/oauth2/auth/oauthchooseaccount?${querystring_1.default.stringify(data)}`; } exports.generateToken = generateToken; async function getRefreshToken(code, ft = false) { const req = { method: 'POST', timeout: API_TIMEOUT_SECONDS * 1000, url: TOKEN_URL, headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': endpoints_1.NestEndpoints.USER_AGENT_STRING, }, data: querystring_1.default.stringify({ code: code, redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', client_id: ft ? CLIENT_ID_FT : CLIENT_ID, grant_type: 'authorization_code', }), }; const result = (await (0, axios_1.default)(req)).data; return result.refresh_token; } exports.getRefreshToken = getRefreshToken; async function auth(refreshToken, ft = false, log) { let req; const apiKey = ft ? APIKEY_FT : APIKEY; log === null || log === void 0 ? void 0 : log.debug('Authenticating via Google refresh token.'); let result; try { req = { method: 'POST', timeout: API_TIMEOUT_SECONDS * 1000, url: TOKEN_URL, headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': endpoints_1.NestEndpoints.USER_AGENT_STRING, }, data: querystring_1.default.stringify({ refresh_token: refreshToken, client_id: ft ? CLIENT_ID_FT : CLIENT_ID, grant_type: 'refresh_token', }), }; result = (await (0, axios_1.default)(req)).data; const googleAccessToken = result.access_token; if (result.error) { log === null || log === void 0 ? void 0 : log.error('Google authentication was unsuccessful.'); throw result; } req = { method: 'POST', timeout: API_TIMEOUT_SECONDS * 1000, url: ISSUE_JWT_URL, data: { embed_google_oauth_access_token: true, expire_after: '3600s', google_oauth_access_token: googleAccessToken, policy_id: 'authproxy-oauth-policy', }, headers: { Authorization: 'Bearer ' + googleAccessToken, 'User-Agent': endpoints_1.NestEndpoints.USER_AGENT_STRING, 'x-goog-api-key': apiKey, }, }; result = (await (0, axios_1.default)(req)).data; return result.jwt; } catch (error) { error.status = error.response && error.response.status; log === null || log === void 0 ? void 0 : log.error('Access token acquisition via refresh token failed (code ' + (error.status || error.code) + ').'); if (['ECONNREFUSED', 'ESOCKETTIMEDOUT', 'ECONNABORTED', 'ENOTFOUND', 'ENETUNREACH'].includes(error.code)) { log === null || log === void 0 ? void 0 : log.error('Retrying in ' + API_AUTH_FAIL_RETRY_DELAY_SECONDS + ' second(s).'); await delay(API_AUTH_FAIL_RETRY_DELAY_SECONDS * 1000); return await auth(refreshToken, ft, log); } else { return ''; } } } exports.auth = auth; async function old_auth(issueToken, cookies, apiKey, log) { var _a; let req; issueToken = issueToken.replace('Request URL: ', ''); cookies = cookies.replace('cookie: ', ''); const referer = ((_a = querystring_1.default.parse(issueToken).ss_domain) === null || _a === void 0 ? void 0 : _a.toString()) || ''; if (!referer) { log === null || log === void 0 ? void 0 : log.error('issueToken is invalid'); return ''; } const fieldTest = referer !== 'https://home.nest.com'; apiKey = (apiKey === null || apiKey === void 0 ? void 0 : apiKey.replace('x-goog-api-key: ', '')) || (fieldTest ? 'AIzaSyB0WNyJX2EQQujlknzTDD9jz7iVHK5Jn-U' : 'AIzaSyAdkSIMNc51XGNEAYWasX9UOWkS5P6sZE4'); log === null || log === void 0 ? void 0 : log.debug('Authenticating via Google.'); let result; try { req = { method: 'GET', timeout: API_TIMEOUT_SECONDS * 1000, url: issueToken, headers: { 'Sec-Fetch-Mode': 'cors', 'User-Agent': endpoints_1.NestEndpoints.USER_AGENT_STRING, 'X-Requested-With': 'XmlHttpRequest', Referer: 'https://accounts.google.com/o/oauth2/iframe', cookie: cookies, }, }; result = (await (0, axios_1.default)(req)).data; const googleAccessToken = result.access_token; if (result.error) { log === null || log === void 0 ? void 0 : log.error('Google authentication was unsuccessful. Make sure you did not log out of your Google account after getting your googleAuth parameters.'); throw result; } req = { method: 'POST', timeout: API_TIMEOUT_SECONDS * 1000, url: 'https://nestauthproxyservice-pa.googleapis.com/v1/issue_jwt', data: { embed_google_oauth_access_token: true, expire_after: '3600s', google_oauth_access_token: googleAccessToken, policy_id: 'authproxy-oauth-policy', }, headers: { Authorization: 'Bearer ' + googleAccessToken, 'User-Agent': endpoints_1.NestEndpoints.USER_AGENT_STRING, 'x-goog-api-key': apiKey, Referer: referer, }, }; result = (await (0, axios_1.default)(req)).data; return result.jwt; } catch (error) { error.status = error.response && error.response.status; log === null || log === void 0 ? void 0 : log.error('Access token acquisition via googleAuth failed (code ' + (error.status || error.code) + ').'); if (['ECONNREFUSED', 'ESOCKETTIMEDOUT', 'ECONNABORTED', 'ENOTFOUND', 'ENETUNREACH'].includes(error.code)) { log === null || log === void 0 ? void 0 : log.error('Retrying in ' + API_AUTH_FAIL_RETRY_DELAY_SECONDS + ' second(s).'); await delay(API_AUTH_FAIL_RETRY_DELAY_SECONDS * 1000); return await old_auth(issueToken, cookies); } else { return ''; } } } exports.old_auth = old_auth; async function nest_auth(nest_token, log) { let req; log === null || log === void 0 ? void 0 : log.debug('Authenticating via pre-defined nest_token'); let result; try { req = { method: 'POST', timeout: API_TIMEOUT_SECONDS * 1000, url: NEST_AUTH_URL, data: querystring_1.default.stringify({ access_token: nest_token, }), headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: 'Basic ' + nest_token, 'User-Agent': endpoints_1.NestEndpoints.USER_AGENT_STRING, Referer: 'https://home.ft.nest.com', }, }; result = (await (0, axios_1.default)(req)).data; if (result.error) { log === null || log === void 0 ? void 0 : log.error('Nest authentication was unsuccessful.'); throw result; } return result.items[0].session_token; } catch (error) { error.status = error.response && error.response.status; log === null || log === void 0 ? void 0 : log.error('Nest authentication failed (code ' + (error.status || error.code) + ').'); if (['ECONNREFUSED', 'ESOCKETTIMEDOUT', 'ECONNABORTED', 'ENOTFOUND', 'ENETUNREACH'].includes(error.code)) { log === null || log === void 0 ? void 0 : log.error('Retrying in ' + API_AUTH_FAIL_RETRY_DELAY_SECONDS + ' second(s).'); await delay(API_AUTH_FAIL_RETRY_DELAY_SECONDS * 1000); return await nest_auth(nest_token, log); } else { return ''; } } } exports.nest_auth = nest_auth; //# sourceMappingURL=connection.js.map