esp-idf-provisioning-web 0.0.1

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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -0
  3. package/dist/ESPDevice.d.ts +66 -0
  4. package/dist/ESPDevice.d.ts.map +1 -0
  5. package/dist/ESPProvisionManager.d.ts +34 -0
  6. package/dist/ESPProvisionManager.d.ts.map +1 -0
  7. package/dist/constants.d.ts +19 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/index.d.ts +16 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.es.js +5085 -0
  12. package/dist/protocol/protocol.d.ts +4 -0
  13. package/dist/protocol/protocol.d.ts.map +1 -0
  14. package/dist/protocol/wifiConfig.d.ts +8 -0
  15. package/dist/protocol/wifiConfig.d.ts.map +1 -0
  16. package/dist/protocol/wifiScan.d.ts +8 -0
  17. package/dist/protocol/wifiScan.d.ts.map +1 -0
  18. package/dist/security/Security.d.ts +26 -0
  19. package/dist/security/Security.d.ts.map +1 -0
  20. package/dist/security/Security0.d.ts +13 -0
  21. package/dist/security/Security0.d.ts.map +1 -0
  22. package/dist/transport/BLETransport.d.ts +22 -0
  23. package/dist/transport/BLETransport.d.ts.map +1 -0
  24. package/dist/transport/SoftAPTransport.d.ts +27 -0
  25. package/dist/transport/SoftAPTransport.d.ts.map +1 -0
  26. package/dist/transport/Transport.d.ts +22 -0
  27. package/dist/transport/Transport.d.ts.map +1 -0
  28. package/dist/types.d.ts +73 -0
  29. package/dist/types.d.ts.map +1 -0
  30. package/dist/utils/crypto.d.ts +44 -0
  31. package/dist/utils/crypto.d.ts.map +1 -0
  32. package/package.json +60 -0
  33. package/src/ESPDevice.ts +231 -0
  34. package/src/ESPProvisionManager.ts +78 -0
  35. package/src/constants.ts +29 -0
  36. package/src/generated/.gitkeep +0 -0
  37. package/src/generated/proto.d.ts +3418 -0
  38. package/src/generated/proto.js +10006 -0
  39. package/src/index.ts +31 -0
  40. package/src/proto/constants.proto +14 -0
  41. package/src/proto/sec0.proto +28 -0
  42. package/src/proto/sec1.proto +45 -0
  43. package/src/proto/sec2.proto +48 -0
  44. package/src/proto/session.proto +25 -0
  45. package/src/proto/wifi_config.proto +57 -0
  46. package/src/proto/wifi_constants.proto +32 -0
  47. package/src/proto/wifi_ctrl.proto +38 -0
  48. package/src/proto/wifi_scan.proto +63 -0
  49. package/src/protocol/protocol.ts +23 -0
  50. package/src/protocol/wifiConfig.ts +108 -0
  51. package/src/protocol/wifiScan.ts +91 -0
  52. package/src/security/Security.ts +29 -0
  53. package/src/security/Security0.ts +40 -0
  54. package/src/transport/BLETransport.ts +111 -0
  55. package/src/transport/SoftAPTransport.ts +89 -0
  56. package/src/transport/Transport.ts +24 -0
  57. package/src/types.ts +86 -0
  58. package/src/utils/crypto.ts +129 -0
package/src/index.ts ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ESP-IDF Provisioning Web SDK
3
+ *
4
+ * A TypeScript library for provisioning ESP32 devices via Web Bluetooth API and HTTP.
5
+ * Supports both BLE and SoftAP transport modes with Security0, Security1, and Security2.
6
+ *
7
+ * Note: Browser limitations apply:
8
+ * - BLE requires user interaction to select devices
9
+ * - SoftAP requires manual WiFi connection by the user
10
+ * - Some security features may require additional crypto libraries for production use
11
+ */
12
+
13
+ export { ESPDevice } from './ESPDevice';
14
+ export { ESPProvisionManager } from './ESPProvisionManager';
15
+
16
+ export {
17
+ ESPWifiAuthMode,
18
+ ESPWifiStaState,
19
+ type ESPDeviceInterface,
20
+ type ESPSecurity1Config,
21
+ type ESPSecurity2Config,
22
+ type ESPWifiAp,
23
+ type ESPScanStatusResponse as ESPStatusResponse,
24
+ type ESPConnectFailReason,
25
+ type ESPWifiStatus,
26
+ } from './types';
27
+
28
+ export {
29
+ FALLBACK_SERVICE_UUID,
30
+ DEFAULT_DEVICE_PREFIX,
31
+ } from './constants';
@@ -0,0 +1,14 @@
1
+ syntax = "proto3";
2
+
3
+ /* Allowed values for the status
4
+ * of a protocomm instance */
5
+ enum Status {
6
+ Success = 0;
7
+ InvalidSecScheme = 1;
8
+ InvalidProto = 2;
9
+ TooManySessions = 3;
10
+ InvalidArgument = 4;
11
+ InternalError = 5;
12
+ CryptoError = 6;
13
+ InvalidSession = 7;
14
+ }
@@ -0,0 +1,28 @@
1
+ syntax = "proto3";
2
+
3
+ import "constants.proto";
4
+
5
+ /* Data structure of Session command/request packet */
6
+ message S0SessionCmd {
7
+
8
+ }
9
+
10
+ /* Data structure of Session response packet */
11
+ message S0SessionResp {
12
+ Status status = 1;
13
+ }
14
+
15
+ /* A message must be of type Cmd or Resp */
16
+ enum Sec0MsgType {
17
+ S0_Session_Command = 0;
18
+ S0_Session_Response = 1;
19
+ }
20
+
21
+ /* Payload structure of session data */
22
+ message Sec0Payload {
23
+ Sec0MsgType msg = 1; /*!< Type of message */
24
+ oneof payload {
25
+ S0SessionCmd sc = 20; /*!< Payload data interpreted as Cmd */
26
+ S0SessionResp sr = 21; /*!< Payload data interpreted as Resp */
27
+ }
28
+ }
@@ -0,0 +1,45 @@
1
+ syntax = "proto3";
2
+
3
+ import "constants.proto";
4
+
5
+ /* Data structure of Session command1 packet */
6
+ message SessionCmd1 {
7
+ bytes client_verify_data = 2;
8
+ }
9
+
10
+ /* Data structure of Session response1 packet */
11
+ message SessionResp1 {
12
+ Status status = 1;
13
+ bytes device_verify_data = 3;
14
+ }
15
+
16
+ /* Data structure of Session command0 packet */
17
+ message SessionCmd0 {
18
+ bytes client_pubkey = 1;
19
+ }
20
+
21
+ /* Data structure of Session response0 packet */
22
+ message SessionResp0 {
23
+ Status status = 1;
24
+ bytes device_pubkey = 2;
25
+ bytes device_random = 3;
26
+ }
27
+
28
+ /* A message must be of type Cmd0 / Cmd1 / Resp0 / Resp1 */
29
+ enum Sec1MsgType {
30
+ Session_Command0 = 0;
31
+ Session_Response0 = 1;
32
+ Session_Command1 = 2;
33
+ Session_Response1 = 3;
34
+ }
35
+
36
+ /* Payload structure of session data */
37
+ message Sec1Payload {
38
+ Sec1MsgType msg = 1; /*!< Type of message */
39
+ oneof payload {
40
+ SessionCmd0 sc0 = 20; /*!< Payload data interpreted as Cmd0 */
41
+ SessionResp0 sr0 = 21; /*!< Payload data interpreted as Resp0 */
42
+ SessionCmd1 sc1 = 22; /*!< Payload data interpreted as Cmd1 */
43
+ SessionResp1 sr1 = 23; /*!< Payload data interpreted as Resp1 */
44
+ }
45
+ }
@@ -0,0 +1,48 @@
1
+ syntax = "proto3";
2
+
3
+ import "constants.proto";
4
+
5
+ /* A message must be of type Cmd0 / Cmd1 / Resp0 / Resp1 */
6
+ enum Sec2MsgType {
7
+ S2Session_Command0 = 0;
8
+ S2Session_Response0 = 1;
9
+ S2Session_Command1 = 2;
10
+ S2Session_Response1 = 3;
11
+ }
12
+
13
+ // NOTE: Client: Host (shell, Android/iOS) | Device: ESP32-XX
14
+ /* Data structure of Session command0 packet */
15
+ message S2SessionCmd0 {
16
+ bytes client_username = 1;
17
+ bytes client_pubkey = 2;
18
+ }
19
+
20
+ /* Data structure of Session response0 packet */
21
+ message S2SessionResp0 {
22
+ Status status = 1;
23
+ bytes device_pubkey = 2;
24
+ bytes device_salt = 3;
25
+ }
26
+
27
+ /* Data structure of Session command1 packet */
28
+ message S2SessionCmd1 {
29
+ bytes client_proof = 1;
30
+ }
31
+
32
+ /* Data structure of Session response1 packet */
33
+ message S2SessionResp1 {
34
+ Status status = 1;
35
+ bytes device_proof = 2;
36
+ bytes device_nonce = 3;
37
+ }
38
+
39
+ /* Payload structure of session data */
40
+ message Sec2Payload {
41
+ Sec2MsgType msg = 1; /*!< Type of message */
42
+ oneof payload {
43
+ S2SessionCmd0 sc0 = 20; /*!< Payload data interpreted as Cmd0 */
44
+ S2SessionResp0 sr0 = 21; /*!< Payload data interpreted as Resp0 */
45
+ S2SessionCmd1 sc1 = 22; /*!< Payload data interpreted as Cmd1 */
46
+ S2SessionResp1 sr1 = 23; /*!< Payload data interpreted as Resp1 */
47
+ }
48
+ }
@@ -0,0 +1,25 @@
1
+ syntax = "proto3";
2
+
3
+ import "sec0.proto";
4
+ import "sec1.proto";
5
+ import "sec2.proto";
6
+
7
+ /* Allowed values for the type of security
8
+ * being used in a protocomm session */
9
+ enum SecSchemeVersion {
10
+ SecScheme0 = 0; /*!< Unsecured - plaintext communication */
11
+ SecScheme1 = 1; /*!< Security scheme 1 - Curve25519 + AES-256-CTR*/
12
+ SecScheme2 = 2; /*!< Security scheme 2 - SRP6a + AES-256-GCM*/
13
+
14
+ }
15
+
16
+ /* Data structure exchanged when establishing
17
+ * secure session between Host and Client */
18
+ message SessionData {
19
+ SecSchemeVersion sec_ver = 2; /*!< Type of security */
20
+ oneof proto {
21
+ Sec0Payload sec0 = 10; /*!< Payload data in case of security 0 */
22
+ Sec1Payload sec1 = 11; /*!< Payload data in case of security 1 */
23
+ Sec2Payload sec2 = 12; /*!< Payload data in case of security 2 */
24
+ }
25
+ }
@@ -0,0 +1,57 @@
1
+ syntax = "proto3";
2
+
3
+ import "constants.proto";
4
+ import "wifi_constants.proto";
5
+
6
+ message CmdGetStatus {
7
+
8
+ }
9
+
10
+ message RespGetStatus {
11
+ Status status = 1;
12
+ WifiStationState sta_state = 2;
13
+ oneof state {
14
+ WifiConnectFailedReason fail_reason = 10;
15
+ WifiConnectedState connected = 11;
16
+ }
17
+ }
18
+
19
+ message CmdSetConfig {
20
+ bytes ssid = 1;
21
+ bytes passphrase = 2;
22
+ bytes bssid = 3;
23
+ int32 channel = 4;
24
+ }
25
+
26
+ message RespSetConfig {
27
+ Status status = 1;
28
+ }
29
+
30
+ message CmdApplyConfig {
31
+
32
+ }
33
+
34
+ message RespApplyConfig {
35
+ Status status = 1;
36
+ }
37
+
38
+ enum WiFiConfigMsgType {
39
+ TypeCmdGetStatus = 0;
40
+ TypeRespGetStatus = 1;
41
+ TypeCmdSetConfig = 2;
42
+ TypeRespSetConfig = 3;
43
+ TypeCmdApplyConfig = 4;
44
+ TypeRespApplyConfig = 5;
45
+ }
46
+
47
+ message WiFiConfigPayload {
48
+ WiFiConfigMsgType msg = 1;
49
+ oneof payload {
50
+ CmdGetStatus cmd_get_status = 10;
51
+ RespGetStatus resp_get_status = 11;
52
+ CmdSetConfig cmd_set_config = 12;
53
+ RespSetConfig resp_set_config = 13;
54
+ CmdApplyConfig cmd_apply_config = 14;
55
+ RespApplyConfig resp_apply_config = 15;
56
+ }
57
+ }
@@ -0,0 +1,32 @@
1
+ syntax = "proto3";
2
+
3
+ enum WifiStationState {
4
+ Connected = 0;
5
+ Connecting = 1;
6
+ Disconnected = 2;
7
+ ConnectionFailed = 3;
8
+ }
9
+
10
+ enum WifiConnectFailedReason {
11
+ AuthError = 0;
12
+ NetworkNotFound = 1;
13
+ }
14
+
15
+ enum WifiAuthMode {
16
+ Open = 0;
17
+ WEP = 1;
18
+ WPA_PSK = 2;
19
+ WPA2_PSK = 3;
20
+ WPA_WPA2_PSK = 4;
21
+ WPA2_ENTERPRISE = 5;
22
+ WPA3_PSK = 6;
23
+ WPA2_WPA3_PSK = 7;
24
+ }
25
+
26
+ message WifiConnectedState {
27
+ string ip4_addr = 1;
28
+ WifiAuthMode auth_mode = 2;
29
+ bytes ssid = 3;
30
+ bytes bssid = 4;
31
+ int32 channel = 5;
32
+ }
@@ -0,0 +1,38 @@
1
+ syntax = "proto3";
2
+
3
+ import "constants.proto";
4
+
5
+ message CmdCtrlReset {
6
+
7
+ }
8
+
9
+ message RespCtrlReset {
10
+
11
+ }
12
+
13
+ message CmdCtrlReprov {
14
+
15
+ }
16
+
17
+ message RespCtrlReprov{
18
+
19
+ }
20
+
21
+ enum WiFiCtrlMsgType {
22
+ TypeCtrlReserved = 0;
23
+ TypeCmdCtrlReset = 1;
24
+ TypeRespCtrlReset = 2;
25
+ TypeCmdCtrlReprov = 3;
26
+ TypeRespCtrlReprov = 4;
27
+ }
28
+
29
+ message WiFiCtrlPayload {
30
+ WiFiCtrlMsgType msg = 1;
31
+ Status status = 2;
32
+ oneof payload {
33
+ CmdCtrlReset cmd_ctrl_reset = 11;
34
+ RespCtrlReset resp_ctrl_reset = 12;
35
+ CmdCtrlReprov cmd_ctrl_reprov = 13;
36
+ RespCtrlReprov resp_ctrl_reprov = 14;
37
+ }
38
+ }
@@ -0,0 +1,63 @@
1
+ syntax = "proto3";
2
+
3
+ import "constants.proto";
4
+ import "wifi_constants.proto";
5
+
6
+ message CmdScanStart {
7
+ bool blocking = 1;
8
+ bool passive = 2;
9
+ uint32 group_channels = 3;
10
+ uint32 period_ms = 4;
11
+ }
12
+
13
+ message RespScanStart {
14
+
15
+ }
16
+
17
+ message CmdScanStatus {
18
+
19
+ }
20
+
21
+ message RespScanStatus {
22
+ bool scan_finished = 1;
23
+ uint32 result_count = 2;
24
+ }
25
+
26
+ message CmdScanResult {
27
+ uint32 start_index = 1;
28
+ uint32 count = 2;
29
+ }
30
+
31
+ message WiFiScanResult {
32
+ bytes ssid = 1;
33
+ uint32 channel = 2;
34
+ int32 rssi = 3;
35
+ bytes bssid = 4;
36
+ WifiAuthMode auth = 5;
37
+ }
38
+
39
+ message RespScanResult {
40
+ repeated WiFiScanResult entries = 1;
41
+ }
42
+
43
+ enum WiFiScanMsgType {
44
+ TypeCmdScanStart = 0;
45
+ TypeRespScanStart = 1;
46
+ TypeCmdScanStatus = 2;
47
+ TypeRespScanStatus = 3;
48
+ TypeCmdScanResult = 4;
49
+ TypeRespScanResult = 5;
50
+ }
51
+
52
+ message WiFiScanPayload {
53
+ WiFiScanMsgType msg = 1;
54
+ Status status = 2;
55
+ oneof payload {
56
+ CmdScanStart cmd_scan_start = 10;
57
+ RespScanStart resp_scan_start = 11;
58
+ CmdScanStatus cmd_scan_status = 12;
59
+ RespScanStatus resp_scan_status = 13;
60
+ CmdScanResult cmd_scan_result = 14;
61
+ RespScanResult resp_scan_result = 15;
62
+ }
63
+ }
@@ -0,0 +1,23 @@
1
+ import * as proto from '../generated/proto.js';
2
+ import { ESPWifiAuthMode } from '../types.js';
3
+
4
+ export function wifiAuthModeToESPWifiAuthMode(mode: proto.WifiAuthMode): ESPWifiAuthMode {
5
+ switch (mode) {
6
+ case proto.WifiAuthMode.Open:
7
+ return ESPWifiAuthMode.open;
8
+ case proto.WifiAuthMode.WEP:
9
+ return ESPWifiAuthMode.wep;
10
+ case proto.WifiAuthMode.WPA_PSK:
11
+ return ESPWifiAuthMode.wpaPsk;
12
+ case proto.WifiAuthMode.WPA2_PSK:
13
+ return ESPWifiAuthMode.wpa2Psk;
14
+ case proto.WifiAuthMode.WPA_WPA2_PSK:
15
+ return ESPWifiAuthMode.wpaWpa2Psk;
16
+ case proto.WifiAuthMode.WPA2_ENTERPRISE:
17
+ return ESPWifiAuthMode.wpa2Enterprise;
18
+ case proto.WifiAuthMode.WPA3_PSK:
19
+ return ESPWifiAuthMode.wpa3Psk;
20
+ case proto.WifiAuthMode.WPA2_WPA3_PSK:
21
+ return ESPWifiAuthMode.wpa2Wpa3Psk;
22
+ }
23
+ }
@@ -0,0 +1,108 @@
1
+ import * as proto from '../generated/proto.js';
2
+ import { ESPConnectFailReason, ESPWifiAp, ESPWifiStaState, ESPWifiStatus } from '../types.js';
3
+ import { bytesToHex, bytesToString, stringToBytes } from '../utils/crypto.js';
4
+ import { wifiAuthModeToESPWifiAuthMode } from './protocol.js';
5
+
6
+ export function getConfigStatusRequest(): Uint8Array {
7
+ let configRequest = proto.WiFiConfigPayload.create({});
8
+ configRequest.msg = proto.WiFiConfigMsgType.TypeCmdGetStatus;
9
+ configRequest.cmdGetStatus = proto.CmdGetStatus.create({});
10
+ return proto.WiFiConfigPayload.encode(configRequest).finish();
11
+ }
12
+
13
+ export function processConfigStatusResponse(response: Uint8Array): ESPWifiStatus {
14
+ try {
15
+ const configResponse = proto.WiFiConfigPayload.decode(response);
16
+ const result = configResponse.respGetStatus as proto.RespGetStatus;
17
+ if (result.status !== proto.Status.Success) {
18
+ throw new Error(`Config status failed: ${result.status}`);
19
+ }
20
+ let staState: ESPWifiStaState;
21
+ switch (result.staState) {
22
+ case proto.WifiStationState.Disconnected:
23
+ staState = ESPWifiStaState.disconnected;
24
+ break;
25
+ case proto.WifiStationState.Connecting:
26
+ staState = ESPWifiStaState.connecting;
27
+ break;
28
+ case proto.WifiStationState.Connected:
29
+ staState = ESPWifiStaState.connected;
30
+ break;
31
+ case proto.WifiStationState.ConnectionFailed:
32
+ staState = ESPWifiStaState.failed;
33
+ break;
34
+ }
35
+
36
+ let failedReason: ESPConnectFailReason | undefined;
37
+ switch (result.failReason) {
38
+ case proto.WifiConnectFailedReason.AuthError:
39
+ failedReason = ESPConnectFailReason.authError;
40
+ break;
41
+ case proto.WifiConnectFailedReason.NetworkNotFound:
42
+ failedReason = ESPConnectFailReason.networkNotFound;
43
+ break;
44
+ default:
45
+ break;
46
+ }
47
+
48
+ let connected: ESPWifiAp | undefined;
49
+ if (result.connected) {
50
+ connected = {
51
+ ssid: bytesToString(result.connected.ssid),
52
+ rssi: result.connected.rssi,
53
+ auth: wifiAuthModeToESPWifiAuthMode(result.connected.auth),
54
+ bssid: bytesToHex(result.connected.bssid),
55
+ channel: result.connected.channel,
56
+ };
57
+ }
58
+
59
+ return {
60
+ staState,
61
+ failedReason,
62
+ connected,
63
+ };
64
+ } catch (error) {
65
+ throw new Error('Failed to decode config status response');
66
+ }
67
+ }
68
+
69
+ export function getConfigUpdateRequest(ssid: string, passphrase: string): Uint8Array {
70
+ let configRequest = proto.WiFiConfigPayload.create({});
71
+ configRequest.msg = proto.WiFiConfigMsgType.TypeCmdSetConfig;
72
+ configRequest.cmdSetConfig = proto.CmdSetConfig.create({
73
+ ssid: stringToBytes(ssid),
74
+ passphrase: stringToBytes(passphrase),
75
+ });
76
+ return proto.WiFiConfigPayload.encode(configRequest).finish();
77
+ }
78
+
79
+ export function processConfigUpdateResponse(response: Uint8Array): void {
80
+ try {
81
+ const configResponse = proto.WiFiConfigPayload.decode(response);
82
+ const result = configResponse.respSetConfig as proto.RespSetConfig;
83
+ if (result.status !== proto.Status.Success) {
84
+ throw new Error(`Config update failed: ${result.status}`);
85
+ }
86
+ } catch (error) {
87
+ throw new Error('Failed to decode config update response');
88
+ }
89
+ }
90
+
91
+ export function getConfigApplyRequest(): Uint8Array {
92
+ let configRequest = proto.WiFiConfigPayload.create({});
93
+ configRequest.msg = proto.WiFiConfigMsgType.TypeCmdApplyConfig;
94
+ configRequest.cmdApplyConfig = proto.CmdApplyConfig.create({});
95
+ return proto.WiFiConfigPayload.encode(configRequest).finish();
96
+ }
97
+
98
+ export function processConfigApplyResponse(response: Uint8Array): void {
99
+ try {
100
+ const configResponse = proto.WiFiConfigPayload.decode(response);
101
+ const result = configResponse.respApplyConfig as proto.RespApplyConfig;
102
+ if (result.status !== proto.Status.Success) {
103
+ throw new Error(`Config apply failed: ${result.status}`);
104
+ }
105
+ } catch (error) {
106
+ throw new Error('Failed to decode config apply response');
107
+ }
108
+ }
@@ -0,0 +1,91 @@
1
+ import * as proto from '../generated/proto.js';
2
+ import { ESPScanStatusResponse, ESPWifiAp } from '../types.js';
3
+ import { bytesToHex, bytesToString } from '../utils/crypto.js';
4
+ import { wifiAuthModeToESPWifiAuthMode } from './protocol.js';
5
+
6
+ export function getScanStartRequest(
7
+ blocking: boolean = true,
8
+ passive: boolean = false,
9
+ groupChannels: number = 5,
10
+ periodMs: number = 120
11
+ ): Uint8Array {
12
+ let cmd = proto.CmdScanStart.create({});
13
+ cmd.blocking = blocking;
14
+ cmd.passive = passive;
15
+ cmd.groupChannels = groupChannels;
16
+ cmd.periodMs = periodMs;
17
+ const scanRequest = proto.WiFiScanPayload.create({
18
+ msg: proto.WiFiScanMsgType.TypeCmdScanStart,
19
+ cmdScanStart: cmd,
20
+ });
21
+ return proto.WiFiScanPayload.encode(scanRequest).finish();
22
+ }
23
+
24
+ export function processScanStartResponse(response: Uint8Array): void {
25
+ try {
26
+ const scanResponse = proto.WiFiScanPayload.decode(response);
27
+ if (scanResponse.status !== proto.Status.Success) {
28
+ throw new Error(`Scan start failed: ${scanResponse.status}`);
29
+ }
30
+ } catch (error) {
31
+ console.error('Error processing scan start response:', error);
32
+ }
33
+ }
34
+
35
+ export function getScanStatusRequest(): Uint8Array {
36
+ const scanRequest = proto.WiFiScanPayload.create({
37
+ msg: proto.WiFiScanMsgType.TypeCmdScanStatus,
38
+ cmdScanStatus: proto.CmdScanStatus.create({}),
39
+ });
40
+ return proto.WiFiScanPayload.encode(scanRequest).finish();
41
+ }
42
+
43
+ export function processScanStatusResponse(response: Uint8Array): ESPScanStatusResponse {
44
+ try {
45
+ const scanResponse = proto.WiFiScanPayload.decode(response);
46
+ if (scanResponse.status !== proto.Status.Success) {
47
+ throw new Error(`Scan status failed: ${scanResponse.status}`);
48
+ }
49
+ const result = scanResponse.respScanStatus as proto.RespScanStatus;
50
+ return {
51
+ scanFinished: result.scanFinished,
52
+ count: result.resultCount,
53
+ };
54
+ } catch (error) {
55
+ throw new Error('Failed to decode scan status response');
56
+ }
57
+ }
58
+
59
+ export function getScanResultRequest(index: number, count: number): Uint8Array {
60
+ let cmd = proto.CmdScanResult.create({});
61
+ cmd.startIndex = index;
62
+ cmd.count = count;
63
+ const scanRequest = proto.WiFiScanPayload.create({
64
+ msg: proto.WiFiScanMsgType.TypeCmdScanResult,
65
+ cmdScanResult: cmd,
66
+ });
67
+ return proto.WiFiScanPayload.encode(scanRequest).finish();
68
+ }
69
+
70
+ export function processScanResultResponse(response: Uint8Array): ESPWifiAp[] {
71
+ try {
72
+ const scanResponse = proto.WiFiScanPayload.decode(response);
73
+ if (scanResponse.status !== proto.Status.Success) {
74
+ throw new Error(`Scan result failed: ${scanResponse.status}`);
75
+ }
76
+ const result = scanResponse.respScanResult as proto.RespScanResult;
77
+ const wifiList: ESPWifiAp[] = result.entries.map((entity) => {
78
+ const wifi = entity as proto.WiFiScanResult;
79
+ return {
80
+ ssid: bytesToString(wifi.ssid),
81
+ rssi: wifi.rssi,
82
+ auth: wifiAuthModeToESPWifiAuthMode(wifi.auth),
83
+ bssid: bytesToHex(wifi.bssid),
84
+ channel: wifi.channel,
85
+ };
86
+ });
87
+ return wifiList;
88
+ } catch (error) {
89
+ throw new Error('Failed to decode scan result response');
90
+ }
91
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Base class for security implementations
3
+ */
4
+ export abstract class Security {
5
+ /**
6
+ * Encrypt data for transmission
7
+ */
8
+ abstract encrypt(data: Uint8Array): Promise<Uint8Array>;
9
+
10
+ /**
11
+ * Decrypt received data
12
+ */
13
+ abstract decrypt(data: Uint8Array): Promise<Uint8Array>;
14
+
15
+ /**
16
+ * Get session setup request data
17
+ */
18
+ abstract getSessionSetupRequest(): Promise<Uint8Array>;
19
+
20
+ /**
21
+ * Process session setup response
22
+ */
23
+ abstract processSessionSetupResponse(response: Uint8Array): Promise<void>;
24
+
25
+ /**
26
+ * Check if security is established
27
+ */
28
+ abstract isEstablished(): boolean;
29
+ }
@@ -0,0 +1,40 @@
1
+ import { Security } from './Security';
2
+ import * as proto from '../generated/proto.js';
3
+
4
+ /**
5
+ * Security0 - No encryption (unsecure mode)
6
+ */
7
+ export class Security0 extends Security {
8
+ private established: boolean = false;
9
+
10
+ async encrypt(data: Uint8Array): Promise<Uint8Array> {
11
+ return data;
12
+ }
13
+
14
+ async decrypt(data: Uint8Array): Promise<Uint8Array> {
15
+ return data;
16
+ }
17
+
18
+ async getSessionSetupRequest(): Promise<Uint8Array> {
19
+ let setupReq = proto.SessionData.create({});
20
+ setupReq.secVer = proto.SecSchemeVersion.SecScheme0;
21
+ setupReq.sec0 = proto.Sec0Payload.create({
22
+ msg: proto.Sec0MsgType.S0_Session_Command,
23
+ sc: proto.S0SessionCmd.create({})
24
+ });
25
+ return proto.Sec0Payload.encode(setupReq).finish();
26
+ }
27
+
28
+ async processSessionSetupResponse(response: Uint8Array): Promise<void> {
29
+ const setupResp = proto.SessionData.decode(response);
30
+ if (setupResp.secVer === proto.SecSchemeVersion.SecScheme0 && setupResp.sec0) {
31
+ this.established = true;
32
+ } else {
33
+ throw new Error('Invalid session setup response for Security0');
34
+ }
35
+ }
36
+
37
+ isEstablished(): boolean {
38
+ return this.established;
39
+ }
40
+ }