homebridge-bold
Version:
HomeKit support for the Bold Smart Locks.
157 lines (156 loc) • 8.08 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BoldAPI = void 0;
const axios_1 = __importDefault(require("axios"));
const form_data_1 = __importDefault(require("form-data"));
const const_1 = require("./const");
class BoldAPI {
constructor(config, log) {
this.config = config;
this.log = log;
}
request(method, endpoint, body = undefined, headers = undefined) {
var _a, _b, _c;
return __awaiter(this, void 0, void 0, function* () {
try {
let response = yield axios_1.default.request({
method: method,
url: `https://api.boldsmartlock.com${endpoint}`,
headers: Object.assign(Object.assign({ 'Authorization': `Bearer ${this.config.accessToken}` }, (!Object.keys(headers || {}).some((header) => header.toLowerCase() == 'content-type') && { 'Content-Type': 'application/json' })), headers),
data: body
});
if ((response.data.errorCode != null && response.data.errorCode != 'OK') && (response.data.errorMessage != null && response.data.errorMessage != 'OK')) {
return {
success: false,
error: {
code: response.data.errorCode,
message: response.data.errorMessage
}
};
}
return {
success: true,
data: response.data
};
}
catch (error) {
if (axios_1.default.isAxiosError(error)) {
let axiosError = error;
return {
success: false,
error: {
code: ((_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.data.errorCode) || ((_b = axiosError.response) === null || _b === void 0 ? void 0 : _b.status) || axiosError.code,
message: ((_c = axiosError.response) === null || _c === void 0 ? void 0 : _c.data.errorMessage) || `${axiosError}`
}
};
}
else {
return {
success: false,
error: {
message: `${error}`
}
};
}
}
});
}
getDevices() {
return __awaiter(this, void 0, void 0, function* () {
this.log.debug('Getting all devices');
let response = yield this.request('GET', '/v1/effective-device-permissions');
if (!response.success) {
throw new Error(`Error ${response.error.code ? `(${response.error.code}) ` : ''}while getting devices: ${response.error.message}`);
}
if (Array.isArray(response.data)) {
let devices = response.data;
let supportedDevices = devices.filter((device) => device.id != null && device.name && device.featureSet.isActivatable && device.gateway != null);
this.log.debug(`Total device count: ${devices.length}, Supported device count: ${supportedDevices.length}`);
return supportedDevices;
}
else {
throw new Error('Unknown reponse while getting devices: ${response.data}');
}
});
}
activate(deviceId, hasRefreshedToken = false) {
return __awaiter(this, void 0, void 0, function* () {
this.log.debug(`Activating device (${deviceId})`);
let response = yield this.request('POST', `/v1/devices/${deviceId}/remote-activation`);
if (!response.success && response.error.code == 401 && !hasRefreshedToken) {
// If HTTP 401, try token refresh
this.log.warn(`Error while activating device (${deviceId}). Refreshing token and retrying.`);
yield this.refresh();
let result = yield this.activate(deviceId, true);
if (!result) {
this.log.error('Activation failed even after token refresh. Try logging in again. If this problem persists, open an issue.');
}
return result;
}
else if (!response.success) {
this.log.error(`Error ${response.error.code ? `(${response.error.code}) ` : ''}while activating device (${deviceId}): ${response.error.message}`);
return false;
}
this.log.debug(`Successfully activated device (${deviceId})`);
return true;
});
}
refresh() {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function* () {
this.log.debug('Refreshing access token');
if (this.config.legacyAuthentication) {
return yield this.refreshLegacy();
}
try {
let response = yield axios_1.default.post(this.config.refreshURL || const_1.REFRESH_URL, { refreshToken: this.config.refreshToken });
let { accessToken, refreshToken } = response.data.data;
if (!accessToken || !refreshToken) {
this.log.error(`Missing access or refresh token: ${JSON.stringify(response.data)}`);
return;
}
this.log.debug('Successfully refreshed access token');
return { accessToken, refreshToken };
}
catch (error) {
if (axios_1.default.isAxiosError(error)) {
let axiosError = error;
this.log.error(`Error (${(_a = error.response) === null || _a === void 0 ? void 0 : _a.status}) while refreshing token: ${((_d = (_c = (_b = axiosError.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.error) === null || _d === void 0 ? void 0 : _d.message) || error}`);
}
else {
this.log.error(`Error while refreshing access token: ${error}`);
}
}
});
}
refreshLegacy() {
return __awaiter(this, void 0, void 0, function* () {
let formData = new form_data_1.default();
formData.append('client_id', const_1.LEGACY_CLIENT_ID);
formData.append('client_secret', const_1.LEGACY_CLIENT_SECRET);
formData.append('refresh_token', this.config.refreshToken);
formData.append('grant_type', 'refresh_token');
let response = yield this.request('POST', '/v2/oauth/token', formData, formData.getHeaders());
if (!response.success) {
this.log.error(`Error ${response.error.code ? `(${response.error.code}) ` : ''}while refreshing token: ${response.error.message}`);
return;
}
let data = response.data;
this.log.debug('Successfully refreshed access token');
return { accessToken: data.access_token, refreshToken: data.refresh_token };
});
}
}
exports.BoldAPI = BoldAPI;