esp-idf-provisioning-web 0.0.5 → 0.0.6
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/LICENSE +0 -0
- package/README.md +84 -21
- package/dist/ESPDevice.d.ts +4 -19
- package/dist/ESPDevice.d.ts.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +4623 -3095
- package/dist/security/Security0.d.ts.map +1 -1
- package/dist/security/Security1.d.ts +17 -0
- package/dist/security/Security1.d.ts.map +1 -0
- package/dist/types.d.ts +15 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/crypto.d.ts +9 -0
- package/dist/utils/crypto.d.ts.map +1 -1
- package/package.json +26 -24
- package/src/ESPDevice.ts +79 -74
- package/src/ESPProvisionManager.ts +0 -0
- package/src/constants.ts +0 -0
- package/src/generated/.gitkeep +0 -0
- package/src/generated/proto.d.ts +0 -0
- package/src/generated/proto.js +1864 -659
- package/src/index.ts +8 -2
- package/src/proto/constants.proto +0 -0
- package/src/proto/sec0.proto +0 -0
- package/src/proto/sec1.proto +0 -0
- package/src/proto/sec2.proto +0 -0
- package/src/proto/session.proto +0 -0
- package/src/proto/wifi_config.proto +0 -0
- package/src/proto/wifi_constants.proto +0 -0
- package/src/proto/wifi_ctrl.proto +0 -0
- package/src/proto/wifi_scan.proto +0 -0
- package/src/protocol/protocol.ts +0 -0
- package/src/protocol/wifiConfig.ts +6 -6
- package/src/protocol/wifiScan.ts +4 -4
- package/src/security/Security.ts +0 -0
- package/src/security/Security0.ts +5 -3
- package/src/security/Security1.ts +110 -0
- package/src/transport/BLETransport.ts +0 -0
- package/src/transport/SoftAPTransport.ts +2 -2
- package/src/transport/Transport.ts +0 -0
- package/src/types.ts +17 -1
- package/src/utils/crypto.ts +43 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Security0.d.ts","sourceRoot":"","sources":["../../src/security/Security0.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC;;GAEG;AACH,qBAAa,SAAU,SAAQ,QAAQ;IACrC,OAAO,CAAC,WAAW,CAAkB;IAE/B,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAI9C,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAI9C,sBAAsB,IAAI,OAAO,CAAC,UAAU,CAAC;IAU7C,2BAA2B,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"Security0.d.ts","sourceRoot":"","sources":["../../src/security/Security0.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC;;GAEG;AACH,qBAAa,SAAU,SAAQ,QAAQ;IACrC,OAAO,CAAC,WAAW,CAAkB;IAE/B,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAI9C,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAI9C,sBAAsB,IAAI,OAAO,CAAC,UAAU,CAAC;IAU7C,2BAA2B,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAWtE,aAAa,IAAI,OAAO;CAGzB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Security } from './Security';
|
|
2
|
+
/** ESP-IDF Security 1: X25519, optional PoP, and one continuous AES-CTR stream. */
|
|
3
|
+
export declare class Security1 extends Security {
|
|
4
|
+
private proofOfPossession;
|
|
5
|
+
private phase;
|
|
6
|
+
private keyPair?;
|
|
7
|
+
private publicKey?;
|
|
8
|
+
private devicePublicKey?;
|
|
9
|
+
private cipher?;
|
|
10
|
+
constructor(proofOfPossession: string, patchVersion?: number);
|
|
11
|
+
getSessionSetupRequest(): Promise<Uint8Array>;
|
|
12
|
+
processSessionSetupResponse(response: Uint8Array): Promise<void>;
|
|
13
|
+
encrypt(data: Uint8Array): Promise<Uint8Array>;
|
|
14
|
+
decrypt(data: Uint8Array): Promise<Uint8Array>;
|
|
15
|
+
isEstablished(): boolean;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=Security1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Security1.d.ts","sourceRoot":"","sources":["../../src/security/Security1.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItC,mFAAmF;AACnF,qBAAa,SAAU,SAAQ,QAAQ;IAOzB,OAAO,CAAC,iBAAiB;IANrC,OAAO,CAAC,KAAK,CAAmF;IAChG,OAAO,CAAC,OAAO,CAAC,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAC,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAC,CAAa;IACrC,OAAO,CAAC,MAAM,CAAC,CAAe;gBAEV,iBAAiB,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;IAU9D,sBAAsB,IAAI,OAAO,CAAC,UAAU,CAAC;IAwB7C,2BAA2B,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmDhE,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAK9C,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAIpD,aAAa,IAAI,OAAO;CAGzB"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/** Public proto-ver metadata, including application-defined capability lists. */
|
|
2
|
+
export interface ESPProvisioningMetadata {
|
|
3
|
+
ver?: string;
|
|
4
|
+
cap?: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface ESPProvisioningInfo {
|
|
7
|
+
prov: ESPProvisioningMetadata & {
|
|
8
|
+
sec_ver?: number;
|
|
9
|
+
sec_patch_ver?: number;
|
|
10
|
+
};
|
|
11
|
+
[name: string]: ESPProvisioningMetadata;
|
|
12
|
+
}
|
|
13
|
+
/** Resolve the security configuration after reading public discovery data. */
|
|
14
|
+
export type ESPSecurityResolver = (info: ESPProvisioningInfo) => ESPSecurityConfig | undefined | Promise<ESPSecurityConfig | undefined>;
|
|
1
15
|
export type ESPSecurityConfig = ESPSecurity1Config | ESPSecurity2Config;
|
|
2
16
|
export interface ESPSecurity1Config {
|
|
3
17
|
type: 'Security1';
|
|
@@ -63,7 +77,7 @@ export interface ESPScanStatusResponse {
|
|
|
63
77
|
* Device interface for ESP provisioning
|
|
64
78
|
*/
|
|
65
79
|
export interface ESPDeviceInterface {
|
|
66
|
-
connect(security?: ESPSecurityConfig): Promise<void>;
|
|
80
|
+
connect(security?: ESPSecurityConfig | ESPSecurityResolver): Promise<void>;
|
|
67
81
|
scanWifiList(): Promise<ESPWifiAp[]>;
|
|
68
82
|
provision(ssid: string, passphrase: string): Promise<void>;
|
|
69
83
|
fetchWifiStatus(): Promise<ESPWifiStatus>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AAExE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,IAAI,IAAI;IACR,GAAG,IAAI;IACP,cAAc,IAAI;IAClB,OAAO,IAAI;IACX,MAAM,IAAI;IACV,UAAU,IAAI;IACd,OAAO,IAAI;IACX,WAAW,IAAI;CAChB;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,SAAS,IAAI;IACb,UAAU,IAAI;IACd,YAAY,IAAI;IAChB,MAAM,IAAI;CACX;AAED;;GAEG;AACH,oBAAY,oBAAoB;IAC9B,SAAS,IAAI;IACb,eAAe,IAAI;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,MAAM,WAAW,uBAAuB;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,uBAAuB,GAAG;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7E,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,CAAC;CACzC;AAED,8EAA8E;AAC9E,MAAM,MAAM,mBAAmB,GAAG,CAChC,IAAI,EAAE,mBAAmB,KACtB,iBAAiB,GAAG,SAAS,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAAC;AAE5E,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;AAExE,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,IAAI,IAAI;IACR,GAAG,IAAI;IACP,cAAc,IAAI;IAClB,OAAO,IAAI;IACX,MAAM,IAAI;IACV,UAAU,IAAI;IACd,OAAO,IAAI;IACX,WAAW,IAAI;CAChB;AAED;;GAEG;AACH,oBAAY,eAAe;IACzB,SAAS,IAAI;IACb,UAAU,IAAI;IACd,YAAY,IAAI;IAChB,MAAM,IAAI;CACX;AAED;;GAEG;AACH,oBAAY,oBAAoB;IAC9B,SAAS,IAAI;IACb,eAAe,IAAI;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,QAAQ,CAAC,EAAE,iBAAiB,GAAG,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3E,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAErC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAE1C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAE9D,UAAU,IAAI,IAAI,CAAC;IAEnB,SAAS,IAAI,eAAe,GAAG,GAAG,CAAC;CACpC"}
|
package/dist/utils/crypto.d.ts
CHANGED
|
@@ -41,4 +41,13 @@ export declare function aesDecrypt(key: Uint8Array, counter: Uint8Array, data: U
|
|
|
41
41
|
* Concatenate multiple Uint8Arrays
|
|
42
42
|
*/
|
|
43
43
|
export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
|
|
44
|
+
/** Stateful AES-CTR, preserving partial blocks across requests and responses. */
|
|
45
|
+
export declare class AESCTRStream {
|
|
46
|
+
private key;
|
|
47
|
+
private counter;
|
|
48
|
+
private offset;
|
|
49
|
+
private constructor();
|
|
50
|
+
static create(key: Uint8Array, counter: Uint8Array): Promise<AESCTRStream>;
|
|
51
|
+
update(data: Uint8Array): Promise<Uint8Array>;
|
|
52
|
+
}
|
|
44
53
|
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAI9D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAMlD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAErD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEvD;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAGlE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAUvF;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAcrB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAcrB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAS/D"}
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../src/utils/crypto.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAI9D;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAMlD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAErD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEvD;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAGlE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAUvF;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAcrB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,UAAU,EACnB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAcrB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAS/D;AAED,iFAAiF;AACjF,qBAAa,YAAY;IAGH,OAAO,CAAC,GAAG;IAAa,OAAO,CAAC,OAAO;IAF3D,OAAO,CAAC,MAAM,CAAK;IAEnB,OAAO;WAEM,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAQ1E,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;CAkBpD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "esp-idf-provisioning-web",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "ESP-IDF WiFi Provisioning SDK for web browsers",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.es.js",
|
|
@@ -12,6 +12,17 @@
|
|
|
12
12
|
"require": "./dist/index.cjs.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"prebuild": "pbjs -t static-module -w es6 -o src/generated/proto.js src/proto/*.proto && pbts -o src/generated/proto.d.ts src/generated/proto.js",
|
|
17
|
+
"build": "vite build && tsc --emitDeclarationOnly",
|
|
18
|
+
"dev": "vite build --watch",
|
|
19
|
+
"example": "npx http-server -p 8080 -o /examples/ble-provisioning.html",
|
|
20
|
+
"serve": "npx http-server -p 8080",
|
|
21
|
+
"test": "jest",
|
|
22
|
+
"lint": "eslint src --ext .ts",
|
|
23
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
24
|
+
"prepack": "npm run build"
|
|
25
|
+
},
|
|
15
26
|
"keywords": [
|
|
16
27
|
"esp32",
|
|
17
28
|
"esp-idf",
|
|
@@ -26,20 +37,21 @@
|
|
|
26
37
|
"author": "",
|
|
27
38
|
"license": "MIT",
|
|
28
39
|
"dependencies": {
|
|
29
|
-
"
|
|
40
|
+
"@types/web-bluetooth": "0.0.22",
|
|
41
|
+
"protobufjs": "^7.6.6"
|
|
30
42
|
},
|
|
31
43
|
"devDependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"@types/
|
|
34
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
35
|
-
"@typescript-eslint/parser": "8.
|
|
36
|
-
"eslint": "
|
|
37
|
-
"jest": "30.2
|
|
38
|
-
"prettier": "^3.
|
|
39
|
-
"protobufjs-cli": "^1.
|
|
40
|
-
"ts-jest": "^29.
|
|
41
|
-
"typescript": "^5.
|
|
42
|
-
"vite": "7.
|
|
44
|
+
"@eslint/js": "10.0.1",
|
|
45
|
+
"@types/jest": "^30.0.0",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "8.72.0",
|
|
47
|
+
"@typescript-eslint/parser": "8.72.0",
|
|
48
|
+
"eslint": "10.13.0",
|
|
49
|
+
"jest": "30.5.2",
|
|
50
|
+
"prettier": "^3.9.10",
|
|
51
|
+
"protobufjs-cli": "^1.3.3",
|
|
52
|
+
"ts-jest": "^29.4.15",
|
|
53
|
+
"typescript": "^5.9.3",
|
|
54
|
+
"vite": "7.3.7"
|
|
43
55
|
},
|
|
44
56
|
"files": [
|
|
45
57
|
"dist",
|
|
@@ -53,15 +65,5 @@
|
|
|
53
65
|
},
|
|
54
66
|
"bugs": {
|
|
55
67
|
"url": "https://github.com/ho-229/esp-idf-provisioning-web/issues"
|
|
56
|
-
},
|
|
57
|
-
"scripts": {
|
|
58
|
-
"prebuild": "pbjs -t static-module -w es6 -o src/generated/proto.js src/proto/*.proto && pbts -o src/generated/proto.d.ts src/generated/proto.js",
|
|
59
|
-
"build": "vite build && tsc --emitDeclarationOnly",
|
|
60
|
-
"dev": "vite build --watch",
|
|
61
|
-
"example": "npx http-server -p 8080 -o /examples/ble-provisioning.html",
|
|
62
|
-
"serve": "npx http-server -p 8080",
|
|
63
|
-
"test": "jest",
|
|
64
|
-
"lint": "eslint src --ext .ts",
|
|
65
|
-
"format": "prettier --write \"src/**/*.ts\""
|
|
66
68
|
}
|
|
67
|
-
}
|
|
69
|
+
}
|
package/src/ESPDevice.ts
CHANGED
|
@@ -3,12 +3,16 @@ import {
|
|
|
3
3
|
ESPWifiAp,
|
|
4
4
|
ESPWifiStatus,
|
|
5
5
|
ESPSecurityConfig,
|
|
6
|
+
ESPSecurityResolver,
|
|
7
|
+
ESPProvisioningInfo,
|
|
6
8
|
} from './types';
|
|
7
9
|
import { Transport } from './transport/Transport';
|
|
8
10
|
import { BLETransport } from './transport/BLETransport';
|
|
9
11
|
import { SoftAPTransport } from './transport/SoftAPTransport';
|
|
10
12
|
import { Security } from './security/Security';
|
|
11
13
|
import { Security0 } from './security/Security0';
|
|
14
|
+
import { Security1 } from './security/Security1';
|
|
15
|
+
import { bytesToString, stringToBytes } from './utils/crypto';
|
|
12
16
|
import { FALLBACK_NU_LOOKUP, FALLBACK_SERVICE_UUID, PROTO_ENDPOINTS } from './constants';
|
|
13
17
|
import {
|
|
14
18
|
getScanResultRequest,
|
|
@@ -34,6 +38,7 @@ export class ESPDevice implements ESPDeviceInterface {
|
|
|
34
38
|
private device: BluetoothDevice | URL;
|
|
35
39
|
private transportImpl?: Transport;
|
|
36
40
|
private securityImpl?: Security;
|
|
41
|
+
private requestQueue: Promise<void> = Promise.resolve();
|
|
37
42
|
|
|
38
43
|
/**
|
|
39
44
|
* Create a new ESPDevice instance
|
|
@@ -43,22 +48,47 @@ export class ESPDevice implements ESPDeviceInterface {
|
|
|
43
48
|
this.device = device;
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
51
|
+
/** Connect, read public metadata, resolve credentials, then complete the handshake. */
|
|
52
|
+
async connect(security?: ESPSecurityConfig | ESPSecurityResolver): Promise<void> {
|
|
53
|
+
if (this.transportImpl) throw new Error('Device already connected or connecting');
|
|
54
|
+
const transport = this.device instanceof URL
|
|
55
|
+
? new SoftAPTransport(this.device.toString())
|
|
56
|
+
: new BLETransport(this.device, FALLBACK_SERVICE_UUID, new Map(Object.entries(FALLBACK_NU_LOOKUP)));
|
|
57
|
+
this.transportImpl = transport;
|
|
58
|
+
try {
|
|
59
|
+
await transport.connect();
|
|
60
|
+
const response = await transport.sendData(PROTO_ENDPOINTS.PROTO_VER, stringToBytes('ESP'));
|
|
61
|
+
const info: ESPProvisioningInfo = JSON.parse(bytesToString(response));
|
|
62
|
+
if (!info || !info.prov || typeof info.prov !== 'object' || Array.isArray(info.prov)) {
|
|
63
|
+
throw new Error('Invalid proto-ver metadata');
|
|
64
|
+
}
|
|
65
|
+
if (this.transportImpl !== transport || !transport.isConnected()) {
|
|
66
|
+
throw new Error('Device disconnected during discovery');
|
|
67
|
+
}
|
|
68
|
+
const config = typeof security === 'function' ? await security(info) : security;
|
|
69
|
+
if (this.transportImpl !== transport || !transport.isConnected()) {
|
|
70
|
+
throw new Error('Device disconnected while resolving security');
|
|
71
|
+
}
|
|
72
|
+
const version = config?.type === 'Security1' ? 1 : config?.type === 'Security2' ? 2 : 0;
|
|
73
|
+
if (info.prov.sec_ver !== undefined && info.prov.sec_ver !== version) {
|
|
74
|
+
throw new Error(`Device requires Security${info.prov.sec_ver}; provide a matching security configuration`);
|
|
75
|
+
}
|
|
76
|
+
let session: Security;
|
|
77
|
+
if (!config) {
|
|
78
|
+
session = new Security0();
|
|
79
|
+
} else if (config.type === 'Security1') {
|
|
80
|
+
session = new Security1(config.proofOfPossession, info.prov.sec_patch_ver);
|
|
81
|
+
} else {
|
|
82
|
+
throw new Error('Unsupported security configuration');
|
|
83
|
+
}
|
|
84
|
+
await this.establishSession(transport, session);
|
|
85
|
+
if (this.transportImpl !== transport || !transport.isConnected()) {
|
|
86
|
+
throw new Error('Device disconnected during handshake');
|
|
87
|
+
}
|
|
88
|
+
this.securityImpl = session;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (this.transportImpl === transport) this.disconnect();
|
|
91
|
+
throw error;
|
|
62
92
|
}
|
|
63
93
|
}
|
|
64
94
|
|
|
@@ -148,19 +178,30 @@ export class ESPDevice implements ESPDeviceInterface {
|
|
|
148
178
|
* @returns Response data from device
|
|
149
179
|
*/
|
|
150
180
|
async sendData(path: string, data: Uint8Array): Promise<Uint8Array> {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
181
|
+
const transport = this.transportImpl;
|
|
182
|
+
const security = this.securityImpl;
|
|
183
|
+
if (!transport || !security?.isEstablished()) throw new Error('Device not connected');
|
|
184
|
+
if (path === PROTO_ENDPOINTS.PROV_SESSION) throw new Error('Session endpoint is managed by connect()');
|
|
185
|
+
|
|
186
|
+
// Security1 shares one CTR stream in both directions. Serialize the entire
|
|
187
|
+
// request/response pair, including custom endpoints.
|
|
188
|
+
const request = this.requestQueue.then(async () => {
|
|
189
|
+
if (this.transportImpl !== transport || this.securityImpl !== security || !transport.isConnected()) {
|
|
190
|
+
throw new Error('Device disconnected');
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
if (path === PROTO_ENDPOINTS.PROTO_VER) return await transport.sendData(path, data);
|
|
194
|
+
const encrypted = await security.encrypt(data);
|
|
195
|
+
const response = await transport.sendData(path, encrypted);
|
|
196
|
+
return await security.decrypt(response);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
// A lost response leaves the shared cipher position unknown.
|
|
199
|
+
if (this.transportImpl === transport) this.disconnect();
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
this.requestQueue = request.then(() => {}, () => {});
|
|
204
|
+
return request;
|
|
164
205
|
}
|
|
165
206
|
|
|
166
207
|
/**
|
|
@@ -172,6 +213,7 @@ export class ESPDevice implements ESPDeviceInterface {
|
|
|
172
213
|
this.transportImpl = undefined;
|
|
173
214
|
}
|
|
174
215
|
this.securityImpl = undefined;
|
|
216
|
+
this.requestQueue = Promise.resolve();
|
|
175
217
|
}
|
|
176
218
|
|
|
177
219
|
/**
|
|
@@ -181,51 +223,14 @@ export class ESPDevice implements ESPDeviceInterface {
|
|
|
181
223
|
return this.device;
|
|
182
224
|
}
|
|
183
225
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Establish secure session with device
|
|
197
|
-
*/
|
|
198
|
-
private async establishSession(): Promise<void> {
|
|
199
|
-
if (!this.transportImpl || !this.securityImpl) {
|
|
200
|
-
throw new Error('Transport or security not initialized');
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Get session setup request
|
|
204
|
-
const setupRequest = await this.securityImpl.getSessionSetupRequest();
|
|
205
|
-
|
|
206
|
-
// Send session setup request
|
|
207
|
-
const setupResponse = await this.transportImpl.sendData(
|
|
208
|
-
PROTO_ENDPOINTS.PROV_SESSION,
|
|
209
|
-
setupRequest
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
// Process session setup response
|
|
213
|
-
await this.securityImpl.processSessionSetupResponse(setupResponse);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Initialize transport layer based on transport type
|
|
218
|
-
*/
|
|
219
|
-
private async initializeTransport(): Promise<void> {
|
|
220
|
-
if (this.device instanceof URL) {
|
|
221
|
-
this.transportImpl = new SoftAPTransport(this.device.toString());
|
|
222
|
-
} else { // BluetoothDevice
|
|
223
|
-
this.transportImpl = new BLETransport(
|
|
224
|
-
this.device,
|
|
225
|
-
FALLBACK_SERVICE_UUID,
|
|
226
|
-
new Map(Object.entries(FALLBACK_NU_LOOKUP))
|
|
227
|
-
);
|
|
226
|
+
private async establishSession(transport: Transport, security: Security): Promise<void> {
|
|
227
|
+
while (!security.isEstablished()) {
|
|
228
|
+
if (this.transportImpl !== transport || !transport.isConnected()) {
|
|
229
|
+
throw new Error('Device disconnected during handshake');
|
|
230
|
+
}
|
|
231
|
+
const request = await security.getSessionSetupRequest();
|
|
232
|
+
const response = await transport.sendData(PROTO_ENDPOINTS.PROV_SESSION, request);
|
|
233
|
+
await security.processSessionSetupResponse(response);
|
|
228
234
|
}
|
|
229
|
-
await this.transportImpl.connect();
|
|
230
235
|
}
|
|
231
236
|
}
|
|
File without changes
|
package/src/constants.ts
CHANGED
|
File without changes
|
package/src/generated/.gitkeep
CHANGED
|
File without changes
|
package/src/generated/proto.d.ts
CHANGED
|
File without changes
|