UNPKG

@constructorfleet/ultimate-govee

Version:

Library for interacting with Govee devices written in Typescript.

181 lines 8.83 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var GoveeAccountService_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.GoveeAccountService = void 0; const common_1 = require("@nestjs/common"); const moment_1 = __importDefault(require("moment")); const _ultimate_govee_common_1 = require("../../../common"); const _ultimate_govee_persist_1 = require("../../../persist"); const utils_1 = require("../../utils"); const govee_account_configuration_1 = require("./govee-account.configuration"); const iot_certificate_response_1 = require("./models/iot-certificate.response"); const jwt_1 = require("./models/jwt"); const login_response_1 = require("./models/login.response"); const refresh_token_response_1 = require("./models/refresh-token.response"); let GoveeAccountService = GoveeAccountService_1 = class GoveeAccountService { constructor(config, persistedAccount) { this.config = config; this.logger = new common_1.Logger(GoveeAccountService_1.name); this.persistedAccount = persistedAccount ?? { accountId: '', clientId: '', topic: '', iot: undefined, oauth: undefined, bffOAuth: undefined, }; } isTokenValid(token) { const jwt = (0, jwt_1.decodeJWT)(token); try { if (!jwt?.exp || !jwt?.iat) { return false; } const expirationDateUTC = new Date(1970, 1, 1).setSeconds(jwt.exp); const nowUTC = new Date().getTime(); return nowUTC < expirationDateUTC; } catch (error) { this.logger.error('RestClient', 'isTokenValid', error); } return false; } async refresh(oauth) { try { this.logger.log('Refreshing access token'); const response = await (0, utils_1.request)(this.config.refreshTokenUrl, this.config.authenticatedHeaders(oauth)).get(refresh_token_response_1.RefreshTokenResponse); return { accessToken: response.data.data.token, refreshToken: response.data.data.refreshToken, expiresAt: new Date().getTime() + response.data.data.tokenExpireCycle * 1000, clientId: oauth.clientId, }; } catch (err) { this.logger.error('Unable to refresh token.', err); throw new Error('Unable to refresh token.'); } } async authenticate(credentials) { if (await this.authenticateWithGovee(credentials)) { await this.authenticateWithAWSIoT(); } await this.authenticateWithCommunity(credentials); return this.persistedAccount; } async authenticateWithGovee(credentials) { if (this.persistedAccount?.oauth && (0, moment_1.default)(this.persistedAccount.oauth.expiresAt).isAfter((0, moment_1.default)().utc().subtract(1, 'day')) && this.isTokenValid(this.persistedAccount.oauth.accessToken)) { this.logger.log('Using persisted Govee API credentials'); return false; } try { this.logger.log('Authenticating with Govee REST API'); const response = await (0, utils_1.request)(this.config.authUrl, {}, { email: credentials.username, password: credentials.password, client: credentials.clientId, }).post(login_response_1.LoginResponse); const loginResponse = response.data; this.persistedAccount.accountId = loginResponse.client.accountId; this.persistedAccount.clientId = loginResponse.client.clientId; this.persistedAccount.topic = loginResponse.client.topic; this.persistedAccount.oauth = { accessToken: loginResponse.client.accessToken, refreshToken: loginResponse.client.refreshToken, expiresAt: new Date().getTime() + loginResponse.client.tokenExpireCycle * 1000, clientId: loginResponse.client.clientId, }; return true; } catch (error) { this.logger.error('Unable to authenticate with Govee servers', error.message); throw new _ultimate_govee_common_1.GoveeApiAuthenticationError(); } } async authenticateWithCommunity(credentials) { if (this.persistedAccount.bffOAuth && (0, moment_1.default)(this.persistedAccount.bffOAuth.expiresAt).isAfter((0, moment_1.default)().utc().subtract(1, 'day')) && this.isTokenValid(this.persistedAccount.bffOAuth.accessToken)) { this.logger.log('Using persisted Govee Community credentials'); return false; } try { this.logger.log('Authenticating with Govee Community API'); const response = await (0, utils_1.request)(this.config.communityAuthUrl, {}, { email: credentials.username, password: credentials.password, }).post(login_response_1.CommunityLoginResponse); const loginResponse = response.data; this.persistedAccount.bffOAuth = { accessToken: loginResponse.community.token, refreshToken: '', expiresAt: loginResponse.community.expiresAt, clientId: this.persistedAccount.clientId, }; return true; } catch (error) { this.logger.error('Unable to authenticate with Govee community servers', error.message); throw new _ultimate_govee_common_1.GoveeCommunityApiAuthenticationError(); } } async authenticateWithAWSIoT() { try { if (!this.persistedAccount.oauth) { this.logger.error('Cannot retreive IoT certificate: not logged in'); throw new _ultimate_govee_common_1.GoveeError('Unable to authenticate with AWS IoT broker'); } this.logger.log('Getting IoT authentication information'); const response = await (0, utils_1.request)(this.config.iotCertUrl, this.config.authenticatedHeaders(this.persistedAccount.oauth)).get(iot_certificate_response_1.IoTCertificateResponse); const iotCertResponse = response.data; const iotCertificate = await (0, utils_1.parseP12Certificate)(iotCertResponse.iotData.p12Certificate, iotCertResponse.iotData.certificatePassword); this.persistedAccount.iot = { ...iotCertificate, endpoint: iotCertResponse.iotData.brokerUrl, accountId: this.persistedAccount.accountId, clientId: this.persistedAccount.clientId, topic: this.persistedAccount.topic, }; } catch (err) { this.logger.error('Unable to retrieve IoT certificate', err); throw new Error('Unable to retrieve IoT certificate'); } } }; exports.GoveeAccountService = GoveeAccountService; __decorate([ (0, _ultimate_govee_persist_1.PersistResult)({ filename: 'govee.accountClient.json', }), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], GoveeAccountService.prototype, "authenticate", null); exports.GoveeAccountService = GoveeAccountService = GoveeAccountService_1 = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)(govee_account_configuration_1.GoveeAccountConfig.KEY)), __param(1, (0, _ultimate_govee_persist_1.InjectPersisted)({ filename: 'govee.accountClient.json', })), __metadata("design:paramtypes", [void 0, Object]) ], GoveeAccountService); //# sourceMappingURL=govee-account.service.js.map