homebridge-xbox-tv 2.14.1 → 2.14.2
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/README.md +14 -12
- package/config.schema.json +151 -121
- package/homebridge-ui/server.js +3 -0
- package/package.json +2 -2
- package/src/localApi/sgcrypto.js +40 -40
- package/src/localApi/xboxlocalapi.js +228 -245
- package/src/webApi/authentication.js +207 -225
- package/src/webApi/xboxwebapi.js +325 -351
- package/src/xboxdevice.js +640 -648
package/README.md
CHANGED
|
@@ -109,18 +109,20 @@ Homebridge plugin for Microsoft game Consoles. Tested with Xbox One X/S and Xbox
|
|
|
109
109
|
| `enableDebugMode` | If enabled, deep log will be present in homebridge console. |
|
|
110
110
|
| `disableLogInfo` | If enabled, disable log info, all values and state will not be displayed in Homebridge log console. |
|
|
111
111
|
| `disableLogDeviceInfo` | If enabled, add ability to disable log device info by every connections device to the network. |
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
119
|
-
| `
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
112
|
+
| `restFul` | This is RSTful server. |
|
|
113
|
+
| `enable` | If enabled, RESTful server will start automatically and respond to any path request. |
|
|
114
|
+
| `port` | Here set the listening `Port` for RESTful server. |
|
|
115
|
+
| `debug` | If enabled, deep log will be present in homebridge console for RESTFul server. |
|
|
116
|
+
| `mqtt` | This is MQTT Broker. |
|
|
117
|
+
| `enable` | If enabled, MQTT Broker will start automatically and publish all awailable PV data. |
|
|
118
|
+
| `host` | Here set the `IP Address` or `Hostname` for MQTT Broker. |
|
|
119
|
+
| `port` | Here set the `Port` for MQTT Broker, default 1883. |
|
|
120
|
+
| `clientId` | Here optional set the `Client Id` of MQTT Broker. |
|
|
121
|
+
| `prefix` | Here set the `Prefix` for `Topic` or leave empty. |
|
|
122
|
+
| `auth` | If enabled, MQTT Broker will use authorization credentials. |
|
|
123
|
+
| `user` | Here set the MQTT Broker user. |
|
|
124
|
+
| `passwd` | Here set the MQTT Broker password. |
|
|
125
|
+
| `debug` | If enabled, deep log will be present in homebridge console for MQTT. |
|
|
124
126
|
| `reference`, `oneStoreProductId` | If web Api enabled then all available in `./homebridge/xboxTv/inputs_xxxxxx` file. |
|
|
125
127
|
|
|
126
128
|
## Create App on Azure AD
|
package/config.schema.json
CHANGED
|
@@ -572,6 +572,7 @@
|
|
|
572
572
|
"type": "string",
|
|
573
573
|
"placeholder": "Web Api Token",
|
|
574
574
|
"description": "Here put the reponse Token (value after ?code=) from the authorization URL.",
|
|
575
|
+
"format": "password",
|
|
575
576
|
"condition": {
|
|
576
577
|
"functionBody": "return model.devices[arrayIndices].webApiControl === true;"
|
|
577
578
|
},
|
|
@@ -592,6 +593,7 @@
|
|
|
592
593
|
"type": "string",
|
|
593
594
|
"placeholder": "Client Secret",
|
|
594
595
|
"description": "Here set your Client Secret from Azure AD or leave empty if you do not have own account.",
|
|
596
|
+
"format": "password",
|
|
595
597
|
"condition": {
|
|
596
598
|
"functionBody": "return model.devices[arrayIndices].webApiControl === true;"
|
|
597
599
|
},
|
|
@@ -719,113 +721,131 @@
|
|
|
719
721
|
"description": "This enable RESTful server.",
|
|
720
722
|
"required": false
|
|
721
723
|
},
|
|
722
|
-
"
|
|
723
|
-
"title": "
|
|
724
|
-
"type": "
|
|
725
|
-
"
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
"description": "This enable debug mode for MQTT.",
|
|
754
|
-
"condition": {
|
|
755
|
-
"functionBody": "return model.devices[arrayIndices].enableMqtt === true;"
|
|
756
|
-
},
|
|
757
|
-
"required": false
|
|
758
|
-
},
|
|
759
|
-
"mqttHost": {
|
|
760
|
-
"title": "IP/Hostname",
|
|
761
|
-
"type": "string",
|
|
762
|
-
"placeholder": "ip or hostname",
|
|
763
|
-
"format": "hostname",
|
|
764
|
-
"description": "Here set the IP/Hostname of MQTT Broker.",
|
|
765
|
-
"condition": {
|
|
766
|
-
"functionBody": "return model.devices[arrayIndices].enableMqtt === true;"
|
|
767
|
-
},
|
|
768
|
-
"required": false
|
|
769
|
-
},
|
|
770
|
-
"mqttPort": {
|
|
771
|
-
"title": "Port",
|
|
772
|
-
"type": "integer",
|
|
773
|
-
"placeholder": 1883,
|
|
774
|
-
"description": "Here set the port of MQTT Broker.",
|
|
775
|
-
"condition": {
|
|
776
|
-
"functionBody": "return model.devices[arrayIndices].enableMqtt === true;"
|
|
777
|
-
},
|
|
778
|
-
"required": false
|
|
779
|
-
},
|
|
780
|
-
"mqttPrefix": {
|
|
781
|
-
"title": "Prefix",
|
|
782
|
-
"type": "string",
|
|
783
|
-
"placeholder": "home/xbox",
|
|
784
|
-
"description": "Here set the prefix.",
|
|
785
|
-
"condition": {
|
|
786
|
-
"functionBody": "return model.devices[arrayIndices].enableMqtt === true;"
|
|
787
|
-
},
|
|
788
|
-
"required": false
|
|
789
|
-
},
|
|
790
|
-
"mqttClientId": {
|
|
791
|
-
"title": "Client ID",
|
|
792
|
-
"type": "string",
|
|
793
|
-
"placeholder": "client id",
|
|
794
|
-
"description": "Here optional set the Client ID of MQTT Broker.",
|
|
795
|
-
"condition": {
|
|
796
|
-
"functionBody": "return model.devices[arrayIndices].enableMqtt === true"
|
|
797
|
-
},
|
|
798
|
-
"required": false
|
|
799
|
-
},
|
|
800
|
-
"mqttAuth": {
|
|
801
|
-
"title": "Authorization",
|
|
802
|
-
"type": "boolean",
|
|
803
|
-
"default": false,
|
|
804
|
-
"description": "This enable authorization for MQTT Broker.",
|
|
805
|
-
"condition": {
|
|
806
|
-
"functionBody": "return model.devices[arrayIndices].enableMqtt === true;"
|
|
807
|
-
},
|
|
808
|
-
"required": false
|
|
809
|
-
},
|
|
810
|
-
"mqttUser": {
|
|
811
|
-
"title": "User",
|
|
812
|
-
"type": "string",
|
|
813
|
-
"placeholder": "user",
|
|
814
|
-
"description": "Here set the user of MQTT Broker.",
|
|
815
|
-
"condition": {
|
|
816
|
-
"functionBody": "return model.devices[arrayIndices].enableMqtt === true && model.devices[arrayIndices].mqttAuth === true;"
|
|
817
|
-
},
|
|
818
|
-
"required": false
|
|
724
|
+
"restFul": {
|
|
725
|
+
"title": "RESTFul",
|
|
726
|
+
"type": "object",
|
|
727
|
+
"properties": {
|
|
728
|
+
"enable": {
|
|
729
|
+
"title": "Enable",
|
|
730
|
+
"type": "boolean",
|
|
731
|
+
"default": false,
|
|
732
|
+
"description": "This enable RESTful server."
|
|
733
|
+
},
|
|
734
|
+
"debug": {
|
|
735
|
+
"title": "Debug",
|
|
736
|
+
"type": "boolean",
|
|
737
|
+
"default": false,
|
|
738
|
+
"description": "This enable debug mode for RESTFul.",
|
|
739
|
+
"condition": {
|
|
740
|
+
"functionBody": "return model.devices[arrayIndices].restFul.enable === true;"
|
|
741
|
+
},
|
|
742
|
+
"required": false
|
|
743
|
+
},
|
|
744
|
+
"port": {
|
|
745
|
+
"title": "Port",
|
|
746
|
+
"type": "integer",
|
|
747
|
+
"placeholder": 3000,
|
|
748
|
+
"description": "Here set the listening Port for RESTful server.",
|
|
749
|
+
"condition": {
|
|
750
|
+
"functionBody": "return model.devices[arrayIndices].restFul.enable === true;"
|
|
751
|
+
},
|
|
752
|
+
"required": false
|
|
753
|
+
}
|
|
754
|
+
}
|
|
819
755
|
},
|
|
820
|
-
"
|
|
821
|
-
"title": "
|
|
822
|
-
"type": "
|
|
823
|
-
"
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
756
|
+
"mqtt": {
|
|
757
|
+
"title": "MQTT",
|
|
758
|
+
"type": "object",
|
|
759
|
+
"properties": {
|
|
760
|
+
"enable": {
|
|
761
|
+
"title": "Enable",
|
|
762
|
+
"type": "boolean",
|
|
763
|
+
"default": false,
|
|
764
|
+
"description": "This enable MQTT client."
|
|
765
|
+
},
|
|
766
|
+
"debug": {
|
|
767
|
+
"title": "Debug",
|
|
768
|
+
"type": "boolean",
|
|
769
|
+
"default": false,
|
|
770
|
+
"description": "This enable debug mode for MQTT.",
|
|
771
|
+
"condition": {
|
|
772
|
+
"functionBody": "return model.devices[arrayIndices].mqtt.enable === true;"
|
|
773
|
+
},
|
|
774
|
+
"required": false
|
|
775
|
+
},
|
|
776
|
+
"host": {
|
|
777
|
+
"title": "IP/Hostname",
|
|
778
|
+
"type": "string",
|
|
779
|
+
"placeholder": "ip or hostname",
|
|
780
|
+
"format": "hostname",
|
|
781
|
+
"description": "Here set the IP/Hostname of MQTT Broker.",
|
|
782
|
+
"condition": {
|
|
783
|
+
"functionBody": "return model.devices[arrayIndices].mqtt.enable === true;"
|
|
784
|
+
},
|
|
785
|
+
"required": false
|
|
786
|
+
},
|
|
787
|
+
"port": {
|
|
788
|
+
"title": "Port",
|
|
789
|
+
"type": "integer",
|
|
790
|
+
"placeholder": 1883,
|
|
791
|
+
"description": "Here set the port of MQTT Broker.",
|
|
792
|
+
"condition": {
|
|
793
|
+
"functionBody": "return model.devices[arrayIndices].mqtt.enable === true;"
|
|
794
|
+
},
|
|
795
|
+
"required": false
|
|
796
|
+
},
|
|
797
|
+
"clientId": {
|
|
798
|
+
"title": "Client ID",
|
|
799
|
+
"type": "string",
|
|
800
|
+
"placeholder": "client id",
|
|
801
|
+
"description": "Here optional set the Client ID of MQTT Broker.",
|
|
802
|
+
"condition": {
|
|
803
|
+
"functionBody": "return model.devices[arrayIndices].mqtt.enable === true"
|
|
804
|
+
},
|
|
805
|
+
"required": false
|
|
806
|
+
},
|
|
807
|
+
"prefix": {
|
|
808
|
+
"title": "Prefix",
|
|
809
|
+
"type": "string",
|
|
810
|
+
"placeholder": "home/envoy",
|
|
811
|
+
"description": "Here set the prefix.",
|
|
812
|
+
"condition": {
|
|
813
|
+
"functionBody": "return model.devices[arrayIndices].mqtt.enable === true;"
|
|
814
|
+
},
|
|
815
|
+
"required": false
|
|
816
|
+
},
|
|
817
|
+
"auth": {
|
|
818
|
+
"title": "Authorization",
|
|
819
|
+
"type": "boolean",
|
|
820
|
+
"default": false,
|
|
821
|
+
"description": "This enable authorization for MQTT Broker.",
|
|
822
|
+
"condition": {
|
|
823
|
+
"functionBody": "return model.devices[arrayIndices].mqtt.enable === true;"
|
|
824
|
+
},
|
|
825
|
+
"required": false
|
|
826
|
+
},
|
|
827
|
+
"user": {
|
|
828
|
+
"title": "User",
|
|
829
|
+
"type": "string",
|
|
830
|
+
"placeholder": "user",
|
|
831
|
+
"description": "Here set the user of MQTT Broker.",
|
|
832
|
+
"condition": {
|
|
833
|
+
"functionBody": "return model.devices[arrayIndices].mqtt.enable === true && model.devices[arrayIndices].mqtt.auth === true;"
|
|
834
|
+
},
|
|
835
|
+
"required": false
|
|
836
|
+
},
|
|
837
|
+
"passwd": {
|
|
838
|
+
"title": "Password",
|
|
839
|
+
"type": "string",
|
|
840
|
+
"placeholder": "password",
|
|
841
|
+
"description": "Here set the password of MQTT Broker.",
|
|
842
|
+
"format": "password",
|
|
843
|
+
"condition": {
|
|
844
|
+
"functionBody": "return model.devices[arrayIndices].mqtt.enable === true && model.devices[arrayIndices].mqtt.auth === true;"
|
|
845
|
+
},
|
|
846
|
+
"required": false
|
|
847
|
+
}
|
|
848
|
+
}
|
|
829
849
|
}
|
|
830
850
|
}
|
|
831
851
|
}
|
|
@@ -955,8 +975,15 @@
|
|
|
955
975
|
"devices[].webApiControl",
|
|
956
976
|
"devices[].webApiPowerOnOff",
|
|
957
977
|
"devices[].webApiToken",
|
|
978
|
+
{
|
|
979
|
+
"key": "devices[].webApiToken",
|
|
980
|
+
"type": "password"
|
|
981
|
+
},
|
|
958
982
|
"devices[].webApiClientId",
|
|
959
|
-
|
|
983
|
+
{
|
|
984
|
+
"key": "devices[].webApiClientSecret",
|
|
985
|
+
"type": "password"
|
|
986
|
+
}
|
|
960
987
|
]
|
|
961
988
|
},
|
|
962
989
|
{
|
|
@@ -978,27 +1005,30 @@
|
|
|
978
1005
|
"title": "{{ value.title }}",
|
|
979
1006
|
"items": [
|
|
980
1007
|
{
|
|
981
|
-
"key": "devices[]",
|
|
1008
|
+
"key": "devices[].restFul",
|
|
982
1009
|
"title": "RESTFul",
|
|
983
1010
|
"items": [
|
|
984
|
-
"devices[].
|
|
985
|
-
"devices[].
|
|
986
|
-
"devices[].
|
|
1011
|
+
"devices[].restFul.enable",
|
|
1012
|
+
"devices[].restFul.debug",
|
|
1013
|
+
"devices[].restFul.port"
|
|
987
1014
|
]
|
|
988
1015
|
},
|
|
989
1016
|
{
|
|
990
|
-
"key": "devices[]",
|
|
1017
|
+
"key": "devices[].mqtt",
|
|
991
1018
|
"title": "MQTT",
|
|
992
1019
|
"items": [
|
|
993
|
-
"devices[].
|
|
994
|
-
"devices[].
|
|
995
|
-
"devices[].
|
|
996
|
-
"devices[].
|
|
997
|
-
"devices[].
|
|
998
|
-
"devices[].
|
|
999
|
-
"devices[].
|
|
1000
|
-
"devices[].
|
|
1001
|
-
|
|
1020
|
+
"devices[].mqtt.enable",
|
|
1021
|
+
"devices[].mqtt.debug",
|
|
1022
|
+
"devices[].mqtt.host",
|
|
1023
|
+
"devices[].mqtt.port",
|
|
1024
|
+
"devices[].mqtt.clientId",
|
|
1025
|
+
"devices[].mqtt.prefix",
|
|
1026
|
+
"devices[].mqtt.auth",
|
|
1027
|
+
"devices[].mqtt.user",
|
|
1028
|
+
{
|
|
1029
|
+
"key": "devices[].mqtt.passwd",
|
|
1030
|
+
"type": "password"
|
|
1031
|
+
}
|
|
1002
1032
|
]
|
|
1003
1033
|
}
|
|
1004
1034
|
]
|
package/homebridge-ui/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "Xbox TV",
|
|
3
3
|
"name": "homebridge-xbox-tv",
|
|
4
|
-
"version": "2.14.
|
|
4
|
+
"version": "2.14.2",
|
|
5
5
|
"description": "Homebridge plugin to control Xbox game consoles.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "grzegorz914",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@homebridge/plugin-ui-utils": "^1.0.3",
|
|
36
36
|
"async-mqtt": "^2.6.3",
|
|
37
|
-
"elliptic": "^6.5.
|
|
37
|
+
"elliptic": "^6.5.7",
|
|
38
38
|
"hex-to-binary": "^1.0.1",
|
|
39
39
|
"jsrsasign": "^11.1.0",
|
|
40
40
|
"uuid": "^10.0.0",
|
package/src/localApi/sgcrypto.js
CHANGED
|
@@ -4,65 +4,65 @@ const Crypto = require('crypto');
|
|
|
4
4
|
const EOL = require('os').EOL;
|
|
5
5
|
const EC = require('elliptic').ec;
|
|
6
6
|
const IV = Buffer.from('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00');
|
|
7
|
+
const EventEmitter = require('events');
|
|
7
8
|
|
|
8
|
-
class SGCRYPTO {
|
|
9
|
+
class SGCRYPTO extends EventEmitter {
|
|
9
10
|
constructor() {
|
|
11
|
+
super();
|
|
10
12
|
this.key = false;
|
|
11
13
|
this.iv = false;
|
|
12
14
|
this.hashKey = false;
|
|
13
15
|
|
|
14
16
|
};
|
|
15
17
|
|
|
16
|
-
getPublicKey(certificate) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
certificate = certificate.toString('base64').match(/.{0,64}/g).join('\n');
|
|
18
|
+
async getPublicKey(certificate) {
|
|
19
|
+
try {
|
|
20
|
+
// Set certyficate
|
|
21
|
+
certificate = certificate.toString('base64').match(/.{0,64}/g).join('\n');
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
// Set pem
|
|
24
|
+
const pem = `-----BEGIN CERTIFICATE-----${EOL}${certificate}-----END CERTIFICATE-----`;
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
// Create public key
|
|
27
|
+
const ecKey = JsRsaSign.X509.getPublicKeyFromCertPEM(pem);
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const ec = new EC('p256');
|
|
30
|
+
const sha512 = Crypto.createHash('sha512');
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// Generate keys
|
|
33
|
+
const key1 = ec.genKeyPair();
|
|
34
|
+
const key2 = ec.keyFromPublic(ecKey.pubKeyHex, 'hex');
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const shared1 = key1.derive(key2.getPublic());
|
|
37
|
+
const derivedSecret = Buffer.from(shared1.toString(16), 'hex');
|
|
38
|
+
const publicKeyClient = key1.getPublic('hex');
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const preSalt = Buffer.from('d637f1aae2f0418c', 'hex');
|
|
41
|
+
const postSalt = Buffer.from('a8f81a574e228ab7', 'hex');
|
|
42
|
+
const prePostSalt = Buffer.concat([preSalt, derivedSecret, postSalt]);
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
// Hash shared secret
|
|
45
|
+
const sha = sha512.update(prePostSalt);
|
|
46
|
+
const shaSecret = sha.digest();
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
const publicKeyHex = publicKeyClient.toString('hex');
|
|
49
|
+
const publicKey = Buffer.from(publicKeyHex.substring(2), 'hex');
|
|
50
|
+
const shaSecretHex = shaSecret.toString('hex');
|
|
51
|
+
const secret = Buffer.from(shaSecretHex, 'hex');
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
this.key = secret.subarray(0, 16);
|
|
54
|
+
this.iv = secret.subarray(16, 32);
|
|
55
|
+
this.hashKey = secret.subarray(32, 64);
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
resolve(data);
|
|
62
|
-
} catch (error) {
|
|
63
|
-
reject(`sign public key error: ${error}`);
|
|
57
|
+
const data = {
|
|
58
|
+
publicKey: publicKey,
|
|
59
|
+
iv: this.iv
|
|
64
60
|
};
|
|
65
|
-
|
|
61
|
+
|
|
62
|
+
return data;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this.emit('error', `sign public key error: ${error}`);
|
|
65
|
+
};
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
getKey() {
|