@constructorfleet/ultimate-govee
Version:
Library for interacting with Govee devices written in Typescript.
181 lines • 8.83 kB
JavaScript
"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