@alwaysai/device-agent 1.5.0 → 2.0.0

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 (273) hide show
  1. package/lib/application-control/config.d.ts.map +1 -1
  2. package/lib/application-control/config.js +8 -3
  3. package/lib/application-control/config.js.map +1 -1
  4. package/lib/application-control/environment-variables.d.ts +1 -5
  5. package/lib/application-control/environment-variables.d.ts.map +1 -1
  6. package/lib/application-control/environment-variables.js +9 -26
  7. package/lib/application-control/environment-variables.js.map +1 -1
  8. package/lib/application-control/environment-variables.test.js +27 -7
  9. package/lib/application-control/environment-variables.test.js.map +1 -1
  10. package/lib/application-control/index.d.ts +4 -4
  11. package/lib/application-control/index.d.ts.map +1 -1
  12. package/lib/application-control/index.js +1 -4
  13. package/lib/application-control/index.js.map +1 -1
  14. package/lib/application-control/install.d.ts.map +1 -1
  15. package/lib/application-control/install.js +8 -7
  16. package/lib/application-control/install.js.map +1 -1
  17. package/lib/application-control/models.d.ts +0 -11
  18. package/lib/application-control/models.d.ts.map +1 -1
  19. package/lib/application-control/models.js +5 -54
  20. package/lib/application-control/models.js.map +1 -1
  21. package/lib/application-control/utils.d.ts +0 -4
  22. package/lib/application-control/utils.d.ts.map +1 -1
  23. package/lib/application-control/utils.js +1 -24
  24. package/lib/application-control/utils.js.map +1 -1
  25. package/lib/cloud-connection/bootstrap-provision.js +3 -2
  26. package/lib/cloud-connection/bootstrap-provision.js.map +1 -1
  27. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +10 -15
  28. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  29. package/lib/cloud-connection/device-agent-cloud-connection.js +279 -250
  30. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  31. package/lib/cloud-connection/device-agent.d.ts.map +1 -1
  32. package/lib/cloud-connection/device-agent.js +11 -9
  33. package/lib/cloud-connection/device-agent.js.map +1 -1
  34. package/lib/cloud-connection/live-updates-handler.d.ts +18 -28
  35. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  36. package/lib/cloud-connection/live-updates-handler.js +54 -169
  37. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  38. package/lib/cloud-connection/live-updates-handler.test.js +71 -165
  39. package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
  40. package/lib/cloud-connection/passthrough-handler.d.ts +4 -1
  41. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
  42. package/lib/cloud-connection/passthrough-handler.js +30 -11
  43. package/lib/cloud-connection/passthrough-handler.js.map +1 -1
  44. package/lib/cloud-connection/shadow-handler.d.ts +5 -3
  45. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  46. package/lib/cloud-connection/shadow-handler.js +59 -27
  47. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  48. package/lib/cloud-connection/shadow-handler.test.js +45 -57
  49. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  50. package/lib/cloud-connection/shadow.d.ts.map +1 -1
  51. package/lib/cloud-connection/shadow.js +2 -1
  52. package/lib/cloud-connection/shadow.js.map +1 -1
  53. package/lib/cloud-connection/transaction-manager.d.ts +4 -2
  54. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  55. package/lib/cloud-connection/transaction-manager.js +18 -29
  56. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  57. package/lib/cloud-connection/transaction-manager.test.js +3 -3
  58. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  59. package/lib/device-control/device-control.d.ts +8 -8
  60. package/lib/device-control/device-control.d.ts.map +1 -1
  61. package/lib/device-control/device-control.js +95 -71
  62. package/lib/device-control/device-control.js.map +1 -1
  63. package/lib/docker/docker-compose.d.ts.map +1 -1
  64. package/lib/docker/docker-compose.js +2 -1
  65. package/lib/docker/docker-compose.js.map +1 -1
  66. package/lib/infrastructure/agent-config.d.ts +2 -1
  67. package/lib/infrastructure/agent-config.d.ts.map +1 -1
  68. package/lib/infrastructure/agent-config.js +7 -7
  69. package/lib/infrastructure/agent-config.js.map +1 -1
  70. package/lib/infrastructure/agent-config.test.js +3 -1
  71. package/lib/infrastructure/agent-config.test.js.map +1 -1
  72. package/lib/infrastructure/config-check-utility.d.ts +6 -0
  73. package/lib/infrastructure/config-check-utility.d.ts.map +1 -0
  74. package/lib/infrastructure/config-check-utility.js +67 -0
  75. package/lib/infrastructure/config-check-utility.js.map +1 -0
  76. package/lib/infrastructure/config-check-utility.test.d.ts +2 -0
  77. package/lib/infrastructure/config-check-utility.test.d.ts.map +1 -0
  78. package/lib/infrastructure/config-check-utility.test.js +109 -0
  79. package/lib/infrastructure/config-check-utility.test.js.map +1 -0
  80. package/lib/infrastructure/device-certificate.d.ts +10 -0
  81. package/lib/infrastructure/device-certificate.d.ts.map +1 -0
  82. package/lib/infrastructure/device-certificate.js +47 -0
  83. package/lib/infrastructure/device-certificate.js.map +1 -0
  84. package/lib/infrastructure/device-certificate.test.d.ts +2 -0
  85. package/lib/infrastructure/device-certificate.test.d.ts.map +1 -0
  86. package/lib/infrastructure/device-certificate.test.js +24 -0
  87. package/lib/infrastructure/device-certificate.test.js.map +1 -0
  88. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts +2 -0
  89. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts.map +1 -0
  90. package/lib/infrastructure/legacy-migration/legacy-file.test.js +61 -0
  91. package/lib/infrastructure/legacy-migration/legacy-file.test.js.map +1 -0
  92. package/lib/infrastructure/legacy-migration/legacy-files.d.ts +75 -0
  93. package/lib/infrastructure/legacy-migration/legacy-files.d.ts.map +1 -0
  94. package/lib/infrastructure/legacy-migration/legacy-files.js +75 -0
  95. package/lib/infrastructure/legacy-migration/legacy-files.js.map +1 -0
  96. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts +6 -0
  97. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -0
  98. package/lib/infrastructure/legacy-migration/legacy-migration.js +149 -0
  99. package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -0
  100. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts +2 -0
  101. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts.map +1 -0
  102. package/lib/infrastructure/legacy-migration/legacy-migration.test.js +226 -0
  103. package/lib/infrastructure/legacy-migration/legacy-migration.test.js.map +1 -0
  104. package/lib/infrastructure/require-files-present-ready.test.d.ts +2 -0
  105. package/lib/infrastructure/require-files-present-ready.test.d.ts.map +1 -0
  106. package/lib/infrastructure/require-files-present-ready.test.js +44 -0
  107. package/lib/infrastructure/require-files-present-ready.test.js.map +1 -0
  108. package/lib/infrastructure/required-config-checks.d.ts +2 -0
  109. package/lib/infrastructure/required-config-checks.d.ts.map +1 -0
  110. package/lib/infrastructure/required-config-checks.js +30 -0
  111. package/lib/infrastructure/required-config-checks.js.map +1 -0
  112. package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -1
  113. package/lib/infrastructure/tokens-and-device-cfg.js +11 -8
  114. package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -1
  115. package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -1
  116. package/lib/local-connection/rabbitmq-connection.js +14 -14
  117. package/lib/local-connection/rabbitmq-connection.js.map +1 -1
  118. package/lib/secure-tunneling/secure-tunneling.d.ts +9 -9
  119. package/lib/secure-tunneling/secure-tunneling.d.ts.map +1 -1
  120. package/lib/secure-tunneling/secure-tunneling.js +21 -16
  121. package/lib/secure-tunneling/secure-tunneling.js.map +1 -1
  122. package/lib/secure-tunneling/secure-tunneling.test.js +11 -13
  123. package/lib/secure-tunneling/secure-tunneling.test.js.map +1 -1
  124. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  125. package/lib/subcommands/app/analytics.js +1 -2
  126. package/lib/subcommands/app/analytics.js.map +1 -1
  127. package/lib/subcommands/app/env-vars.d.ts +4 -0
  128. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  129. package/lib/subcommands/app/env-vars.js +52 -6
  130. package/lib/subcommands/app/env-vars.js.map +1 -1
  131. package/lib/subcommands/app/index.d.ts.map +1 -1
  132. package/lib/subcommands/app/index.js +1 -3
  133. package/lib/subcommands/app/index.js.map +1 -1
  134. package/lib/subcommands/app/models.d.ts +0 -11
  135. package/lib/subcommands/app/models.d.ts.map +1 -1
  136. package/lib/subcommands/app/models.js +2 -58
  137. package/lib/subcommands/app/models.js.map +1 -1
  138. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  139. package/lib/subcommands/app/shadow.js +6 -5
  140. package/lib/subcommands/app/shadow.js.map +1 -1
  141. package/lib/subcommands/app/version.d.ts.map +1 -1
  142. package/lib/subcommands/app/version.js +2 -4
  143. package/lib/subcommands/app/version.js.map +1 -1
  144. package/lib/subcommands/config.d.ts +2 -0
  145. package/lib/subcommands/config.d.ts.map +1 -0
  146. package/lib/subcommands/config.js +39 -0
  147. package/lib/subcommands/config.js.map +1 -0
  148. package/lib/subcommands/device/clean.d.ts +1 -1
  149. package/lib/subcommands/device/clean.d.ts.map +1 -1
  150. package/lib/subcommands/device/clean.js +23 -13
  151. package/lib/subcommands/device/clean.js.map +1 -1
  152. package/lib/subcommands/device/index.d.ts.map +1 -1
  153. package/lib/subcommands/device/index.js +3 -1
  154. package/lib/subcommands/device/index.js.map +1 -1
  155. package/lib/subcommands/device/init.js +8 -8
  156. package/lib/subcommands/device/init.js.map +1 -1
  157. package/lib/subcommands/device/migrate.d.ts +2 -0
  158. package/lib/subcommands/device/migrate.d.ts.map +1 -0
  159. package/lib/subcommands/device/migrate.js +24 -0
  160. package/lib/subcommands/device/migrate.js.map +1 -0
  161. package/lib/subcommands/device/refresh.d.ts.map +1 -1
  162. package/lib/subcommands/device/refresh.js +1 -0
  163. package/lib/subcommands/device/refresh.js.map +1 -1
  164. package/lib/subcommands/index.d.ts +1 -1
  165. package/lib/subcommands/index.d.ts.map +1 -1
  166. package/lib/subcommands/index.js +3 -1
  167. package/lib/subcommands/index.js.map +1 -1
  168. package/lib/subcommands/rabbitmq-connection.d.ts +1 -1
  169. package/lib/subcommands/rabbitmq-connection.d.ts.map +1 -1
  170. package/lib/util/aai-error.d.ts +12 -0
  171. package/lib/util/aai-error.d.ts.map +1 -0
  172. package/lib/util/aai-error.js +11 -0
  173. package/lib/util/aai-error.js.map +1 -0
  174. package/lib/util/aws-regions.d.ts +2 -0
  175. package/lib/util/aws-regions.d.ts.map +1 -0
  176. package/lib/util/{cloud-mode-ready.js → aws-regions.js} +2 -20
  177. package/lib/util/aws-regions.js.map +1 -0
  178. package/lib/util/check-for-updates.d.ts.map +1 -1
  179. package/lib/util/check-for-updates.js +5 -28
  180. package/lib/util/check-for-updates.js.map +1 -1
  181. package/lib/util/clean-certs.d.ts.map +1 -1
  182. package/lib/util/clean-certs.js +5 -4
  183. package/lib/util/clean-certs.js.map +1 -1
  184. package/lib/util/directories.d.ts +4 -18
  185. package/lib/util/directories.d.ts.map +1 -1
  186. package/lib/util/directories.js +18 -32
  187. package/lib/util/directories.js.map +1 -1
  188. package/lib/util/file.d.ts +4 -0
  189. package/lib/util/file.d.ts.map +1 -1
  190. package/lib/util/file.js +65 -4
  191. package/lib/util/file.js.map +1 -1
  192. package/lib/util/get-device-id.d.ts.map +1 -1
  193. package/lib/util/get-device-id.js +7 -1
  194. package/lib/util/get-device-id.js.map +1 -1
  195. package/lib/util/http-client.js +3 -3
  196. package/lib/util/http-client.js.map +1 -1
  197. package/package.json +19 -17
  198. package/readme.md +12 -32
  199. package/src/application-control/config.ts +9 -12
  200. package/src/application-control/environment-variables.test.ts +28 -7
  201. package/src/application-control/environment-variables.ts +13 -40
  202. package/src/application-control/index.ts +3 -16
  203. package/src/application-control/install.ts +15 -10
  204. package/src/application-control/models.ts +6 -87
  205. package/src/application-control/utils.ts +0 -28
  206. package/src/cloud-connection/bootstrap-provision.ts +7 -7
  207. package/src/cloud-connection/device-agent-cloud-connection.ts +639 -525
  208. package/src/cloud-connection/device-agent.ts +16 -7
  209. package/src/cloud-connection/live-updates-handler.test.ts +121 -189
  210. package/src/cloud-connection/live-updates-handler.ts +99 -234
  211. package/src/cloud-connection/passthrough-handler.ts +55 -18
  212. package/src/cloud-connection/shadow-handler.test.ts +45 -57
  213. package/src/cloud-connection/shadow-handler.ts +103 -57
  214. package/src/cloud-connection/shadow.ts +4 -1
  215. package/src/cloud-connection/transaction-manager.test.ts +3 -3
  216. package/src/cloud-connection/transaction-manager.ts +53 -39
  217. package/src/device-control/device-control.ts +102 -70
  218. package/src/docker/docker-compose.ts +3 -2
  219. package/src/infrastructure/agent-config.test.ts +6 -2
  220. package/src/infrastructure/agent-config.ts +8 -7
  221. package/src/infrastructure/config-check-utility.test.ts +154 -0
  222. package/src/infrastructure/config-check-utility.ts +77 -0
  223. package/src/infrastructure/device-certificate.test.ts +40 -0
  224. package/src/infrastructure/device-certificate.ts +58 -0
  225. package/src/infrastructure/legacy-migration/legacy-file.test.ts +88 -0
  226. package/src/infrastructure/legacy-migration/legacy-files.ts +101 -0
  227. package/src/infrastructure/legacy-migration/legacy-migration.test.ts +396 -0
  228. package/src/infrastructure/legacy-migration/legacy-migration.ts +229 -0
  229. package/src/infrastructure/require-files-present-ready.test.ts +53 -0
  230. package/src/infrastructure/required-config-checks.ts +33 -0
  231. package/src/infrastructure/tokens-and-device-cfg.ts +12 -10
  232. package/src/local-connection/rabbitmq-connection.ts +22 -17
  233. package/src/secure-tunneling/secure-tunneling.test.ts +20 -22
  234. package/src/secure-tunneling/secure-tunneling.ts +41 -29
  235. package/src/subcommands/app/analytics.ts +2 -4
  236. package/src/subcommands/app/env-vars.ts +72 -9
  237. package/src/subcommands/app/index.ts +3 -11
  238. package/src/subcommands/app/models.ts +5 -81
  239. package/src/subcommands/app/shadow.ts +6 -5
  240. package/src/subcommands/app/version.ts +3 -4
  241. package/src/subcommands/config.ts +42 -0
  242. package/src/subcommands/device/clean.ts +31 -17
  243. package/src/subcommands/device/index.ts +3 -1
  244. package/src/subcommands/device/init.ts +11 -11
  245. package/src/subcommands/device/migrate.ts +20 -0
  246. package/src/subcommands/device/refresh.ts +1 -0
  247. package/src/subcommands/index.ts +3 -1
  248. package/src/util/aai-error.ts +20 -0
  249. package/src/util/{cloud-mode-ready.ts → aws-regions.ts} +0 -24
  250. package/src/util/check-for-updates.ts +14 -30
  251. package/src/util/clean-certs.ts +8 -4
  252. package/src/util/directories.ts +23 -67
  253. package/src/util/file.ts +83 -3
  254. package/src/util/get-device-id.ts +7 -7
  255. package/src/util/http-client.ts +2 -2
  256. package/lib/util/cloud-mode-ready.d.ts +0 -3
  257. package/lib/util/cloud-mode-ready.d.ts.map +0 -1
  258. package/lib/util/cloud-mode-ready.js.map +0 -1
  259. package/lib/util/download-file.d.ts +0 -6
  260. package/lib/util/download-file.d.ts.map +0 -1
  261. package/lib/util/download-file.js +0 -25
  262. package/lib/util/download-file.js.map +0 -1
  263. package/lib/util/fetch-with-timeout.d.ts +0 -4
  264. package/lib/util/fetch-with-timeout.d.ts.map +0 -1
  265. package/lib/util/fetch-with-timeout.js +0 -30
  266. package/lib/util/fetch-with-timeout.js.map +0 -1
  267. package/lib/util/parsing.d.ts +0 -2
  268. package/lib/util/parsing.d.ts.map +0 -1
  269. package/lib/util/parsing.js +0 -17
  270. package/lib/util/parsing.js.map +0 -1
  271. package/src/util/download-file.ts +0 -25
  272. package/src/util/fetch-with-timeout.ts +0 -35
  273. package/src/util/parsing.ts +0 -11
@@ -0,0 +1,396 @@
1
+ import { device } from 'alwaysai/lib/components';
2
+ import { SystemId } from 'alwaysai/lib/constants';
3
+ import { DeviceConfigFile } from 'alwaysai/lib/core/device';
4
+ import {
5
+ DEVICE_CONFIG_FILE_NAME,
6
+ LocalDeviceCertificates,
7
+ LocalLegacyDeviceCertificates,
8
+ getDeviceConfigPath
9
+ } from 'alwaysai/lib/infrastructure';
10
+ import {
11
+ ALWAYSAI_CONFIG_FILE_NAME,
12
+ DEVICE_TOKEN_FILE_NAME
13
+ } from 'alwaysai/lib/paths';
14
+ import { JsSpawner, exists } from 'alwaysai/lib/util';
15
+ import exp from 'constants';
16
+ import { existsSync } from 'fs';
17
+ import { join } from 'path';
18
+ import { rimraf } from 'rimraf';
19
+ import * as tempy from 'tempy';
20
+ import { AGENT_CONFIG_FILE_NAME, AgentConfigFile } from '../agent-config';
21
+ import { checkAllFilesArePresent } from '../config-check-utility';
22
+ import {
23
+ getBootstrapCertificateDirectoryPath,
24
+ getBootstrapCertificateFileName,
25
+ getBootstrapIDFileName,
26
+ getBootstrapPrivateKeyFileName,
27
+ getBootstrapPrivateKeyFilePath
28
+ } from '../device-certificate';
29
+ import { requiredConfigFilesPresentAndValid } from '../required-config-checks';
30
+ import { LegacyFiles } from './legacy-files';
31
+ import {
32
+ migrateAgentConfigFile,
33
+ migrateDeviceTokens,
34
+ migrateFromLegacyCertsAndTokens
35
+ } from './legacy-migration';
36
+
37
+ describe('test migrateFromLegacyCertsAndTokens function', () => {
38
+ let tmpDir;
39
+ tmpDir = tempy.directory();
40
+
41
+ beforeAll(async () => {
42
+ jest.resetModules();
43
+ jest.clearAllMocks();
44
+ tmpDir = tempy.directory();
45
+ });
46
+ afterAll(async () => {
47
+ await rimraf(tmpDir);
48
+ });
49
+
50
+ async function setupCurrentFiles(spawner, aaiConfig, deviceConfig) {
51
+ await spawner.mkdirp(join(tmpDir, getDeviceConfigPath()));
52
+ await spawner.writeFile(
53
+ join(tmpDir, getDeviceConfigPath(), DEVICE_CONFIG_FILE_NAME),
54
+ JSON.stringify(deviceConfig)
55
+ );
56
+ spawner.writeFile(
57
+ join(tmpDir, ALWAYSAI_CONFIG_FILE_NAME),
58
+ JSON.stringify(aaiConfig)
59
+ );
60
+
61
+ const testCerts = new LocalDeviceCertificates(tmpDir);
62
+ const certFilePath = testCerts.getCertificateDirectoryName();
63
+ await spawner.mkdirp(join(tmpDir, getDeviceConfigPath(), certFilePath));
64
+ await spawner.writeFile(
65
+ join(
66
+ tmpDir,
67
+ getDeviceConfigPath(),
68
+ certFilePath,
69
+ testCerts.getCertificateFileName()
70
+ ),
71
+ 'certificate data'
72
+ );
73
+ await spawner.writeFile(
74
+ join(
75
+ tmpDir,
76
+ getDeviceConfigPath(),
77
+ certFilePath,
78
+ testCerts.getPrivateKeyFileName()
79
+ ),
80
+ 'private key data'
81
+ );
82
+ await spawner.writeFile(
83
+ join(
84
+ tmpDir,
85
+ getDeviceConfigPath(),
86
+ certFilePath,
87
+ testCerts.getRootCertificateFileName()
88
+ ),
89
+ 'root cert data'
90
+ );
91
+ }
92
+
93
+ async function setupLegacyFiles(
94
+ spawner,
95
+ aaiConfig,
96
+ deviceConfig,
97
+ agentConfig
98
+ ) {
99
+ const testCerts = new LocalLegacyDeviceCertificates(tmpDir);
100
+ const certFilePath = testCerts.getCertificateDirectoryPath();
101
+ await spawner.mkdirp(certFilePath);
102
+ await spawner.writeFile(
103
+ join(tmpDir, DEVICE_TOKEN_FILE_NAME),
104
+ JSON.stringify(deviceConfig)
105
+ );
106
+ spawner.writeFile(
107
+ join(tmpDir, ALWAYSAI_CONFIG_FILE_NAME),
108
+ JSON.stringify(aaiConfig)
109
+ );
110
+ spawner.writeFile(
111
+ join(tmpDir, AGENT_CONFIG_FILE_NAME),
112
+ JSON.stringify(agentConfig)
113
+ );
114
+ await spawner.mkdirp(certFilePath);
115
+ await spawner.mkdirp(join(certFilePath, 'bootstrap-certificates'));
116
+ await spawner.writeFile(
117
+ join(testCerts.getCertificateFilePath()),
118
+ 'certificate data'
119
+ );
120
+ await spawner.writeFile(
121
+ join(testCerts.getPrivateKeyFilePath()),
122
+ 'private key data'
123
+ );
124
+ await spawner.writeFile(
125
+ join(testCerts.getRootCertificateFilePath()),
126
+ 'root cert data'
127
+ );
128
+ await spawner.writeFile(
129
+ join(testCerts.getCertificateIdFilePath()),
130
+ 'certificate ID data'
131
+ );
132
+ await spawner.writeFile(
133
+ join(
134
+ certFilePath,
135
+ 'bootstrap-certificates',
136
+ getBootstrapCertificateFileName()
137
+ ),
138
+ 'certificate data'
139
+ );
140
+ await spawner.writeFile(
141
+ join(
142
+ certFilePath,
143
+ 'bootstrap-certificates',
144
+ getBootstrapPrivateKeyFileName()
145
+ ),
146
+ 'private key data'
147
+ );
148
+ await spawner.writeFile(
149
+ join(certFilePath, 'bootstrap-certificates', getBootstrapIDFileName()),
150
+ 'root cert data'
151
+ );
152
+ }
153
+
154
+ test('test current files present migration does not happen', async () => {
155
+ const spawner = JsSpawner({ path: tmpDir });
156
+ const legacyCredentialsConfig = {
157
+ deviceId: '123-4567-8910-1234',
158
+ refreshToken: 'refresh',
159
+ accessToken: 'access',
160
+ idToken: 'id'
161
+ };
162
+ const aaiConfig = {
163
+ systemId: SystemId.production,
164
+ deviceUuid: '123-4567-8910-1234'
165
+ };
166
+ // set up migrated/current configuration files
167
+ await setupCurrentFiles(spawner, legacyCredentialsConfig, aaiConfig);
168
+
169
+ const migrated = await migrateFromLegacyCertsAndTokens(tmpDir);
170
+
171
+ // check migration not called
172
+ expect(migrated).toBe(false);
173
+ });
174
+
175
+ test('test no legacy files migration does not happen', async () => {
176
+ const testCerts = new LocalDeviceCertificates(tmpDir);
177
+ const certFilePath = testCerts.getCertificateDirectoryName();
178
+
179
+ // check pre-conditions
180
+ expect(await exists(join(tmpDir, certFilePath))).toBe(false);
181
+ expect(await exists(join(tmpDir, DEVICE_CONFIG_FILE_NAME))).toBe(false);
182
+ expect(await exists(join(tmpDir, DEVICE_CONFIG_FILE_NAME))).toBe(false);
183
+
184
+ const migrated = await migrateFromLegacyCertsAndTokens(tmpDir);
185
+
186
+ // check migration not called
187
+ expect(migrated).toBe(false);
188
+ });
189
+
190
+ it('test legacy files present but invalid and no current files present migration does not happen', async () => {
191
+ const spawner = JsSpawner({ path: tmpDir });
192
+ const legacyCredentialsConfig = {
193
+ deviceId: '123-abcd-8910-1234',
194
+ refreshToken: 'refresh',
195
+ accessToken: 'access',
196
+ idToken: 'id'
197
+ };
198
+ const aaiConfig = {
199
+ systemId: SystemId.production,
200
+ deviceUuid: '123-4567-8910-1234'
201
+ };
202
+ const agentConfig = {
203
+ applications: []
204
+ };
205
+ // set up legacy files
206
+ await setupLegacyFiles(
207
+ spawner,
208
+ aaiConfig,
209
+ legacyCredentialsConfig,
210
+ agentConfig
211
+ );
212
+
213
+ // confirm legacy files present and valid
214
+ const legacyFiles = LegacyFiles(tmpDir);
215
+ const legacyFilePaths = legacyFiles.getLegacyFileMigrationPaths();
216
+ const legacyFilesPresent = await checkAllFilesArePresent(
217
+ Object.values(legacyFilePaths)
218
+ );
219
+ expect(legacyFilesPresent).toBe(true);
220
+
221
+ // confirm that an error is thrown when the deviceUuid !== deviceId
222
+ await expect(
223
+ migrateFromLegacyCertsAndTokens(tmpDir)
224
+ ).rejects.toThrowError();
225
+ });
226
+
227
+ it('test legacy files present and no current files present migration does happen', async () => {
228
+ const spawner = JsSpawner({ path: tmpDir });
229
+ const legacyCredentialsConfig = {
230
+ deviceId: '123-4567-8910-1234',
231
+ refreshToken: 'refresh',
232
+ accessToken: 'access',
233
+ idToken: 'id'
234
+ };
235
+ const aaiConfig = {
236
+ systemId: SystemId.production,
237
+ deviceUuid: '123-4567-8910-1234'
238
+ };
239
+ const agentConfig = {
240
+ applications: []
241
+ };
242
+ // set up legacy files
243
+ await setupLegacyFiles(
244
+ spawner,
245
+ aaiConfig,
246
+ legacyCredentialsConfig,
247
+ agentConfig
248
+ );
249
+
250
+ // check pre-conditions
251
+ // check that getBootstrapPrivateKeyFilePath() returns false so that
252
+ // bootstrapProvision won't be called on runDeviceAgentCloudInterface
253
+ const newBootstrapsDir = join(
254
+ getBootstrapCertificateDirectoryPath(tmpDir),
255
+ getBootstrapPrivateKeyFileName()
256
+ );
257
+ const newBootstrapsPresent = existsSync(newBootstrapsDir);
258
+ expect(newBootstrapsPresent).toBe(false);
259
+ // check no current files exist
260
+ const newFilesPresentPreMigrate = await requiredConfigFilesPresentAndValid(
261
+ tmpDir
262
+ );
263
+ expect(newFilesPresentPreMigrate).toBe(false);
264
+ // check that legacy files are present
265
+ const legacyFiles = LegacyFiles(tmpDir);
266
+ const legacyFilePaths = legacyFiles.getLegacyFileMigrationPaths();
267
+ const legacyFilesPresent = await checkAllFilesArePresent(
268
+ Object.values(legacyFilePaths)
269
+ );
270
+ expect(legacyFilesPresent).toBe(true);
271
+
272
+ const migrated = await migrateFromLegacyCertsAndTokens(tmpDir);
273
+
274
+ // check output -- current files are present and valid
275
+ expect(migrated).toBe(true);
276
+ const newFilesPresentPostMigrate = await requiredConfigFilesPresentAndValid(
277
+ tmpDir
278
+ );
279
+ expect(newFilesPresentPostMigrate).toBe(true);
280
+ // check that getBootstrapPrivateKeyFilePath() returns false so that
281
+ // bootstrapProvision won't be called on runDeviceAgentCloudInterface
282
+ const newBootstrapsDirAfterMigration = join(
283
+ getBootstrapCertificateDirectoryPath(tmpDir),
284
+ getBootstrapPrivateKeyFileName()
285
+ );
286
+ const newBootstrapsPresentAfterMigration = existsSync(
287
+ newBootstrapsDirAfterMigration
288
+ );
289
+ expect(newBootstrapsPresentAfterMigration).toBe(false);
290
+ });
291
+ });
292
+
293
+ describe('test migrateDeviceTokens function', () => {
294
+ let tmpDir;
295
+ tmpDir = tempy.directory();
296
+
297
+ beforeAll(async () => {
298
+ tmpDir = tempy.directory();
299
+ });
300
+ afterAll(async () => {
301
+ await rimraf(tmpDir);
302
+ });
303
+
304
+ it('test migrateDeviceTokens', async () => {
305
+ const deviceId = '123-4567-8910-1234';
306
+ const parsedConfig = {
307
+ systemId: SystemId.production,
308
+ deviceUuid: deviceId
309
+ };
310
+ const deviceConfig = {
311
+ deviceId: deviceId,
312
+ refreshToken: 'refresh',
313
+ accessToken: 'access',
314
+ idToken: 'id'
315
+ };
316
+
317
+ const spawner = JsSpawner({ path: tmpDir });
318
+ await spawner.mkdirp(join(tmpDir, getDeviceConfigPath()));
319
+ await spawner.writeFile(
320
+ join(tmpDir, DEVICE_TOKEN_FILE_NAME),
321
+ JSON.stringify(deviceConfig)
322
+ );
323
+ await migrateDeviceTokens(parsedConfig, tmpDir);
324
+ const newDeviceConfig = DeviceConfigFile(
325
+ join(tmpDir, getDeviceConfigPath(), DEVICE_CONFIG_FILE_NAME)
326
+ );
327
+ const parsedNewDeviceConfig = newDeviceConfig.read();
328
+ expect(parsedNewDeviceConfig.deviceUuid).toEqual(deviceId);
329
+ expect(parsedNewDeviceConfig.idToken).toEqual(deviceConfig.idToken);
330
+ expect(parsedNewDeviceConfig.accessToken).toEqual(deviceConfig.accessToken);
331
+ expect(parsedNewDeviceConfig.refreshToken).toEqual(
332
+ deviceConfig.refreshToken
333
+ );
334
+ });
335
+ });
336
+
337
+ describe('test migrateAgentConfigFile function', () => {
338
+ let tmpDir;
339
+ tmpDir = tempy.directory();
340
+
341
+ beforeAll(async () => {
342
+ tmpDir = tempy.directory();
343
+ });
344
+ afterAll(async () => {
345
+ await rimraf(tmpDir);
346
+ });
347
+
348
+ it('test migrateAgentConfigFile', async () => {
349
+ const newFilePath = join(
350
+ tmpDir,
351
+ getDeviceConfigPath(),
352
+ AGENT_CONFIG_FILE_NAME
353
+ );
354
+ const legacyFilePath = join(tmpDir, AGENT_CONFIG_FILE_NAME);
355
+ const spawner = JsSpawner({ path: tmpDir });
356
+ const legacyAgentConfigContents = {
357
+ applications: [
358
+ {
359
+ projectId: 'c8a1b5bd-e112-44e4-bfa4-fb9b42a4322c',
360
+ version:
361
+ 'b0139ac93d91e8bd4bcb69575a7312c646f9af086b83364a3fe0b4472af04353',
362
+ ready: true
363
+ }
364
+ ]
365
+ };
366
+ await spawner.writeFile(
367
+ legacyFilePath,
368
+ JSON.stringify(legacyAgentConfigContents)
369
+ );
370
+ const legacyFileExists = await exists(legacyFilePath);
371
+ expect(legacyFileExists).toEqual(true);
372
+ const legacyAgentConfig = AgentConfigFile(
373
+ join(tmpDir, AGENT_CONFIG_FILE_NAME)
374
+ );
375
+ const legacyAgentConfigReadContents = legacyAgentConfig.read();
376
+ expect(legacyAgentConfigReadContents.applications).toEqual(
377
+ legacyAgentConfigContents.applications
378
+ );
379
+
380
+ const newFileExists = await exists(newFilePath);
381
+ expect(newFileExists).toEqual(false);
382
+
383
+ await migrateAgentConfigFile(tmpDir);
384
+
385
+ // confirm new file is valid
386
+ const newAgentConfig = AgentConfigFile(
387
+ join(tmpDir, getDeviceConfigPath(), AGENT_CONFIG_FILE_NAME)
388
+ );
389
+ const newAgentConfigContents = newAgentConfig.read();
390
+ expect(newAgentConfigContents.applications).toEqual(
391
+ legacyAgentConfigContents.applications
392
+ );
393
+ expect(newAgentConfig.path).toEqual(newFilePath);
394
+ expect(legacyFileExists).toEqual(true);
395
+ });
396
+ });
@@ -0,0 +1,229 @@
1
+ import { DeviceConfig, DeviceConfigFile } from 'alwaysai/lib/core/device';
2
+ import {
3
+ CredentialsJsonFile,
4
+ DEVICE_CONFIG_FILE_NAME,
5
+ LocalDeviceCertificates,
6
+ getDeviceConfigPath,
7
+ getSystemId
8
+ } from 'alwaysai/lib/infrastructure';
9
+ import {
10
+ ALWAYSAI_CONFIG_FILE_NAME,
11
+ DEVICE_TOKEN_FILE_NAME,
12
+ LOCAL_AAI_CFG_DIR
13
+ } from 'alwaysai/lib/paths';
14
+ import { JsSpawner, exists, stringifyError } from 'alwaysai/lib/util';
15
+ import { join } from 'path';
16
+ import rimraf from 'rimraf';
17
+ import {
18
+ checkRabbitMQContainerRunning,
19
+ stopRabbitMQContainer
20
+ } from '../../local-connection/rabbitmq-connection';
21
+ import { copyDir } from '../../util/copy-dir';
22
+ import {
23
+ getDeviceAgentConfigPath,
24
+ getDeviceAgentDockerComposePath
25
+ } from '../../util/directories';
26
+ import { logger } from '../../util/logger';
27
+ import { AGENT_CONFIG_FILE_NAME, AgentConfigFile } from '../agent-config';
28
+ import { checkAllFilesArePresent } from '../config-check-utility';
29
+ import { getBootstrapCertificateDirectoryPath } from '../device-certificate';
30
+ import { requiredConfigFilesPresentAndValid } from '../required-config-checks';
31
+ import {
32
+ LEGACY_CREDENTIALS_FILE_DIR,
33
+ LegacyAaiConfig,
34
+ LegacyAaiConfigFile,
35
+ LegacyFiles
36
+ } from './legacy-files';
37
+
38
+ /*===================================================================
39
+ Migration Code
40
+ ===================================================================*/
41
+
42
+ export async function migrateAgentConfigFile(baseDir?: string) {
43
+ logger.debug('Migrating agent configuration file');
44
+ const legacyFiles = LegacyFiles(baseDir);
45
+ const legacyAgentConfigFile = legacyFiles.getLegacyAgentConfigFile();
46
+ const newAgentConfig = AgentConfigFile(
47
+ join(
48
+ baseDir ?? LOCAL_AAI_CFG_DIR,
49
+ getDeviceConfigPath(),
50
+ AGENT_CONFIG_FILE_NAME
51
+ )
52
+ );
53
+ let parsedAgentConfig;
54
+ try {
55
+ parsedAgentConfig = legacyAgentConfigFile.read();
56
+ } catch (e) {
57
+ logger.error(`Error reading agent config for:\n${stringifyError(e)}`);
58
+ logger.error(
59
+ `Agent Config Errors: ${JSON.stringify(
60
+ legacyAgentConfigFile.getErrors(),
61
+ null,
62
+ 2
63
+ )}`
64
+ );
65
+ throw new Error(
66
+ `Could not parse ${legacyAgentConfigFile.path} while migrating your legacy device files.`
67
+ );
68
+ }
69
+ try {
70
+ newAgentConfig.write(parsedAgentConfig);
71
+
72
+ // since this file is owned by the Device Agent
73
+ // we can remove it after migrating it
74
+ await rimraf(legacyAgentConfigFile.path);
75
+ } catch (e) {
76
+ logger.error(`Error writing agent config for:\n${stringifyError(e)}`);
77
+ logger.error(
78
+ `Agent Config Errors: ${JSON.stringify(
79
+ newAgentConfig.getErrors(),
80
+ null,
81
+ 2
82
+ )}`
83
+ );
84
+ throw new Error(
85
+ `Could not parse ${newAgentConfig.path} while migrating your legacy device files.`
86
+ );
87
+ }
88
+ }
89
+
90
+ export async function migrateCertificates(baseDir?: string) {
91
+ logger.debug(`baseDir ${baseDir}`);
92
+ const legacyFiles = LegacyFiles(baseDir);
93
+ const legacyCerts = legacyFiles.getLegacyCertificates();
94
+
95
+ const newDeviceCertificates = new LocalDeviceCertificates(
96
+ baseDir ? join(baseDir, getDeviceConfigPath()) : undefined
97
+ );
98
+ const spawner = JsSpawner(baseDir ? { path: baseDir } : {});
99
+ await spawner.mkdirp(
100
+ join(newDeviceCertificates.getCertificateDirectoryPath())
101
+ );
102
+ await copyDir({
103
+ srcPath: legacyCerts.getCertificateDirectoryPath(),
104
+ destPath: newDeviceCertificates.getCertificateDirectoryPath()
105
+ });
106
+ await rimraf(getBootstrapCertificateDirectoryPath(baseDir));
107
+ }
108
+
109
+ export async function migrateDeviceTokens(
110
+ parsedAaiCfg: LegacyAaiConfig,
111
+ baseDir?: string
112
+ ) {
113
+ const systemId = getSystemId();
114
+ const deviceConfigDir = baseDir
115
+ ? join(baseDir, getDeviceConfigPath(), DEVICE_CONFIG_FILE_NAME)
116
+ : baseDir;
117
+ const deviceConfig = DeviceConfigFile(deviceConfigDir);
118
+
119
+ const deviceUuid = parsedAaiCfg?.deviceUuid;
120
+ if (!deviceUuid) {
121
+ throw new Error(`deviceUuid not found in ${ALWAYSAI_CONFIG_FILE_NAME}.`);
122
+ }
123
+
124
+ let legacyCredentialsFile;
125
+ if (baseDir) {
126
+ legacyCredentialsFile = CredentialsJsonFile(
127
+ join(baseDir, DEVICE_TOKEN_FILE_NAME)
128
+ );
129
+ } else {
130
+ legacyCredentialsFile = CredentialsJsonFile(LEGACY_CREDENTIALS_FILE_DIR);
131
+ }
132
+ const legacyDeviceId = legacyCredentialsFile.getItem('deviceId');
133
+ const legacyTokens = {
134
+ accessToken: legacyCredentialsFile.getItem('accessToken'),
135
+ refreshToken: legacyCredentialsFile.getItem('refreshToken'),
136
+ idToken: legacyCredentialsFile.getItem('idToken')
137
+ };
138
+ const migratedTokens: DeviceConfig = {
139
+ ...legacyTokens,
140
+ systemId,
141
+ deviceUuid
142
+ };
143
+
144
+ if (legacyDeviceId !== migratedTokens.deviceUuid) {
145
+ throw new Error(
146
+ `deviceUuid from ${LEGACY_CREDENTIALS_FILE_DIR} (${legacyDeviceId}) and ${ALWAYSAI_CONFIG_FILE_NAME} (${migratedTokens.deviceUuid}) do not match.`
147
+ );
148
+ }
149
+
150
+ logger.debug('Copying tokens to new device config file.');
151
+ deviceConfig.write(migratedTokens);
152
+ }
153
+
154
+ export async function migrateFromLegacyCertsAndTokens(
155
+ baseDir?: string
156
+ ): Promise<boolean> {
157
+ const requiredConfiguration = await requiredConfigFilesPresentAndValid(
158
+ baseDir
159
+ );
160
+ if (requiredConfiguration) {
161
+ logger.debug(
162
+ 'Device appears to be properly configured, no migration needed.'
163
+ );
164
+ return false;
165
+ }
166
+
167
+ const legacyFiles = LegacyFiles(baseDir);
168
+ const legacyFilePaths = legacyFiles.getLegacyFileMigrationPaths();
169
+ const legacyFilesPresent = await checkAllFilesArePresent(
170
+ Object.values(legacyFilePaths)
171
+ );
172
+ if (legacyFilesPresent) {
173
+ logger.debug(
174
+ 'Legacy certs and config files found. Migrating device certs and config files to updated folders.'
175
+ );
176
+
177
+ // get device ID from original in order to pass to new AaiCfgFile
178
+ const aaiConfig = LegacyAaiConfigFile(baseDir);
179
+ let parsedAaiCfg;
180
+ try {
181
+ parsedAaiCfg = aaiConfig.read();
182
+ } catch (e) {
183
+ logger.error(`Error reading AAI config for:\n${stringifyError(e)}`);
184
+ logger.error(`${JSON.stringify(aaiConfig.getErrors(), null, 2)}`);
185
+ throw new Error(
186
+ `Could not parse ${aaiConfig.path} while migrating your legacy device files.`
187
+ );
188
+ }
189
+
190
+ // migrate deviceID to new alwaysai.device.json
191
+ await migrateDeviceTokens(parsedAaiCfg, baseDir);
192
+
193
+ // migrate certificates
194
+ logger.debug('Copying legacy certificates to new file path.');
195
+ await migrateCertificates(baseDir);
196
+
197
+ // migrate alwaysai.agent.json to device folder
198
+ logger.debug('Copying agent config file to new file path.');
199
+ await migrateAgentConfigFile(baseDir);
200
+
201
+ // if rabbitmq container is present, stop container and migrate files
202
+ try {
203
+ if (await checkRabbitMQContainerRunning()) {
204
+ await stopRabbitMQContainer();
205
+ }
206
+ } catch (e) {
207
+ logger.error(
208
+ `You may need to manually stop the container by running docker-compose down in the following directory: ${getDeviceAgentDockerComposePath()}`
209
+ );
210
+ logger.debug(
211
+ `Error in checking / stopping RabbitMQ container!\n${stringifyError(e)}`
212
+ );
213
+ }
214
+ if (await exists(getDeviceAgentConfigPath(baseDir))) {
215
+ await copyDir({
216
+ srcPath: legacyFiles.getLegacyDeviceAgentConfigDirPath(),
217
+ destPath: getDeviceAgentConfigPath(baseDir)
218
+ });
219
+ }
220
+
221
+ // For now, do not remove the legacy files to support legacy edgeIQ
222
+
223
+ logger.debug(`Device certs and tokens migrated successfully from legacy.`);
224
+ return true;
225
+ }
226
+
227
+ logger.debug('No legacy cert or config files found. Skipping migration.');
228
+ return false;
229
+ }
@@ -0,0 +1,53 @@
1
+ import {
2
+ checkAaiConfigPresent,
3
+ checkCertificatesPresent,
4
+ checkDeviceConfigPresent
5
+ } from './config-check-utility';
6
+ import { requiredConfigFilesPresentAndValid } from './required-config-checks';
7
+
8
+ const mockedDeviceCfgCheckFunction = jest.fn();
9
+ const mockedCertCheckFunction = jest.fn();
10
+ const mockedAaiCfgCheckFunction = jest.fn();
11
+
12
+ jest.mock('./config-check-utility');
13
+
14
+ jest
15
+ .mocked(checkAaiConfigPresent)
16
+ .mockImplementation(mockedAaiCfgCheckFunction);
17
+ jest
18
+ .mocked(checkDeviceConfigPresent)
19
+ .mockImplementation(mockedDeviceCfgCheckFunction);
20
+ jest
21
+ .mocked(checkCertificatesPresent)
22
+ .mockImplementation(mockedCertCheckFunction);
23
+
24
+ describe('test requiredConfigFilesPresentAndValid', () => {
25
+ function setupMocks(mockDeviceCfgCheck, mockCertCheck, mockAaiCfgCheck) {
26
+ mockedDeviceCfgCheckFunction.mockResolvedValue(mockDeviceCfgCheck);
27
+ mockedCertCheckFunction.mockResolvedValue(mockCertCheck);
28
+ mockedAaiCfgCheckFunction.mockResolvedValue(mockAaiCfgCheck);
29
+ }
30
+
31
+ it('test return value when checkDeviceConfigPresent is false', async () => {
32
+ setupMocks(false, true, true);
33
+ const newConfigsPresent = await requiredConfigFilesPresentAndValid();
34
+ expect(newConfigsPresent).toBe(false);
35
+ });
36
+
37
+ it('test return value when checkCertificatesPresent is false', async () => {
38
+ setupMocks(true, false, false);
39
+ const newConfigsPresent = await requiredConfigFilesPresentAndValid();
40
+ expect(newConfigsPresent).toBe(false);
41
+ });
42
+
43
+ it('test return value when checkAaiConfigPresent is false', async () => {
44
+ setupMocks(true, true, false);
45
+ const newConfigsPresent = await requiredConfigFilesPresentAndValid();
46
+ expect(newConfigsPresent).toBe(false);
47
+ });
48
+
49
+ it('test return value when all included functions return true', async () => {
50
+ setupMocks(true, true, true);
51
+ expect(await requiredConfigFilesPresentAndValid()).toBe(true);
52
+ });
53
+ });
@@ -0,0 +1,33 @@
1
+ import { logger } from '../util/logger';
2
+ import {
3
+ checkAaiConfigPresent,
4
+ checkCertificatesPresent,
5
+ checkDeviceConfigPresent
6
+ } from './config-check-utility';
7
+
8
+ export async function requiredConfigFilesPresentAndValid(baseDir?) {
9
+ // we need device/certificates, alwaysai.config.json, and device/alwaysai.device.json
10
+ logger.debug('Checking for required configuration files.');
11
+ const newDeviceConfigPresent = await checkDeviceConfigPresent(baseDir);
12
+ if (!newDeviceConfigPresent) {
13
+ logger.debug('Required device configuration is not present and valid.');
14
+ return false;
15
+ }
16
+
17
+ // check new certificates are present
18
+ const certificatesPresent = await checkCertificatesPresent(baseDir);
19
+ if (!certificatesPresent) {
20
+ logger.debug('Required certificates paths not found.');
21
+ return false;
22
+ }
23
+
24
+ // TODO: add alwaysai.config.json check here
25
+ const aaiConfigPresent = await checkAaiConfigPresent(baseDir);
26
+ if (!aaiConfigPresent) {
27
+ logger.debug('Required aai configuration file is not present and valid.');
28
+ return false;
29
+ }
30
+
31
+ logger.debug('All configuration files appear to be present.');
32
+ return true;
33
+ }