homebridge-nest-cam-ft
Version:
Nest cam plugin for homebridge: https://homebridge.io/
237 lines • 10.3 kB
JavaScript
;
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