hap-nodejs 1.1.1-beta.5 → 1.1.1-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/bonjour-hap.d.ts +53 -50
- package/@types/simple-plist.d.ts +4 -0
- package/README.md +19 -16
- package/dist/accessories/AirConditioner_accessory.js +32 -30
- package/dist/accessories/AirConditioner_accessory.js.map +1 -1
- package/dist/accessories/AppleTVRemote_accessory.js +86 -74
- package/dist/accessories/AppleTVRemote_accessory.js.map +1 -1
- package/dist/accessories/Camera_accessory.js +138 -143
- package/dist/accessories/Camera_accessory.js.map +1 -1
- package/dist/accessories/Fan_accessory.js +24 -20
- package/dist/accessories/Fan_accessory.js.map +1 -1
- package/dist/accessories/GarageDoorOpener_accessory.js +37 -35
- package/dist/accessories/GarageDoorOpener_accessory.js.map +1 -1
- package/dist/accessories/Light-AdaptiveLighting_accessory.js +46 -44
- package/dist/accessories/Light-AdaptiveLighting_accessory.js.map +1 -1
- package/dist/accessories/Light_accessory.js +36 -34
- package/dist/accessories/Light_accessory.js.map +1 -1
- package/dist/accessories/Lock_accessory.js +28 -27
- package/dist/accessories/Lock_accessory.js.map +1 -1
- package/dist/accessories/MotionSensor_accessory.js +18 -15
- package/dist/accessories/MotionSensor_accessory.js.map +1 -1
- package/dist/accessories/Outlet_accessory.js +24 -22
- package/dist/accessories/Outlet_accessory.js.map +1 -1
- package/dist/accessories/SmartSpeaker_accessory.js +22 -20
- package/dist/accessories/SmartSpeaker_accessory.js.map +1 -1
- package/dist/accessories/Sprinkler_accessory.js +39 -36
- package/dist/accessories/Sprinkler_accessory.js.map +1 -1
- package/dist/accessories/TV_accessory.js +47 -45
- package/dist/accessories/TV_accessory.js.map +1 -1
- package/dist/accessories/TemperatureSensor_accessory.js +17 -14
- package/dist/accessories/TemperatureSensor_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.d.ts +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.d.ts.map +1 -1
- package/dist/accessories/Wi-FiRouter_accessory.js +14 -11
- package/dist/accessories/Wi-FiRouter_accessory.js.map +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.d.ts +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.d.ts.map +1 -1
- package/dist/accessories/Wi-FiSatellite_accessory.js +16 -13
- package/dist/accessories/Wi-FiSatellite_accessory.js.map +1 -1
- package/dist/accessories/gstreamer-audioProducer.d.ts +3 -3
- package/dist/accessories/gstreamer-audioProducer.d.ts.map +1 -1
- package/dist/accessories/gstreamer-audioProducer.js +39 -38
- package/dist/accessories/gstreamer-audioProducer.js.map +1 -1
- package/dist/accessories/types.d.ts +63 -63
- package/dist/accessories/types.d.ts.map +1 -1
- package/dist/accessories/types.js +87 -83
- package/dist/accessories/types.js.map +1 -1
- package/dist/index.d.ts +28 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -40
- package/dist/index.js.map +1 -1
- package/dist/internal-types.d.ts +1 -1
- package/dist/internal-types.d.ts.map +1 -1
- package/dist/internal-types.js +21 -19
- package/dist/internal-types.js.map +1 -1
- package/dist/lib/Accessory.d.ts +37 -38
- package/dist/lib/Accessory.d.ts.map +1 -1
- package/dist/lib/Accessory.js +299 -289
- package/dist/lib/Accessory.js.map +1 -1
- package/dist/lib/Advertiser.d.ts +7 -7
- package/dist/lib/Advertiser.d.ts.map +1 -1
- package/dist/lib/Advertiser.js +136 -128
- package/dist/lib/Advertiser.js.map +1 -1
- package/dist/lib/Bridge.d.ts +1 -1
- package/dist/lib/Bridge.d.ts.map +1 -1
- package/dist/lib/Bridge.js +6 -2
- package/dist/lib/Bridge.js.map +1 -1
- package/dist/lib/Characteristic.d.ts +41 -40
- package/dist/lib/Characteristic.d.ts.map +1 -1
- package/dist/lib/Characteristic.js +210 -206
- package/dist/lib/Characteristic.js.map +1 -1
- package/dist/lib/HAPServer.d.ts +30 -35
- package/dist/lib/HAPServer.d.ts.map +1 -1
- package/dist/lib/HAPServer.js +229 -225
- package/dist/lib/HAPServer.js.map +1 -1
- package/dist/lib/Service.d.ts +22 -22
- package/dist/lib/Service.d.ts.map +1 -1
- package/dist/lib/Service.js +71 -67
- package/dist/lib/Service.js.map +1 -1
- package/dist/lib/camera/RTPProxy.d.ts +1 -2
- package/dist/lib/camera/RTPProxy.d.ts.map +1 -1
- package/dist/lib/camera/RTPProxy.js +44 -28
- package/dist/lib/camera/RTPProxy.js.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.d.ts +33 -34
- package/dist/lib/camera/RTPStreamManagement.d.ts.map +1 -1
- package/dist/lib/camera/RTPStreamManagement.js +149 -181
- package/dist/lib/camera/RTPStreamManagement.js.map +1 -1
- package/dist/lib/camera/RecordingManagement.d.ts +17 -19
- package/dist/lib/camera/RecordingManagement.d.ts.map +1 -1
- package/dist/lib/camera/RecordingManagement.js +153 -162
- package/dist/lib/camera/RecordingManagement.js.map +1 -1
- package/dist/lib/camera/index.d.ts +3 -3
- package/dist/lib/camera/index.d.ts.map +1 -1
- package/dist/lib/camera/index.js +6 -3
- package/dist/lib/camera/index.js.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.d.ts +33 -33
- package/dist/lib/controller/AdaptiveLightingController.d.ts.map +1 -1
- package/dist/lib/controller/AdaptiveLightingController.js +146 -154
- package/dist/lib/controller/AdaptiveLightingController.js.map +1 -1
- package/dist/lib/controller/CameraController.d.ts +20 -22
- package/dist/lib/controller/CameraController.d.ts.map +1 -1
- package/dist/lib/controller/CameraController.js +78 -74
- package/dist/lib/controller/CameraController.js.map +1 -1
- package/dist/lib/controller/Controller.d.ts +4 -4
- package/dist/lib/controller/Controller.d.ts.map +1 -1
- package/dist/lib/controller/Controller.js +8 -5
- package/dist/lib/controller/Controller.js.map +1 -1
- package/dist/lib/controller/DoorbellController.d.ts +4 -5
- package/dist/lib/controller/DoorbellController.d.ts.map +1 -1
- package/dist/lib/controller/DoorbellController.js +13 -9
- package/dist/lib/controller/DoorbellController.js.map +1 -1
- package/dist/lib/controller/RemoteController.d.ts +37 -39
- package/dist/lib/controller/RemoteController.d.ts.map +1 -1
- package/dist/lib/controller/RemoteController.js +199 -210
- package/dist/lib/controller/RemoteController.js.map +1 -1
- package/dist/lib/controller/index.d.ts +5 -5
- package/dist/lib/controller/index.d.ts.map +1 -1
- package/dist/lib/controller/index.js +8 -5
- package/dist/lib/controller/index.js.map +1 -1
- package/dist/lib/datastream/DataStreamManagement.d.ts +2 -2
- package/dist/lib/datastream/DataStreamManagement.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamManagement.js +40 -40
- package/dist/lib/datastream/DataStreamManagement.js.map +1 -1
- package/dist/lib/datastream/DataStreamParser.d.ts +0 -1
- package/dist/lib/datastream/DataStreamParser.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamParser.js +77 -57
- package/dist/lib/datastream/DataStreamParser.js.map +1 -1
- package/dist/lib/datastream/DataStreamServer.d.ts +22 -27
- package/dist/lib/datastream/DataStreamServer.d.ts.map +1 -1
- package/dist/lib/datastream/DataStreamServer.js +164 -159
- package/dist/lib/datastream/DataStreamServer.js.map +1 -1
- package/dist/lib/datastream/index.d.ts +3 -3
- package/dist/lib/datastream/index.d.ts.map +1 -1
- package/dist/lib/datastream/index.js +6 -3
- package/dist/lib/datastream/index.js.map +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.d.ts +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.d.ts.map +1 -1
- package/dist/lib/definitions/CharacteristicDefinitions.js +1203 -957
- package/dist/lib/definitions/CharacteristicDefinitions.js.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.d.ts +1 -1
- package/dist/lib/definitions/ServiceDefinitions.d.ts.map +1 -1
- package/dist/lib/definitions/ServiceDefinitions.js +695 -620
- package/dist/lib/definitions/ServiceDefinitions.js.map +1 -1
- package/dist/lib/definitions/generate-definitions.d.ts +3 -3
- package/dist/lib/definitions/generate-definitions.d.ts.map +1 -1
- package/dist/lib/definitions/generate-definitions.js +259 -247
- package/dist/lib/definitions/generate-definitions.js.map +1 -1
- package/dist/lib/definitions/generator-configuration.d.ts +1 -1
- package/dist/lib/definitions/generator-configuration.d.ts.map +1 -1
- package/dist/lib/definitions/generator-configuration.js +181 -176
- package/dist/lib/definitions/generator-configuration.js.map +1 -1
- package/dist/lib/definitions/index.d.ts +2 -2
- package/dist/lib/definitions/index.d.ts.map +1 -1
- package/dist/lib/definitions/index.js +5 -2
- package/dist/lib/definitions/index.js.map +1 -1
- package/dist/lib/gen/HomeKit.d.ts +7 -0
- package/dist/lib/gen/HomeKit.d.ts.map +1 -0
- package/dist/lib/gen/HomeKit.js +8 -0
- package/dist/lib/gen/HomeKit.js.map +1 -0
- package/dist/lib/model/AccessoryInfo.d.ts +3 -4
- package/dist/lib/model/AccessoryInfo.d.ts.map +1 -1
- package/dist/lib/model/AccessoryInfo.js +55 -52
- package/dist/lib/model/AccessoryInfo.js.map +1 -1
- package/dist/lib/model/ControllerStorage.d.ts +3 -3
- package/dist/lib/model/ControllerStorage.d.ts.map +1 -1
- package/dist/lib/model/ControllerStorage.js +23 -18
- package/dist/lib/model/ControllerStorage.js.map +1 -1
- package/dist/lib/model/HAPStorage.d.ts +2 -2
- package/dist/lib/model/HAPStorage.d.ts.map +1 -1
- package/dist/lib/model/HAPStorage.js +11 -4
- package/dist/lib/model/HAPStorage.js.map +1 -1
- package/dist/lib/model/IdentifierCache.d.ts +1 -1
- package/dist/lib/model/IdentifierCache.d.ts.map +1 -1
- package/dist/lib/model/IdentifierCache.js +27 -19
- package/dist/lib/model/IdentifierCache.js.map +1 -1
- package/dist/lib/tv/AccessControlManagement.d.ts +9 -9
- package/dist/lib/tv/AccessControlManagement.d.ts.map +1 -1
- package/dist/lib/tv/AccessControlManagement.js +29 -27
- package/dist/lib/tv/AccessControlManagement.js.map +1 -1
- package/dist/lib/util/checkName.d.ts +2 -2
- package/dist/lib/util/checkName.d.ts.map +1 -1
- package/dist/lib/util/checkName.js +9 -6
- package/dist/lib/util/checkName.js.map +1 -1
- package/dist/lib/util/clone.d.ts.map +1 -1
- package/dist/lib/util/clone.js +5 -1
- package/dist/lib/util/clone.js.map +1 -1
- package/dist/lib/util/color-utils.d.ts +1 -1
- package/dist/lib/util/color-utils.d.ts.map +1 -1
- package/dist/lib/util/color-utils.js +9 -4
- package/dist/lib/util/color-utils.js.map +1 -1
- package/dist/lib/util/eventedhttp.d.ts +22 -23
- package/dist/lib/util/eventedhttp.d.ts.map +1 -1
- package/dist/lib/util/eventedhttp.js +116 -109
- package/dist/lib/util/eventedhttp.js.map +1 -1
- package/dist/lib/util/hapCrypto.d.ts +2 -3
- package/dist/lib/util/hapCrypto.d.ts.map +1 -1
- package/dist/lib/util/hapCrypto.js +40 -31
- package/dist/lib/util/hapCrypto.js.map +1 -1
- package/dist/lib/util/hapStatusError.d.ts +1 -1
- package/dist/lib/util/hapStatusError.d.ts.map +1 -1
- package/dist/lib/util/hapStatusError.js +8 -4
- package/dist/lib/util/hapStatusError.js.map +1 -1
- package/dist/lib/util/net-utils.d.ts +1 -1
- package/dist/lib/util/net-utils.js +23 -17
- package/dist/lib/util/net-utils.js.map +1 -1
- package/dist/lib/util/once.d.ts.map +1 -1
- package/dist/lib/util/once.js +6 -2
- package/dist/lib/util/once.js.map +1 -1
- package/dist/lib/util/promise-utils.d.ts +1 -1
- package/dist/lib/util/promise-utils.d.ts.map +1 -1
- package/dist/lib/util/promise-utils.js +10 -3
- package/dist/lib/util/promise-utils.js.map +1 -1
- package/dist/lib/util/request-util.d.ts +2 -3
- package/dist/lib/util/request-util.d.ts.map +1 -1
- package/dist/lib/util/request-util.js +19 -11
- package/dist/lib/util/request-util.js.map +1 -1
- package/dist/lib/util/time.d.ts +0 -1
- package/dist/lib/util/time.d.ts.map +1 -1
- package/dist/lib/util/time.js +11 -6
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/tlv.d.ts +0 -1
- package/dist/lib/util/tlv.d.ts.map +1 -1
- package/dist/lib/util/tlv.js +43 -28
- package/dist/lib/util/tlv.js.map +1 -1
- package/dist/lib/util/uuid.d.ts +0 -1
- package/dist/lib/util/uuid.d.ts.map +1 -1
- package/dist/lib/util/uuid.js +38 -26
- package/dist/lib/util/uuid.js.map +1 -1
- package/dist/types.d.ts +24 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -3
- package/dist/types.js.map +1 -1
- package/package.json +47 -52
- package/dist/lib/dbus/align.d.ts +0 -2
- package/dist/lib/dbus/align.d.ts.map +0 -1
- package/dist/lib/dbus/align.js +0 -12
- package/dist/lib/dbus/align.js.map +0 -1
- package/dist/lib/dbus/bus.d.ts +0 -38
- package/dist/lib/dbus/bus.d.ts.map +0 -1
- package/dist/lib/dbus/bus.js +0 -222
- package/dist/lib/dbus/bus.js.map +0 -1
- package/dist/lib/dbus/constants.d.ts +0 -43
- package/dist/lib/dbus/constants.d.ts.map +0 -1
- package/dist/lib/dbus/constants.js +0 -53
- package/dist/lib/dbus/constants.js.map +0 -1
- package/dist/lib/dbus/dbus-buffer.d.ts +0 -30
- package/dist/lib/dbus/dbus-buffer.d.ts.map +0 -1
- package/dist/lib/dbus/dbus-buffer.js +0 -175
- package/dist/lib/dbus/dbus-buffer.js.map +0 -1
- package/dist/lib/dbus/handshake.d.ts +0 -2
- package/dist/lib/dbus/handshake.d.ts.map +0 -1
- package/dist/lib/dbus/handshake.js +0 -130
- package/dist/lib/dbus/handshake.js.map +0 -1
- package/dist/lib/dbus/index.d.ts +0 -3
- package/dist/lib/dbus/index.d.ts.map +0 -1
- package/dist/lib/dbus/index.js +0 -123
- package/dist/lib/dbus/index.js.map +0 -1
- package/dist/lib/dbus/introspect.d.ts +0 -30
- package/dist/lib/dbus/introspect.d.ts.map +0 -1
- package/dist/lib/dbus/introspect.js +0 -208
- package/dist/lib/dbus/introspect.js.map +0 -1
- package/dist/lib/dbus/marshall.d.ts +0 -2
- package/dist/lib/dbus/marshall.d.ts.map +0 -1
- package/dist/lib/dbus/marshall.js +0 -97
- package/dist/lib/dbus/marshall.js.map +0 -1
- package/dist/lib/dbus/marshallers.d.ts +0 -10
- package/dist/lib/dbus/marshallers.d.ts.map +0 -1
- package/dist/lib/dbus/marshallers.js +0 -329
- package/dist/lib/dbus/marshallers.js.map +0 -1
- package/dist/lib/dbus/message.d.ts +0 -4
- package/dist/lib/dbus/message.d.ts.map +0 -1
- package/dist/lib/dbus/message.js +0 -116
- package/dist/lib/dbus/message.js.map +0 -1
- package/dist/lib/dbus/put.d.ts +0 -21
- package/dist/lib/dbus/put.d.ts.map +0 -1
- package/dist/lib/dbus/put.js +0 -120
- package/dist/lib/dbus/put.js.map +0 -1
- package/dist/lib/dbus/readline.d.ts +0 -2
- package/dist/lib/dbus/readline.d.ts.map +0 -1
- package/dist/lib/dbus/readline.js +0 -27
- package/dist/lib/dbus/readline.js.map +0 -1
- package/dist/lib/dbus/signature.d.ts +0 -2
- package/dist/lib/dbus/signature.d.ts.map +0 -1
- package/dist/lib/dbus/signature.js +0 -59
- package/dist/lib/dbus/signature.js.map +0 -1
- package/dist/lib/dbus/stdifaces.d.ts +0 -3
- package/dist/lib/dbus/stdifaces.d.ts.map +0 -1
- package/dist/lib/dbus/stdifaces.js +0 -206
- package/dist/lib/dbus/stdifaces.js.map +0 -1
package/dist/lib/HAPServer.js
CHANGED
|
@@ -1,40 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HAPServer = exports.HAPServerEventTypes = exports.HAPPairingHTTPCode = exports.HAPHTTPCode = exports.HAPStatus = exports.TLVErrorCode = void 0;
|
|
4
|
+
exports.IsKnownHAPStatusError = IsKnownHAPStatusError;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const crypto_1 = tslib_1.__importDefault(require("crypto"));
|
|
7
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
8
|
+
const events_1 = require("events");
|
|
9
|
+
const fast_srp_hap_1 = require("fast-srp-hap");
|
|
10
|
+
const tweetnacl_1 = tslib_1.__importDefault(require("tweetnacl"));
|
|
11
|
+
const url_1 = require("url");
|
|
12
|
+
const internal_types_1 = require("../internal-types");
|
|
13
|
+
const eventedhttp_1 = require("./util/eventedhttp");
|
|
14
|
+
const hapCrypto = tslib_1.__importStar(require("./util/hapCrypto"));
|
|
15
|
+
const once_1 = require("./util/once");
|
|
16
|
+
const tlv = tslib_1.__importStar(require("./util/tlv"));
|
|
17
|
+
const debug = (0, debug_1.default)("HAP-NodeJS:HAPServer");
|
|
14
18
|
/**
|
|
15
19
|
* TLV error codes for the `TLVValues.ERROR_CODE` field.
|
|
16
20
|
*
|
|
17
21
|
* @group HAP Accessory Server
|
|
18
22
|
*/
|
|
19
|
-
|
|
20
|
-
export var TLVErrorCode;
|
|
23
|
+
var TLVErrorCode;
|
|
21
24
|
(function (TLVErrorCode) {
|
|
25
|
+
// noinspection JSUnusedGlobalSymbols
|
|
22
26
|
TLVErrorCode[TLVErrorCode["UNKNOWN"] = 1] = "UNKNOWN";
|
|
23
27
|
TLVErrorCode[TLVErrorCode["INVALID_REQUEST"] = 2] = "INVALID_REQUEST";
|
|
24
|
-
// eslint-disable-next-line
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
|
|
25
29
|
TLVErrorCode[TLVErrorCode["AUTHENTICATION"] = 2] = "AUTHENTICATION";
|
|
26
30
|
TLVErrorCode[TLVErrorCode["BACKOFF"] = 3] = "BACKOFF";
|
|
27
31
|
TLVErrorCode[TLVErrorCode["MAX_PEERS"] = 4] = "MAX_PEERS";
|
|
28
32
|
TLVErrorCode[TLVErrorCode["MAX_TRIES"] = 5] = "MAX_TRIES";
|
|
29
33
|
TLVErrorCode[TLVErrorCode["UNAVAILABLE"] = 6] = "UNAVAILABLE";
|
|
30
|
-
TLVErrorCode[TLVErrorCode["BUSY"] = 7] = "BUSY";
|
|
31
|
-
})(TLVErrorCode || (TLVErrorCode = {}));
|
|
34
|
+
TLVErrorCode[TLVErrorCode["BUSY"] = 7] = "BUSY"; // cannot accept pairing request at this time
|
|
35
|
+
})(TLVErrorCode || (exports.TLVErrorCode = TLVErrorCode = {}));
|
|
32
36
|
/**
|
|
33
37
|
* @group HAP Accessory Server
|
|
34
38
|
*/
|
|
35
|
-
|
|
36
|
-
export var HAPStatus;
|
|
39
|
+
var HAPStatus;
|
|
37
40
|
(function (HAPStatus) {
|
|
41
|
+
// noinspection JSUnusedGlobalSymbols
|
|
38
42
|
/**
|
|
39
43
|
* Success of the request.
|
|
40
44
|
*/
|
|
@@ -87,24 +91,19 @@ export var HAPStatus;
|
|
|
87
91
|
* Operation not allowed in the current state.
|
|
88
92
|
*/
|
|
89
93
|
HAPStatus[HAPStatus["NOT_ALLOWED_IN_CURRENT_STATE"] = -70412] = "NOT_ALLOWED_IN_CURRENT_STATE";
|
|
90
|
-
// when adding new status codes, remember to update bounds in
|
|
91
|
-
})(HAPStatus || (HAPStatus = {}));
|
|
92
|
-
/**
|
|
93
|
-
* @hidden
|
|
94
|
-
*/
|
|
95
|
-
// @ts-expect-error - workaround for import issues in the compiled output, when accessing values using a variable key
|
|
96
|
-
export const HAPStatusConst = HAPStatus;
|
|
94
|
+
// when adding new status codes, remember to update bounds in IsKnownHAPStatusError below
|
|
95
|
+
})(HAPStatus || (exports.HAPStatus = HAPStatus = {}));
|
|
97
96
|
/**
|
|
98
97
|
* Determines if the given status code is a known {@link HAPStatus} error code.
|
|
99
98
|
*
|
|
100
99
|
* @group HAP Accessory Server
|
|
101
100
|
*/
|
|
102
|
-
|
|
101
|
+
function IsKnownHAPStatusError(status) {
|
|
103
102
|
return (
|
|
104
103
|
// Lower bound (most negative error code)
|
|
105
|
-
status >= -70412 /* HAPStatus.NOT_ALLOWED_IN_CURRENT_STATE */
|
|
104
|
+
status >= -70412 /* HAPStatus.NOT_ALLOWED_IN_CURRENT_STATE */ &&
|
|
106
105
|
// Upper bound (negative error code closest to zero)
|
|
107
|
-
|
|
106
|
+
status <= -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */);
|
|
108
107
|
}
|
|
109
108
|
/**
|
|
110
109
|
* Those status codes are the one listed as appropriate for the HAP spec!
|
|
@@ -116,9 +115,9 @@ export function isKnownHAPStatusError(status) {
|
|
|
116
115
|
*
|
|
117
116
|
* @group HAP Accessory Server
|
|
118
117
|
*/
|
|
119
|
-
|
|
120
|
-
export var HAPHTTPCode;
|
|
118
|
+
var HAPHTTPCode;
|
|
121
119
|
(function (HAPHTTPCode) {
|
|
120
|
+
// noinspection JSUnusedGlobalSymbols
|
|
122
121
|
HAPHTTPCode[HAPHTTPCode["OK"] = 200] = "OK";
|
|
123
122
|
HAPHTTPCode[HAPHTTPCode["NO_CONTENT"] = 204] = "NO_CONTENT";
|
|
124
123
|
HAPHTTPCode[HAPHTTPCode["MULTI_STATUS"] = 207] = "MULTI_STATUS";
|
|
@@ -129,28 +128,27 @@ export var HAPHTTPCode;
|
|
|
129
128
|
// server error
|
|
130
129
|
HAPHTTPCode[HAPHTTPCode["INTERNAL_SERVER_ERROR"] = 500] = "INTERNAL_SERVER_ERROR";
|
|
131
130
|
HAPHTTPCode[HAPHTTPCode["SERVICE_UNAVAILABLE"] = 503] = "SERVICE_UNAVAILABLE";
|
|
132
|
-
})(HAPHTTPCode || (HAPHTTPCode = {}));
|
|
131
|
+
})(HAPHTTPCode || (exports.HAPHTTPCode = HAPHTTPCode = {}));
|
|
133
132
|
/**
|
|
134
133
|
* When in a request is made to the pairing endpoints, and mime type is 'application/pairing+tlv8'
|
|
135
134
|
* one should use the below status codes.
|
|
136
135
|
*
|
|
137
136
|
* @group HAP Accessory Server
|
|
138
137
|
*/
|
|
139
|
-
|
|
140
|
-
export var HAPPairingHTTPCode;
|
|
138
|
+
var HAPPairingHTTPCode;
|
|
141
139
|
(function (HAPPairingHTTPCode) {
|
|
140
|
+
// noinspection JSUnusedGlobalSymbols
|
|
142
141
|
HAPPairingHTTPCode[HAPPairingHTTPCode["OK"] = 200] = "OK";
|
|
143
142
|
HAPPairingHTTPCode[HAPPairingHTTPCode["BAD_REQUEST"] = 400] = "BAD_REQUEST";
|
|
144
143
|
HAPPairingHTTPCode[HAPPairingHTTPCode["METHOD_NOT_ALLOWED"] = 405] = "METHOD_NOT_ALLOWED";
|
|
145
144
|
HAPPairingHTTPCode[HAPPairingHTTPCode["TOO_MANY_REQUESTS"] = 429] = "TOO_MANY_REQUESTS";
|
|
146
145
|
HAPPairingHTTPCode[HAPPairingHTTPCode["CONNECTION_AUTHORIZATION_REQUIRED"] = 470] = "CONNECTION_AUTHORIZATION_REQUIRED";
|
|
147
146
|
HAPPairingHTTPCode[HAPPairingHTTPCode["INTERNAL_SERVER_ERROR"] = 500] = "INTERNAL_SERVER_ERROR";
|
|
148
|
-
})(HAPPairingHTTPCode || (HAPPairingHTTPCode = {}));
|
|
147
|
+
})(HAPPairingHTTPCode || (exports.HAPPairingHTTPCode = HAPPairingHTTPCode = {}));
|
|
149
148
|
/**
|
|
150
149
|
* @group HAP Accessory Server
|
|
151
150
|
*/
|
|
152
|
-
|
|
153
|
-
export var HAPServerEventTypes;
|
|
151
|
+
var HAPServerEventTypes;
|
|
154
152
|
(function (HAPServerEventTypes) {
|
|
155
153
|
/**
|
|
156
154
|
* Emitted when the server is fully set up and ready to receive connections.
|
|
@@ -193,7 +191,7 @@ export var HAPServerEventTypes;
|
|
|
193
191
|
HAPServerEventTypes["SET_CHARACTERISTICS"] = "set-characteristics";
|
|
194
192
|
HAPServerEventTypes["REQUEST_RESOURCE"] = "request-resource";
|
|
195
193
|
HAPServerEventTypes["CONNECTION_CLOSED"] = "connection-closed";
|
|
196
|
-
})(HAPServerEventTypes || (HAPServerEventTypes = {}));
|
|
194
|
+
})(HAPServerEventTypes || (exports.HAPServerEventTypes = HAPServerEventTypes = {}));
|
|
197
195
|
/**
|
|
198
196
|
* The actual HAP server that iOS devices talk to.
|
|
199
197
|
*
|
|
@@ -215,8 +213,8 @@ export var HAPServerEventTypes;
|
|
|
215
213
|
*
|
|
216
214
|
* @group HAP Accessory Server
|
|
217
215
|
*/
|
|
218
|
-
// eslint-disable-next-line
|
|
219
|
-
|
|
216
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
|
217
|
+
class HAPServer extends events_1.EventEmitter {
|
|
220
218
|
accessoryInfo;
|
|
221
219
|
httpServer;
|
|
222
220
|
unsuccessfulPairAttempts = 0; // after 100 unsuccessful attempts the server won't accept any further attempts. Will currently be reset on a reboot
|
|
@@ -226,13 +224,13 @@ export class HAPServer extends EventEmitter {
|
|
|
226
224
|
this.accessoryInfo = accessoryInfo;
|
|
227
225
|
this.allowInsecureRequest = false;
|
|
228
226
|
// internal server that does all the actual communication
|
|
229
|
-
this.httpServer = new EventedHTTPServer();
|
|
227
|
+
this.httpServer = new eventedhttp_1.EventedHTTPServer();
|
|
230
228
|
this.httpServer.on("listening" /* EventedHTTPServerEvent.LISTENING */, this.onListening.bind(this));
|
|
231
229
|
this.httpServer.on("request" /* EventedHTTPServerEvent.REQUEST */, this.handleRequestOnHAPConnection.bind(this));
|
|
232
230
|
this.httpServer.on("connection-closed" /* EventedHTTPServerEvent.CONNECTION_CLOSED */, this.handleConnectionClosed.bind(this));
|
|
233
231
|
}
|
|
234
232
|
listen(port = 0, host) {
|
|
235
|
-
if (host ===
|
|
233
|
+
if (host === "::") {
|
|
236
234
|
// this will work around "EAFNOSUPPORT: address family not supported" errors
|
|
237
235
|
// on systems where IPv6 is not supported/enabled, we just use the node default then by supplying undefined
|
|
238
236
|
host = undefined;
|
|
@@ -255,14 +253,14 @@ export class HAPServer extends EventEmitter {
|
|
|
255
253
|
* @param value - The newly set value of the characteristic.
|
|
256
254
|
* @param originator - If specified, the connection will not get an event message.
|
|
257
255
|
* @param immediateDelivery - The HAP spec requires some characteristics to be delivery immediately.
|
|
258
|
-
*
|
|
256
|
+
* Namely, for the {@link Characteristic.ButtonEvent} and the {@link Characteristic.ProgrammableSwitchEvent} characteristics.
|
|
259
257
|
*/
|
|
260
258
|
sendEventNotifications(aid, iid, value, originator, immediateDelivery) {
|
|
261
259
|
try {
|
|
262
260
|
this.httpServer.broadcastEvent(aid, iid, value, originator, immediateDelivery);
|
|
263
261
|
}
|
|
264
262
|
catch (error) {
|
|
265
|
-
console.warn(
|
|
263
|
+
console.warn("[" + this.accessoryInfo.username + "] Error when sending event notifications: " + error.message);
|
|
266
264
|
}
|
|
267
265
|
}
|
|
268
266
|
onListening(port, hostname) {
|
|
@@ -270,15 +268,15 @@ export class HAPServer extends EventEmitter {
|
|
|
270
268
|
}
|
|
271
269
|
// Called when an HTTP request was detected.
|
|
272
270
|
handleRequestOnHAPConnection(connection, request, response) {
|
|
273
|
-
debug(
|
|
271
|
+
debug("[%s] HAP Request: %s %s", this.accessoryInfo.username, request.method, request.url);
|
|
274
272
|
const buffers = [];
|
|
275
|
-
request.on(
|
|
276
|
-
request.on(
|
|
277
|
-
const url = new URL(request.url,
|
|
273
|
+
request.on("data", data => buffers.push(data));
|
|
274
|
+
request.on("end", () => {
|
|
275
|
+
const url = new url_1.URL(request.url, "http://hap-nodejs.local"); // parse the url (query strings etc)
|
|
278
276
|
const handler = this.getHandler(url);
|
|
279
277
|
if (!handler) {
|
|
280
|
-
debug(
|
|
281
|
-
response.writeHead(404 /* HAPHTTPCode.NOT_FOUND */, {
|
|
278
|
+
debug("[%s] WARNING: Handler for %s not implemented", this.accessoryInfo.username, request.url);
|
|
279
|
+
response.writeHead(404 /* HAPHTTPCode.NOT_FOUND */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
282
280
|
response.end(JSON.stringify({ status: -70409 /* HAPStatus.RESOURCE_DOES_NOT_EXIST */ }));
|
|
283
281
|
}
|
|
284
282
|
else {
|
|
@@ -287,8 +285,8 @@ export class HAPServer extends EventEmitter {
|
|
|
287
285
|
handler(connection, url, request, data, response);
|
|
288
286
|
}
|
|
289
287
|
catch (error) {
|
|
290
|
-
debug(
|
|
291
|
-
response.writeHead(500 /* HAPHTTPCode.INTERNAL_SERVER_ERROR */, {
|
|
288
|
+
debug("[%s] Error executing route handler: %s", this.accessoryInfo.username, error.stack);
|
|
289
|
+
response.writeHead(500 /* HAPHTTPCode.INTERNAL_SERVER_ERROR */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
292
290
|
response.end(JSON.stringify({ status: -70403 /* HAPStatus.RESOURCE_BUSY */ })); // resource busy try again, does somehow fit?
|
|
293
291
|
}
|
|
294
292
|
}
|
|
@@ -299,21 +297,21 @@ export class HAPServer extends EventEmitter {
|
|
|
299
297
|
}
|
|
300
298
|
getHandler(url) {
|
|
301
299
|
switch (url.pathname.toLowerCase()) {
|
|
302
|
-
case
|
|
300
|
+
case "/identify":
|
|
303
301
|
return this.handleIdentifyRequest.bind(this);
|
|
304
|
-
case
|
|
302
|
+
case "/pair-setup":
|
|
305
303
|
return this.handlePairSetup.bind(this);
|
|
306
|
-
case
|
|
304
|
+
case "/pair-verify":
|
|
307
305
|
return this.handlePairVerify.bind(this);
|
|
308
|
-
case
|
|
306
|
+
case "/pairings":
|
|
309
307
|
return this.handlePairings.bind(this);
|
|
310
|
-
case
|
|
308
|
+
case "/accessories":
|
|
311
309
|
return this.handleAccessories.bind(this);
|
|
312
|
-
case
|
|
310
|
+
case "/characteristics":
|
|
313
311
|
return this.handleCharacteristics.bind(this);
|
|
314
|
-
case
|
|
312
|
+
case "/prepare":
|
|
315
313
|
return this.handlePrepareWrite.bind(this);
|
|
316
|
-
case
|
|
314
|
+
case "/resource":
|
|
317
315
|
return this.handleResource.bind(this);
|
|
318
316
|
default:
|
|
319
317
|
return undefined;
|
|
@@ -325,19 +323,19 @@ export class HAPServer extends EventEmitter {
|
|
|
325
323
|
handleIdentifyRequest(connection, url, request, data, response) {
|
|
326
324
|
// POST body is empty
|
|
327
325
|
if (this.accessoryInfo.paired() && !this.allowInsecureRequest) {
|
|
328
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
326
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
329
327
|
response.end(JSON.stringify({ status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }));
|
|
330
328
|
return;
|
|
331
329
|
}
|
|
332
|
-
this.emit("identify" /* HAPServerEventTypes.IDENTIFY */, once(
|
|
330
|
+
this.emit("identify" /* HAPServerEventTypes.IDENTIFY */, (0, once_1.once)(err => {
|
|
333
331
|
if (!err) {
|
|
334
|
-
debug(
|
|
332
|
+
debug("[%s] Identification success", this.accessoryInfo.username);
|
|
335
333
|
response.writeHead(204 /* HAPHTTPCode.NO_CONTENT */);
|
|
336
334
|
response.end();
|
|
337
335
|
}
|
|
338
336
|
else {
|
|
339
|
-
debug(
|
|
340
|
-
response.writeHead(500 /* HAPHTTPCode.INTERNAL_SERVER_ERROR */, {
|
|
337
|
+
debug("[%s] Identification error: %s", this.accessoryInfo.username, err.message);
|
|
338
|
+
response.writeHead(500 /* HAPHTTPCode.INTERNAL_SERVER_ERROR */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
341
339
|
response.end(JSON.stringify({ status: -70403 /* HAPStatus.RESOURCE_BUSY */ }));
|
|
342
340
|
}
|
|
343
341
|
}));
|
|
@@ -345,17 +343,17 @@ export class HAPServer extends EventEmitter {
|
|
|
345
343
|
handlePairSetup(connection, url, request, data, response) {
|
|
346
344
|
// Can only be directly paired with one iOS device
|
|
347
345
|
if (!this.allowInsecureRequest && this.accessoryInfo.paired()) {
|
|
348
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
349
|
-
response.end(encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, 6 /* TLVErrorCode.UNAVAILABLE */));
|
|
346
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
347
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, 6 /* TLVErrorCode.UNAVAILABLE */));
|
|
350
348
|
return;
|
|
351
349
|
}
|
|
352
350
|
if (this.unsuccessfulPairAttempts > 100) {
|
|
353
|
-
debug(
|
|
354
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
355
|
-
response.end(encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, 5 /* TLVErrorCode.MAX_TRIES */));
|
|
351
|
+
debug("[%s] Reached maximum amount of unsuccessful pair attempts!", this.accessoryInfo.username);
|
|
352
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
353
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, 5 /* TLVErrorCode.MAX_TRIES */));
|
|
356
354
|
return;
|
|
357
355
|
}
|
|
358
|
-
const tlvData = decode(data);
|
|
356
|
+
const tlvData = tlv.decode(data);
|
|
359
357
|
const sequence = tlvData[6 /* TLVValues.SEQUENCE_NUM */][0]; // value is single byte with sequence number
|
|
360
358
|
if (sequence === 1 /* PairingStates.M1 */) {
|
|
361
359
|
this.handlePairSetupM1(connection, request, response);
|
|
@@ -368,31 +366,33 @@ export class HAPServer extends EventEmitter {
|
|
|
368
366
|
}
|
|
369
367
|
else {
|
|
370
368
|
// Invalid state/sequence number
|
|
371
|
-
response.writeHead(400 /* HAPPairingHTTPCode.BAD_REQUEST */, {
|
|
372
|
-
response.end(encode(6 /* TLVValues.STATE */, sequence + 1, 7 /* TLVValues.ERROR_CODE */, 1 /* TLVErrorCode.UNKNOWN */));
|
|
369
|
+
response.writeHead(400 /* HAPPairingHTTPCode.BAD_REQUEST */, { "Content-Type": "application/pairing+tlv8" });
|
|
370
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, sequence + 1, 7 /* TLVValues.ERROR_CODE */, 1 /* TLVErrorCode.UNKNOWN */));
|
|
371
|
+
return;
|
|
373
372
|
}
|
|
374
373
|
}
|
|
375
374
|
handlePairSetupM1(connection, request, response) {
|
|
376
|
-
debug(
|
|
377
|
-
const salt = randomBytes(16);
|
|
378
|
-
const srpParams = SRP.params.hap;
|
|
379
|
-
SRP.genKey(32).then(
|
|
375
|
+
debug("[%s] Pair step 1/5", this.accessoryInfo.username);
|
|
376
|
+
const salt = crypto_1.default.randomBytes(16);
|
|
377
|
+
const srpParams = fast_srp_hap_1.SRP.params.hap;
|
|
378
|
+
fast_srp_hap_1.SRP.genKey(32).then(key => {
|
|
380
379
|
// create a new SRP server
|
|
381
|
-
const srpServer = new SrpServer(srpParams, salt, Buffer.from(
|
|
380
|
+
const srpServer = new fast_srp_hap_1.SrpServer(srpParams, salt, Buffer.from("Pair-Setup"), Buffer.from(this.accessoryInfo.pincode), key);
|
|
382
381
|
const srpB = srpServer.computeB();
|
|
383
382
|
// attach it to the current TCP session
|
|
384
383
|
connection.srpServer = srpServer;
|
|
385
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
386
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 2 /* PairingStates.M2 */, 2 /* TLVValues.SALT */, salt, 3 /* TLVValues.PUBLIC_KEY */, srpB));
|
|
384
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
385
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 2 /* PairingStates.M2 */, 2 /* TLVValues.SALT */, salt, 3 /* TLVValues.PUBLIC_KEY */, srpB));
|
|
387
386
|
connection._pairSetupState = 2 /* PairingStates.M2 */;
|
|
388
|
-
}).catch(
|
|
389
|
-
debug(
|
|
390
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
391
|
-
response.end(encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, 1 /* TLVErrorCode.UNKNOWN */));
|
|
387
|
+
}).catch(error => {
|
|
388
|
+
debug("[%s] Error occurred when generating srp key: %s", this.accessoryInfo.username, error.message);
|
|
389
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
390
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, 1 /* TLVErrorCode.UNKNOWN */));
|
|
391
|
+
return;
|
|
392
392
|
});
|
|
393
393
|
}
|
|
394
394
|
handlePairSetupM3(connection, request, response, tlvData) {
|
|
395
|
-
debug(
|
|
395
|
+
debug("[%s] Pair step 2/5", this.accessoryInfo.username);
|
|
396
396
|
const A = tlvData[3 /* TLVValues.PUBLIC_KEY */]; // "A is a public key that exists only for a single login session."
|
|
397
397
|
const M1 = tlvData[4 /* TLVValues.PASSWORD_PROOF */]; // "M1 is the proof that you actually know your own password."
|
|
398
398
|
// pull the SRP server we created in stepOne out of the current session
|
|
@@ -404,20 +404,20 @@ export class HAPServer extends EventEmitter {
|
|
|
404
404
|
catch (err) {
|
|
405
405
|
// most likely the client supplied an incorrect pincode.
|
|
406
406
|
this.unsuccessfulPairAttempts++;
|
|
407
|
-
debug(
|
|
408
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
409
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
407
|
+
debug("[%s] Error while checking pincode: %s", this.accessoryInfo.username, err.message);
|
|
408
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
409
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
410
410
|
connection._pairSetupState = undefined;
|
|
411
411
|
return;
|
|
412
412
|
}
|
|
413
413
|
// "M2 is the proof that the server actually knows your password."
|
|
414
414
|
const M2 = srpServer.computeM2();
|
|
415
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
416
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 4 /* PairingStates.M4 */, 4 /* TLVValues.PASSWORD_PROOF */, M2));
|
|
415
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
416
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 4 /* PairingStates.M4 */, 4 /* TLVValues.PASSWORD_PROOF */, M2));
|
|
417
417
|
connection._pairSetupState = 4 /* PairingStates.M4 */;
|
|
418
418
|
}
|
|
419
419
|
handlePairSetupM5(connection, request, response, tlvData) {
|
|
420
|
-
debug(
|
|
420
|
+
debug("[%s] Pair step 3/5", this.accessoryInfo.username);
|
|
421
421
|
// pull the SRP server we created in stepOne out of the current session
|
|
422
422
|
const srpServer = connection.srpServer;
|
|
423
423
|
const encryptedData = tlvData[5 /* TLVValues.ENCRYPTED_DATA */];
|
|
@@ -426,22 +426,22 @@ export class HAPServer extends EventEmitter {
|
|
|
426
426
|
encryptedData.copy(messageData, 0, 0, encryptedData.length - 16);
|
|
427
427
|
encryptedData.copy(authTagData, 0, encryptedData.length - 16, encryptedData.length);
|
|
428
428
|
const S_private = srpServer.computeK();
|
|
429
|
-
const encSalt = Buffer.from(
|
|
430
|
-
const encInfo = Buffer.from(
|
|
431
|
-
const outputKey = HKDF(
|
|
429
|
+
const encSalt = Buffer.from("Pair-Setup-Encrypt-Salt");
|
|
430
|
+
const encInfo = Buffer.from("Pair-Setup-Encrypt-Info");
|
|
431
|
+
const outputKey = hapCrypto.HKDF("sha512", encSalt, S_private, encInfo, 32);
|
|
432
432
|
let plaintext;
|
|
433
433
|
try {
|
|
434
|
-
plaintext = chacha20_poly1305_decryptAndVerify(outputKey, Buffer.from(
|
|
434
|
+
plaintext = hapCrypto.chacha20_poly1305_decryptAndVerify(outputKey, Buffer.from("PS-Msg05"), null, messageData, authTagData);
|
|
435
435
|
}
|
|
436
436
|
catch (error) {
|
|
437
|
-
debug(
|
|
438
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
439
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
437
|
+
debug("[%s] Error while decrypting and verifying M5 subTlv: %s", this.accessoryInfo.username);
|
|
438
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
439
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
440
440
|
connection._pairSetupState = undefined;
|
|
441
441
|
return;
|
|
442
442
|
}
|
|
443
443
|
// decode the client payload and pass it on to the next step
|
|
444
|
-
const M5Packet = decode(plaintext);
|
|
444
|
+
const M5Packet = tlv.decode(plaintext);
|
|
445
445
|
const clientUsername = M5Packet[1 /* TLVValues.USERNAME */];
|
|
446
446
|
const clientLTPK = M5Packet[3 /* TLVValues.PUBLIC_KEY */];
|
|
447
447
|
const clientProof = M5Packet[10 /* TLVValues.PROOF */];
|
|
@@ -449,16 +449,16 @@ export class HAPServer extends EventEmitter {
|
|
|
449
449
|
}
|
|
450
450
|
// M5-2
|
|
451
451
|
handlePairSetupM5_2(connection, request, response, clientUsername, clientLTPK, clientProof, hkdfEncKey) {
|
|
452
|
-
debug(
|
|
452
|
+
debug("[%s] Pair step 4/5", this.accessoryInfo.username);
|
|
453
453
|
const S_private = connection.srpServer.computeK();
|
|
454
|
-
const controllerSalt = Buffer.from(
|
|
455
|
-
const controllerInfo = Buffer.from(
|
|
456
|
-
const outputKey = HKDF(
|
|
454
|
+
const controllerSalt = Buffer.from("Pair-Setup-Controller-Sign-Salt");
|
|
455
|
+
const controllerInfo = Buffer.from("Pair-Setup-Controller-Sign-Info");
|
|
456
|
+
const outputKey = hapCrypto.HKDF("sha512", controllerSalt, S_private, controllerInfo, 32);
|
|
457
457
|
const completeData = Buffer.concat([outputKey, clientUsername, clientLTPK]);
|
|
458
|
-
if (!
|
|
459
|
-
debug(
|
|
460
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
461
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 6 /* PairingStates.M6 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
458
|
+
if (!tweetnacl_1.default.sign.detached.verify(completeData, clientProof, clientLTPK)) {
|
|
459
|
+
debug("[%s] Invalid signature", this.accessoryInfo.username);
|
|
460
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
461
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 6 /* PairingStates.M6 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
462
462
|
connection._pairSetupState = undefined;
|
|
463
463
|
return;
|
|
464
464
|
}
|
|
@@ -466,35 +466,35 @@ export class HAPServer extends EventEmitter {
|
|
|
466
466
|
}
|
|
467
467
|
// M5 - F + M6
|
|
468
468
|
handlePairSetupM5_3(connection, request, response, clientUsername, clientLTPK, hkdfEncKey) {
|
|
469
|
-
debug(
|
|
469
|
+
debug("[%s] Pair step 5/5", this.accessoryInfo.username);
|
|
470
470
|
const S_private = connection.srpServer.computeK();
|
|
471
|
-
const accessorySalt = Buffer.from(
|
|
472
|
-
const accessoryInfo = Buffer.from(
|
|
473
|
-
const outputKey = HKDF(
|
|
471
|
+
const accessorySalt = Buffer.from("Pair-Setup-Accessory-Sign-Salt");
|
|
472
|
+
const accessoryInfo = Buffer.from("Pair-Setup-Accessory-Sign-Info");
|
|
473
|
+
const outputKey = hapCrypto.HKDF("sha512", accessorySalt, S_private, accessoryInfo, 32);
|
|
474
474
|
const serverLTPK = this.accessoryInfo.signPk;
|
|
475
475
|
const usernameData = Buffer.from(this.accessoryInfo.username);
|
|
476
476
|
const material = Buffer.concat([outputKey, usernameData, serverLTPK]);
|
|
477
477
|
const privateKey = Buffer.from(this.accessoryInfo.signSk);
|
|
478
|
-
const serverProof =
|
|
479
|
-
const message = encode(1 /* TLVValues.USERNAME */, usernameData, 3 /* TLVValues.PUBLIC_KEY */, serverLTPK, 10 /* TLVValues.PROOF */, serverProof);
|
|
480
|
-
const encrypted = chacha20_poly1305_encryptAndSeal(hkdfEncKey, Buffer.from(
|
|
478
|
+
const serverProof = tweetnacl_1.default.sign.detached(material, privateKey);
|
|
479
|
+
const message = tlv.encode(1 /* TLVValues.USERNAME */, usernameData, 3 /* TLVValues.PUBLIC_KEY */, serverLTPK, 10 /* TLVValues.PROOF */, serverProof);
|
|
480
|
+
const encrypted = hapCrypto.chacha20_poly1305_encryptAndSeal(hkdfEncKey, Buffer.from("PS-Msg06"), null, message);
|
|
481
481
|
// finally, notify listeners that we have been paired with a client
|
|
482
|
-
this.emit("pair" /* HAPServerEventTypes.PAIR */, clientUsername.toString(), clientLTPK, once(
|
|
482
|
+
this.emit("pair" /* HAPServerEventTypes.PAIR */, clientUsername.toString(), clientLTPK, (0, once_1.once)(err => {
|
|
483
483
|
if (err) {
|
|
484
|
-
debug(
|
|
485
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
486
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 6 /* PairingStates.M6 */, 7 /* TLVValues.ERROR_CODE */, 1 /* TLVErrorCode.UNKNOWN */));
|
|
484
|
+
debug("[%s] Error adding pairing info: %s", this.accessoryInfo.username, err.message);
|
|
485
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
486
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 6 /* PairingStates.M6 */, 7 /* TLVValues.ERROR_CODE */, 1 /* TLVErrorCode.UNKNOWN */));
|
|
487
487
|
connection._pairSetupState = undefined;
|
|
488
488
|
return;
|
|
489
489
|
}
|
|
490
490
|
// send final pairing response to client
|
|
491
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
492
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 6 /* PairingStates.M6 */, 5 /* TLVValues.ENCRYPTED_DATA */, Buffer.concat([encrypted.ciphertext, encrypted.authTag])));
|
|
491
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
492
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 6 /* PairingStates.M6 */, 5 /* TLVValues.ENCRYPTED_DATA */, Buffer.concat([encrypted.ciphertext, encrypted.authTag])));
|
|
493
493
|
connection._pairSetupState = undefined;
|
|
494
494
|
}));
|
|
495
495
|
}
|
|
496
496
|
handlePairVerify(connection, url, request, data, response) {
|
|
497
|
-
const tlvData = decode(data);
|
|
497
|
+
const tlvData = tlv.decode(data);
|
|
498
498
|
const sequence = tlvData[6 /* TLVValues.SEQUENCE_NUM */][0]; // value is single byte with sequence number
|
|
499
499
|
if (sequence === 1 /* PairingStates.M1 */) {
|
|
500
500
|
this.handlePairVerifyM1(connection, request, response, tlvData);
|
|
@@ -504,35 +504,36 @@ export class HAPServer extends EventEmitter {
|
|
|
504
504
|
}
|
|
505
505
|
else {
|
|
506
506
|
// Invalid state/sequence number
|
|
507
|
-
response.writeHead(400 /* HAPPairingHTTPCode.BAD_REQUEST */, {
|
|
508
|
-
response.end(encode(6 /* TLVValues.STATE */, sequence + 1, 7 /* TLVValues.ERROR_CODE */, 1 /* TLVErrorCode.UNKNOWN */));
|
|
507
|
+
response.writeHead(400 /* HAPPairingHTTPCode.BAD_REQUEST */, { "Content-Type": "application/pairing+tlv8" });
|
|
508
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, sequence + 1, 7 /* TLVValues.ERROR_CODE */, 1 /* TLVErrorCode.UNKNOWN */));
|
|
509
|
+
return;
|
|
509
510
|
}
|
|
510
511
|
}
|
|
511
512
|
handlePairVerifyM1(connection, request, response, tlvData) {
|
|
512
|
-
debug(
|
|
513
|
+
debug("[%s] Pair verify step 1/2", this.accessoryInfo.username);
|
|
513
514
|
const clientPublicKey = tlvData[3 /* TLVValues.PUBLIC_KEY */]; // Buffer
|
|
514
515
|
// generate new encryption keys for this session
|
|
515
|
-
const keyPair = generateCurve25519KeyPair();
|
|
516
|
+
const keyPair = hapCrypto.generateCurve25519KeyPair();
|
|
516
517
|
const secretKey = Buffer.from(keyPair.secretKey);
|
|
517
518
|
const publicKey = Buffer.from(keyPair.publicKey);
|
|
518
|
-
const sharedSec = Buffer.from(generateCurve25519SharedSecKey(secretKey, clientPublicKey));
|
|
519
|
+
const sharedSec = Buffer.from(hapCrypto.generateCurve25519SharedSecKey(secretKey, clientPublicKey));
|
|
519
520
|
const usernameData = Buffer.from(this.accessoryInfo.username);
|
|
520
521
|
const material = Buffer.concat([publicKey, usernameData, clientPublicKey]);
|
|
521
522
|
const privateKey = Buffer.from(this.accessoryInfo.signSk);
|
|
522
|
-
const serverProof =
|
|
523
|
-
const encSalt = Buffer.from(
|
|
524
|
-
const encInfo = Buffer.from(
|
|
525
|
-
const outputKey = HKDF(
|
|
526
|
-
connection.encryption = new HAPEncryption(clientPublicKey, secretKey, publicKey, sharedSec, outputKey);
|
|
523
|
+
const serverProof = tweetnacl_1.default.sign.detached(material, privateKey);
|
|
524
|
+
const encSalt = Buffer.from("Pair-Verify-Encrypt-Salt");
|
|
525
|
+
const encInfo = Buffer.from("Pair-Verify-Encrypt-Info");
|
|
526
|
+
const outputKey = hapCrypto.HKDF("sha512", encSalt, sharedSec, encInfo, 32).slice(0, 32);
|
|
527
|
+
connection.encryption = new eventedhttp_1.HAPEncryption(clientPublicKey, secretKey, publicKey, sharedSec, outputKey);
|
|
527
528
|
// compose the response data in TLV format
|
|
528
|
-
const message = encode(1 /* TLVValues.USERNAME */, usernameData, 10 /* TLVValues.PROOF */, serverProof);
|
|
529
|
-
const encrypted = chacha20_poly1305_encryptAndSeal(outputKey, Buffer.from(
|
|
530
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
531
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 2 /* PairingStates.M2 */, 5 /* TLVValues.ENCRYPTED_DATA */, Buffer.concat([encrypted.ciphertext, encrypted.authTag]), 3 /* TLVValues.PUBLIC_KEY */, publicKey));
|
|
529
|
+
const message = tlv.encode(1 /* TLVValues.USERNAME */, usernameData, 10 /* TLVValues.PROOF */, serverProof);
|
|
530
|
+
const encrypted = hapCrypto.chacha20_poly1305_encryptAndSeal(outputKey, Buffer.from("PV-Msg02"), null, message);
|
|
531
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
532
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 2 /* PairingStates.M2 */, 5 /* TLVValues.ENCRYPTED_DATA */, Buffer.concat([encrypted.ciphertext, encrypted.authTag]), 3 /* TLVValues.PUBLIC_KEY */, publicKey));
|
|
532
533
|
connection._pairVerifyState = 2 /* PairingStates.M2 */;
|
|
533
534
|
}
|
|
534
535
|
handlePairVerifyM3(connection, request, response, objects) {
|
|
535
|
-
debug(
|
|
536
|
+
debug("[%s] Pair verify step 2/2", this.accessoryInfo.username);
|
|
536
537
|
const encryptedData = objects[5 /* TLVValues.ENCRYPTED_DATA */];
|
|
537
538
|
const messageData = Buffer.alloc(encryptedData.length - 16);
|
|
538
539
|
const authTagData = Buffer.alloc(16);
|
|
@@ -542,16 +543,16 @@ export class HAPServer extends EventEmitter {
|
|
|
542
543
|
const enc = connection.encryption;
|
|
543
544
|
let plaintext;
|
|
544
545
|
try {
|
|
545
|
-
plaintext = chacha20_poly1305_decryptAndVerify(enc.hkdfPairEncryptionKey, Buffer.from(
|
|
546
|
+
plaintext = hapCrypto.chacha20_poly1305_decryptAndVerify(enc.hkdfPairEncryptionKey, Buffer.from("PV-Msg03"), null, messageData, authTagData);
|
|
546
547
|
}
|
|
547
548
|
catch (error) {
|
|
548
|
-
debug(
|
|
549
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
550
|
-
response.end(encode(6 /* TLVValues.STATE */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
549
|
+
debug("[%s] M3: Failed to decrypt and/or verify", this.accessoryInfo.username);
|
|
550
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
551
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
551
552
|
connection._pairVerifyState = undefined;
|
|
552
553
|
return;
|
|
553
554
|
}
|
|
554
|
-
const decoded = decode(plaintext);
|
|
555
|
+
const decoded = tlv.decode(plaintext);
|
|
555
556
|
const clientUsername = decoded[1 /* TLVValues.USERNAME */];
|
|
556
557
|
const proof = decoded[10 /* TLVValues.PROOF */];
|
|
557
558
|
const material = Buffer.concat([enc.clientPublicKey, clientUsername, enc.publicKey]);
|
|
@@ -560,30 +561,30 @@ export class HAPServer extends EventEmitter {
|
|
|
560
561
|
// if we're not actually paired, then there's nothing to verify - this client thinks it's paired with us, but we
|
|
561
562
|
// disagree. Respond with invalid request (seems to match HomeKit Accessory Simulator behavior)
|
|
562
563
|
if (!clientPublicKey) {
|
|
563
|
-
debug(
|
|
564
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
565
|
-
response.end(encode(6 /* TLVValues.STATE */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
564
|
+
debug("[%s] Client %s attempting to verify, but we are not paired; rejecting client", this.accessoryInfo.username, clientUsername);
|
|
565
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
566
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
566
567
|
connection._pairVerifyState = undefined;
|
|
567
568
|
return;
|
|
568
569
|
}
|
|
569
|
-
if (!
|
|
570
|
-
debug(
|
|
571
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
572
|
-
response.end(encode(6 /* TLVValues.STATE */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
570
|
+
if (!tweetnacl_1.default.sign.detached.verify(material, proof, clientPublicKey)) {
|
|
571
|
+
debug("[%s] Client %s provided an invalid signature", this.accessoryInfo.username, clientUsername);
|
|
572
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
573
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 4 /* PairingStates.M4 */, 7 /* TLVValues.ERROR_CODE */, 2 /* TLVErrorCode.AUTHENTICATION */));
|
|
573
574
|
connection._pairVerifyState = undefined;
|
|
574
575
|
return;
|
|
575
576
|
}
|
|
576
|
-
debug(
|
|
577
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
578
|
-
response.end(encode(6 /* TLVValues.SEQUENCE_NUM */, 4 /* PairingStates.M4 */));
|
|
577
|
+
debug("[%s] Client %s verification complete", this.accessoryInfo.username, clientUsername);
|
|
578
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
579
|
+
response.end(tlv.encode(6 /* TLVValues.SEQUENCE_NUM */, 4 /* PairingStates.M4 */));
|
|
579
580
|
// now that the client has been verified, we must "upgrade" our pseudo-HTTP connection to include
|
|
580
581
|
// TCP-level encryption. We'll do this by adding some more encryption vars to the session, and using them
|
|
581
582
|
// in future calls to onEncrypt, onDecrypt.
|
|
582
|
-
const encSalt = Buffer.from(
|
|
583
|
-
const infoRead = Buffer.from(
|
|
584
|
-
const infoWrite = Buffer.from(
|
|
585
|
-
enc.accessoryToControllerKey = HKDF(
|
|
586
|
-
enc.controllerToAccessoryKey = HKDF(
|
|
583
|
+
const encSalt = Buffer.from("Control-Salt");
|
|
584
|
+
const infoRead = Buffer.from("Control-Read-Encryption-Key");
|
|
585
|
+
const infoWrite = Buffer.from("Control-Write-Encryption-Key");
|
|
586
|
+
enc.accessoryToControllerKey = hapCrypto.HKDF("sha512", encSalt, enc.sharedSecret, infoRead, 32);
|
|
587
|
+
enc.controllerToAccessoryKey = hapCrypto.HKDF("sha512", encSalt, enc.sharedSecret, infoWrite, 32);
|
|
587
588
|
// Our connection is now completely setup. We now want to subscribe this connection to special
|
|
588
589
|
connection.connectionAuthenticated(clientUsername.toString());
|
|
589
590
|
connection._pairVerifyState = undefined;
|
|
@@ -591,11 +592,11 @@ export class HAPServer extends EventEmitter {
|
|
|
591
592
|
handlePairings(connection, url, request, data, response) {
|
|
592
593
|
// Only accept /pairing request if there is a secure session
|
|
593
594
|
if (!this.allowInsecureRequest && !connection.isAuthenticated()) {
|
|
594
|
-
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, {
|
|
595
|
+
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
595
596
|
response.end(JSON.stringify({ status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }));
|
|
596
597
|
return;
|
|
597
598
|
}
|
|
598
|
-
const objects = decode(data);
|
|
599
|
+
const objects = tlv.decode(data);
|
|
599
600
|
const method = objects[0 /* TLVValues.METHOD */][0]; // value is single byte with request type
|
|
600
601
|
const state = objects[6 /* TLVValues.STATE */][0];
|
|
601
602
|
if (state !== 1 /* PairingStates.M1 */) {
|
|
@@ -605,40 +606,41 @@ export class HAPServer extends EventEmitter {
|
|
|
605
606
|
const identifier = objects[1 /* TLVValues.IDENTIFIER */].toString();
|
|
606
607
|
const publicKey = objects[3 /* TLVValues.PUBLIC_KEY */];
|
|
607
608
|
const permissions = objects[11 /* TLVValues.PERMISSIONS */][0];
|
|
608
|
-
this.emit("add-pairing" /* HAPServerEventTypes.ADD_PAIRING */, connection, identifier, publicKey, permissions, once((error) => {
|
|
609
|
+
this.emit("add-pairing" /* HAPServerEventTypes.ADD_PAIRING */, connection, identifier, publicKey, permissions, (0, once_1.once)((error) => {
|
|
609
610
|
if (error > 0) {
|
|
610
|
-
debug(
|
|
611
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
612
|
-
response.end(encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, error));
|
|
611
|
+
debug("[%s] Pairings: failed ADD_PAIRING with code %d", this.accessoryInfo.username, error);
|
|
612
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
613
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, error));
|
|
613
614
|
return;
|
|
614
615
|
}
|
|
615
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
616
|
-
response.end(encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */));
|
|
617
|
-
debug(
|
|
616
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
617
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */));
|
|
618
|
+
debug("[%s] Pairings: successfully executed ADD_PAIRING", this.accessoryInfo.username);
|
|
618
619
|
}));
|
|
619
620
|
}
|
|
620
621
|
else if (method === 4 /* PairMethods.REMOVE_PAIRING */) {
|
|
621
622
|
const identifier = objects[1 /* TLVValues.IDENTIFIER */].toString();
|
|
622
|
-
this.emit("remove-pairing" /* HAPServerEventTypes.REMOVE_PAIRING */, connection, identifier, once((error) => {
|
|
623
|
+
this.emit("remove-pairing" /* HAPServerEventTypes.REMOVE_PAIRING */, connection, identifier, (0, once_1.once)((error) => {
|
|
623
624
|
if (error > 0) {
|
|
624
|
-
debug(
|
|
625
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
626
|
-
response.end(encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, error));
|
|
625
|
+
debug("[%s] Pairings: failed REMOVE_PAIRING with code %d", this.accessoryInfo.username, error);
|
|
626
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
627
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, error));
|
|
627
628
|
return;
|
|
628
629
|
}
|
|
629
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
630
|
-
response.end(encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */));
|
|
631
|
-
debug(
|
|
630
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
631
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */));
|
|
632
|
+
debug("[%s] Pairings: successfully executed REMOVE_PAIRING", this.accessoryInfo.username);
|
|
632
633
|
}));
|
|
633
634
|
}
|
|
634
635
|
else if (method === 5 /* PairMethods.LIST_PAIRINGS */) {
|
|
635
|
-
this.emit("list-pairings" /* HAPServerEventTypes.LIST_PAIRINGS */, connection, once((error, data) => {
|
|
636
|
+
this.emit("list-pairings" /* HAPServerEventTypes.LIST_PAIRINGS */, connection, (0, once_1.once)((error, data) => {
|
|
636
637
|
if (error > 0) {
|
|
637
|
-
debug(
|
|
638
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
639
|
-
response.end(encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, error));
|
|
638
|
+
debug("[%s] Pairings: failed LIST_PAIRINGS with code %d", this.accessoryInfo.username, error);
|
|
639
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" });
|
|
640
|
+
response.end(tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, 7 /* TLVValues.ERROR_CODE */, error));
|
|
640
641
|
return;
|
|
641
642
|
}
|
|
643
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
642
644
|
const tlvList = [];
|
|
643
645
|
data.forEach((value, index) => {
|
|
644
646
|
if (index > 0) {
|
|
@@ -646,63 +648,63 @@ export class HAPServer extends EventEmitter {
|
|
|
646
648
|
}
|
|
647
649
|
tlvList.push(1 /* TLVValues.IDENTIFIER */, value.username, 3 /* TLVValues.PUBLIC_KEY */, value.publicKey, 11 /* TLVValues.PERMISSIONS */, value.permission);
|
|
648
650
|
});
|
|
649
|
-
const list = encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, ...tlvList);
|
|
650
|
-
response.writeHead(200 /* HAPPairingHTTPCode.OK */, {
|
|
651
|
+
const list = tlv.encode(6 /* TLVValues.STATE */, 2 /* PairingStates.M2 */, ...tlvList);
|
|
652
|
+
response.writeHead(200 /* HAPPairingHTTPCode.OK */, { "Content-Type": "application/pairing+tlv8" /* HAPMimeTypes.PAIRING_TLV8 */ });
|
|
651
653
|
response.end(list);
|
|
652
|
-
debug(
|
|
654
|
+
debug("[%s] Pairings: successfully executed LIST_PAIRINGS", this.accessoryInfo.username);
|
|
653
655
|
}));
|
|
654
656
|
}
|
|
655
657
|
}
|
|
656
658
|
handleAccessories(connection, url, request, data, response) {
|
|
657
659
|
if (!this.allowInsecureRequest && !connection.isAuthenticated()) {
|
|
658
|
-
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, {
|
|
660
|
+
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
659
661
|
response.end(JSON.stringify({ status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }));
|
|
660
662
|
return;
|
|
661
663
|
}
|
|
662
664
|
// call out to listeners to retrieve the latest accessories JSON
|
|
663
|
-
this.emit("accessories" /* HAPServerEventTypes.ACCESSORIES */, connection, once((error, result) => {
|
|
665
|
+
this.emit("accessories" /* HAPServerEventTypes.ACCESSORIES */, connection, (0, once_1.once)((error, result) => {
|
|
664
666
|
if (error) {
|
|
665
|
-
response.writeHead(error.httpCode, {
|
|
667
|
+
response.writeHead(error.httpCode, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
666
668
|
response.end(JSON.stringify({ status: error.status }));
|
|
667
669
|
}
|
|
668
670
|
else {
|
|
669
|
-
response.writeHead(200 /* HAPHTTPCode.OK */, {
|
|
671
|
+
response.writeHead(200 /* HAPHTTPCode.OK */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
670
672
|
response.end(JSON.stringify(result));
|
|
671
673
|
}
|
|
672
674
|
}));
|
|
673
675
|
}
|
|
674
676
|
handleCharacteristics(connection, url, request, data, response) {
|
|
675
677
|
if (!this.allowInsecureRequest && !connection.isAuthenticated()) {
|
|
676
|
-
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, {
|
|
678
|
+
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
677
679
|
response.end(JSON.stringify({ status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }));
|
|
678
680
|
return;
|
|
679
681
|
}
|
|
680
|
-
if (request.method ===
|
|
682
|
+
if (request.method === "GET") {
|
|
681
683
|
const searchParams = url.searchParams;
|
|
682
|
-
const idParam = searchParams.get(
|
|
684
|
+
const idParam = searchParams.get("id");
|
|
683
685
|
if (!idParam) {
|
|
684
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
686
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
685
687
|
response.end(JSON.stringify({ status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }));
|
|
686
688
|
return;
|
|
687
689
|
}
|
|
688
690
|
const ids = [];
|
|
689
|
-
for (const entry of idParam.split(
|
|
690
|
-
const split = entry.split(
|
|
691
|
+
for (const entry of idParam.split(",")) { // ["1.9","2.14"]
|
|
692
|
+
const split = entry.split("."); // ["1","9"]
|
|
691
693
|
ids.push({
|
|
692
|
-
aid:
|
|
693
|
-
iid:
|
|
694
|
+
aid: parseInt(split[0], 10), // accessory id
|
|
695
|
+
iid: parseInt(split[1], 10), // (characteristic) instance id
|
|
694
696
|
});
|
|
695
697
|
}
|
|
696
698
|
const readRequest = {
|
|
697
|
-
ids,
|
|
698
|
-
includeMeta: consideredTrue(searchParams.get(
|
|
699
|
-
includePerms: consideredTrue(searchParams.get(
|
|
700
|
-
includeType: consideredTrue(searchParams.get(
|
|
701
|
-
includeEvent: consideredTrue(searchParams.get(
|
|
699
|
+
ids: ids,
|
|
700
|
+
includeMeta: (0, internal_types_1.consideredTrue)(searchParams.get("meta")),
|
|
701
|
+
includePerms: (0, internal_types_1.consideredTrue)(searchParams.get("perms")),
|
|
702
|
+
includeType: (0, internal_types_1.consideredTrue)(searchParams.get("type")),
|
|
703
|
+
includeEvent: (0, internal_types_1.consideredTrue)(searchParams.get("ev")),
|
|
702
704
|
};
|
|
703
|
-
this.emit("get-characteristics" /* HAPServerEventTypes.GET_CHARACTERISTICS */, connection, readRequest, once((error, readResponse) => {
|
|
705
|
+
this.emit("get-characteristics" /* HAPServerEventTypes.GET_CHARACTERISTICS */, connection, readRequest, (0, once_1.once)((error, readResponse) => {
|
|
704
706
|
if (error) {
|
|
705
|
-
response.writeHead(error.httpCode, {
|
|
707
|
+
response.writeHead(error.httpCode, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
706
708
|
response.end(JSON.stringify({ status: error.status }));
|
|
707
709
|
return;
|
|
708
710
|
}
|
|
@@ -722,27 +724,27 @@ export class HAPServer extends EventEmitter {
|
|
|
722
724
|
}
|
|
723
725
|
}
|
|
724
726
|
// 207 "multi-status" is returned when an error occurs reading a characteristic. otherwise 200 is returned
|
|
725
|
-
response.writeHead(errorOccurred ? 207 /* HAPHTTPCode.MULTI_STATUS */ : 200 /* HAPHTTPCode.OK */, {
|
|
726
|
-
response.end(JSON.stringify({ characteristics }));
|
|
727
|
+
response.writeHead(errorOccurred ? 207 /* HAPHTTPCode.MULTI_STATUS */ : 200 /* HAPHTTPCode.OK */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
728
|
+
response.end(JSON.stringify({ characteristics: characteristics }));
|
|
727
729
|
}));
|
|
728
730
|
}
|
|
729
|
-
else if (request.method ===
|
|
731
|
+
else if (request.method === "PUT") {
|
|
730
732
|
if (!connection.isAuthenticated()) {
|
|
731
733
|
if (!request.headers || (request.headers && request.headers.authorization !== this.accessoryInfo.pincode)) {
|
|
732
|
-
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, {
|
|
734
|
+
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
733
735
|
response.end(JSON.stringify({ status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }));
|
|
734
736
|
return;
|
|
735
737
|
}
|
|
736
738
|
}
|
|
737
739
|
if (data.length === 0) {
|
|
738
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
740
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
739
741
|
response.end(JSON.stringify({ status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }));
|
|
740
742
|
return;
|
|
741
743
|
}
|
|
742
|
-
const writeRequest = JSON.parse(data.toString(
|
|
743
|
-
this.emit("set-characteristics" /* HAPServerEventTypes.SET_CHARACTERISTICS */, connection, writeRequest, once((error, writeResponse) => {
|
|
744
|
+
const writeRequest = JSON.parse(data.toString("utf8"));
|
|
745
|
+
this.emit("set-characteristics" /* HAPServerEventTypes.SET_CHARACTERISTICS */, connection, writeRequest, (0, once_1.once)((error, writeResponse) => {
|
|
744
746
|
if (error) {
|
|
745
|
-
response.writeHead(error.httpCode, {
|
|
747
|
+
response.writeHead(error.httpCode, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
746
748
|
response.end(JSON.stringify({ status: error.status }));
|
|
747
749
|
return;
|
|
748
750
|
}
|
|
@@ -757,8 +759,8 @@ export class HAPServer extends EventEmitter {
|
|
|
757
759
|
}
|
|
758
760
|
if (multiStatus) {
|
|
759
761
|
// 207 is "multi-status" since HomeKit may be setting multiple things and any one can fail independently
|
|
760
|
-
response.writeHead(207 /* HAPHTTPCode.MULTI_STATUS */, {
|
|
761
|
-
response.end(JSON.stringify({ characteristics }));
|
|
762
|
+
response.writeHead(207 /* HAPHTTPCode.MULTI_STATUS */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
763
|
+
response.end(JSON.stringify({ characteristics: characteristics }));
|
|
762
764
|
}
|
|
763
765
|
else {
|
|
764
766
|
// if everything went fine send 204 no content response
|
|
@@ -768,78 +770,80 @@ export class HAPServer extends EventEmitter {
|
|
|
768
770
|
}));
|
|
769
771
|
}
|
|
770
772
|
else {
|
|
771
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
773
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ }); // method not allowed
|
|
772
774
|
response.end(JSON.stringify({ status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }));
|
|
773
775
|
}
|
|
774
776
|
}
|
|
775
777
|
handlePrepareWrite(connection, url, request, data, response) {
|
|
776
778
|
if (!this.allowInsecureRequest && !connection.isAuthenticated()) {
|
|
777
|
-
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, {
|
|
779
|
+
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
778
780
|
response.end(JSON.stringify({ status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }));
|
|
779
781
|
return;
|
|
780
782
|
}
|
|
781
|
-
if (request.method ===
|
|
783
|
+
if (request.method === "PUT") {
|
|
782
784
|
if (data.length === 0) {
|
|
783
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
785
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
784
786
|
response.end(JSON.stringify({ status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }));
|
|
785
787
|
return;
|
|
786
788
|
}
|
|
787
789
|
const prepareRequest = JSON.parse(data.toString());
|
|
788
790
|
if (prepareRequest.pid && prepareRequest.ttl) {
|
|
789
|
-
debug(
|
|
791
|
+
debug("[%s] Received prepare write request with pid %d and ttl %d", this.accessoryInfo.username, prepareRequest.pid, prepareRequest.ttl);
|
|
790
792
|
if (connection.timedWriteTimeout) { // clear any currently existing timeouts
|
|
791
793
|
clearTimeout(connection.timedWriteTimeout);
|
|
792
794
|
}
|
|
793
795
|
connection.timedWritePid = prepareRequest.pid;
|
|
794
796
|
connection.timedWriteTimeout = setTimeout(() => {
|
|
795
|
-
debug(
|
|
797
|
+
debug("[%s] Timed write request timed out for pid %d", this.accessoryInfo.username, prepareRequest.pid);
|
|
796
798
|
connection.timedWritePid = undefined;
|
|
797
799
|
connection.timedWriteTimeout = undefined;
|
|
798
800
|
}, prepareRequest.ttl);
|
|
799
|
-
response.writeHead(200 /* HAPHTTPCode.OK */, {
|
|
801
|
+
response.writeHead(200 /* HAPHTTPCode.OK */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
800
802
|
response.end(JSON.stringify({ status: 0 /* HAPStatus.SUCCESS */ }));
|
|
803
|
+
return;
|
|
801
804
|
}
|
|
802
805
|
else {
|
|
803
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
806
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
804
807
|
response.end(JSON.stringify({ status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }));
|
|
805
808
|
}
|
|
806
809
|
}
|
|
807
810
|
else {
|
|
808
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
811
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
809
812
|
response.end(JSON.stringify({ status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }));
|
|
810
813
|
}
|
|
811
814
|
}
|
|
812
815
|
handleResource(connection, url, request, data, response) {
|
|
813
816
|
if (!connection.isAuthenticated()) {
|
|
814
817
|
if (!(this.allowInsecureRequest && request.headers && request.headers.authorization === this.accessoryInfo.pincode)) {
|
|
815
|
-
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, {
|
|
818
|
+
response.writeHead(470 /* HAPPairingHTTPCode.CONNECTION_AUTHORIZATION_REQUIRED */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
816
819
|
response.end(JSON.stringify({ status: -70401 /* HAPStatus.INSUFFICIENT_PRIVILEGES */ }));
|
|
817
820
|
return;
|
|
818
821
|
}
|
|
819
822
|
}
|
|
820
|
-
if (request.method ===
|
|
823
|
+
if (request.method === "POST") {
|
|
821
824
|
if (data.length === 0) {
|
|
822
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
825
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
823
826
|
response.end(JSON.stringify({ status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }));
|
|
824
827
|
return;
|
|
825
828
|
}
|
|
826
829
|
const resourceRequest = JSON.parse(data.toString());
|
|
827
830
|
// call out to listeners to retrieve the resource, snapshot only right now
|
|
828
|
-
this.emit("request-resource" /* HAPServerEventTypes.REQUEST_RESOURCE */, resourceRequest, once((error, resource) => {
|
|
831
|
+
this.emit("request-resource" /* HAPServerEventTypes.REQUEST_RESOURCE */, resourceRequest, (0, once_1.once)((error, resource) => {
|
|
829
832
|
if (error) {
|
|
830
|
-
response.writeHead(error.httpCode, {
|
|
833
|
+
response.writeHead(error.httpCode, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ });
|
|
831
834
|
response.end(JSON.stringify({ status: error.status }));
|
|
832
835
|
}
|
|
833
836
|
else {
|
|
834
|
-
response.writeHead(200 /* HAPHTTPCode.OK */, {
|
|
837
|
+
response.writeHead(200 /* HAPHTTPCode.OK */, { "Content-Type": "image/jpeg" /* HAPMimeTypes.IMAGE_JPEG */ });
|
|
835
838
|
response.end(resource);
|
|
836
839
|
}
|
|
837
840
|
}));
|
|
838
841
|
}
|
|
839
842
|
else {
|
|
840
|
-
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, {
|
|
843
|
+
response.writeHead(400 /* HAPHTTPCode.BAD_REQUEST */, { "Content-Type": "application/hap+json" /* HAPMimeTypes.HAP_JSON */ }); // method not allowed
|
|
841
844
|
response.end(JSON.stringify({ status: -70410 /* HAPStatus.INVALID_VALUE_IN_REQUEST */ }));
|
|
842
845
|
}
|
|
843
846
|
}
|
|
844
847
|
}
|
|
848
|
+
exports.HAPServer = HAPServer;
|
|
845
849
|
//# sourceMappingURL=HAPServer.js.map
|