@sudoplatform/sudo-common 7.1.2 → 7.1.3

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 (310) hide show
  1. package/lib/configurationManager/defaultConfigurationManager.js +3 -5
  2. package/package.json +2 -3
  3. package/.babelrc +0 -10
  4. package/.eslintrc.js +0 -91
  5. package/.gitignore +0 -14
  6. package/.gitlab-ci.yml +0 -101
  7. package/.npmignore +0 -1
  8. package/.prettierignore +0 -3
  9. package/.prettierrc.js +0 -7
  10. package/.publisher.json +0 -7
  11. package/.vscode/settings.json +0 -5
  12. package/.yarn/releases/yarn-1.22.19.cjs +0 -147529
  13. package/.yarnrc +0 -5
  14. package/bin/outdated-with-suppression.sh +0 -203
  15. package/bin/suppress-audit.sh +0 -15
  16. package/bin/suppress-outdated.sh +0 -60
  17. package/bin/yarn-audit-with-suppression.sh +0 -19
  18. package/dependencies-report.json +0 -640
  19. package/docs/.nojekyll +0 -1
  20. package/docs/assets/highlight.css +0 -57
  21. package/docs/assets/main.js +0 -54
  22. package/docs/assets/search.js +0 -1
  23. package/docs/assets/style.css +0 -1224
  24. package/docs/assets/widgets.png +0 -0
  25. package/docs/assets/widgets@2x.png +0 -0
  26. package/docs/classes/AccountLockedError.html +0 -163
  27. package/docs/classes/AuthenticationError.html +0 -169
  28. package/docs/classes/Base64.html +0 -245
  29. package/docs/classes/Buffer.html +0 -158
  30. package/docs/classes/ConfigurationNotSetError.html +0 -164
  31. package/docs/classes/ConfigurationSetNotFoundError.html +0 -168
  32. package/docs/classes/DecodeError.html +0 -168
  33. package/docs/classes/DefaultConfigurationManager.html +0 -213
  34. package/docs/classes/DefaultLogger.html +0 -291
  35. package/docs/classes/DefaultSudoKeyArchive.html +0 -363
  36. package/docs/classes/DefaultSudoKeyManager.html +0 -814
  37. package/docs/classes/FatalError.html +0 -169
  38. package/docs/classes/IllegalArgumentError.html +0 -168
  39. package/docs/classes/IllegalStateError.html +0 -169
  40. package/docs/classes/InsufficientEntitlementsError.html +0 -164
  41. package/docs/classes/InvalidOwnershipProofError.html +0 -163
  42. package/docs/classes/InvalidTokenError.html +0 -163
  43. package/docs/classes/KeyArchiveDecodingError.html +0 -168
  44. package/docs/classes/KeyArchiveIncorrectPasswordError.html +0 -168
  45. package/docs/classes/KeyArchiveMissingError.html +0 -168
  46. package/docs/classes/KeyArchiveNoPasswordRequiredError.html +0 -168
  47. package/docs/classes/KeyArchivePasswordRequiredError.html +0 -168
  48. package/docs/classes/KeyArchiveTypeError.html +0 -168
  49. package/docs/classes/KeyArchiveUnknownKeyTypeError.html +0 -168
  50. package/docs/classes/KeyArchiveVersionError.html +0 -168
  51. package/docs/classes/KeyNotFoundError.html +0 -168
  52. package/docs/classes/KeyStoreNotExportableError.html +0 -168
  53. package/docs/classes/LimitExceededError.html +0 -164
  54. package/docs/classes/NoEntitlementsError.html +0 -163
  55. package/docs/classes/NotAuthorizedError.html +0 -169
  56. package/docs/classes/NotRegisteredError.html +0 -168
  57. package/docs/classes/NotSignedInError.html +0 -164
  58. package/docs/classes/OperationNotImplementedError.html +0 -168
  59. package/docs/classes/RegisterError.html +0 -169
  60. package/docs/classes/RequestFailedError.html +0 -189
  61. package/docs/classes/ServiceError.html +0 -170
  62. package/docs/classes/SignOutError.html +0 -168
  63. package/docs/classes/SudoCryptoProviderDefaults.html +0 -106
  64. package/docs/classes/UnknownGraphQLError.html +0 -169
  65. package/docs/classes/UnrecognizedAlgorithmError.html +0 -168
  66. package/docs/classes/UserNotConfirmedError.html +0 -164
  67. package/docs/classes/VersionMismatchError.html +0 -166
  68. package/docs/enums/CachePolicy.html +0 -72
  69. package/docs/enums/EncryptionAlgorithm.html +0 -80
  70. package/docs/enums/KeyArchiveKeyType.html +0 -86
  71. package/docs/enums/KeyDataKeyFormat.html +0 -92
  72. package/docs/enums/KeyDataKeyType.html +0 -85
  73. package/docs/enums/ListOperationResultStatus.html +0 -85
  74. package/docs/enums/PublicKeyFormat.html +0 -68
  75. package/docs/functions/isAppSyncNetworkError.html +0 -147
  76. package/docs/functions/isInsecureKeyArchive.html +0 -147
  77. package/docs/functions/isSecureKeyArchive.html +0 -147
  78. package/docs/functions/isUnrecognizedKeyArchive.html +0 -147
  79. package/docs/functions/keyArchiveInfoFromKeyData.html +0 -147
  80. package/docs/functions/keyArchiveKeyTypeFromKeyDataKeyType.html +0 -147
  81. package/docs/functions/mapGraphQLToClientError.html +0 -154
  82. package/docs/functions/mapNetworkErrorToClientError.html +0 -154
  83. package/docs/index.html +0 -146
  84. package/docs/interfaces/AsymmetricEncryptionOptions.html +0 -68
  85. package/docs/interfaces/BooleanFilter.html +0 -75
  86. package/docs/interfaces/ConfigurationManager.html +0 -200
  87. package/docs/interfaces/KeyData.html +0 -106
  88. package/docs/interfaces/ListOperationFailureResult.html +0 -76
  89. package/docs/interfaces/ListOperationPartialResult.html +0 -102
  90. package/docs/interfaces/ListOperationSuccessResult.html +0 -90
  91. package/docs/interfaces/ListOutput.html +0 -80
  92. package/docs/interfaces/Logger.html +0 -251
  93. package/docs/interfaces/Owner.html +0 -72
  94. package/docs/interfaces/PublicKey.html +0 -72
  95. package/docs/interfaces/ServiceCompatibilityInfo.html +0 -110
  96. package/docs/interfaces/StringFilter.html +0 -82
  97. package/docs/interfaces/SudoCryptoProvider.html +0 -865
  98. package/docs/interfaces/SudoKeyArchive.html +0 -257
  99. package/docs/interfaces/SudoKeyManager.html +0 -848
  100. package/docs/interfaces/SymmetricEncryptionOptions.html +0 -75
  101. package/docs/interfaces/ValidationResult.html +0 -83
  102. package/docs/modules.html +0 -248
  103. package/docs/types/AppSyncError.html +0 -138
  104. package/docs/types/AppSyncNetworkError.html +0 -138
  105. package/docs/types/InsecureKeyArchive.html +0 -138
  106. package/docs/types/KeyArchive.html +0 -138
  107. package/docs/types/KeyArchiveKeyInfo.html +0 -154
  108. package/docs/types/KeyArchiveKeyInfoDecoded.html +0 -138
  109. package/docs/types/ListOperationResult.html +0 -148
  110. package/docs/types/SecureKeyArchive.html +0 -138
  111. package/docs/types/Subset.html +0 -144
  112. package/docs/types/UnrecognizedKeyArchive.html +0 -138
  113. package/docs/variables/CURRENT_ARCHIVE_VERSION.html +0 -138
  114. package/docs/variables/InsecureKeyArchiveCodec.html +0 -138
  115. package/docs/variables/InsecureKeyArchiveType.html +0 -138
  116. package/docs/variables/KeyArchiveCodec.html +0 -138
  117. package/docs/variables/KeyArchiveKeyInfoArrayCodec.html +0 -138
  118. package/docs/variables/KeyArchiveKeyInfoCodec.html +0 -138
  119. package/docs/variables/KeyArchiveKeyTypeCodec.html +0 -138
  120. package/docs/variables/SecureKeyArchiveCodec.html +0 -138
  121. package/docs/variables/SecureKeyArchiveType.html +0 -138
  122. package/docs/variables/UnrecognizedKeyArchiveCodec.html +0 -138
  123. package/github/.babelrc +0 -10
  124. package/github/.eslintrc.js +0 -91
  125. package/github/.gitignore +0 -14
  126. package/github/.gitlab-ci.yml +0 -101
  127. package/github/.npmignore +0 -1
  128. package/github/.prettierignore +0 -3
  129. package/github/.prettierrc.js +0 -7
  130. package/github/.publisher.json +0 -7
  131. package/github/.vscode/settings.json +0 -5
  132. package/github/.yarn/releases/yarn-1.22.19.cjs +0 -147529
  133. package/github/.yarnrc +0 -5
  134. package/github/CHANGELOG.md +0 -51
  135. package/github/README.md +0 -8
  136. package/github/bin/outdated-with-suppression.sh +0 -203
  137. package/github/bin/suppress-audit.sh +0 -15
  138. package/github/bin/suppress-outdated.sh +0 -60
  139. package/github/bin/yarn-audit-with-suppression.sh +0 -19
  140. package/github/docs/.nojekyll +0 -1
  141. package/github/docs/assets/highlight.css +0 -57
  142. package/github/docs/assets/main.js +0 -54
  143. package/github/docs/assets/search.js +0 -1
  144. package/github/docs/assets/style.css +0 -1224
  145. package/github/docs/assets/widgets.png +0 -0
  146. package/github/docs/assets/widgets@2x.png +0 -0
  147. package/github/docs/classes/AccountLockedError.html +0 -163
  148. package/github/docs/classes/AuthenticationError.html +0 -169
  149. package/github/docs/classes/Base64.html +0 -245
  150. package/github/docs/classes/Buffer.html +0 -158
  151. package/github/docs/classes/ConfigurationNotSetError.html +0 -164
  152. package/github/docs/classes/ConfigurationSetNotFoundError.html +0 -168
  153. package/github/docs/classes/DecodeError.html +0 -168
  154. package/github/docs/classes/DefaultConfigurationManager.html +0 -213
  155. package/github/docs/classes/DefaultLogger.html +0 -291
  156. package/github/docs/classes/DefaultSudoKeyArchive.html +0 -363
  157. package/github/docs/classes/DefaultSudoKeyManager.html +0 -814
  158. package/github/docs/classes/FatalError.html +0 -169
  159. package/github/docs/classes/IllegalArgumentError.html +0 -168
  160. package/github/docs/classes/IllegalStateError.html +0 -169
  161. package/github/docs/classes/InsufficientEntitlementsError.html +0 -164
  162. package/github/docs/classes/InvalidOwnershipProofError.html +0 -163
  163. package/github/docs/classes/InvalidTokenError.html +0 -163
  164. package/github/docs/classes/KeyArchiveDecodingError.html +0 -168
  165. package/github/docs/classes/KeyArchiveIncorrectPasswordError.html +0 -168
  166. package/github/docs/classes/KeyArchiveMissingError.html +0 -168
  167. package/github/docs/classes/KeyArchiveNoPasswordRequiredError.html +0 -168
  168. package/github/docs/classes/KeyArchivePasswordRequiredError.html +0 -168
  169. package/github/docs/classes/KeyArchiveTypeError.html +0 -168
  170. package/github/docs/classes/KeyArchiveUnknownKeyTypeError.html +0 -168
  171. package/github/docs/classes/KeyArchiveVersionError.html +0 -168
  172. package/github/docs/classes/KeyNotFoundError.html +0 -168
  173. package/github/docs/classes/KeyStoreNotExportableError.html +0 -168
  174. package/github/docs/classes/LimitExceededError.html +0 -164
  175. package/github/docs/classes/NoEntitlementsError.html +0 -163
  176. package/github/docs/classes/NotAuthorizedError.html +0 -169
  177. package/github/docs/classes/NotRegisteredError.html +0 -168
  178. package/github/docs/classes/NotSignedInError.html +0 -164
  179. package/github/docs/classes/OperationNotImplementedError.html +0 -168
  180. package/github/docs/classes/RegisterError.html +0 -169
  181. package/github/docs/classes/RequestFailedError.html +0 -189
  182. package/github/docs/classes/ServiceError.html +0 -170
  183. package/github/docs/classes/SignOutError.html +0 -168
  184. package/github/docs/classes/SudoCryptoProviderDefaults.html +0 -106
  185. package/github/docs/classes/UnknownGraphQLError.html +0 -169
  186. package/github/docs/classes/UnrecognizedAlgorithmError.html +0 -168
  187. package/github/docs/classes/UserNotConfirmedError.html +0 -164
  188. package/github/docs/classes/VersionMismatchError.html +0 -166
  189. package/github/docs/enums/CachePolicy.html +0 -72
  190. package/github/docs/enums/EncryptionAlgorithm.html +0 -80
  191. package/github/docs/enums/KeyArchiveKeyType.html +0 -86
  192. package/github/docs/enums/KeyDataKeyFormat.html +0 -92
  193. package/github/docs/enums/KeyDataKeyType.html +0 -85
  194. package/github/docs/enums/ListOperationResultStatus.html +0 -85
  195. package/github/docs/enums/PublicKeyFormat.html +0 -68
  196. package/github/docs/functions/isAppSyncNetworkError.html +0 -147
  197. package/github/docs/functions/isInsecureKeyArchive.html +0 -147
  198. package/github/docs/functions/isSecureKeyArchive.html +0 -147
  199. package/github/docs/functions/isUnrecognizedKeyArchive.html +0 -147
  200. package/github/docs/functions/keyArchiveInfoFromKeyData.html +0 -147
  201. package/github/docs/functions/keyArchiveKeyTypeFromKeyDataKeyType.html +0 -147
  202. package/github/docs/functions/mapGraphQLToClientError.html +0 -154
  203. package/github/docs/functions/mapNetworkErrorToClientError.html +0 -154
  204. package/github/docs/index.html +0 -146
  205. package/github/docs/interfaces/AsymmetricEncryptionOptions.html +0 -68
  206. package/github/docs/interfaces/BooleanFilter.html +0 -75
  207. package/github/docs/interfaces/ConfigurationManager.html +0 -200
  208. package/github/docs/interfaces/KeyData.html +0 -106
  209. package/github/docs/interfaces/ListOperationFailureResult.html +0 -76
  210. package/github/docs/interfaces/ListOperationPartialResult.html +0 -102
  211. package/github/docs/interfaces/ListOperationSuccessResult.html +0 -90
  212. package/github/docs/interfaces/ListOutput.html +0 -80
  213. package/github/docs/interfaces/Logger.html +0 -251
  214. package/github/docs/interfaces/Owner.html +0 -72
  215. package/github/docs/interfaces/PublicKey.html +0 -72
  216. package/github/docs/interfaces/ServiceCompatibilityInfo.html +0 -110
  217. package/github/docs/interfaces/StringFilter.html +0 -82
  218. package/github/docs/interfaces/SudoCryptoProvider.html +0 -865
  219. package/github/docs/interfaces/SudoKeyArchive.html +0 -257
  220. package/github/docs/interfaces/SudoKeyManager.html +0 -848
  221. package/github/docs/interfaces/SymmetricEncryptionOptions.html +0 -75
  222. package/github/docs/interfaces/ValidationResult.html +0 -83
  223. package/github/docs/modules.html +0 -248
  224. package/github/docs/types/AppSyncError.html +0 -138
  225. package/github/docs/types/AppSyncNetworkError.html +0 -138
  226. package/github/docs/types/InsecureKeyArchive.html +0 -138
  227. package/github/docs/types/KeyArchive.html +0 -138
  228. package/github/docs/types/KeyArchiveKeyInfo.html +0 -154
  229. package/github/docs/types/KeyArchiveKeyInfoDecoded.html +0 -138
  230. package/github/docs/types/ListOperationResult.html +0 -148
  231. package/github/docs/types/SecureKeyArchive.html +0 -138
  232. package/github/docs/types/Subset.html +0 -144
  233. package/github/docs/types/UnrecognizedKeyArchive.html +0 -138
  234. package/github/docs/variables/CURRENT_ARCHIVE_VERSION.html +0 -138
  235. package/github/docs/variables/InsecureKeyArchiveCodec.html +0 -138
  236. package/github/docs/variables/InsecureKeyArchiveType.html +0 -138
  237. package/github/docs/variables/KeyArchiveCodec.html +0 -138
  238. package/github/docs/variables/KeyArchiveKeyInfoArrayCodec.html +0 -138
  239. package/github/docs/variables/KeyArchiveKeyInfoCodec.html +0 -138
  240. package/github/docs/variables/KeyArchiveKeyTypeCodec.html +0 -138
  241. package/github/docs/variables/SecureKeyArchiveCodec.html +0 -138
  242. package/github/docs/variables/SecureKeyArchiveType.html +0 -138
  243. package/github/docs/variables/UnrecognizedKeyArchiveCodec.html +0 -138
  244. package/github/jest.config.json +0 -14
  245. package/github/package.json +0 -91
  246. package/github/src/configurationManager/defaultConfigurationManager.ts +0 -281
  247. package/github/src/errors/error.ts +0 -469
  248. package/github/src/index.ts +0 -8
  249. package/github/src/logging/bunyanLogger.ts +0 -47
  250. package/github/src/logging/logger.ts +0 -164
  251. package/github/src/sudoKeyArchive/index.ts +0 -4
  252. package/github/src/sudoKeyArchive/keyArchive.ts +0 -120
  253. package/github/src/sudoKeyArchive/keyInfo.ts +0 -47
  254. package/github/src/sudoKeyArchive/keyType.ts +0 -50
  255. package/github/src/sudoKeyArchive/sudoKeyArchive.ts +0 -591
  256. package/github/src/sudoKeyManager/index.ts +0 -4
  257. package/github/src/sudoKeyManager/keyData.ts +0 -60
  258. package/github/src/sudoKeyManager/publicKey.ts +0 -9
  259. package/github/src/sudoKeyManager/sudoCryptoProvider.ts +0 -416
  260. package/github/src/sudoKeyManager/sudoKeyManager.ts +0 -609
  261. package/github/src/types/types.ts +0 -129
  262. package/github/src/utils/base64.ts +0 -75
  263. package/github/src/utils/buffer.ts +0 -39
  264. package/github/test/integration/defaultConfigurationManager.spec.ts +0 -85
  265. package/github/test/matchers.ts +0 -122
  266. package/github/test/unit/configurationManager/defaultConfigurationManager.spec.ts +0 -506
  267. package/github/test/unit/errors/error.spec.ts +0 -115
  268. package/github/test/unit/keyType.spec.ts +0 -54
  269. package/github/test/unit/logging/logger.spec.ts +0 -182
  270. package/github/test/unit/sudoKeyArchive.spec.ts +0 -1609
  271. package/github/test/unit/sudoKeyManager.spec.ts +0 -1045
  272. package/github/test/unit/utils/base64.spec.ts +0 -45
  273. package/github/test/unit/utils/buffer.spec.ts +0 -45
  274. package/github/test/unit/utils/listOperationResult.spec.ts +0 -84
  275. package/github/tsconfig.json +0 -20
  276. package/github/tsconfig.test.json +0 -7
  277. package/github/yarn.lock +0 -5922
  278. package/jest.config.json +0 -14
  279. package/src/configurationManager/defaultConfigurationManager.ts +0 -281
  280. package/src/errors/error.ts +0 -469
  281. package/src/index.ts +0 -8
  282. package/src/logging/bunyanLogger.ts +0 -47
  283. package/src/logging/logger.ts +0 -164
  284. package/src/sudoKeyArchive/index.ts +0 -4
  285. package/src/sudoKeyArchive/keyArchive.ts +0 -120
  286. package/src/sudoKeyArchive/keyInfo.ts +0 -47
  287. package/src/sudoKeyArchive/keyType.ts +0 -50
  288. package/src/sudoKeyArchive/sudoKeyArchive.ts +0 -591
  289. package/src/sudoKeyManager/index.ts +0 -4
  290. package/src/sudoKeyManager/keyData.ts +0 -60
  291. package/src/sudoKeyManager/publicKey.ts +0 -9
  292. package/src/sudoKeyManager/sudoCryptoProvider.ts +0 -416
  293. package/src/sudoKeyManager/sudoKeyManager.ts +0 -609
  294. package/src/types/types.ts +0 -129
  295. package/src/utils/base64.ts +0 -75
  296. package/src/utils/buffer.ts +0 -39
  297. package/test/integration/defaultConfigurationManager.spec.ts +0 -85
  298. package/test/matchers.ts +0 -122
  299. package/test/unit/configurationManager/defaultConfigurationManager.spec.ts +0 -506
  300. package/test/unit/errors/error.spec.ts +0 -115
  301. package/test/unit/keyType.spec.ts +0 -54
  302. package/test/unit/logging/logger.spec.ts +0 -182
  303. package/test/unit/sudoKeyArchive.spec.ts +0 -1609
  304. package/test/unit/sudoKeyManager.spec.ts +0 -1045
  305. package/test/unit/utils/base64.spec.ts +0 -45
  306. package/test/unit/utils/buffer.spec.ts +0 -45
  307. package/test/unit/utils/listOperationResult.spec.ts +0 -84
  308. package/tsconfig.json +0 -20
  309. package/tsconfig.test.json +0 -7
  310. package/yarn.lock +0 -5922
@@ -1,1609 +0,0 @@
1
- import { gunzipSync, gzipSync } from 'fflate'
2
- import { isLeft, isRight } from 'fp-ts/lib/Either'
3
- import * as t from 'io-ts'
4
- import {
5
- anything,
6
- capture,
7
- deepEqual,
8
- instance,
9
- mock,
10
- reset,
11
- verify,
12
- when,
13
- } from 'ts-mockito'
14
-
15
- import {
16
- IllegalArgumentError,
17
- KeyArchiveDecodingError,
18
- KeyArchiveIncorrectPasswordError,
19
- KeyArchiveMissingError,
20
- KeyArchiveNoPasswordRequiredError,
21
- KeyArchivePasswordRequiredError,
22
- KeyArchiveTypeError,
23
- KeyArchiveVersionError,
24
- KeyNotFoundError,
25
- } from '../../src/errors/error'
26
- import {
27
- InsecureKeyArchive,
28
- InsecureKeyArchiveCodec,
29
- SecureKeyArchive,
30
- SecureKeyArchiveCodec,
31
- } from '../../src/sudoKeyArchive/keyArchive'
32
- import {
33
- KeyArchiveKeyInfo,
34
- KeyArchiveKeyInfoCodec,
35
- } from '../../src/sudoKeyArchive/keyInfo'
36
- import { KeyArchiveKeyType } from '../../src/sudoKeyArchive/keyType'
37
- import { DefaultSudoKeyArchive } from '../../src/sudoKeyArchive/sudoKeyArchive'
38
- import {
39
- KeyData,
40
- KeyDataKeyFormat,
41
- KeyDataKeyType,
42
- SudoCryptoProviderDefaults,
43
- } from '../../src/sudoKeyManager'
44
- import { SudoKeyManager } from '../../src/sudoKeyManager/sudoKeyManager'
45
- import { Base64 } from '../../src/utils/base64'
46
- import { Buffer as BufferUtil } from '../../src/utils/buffer'
47
-
48
- import '../matchers'
49
-
50
- describe('DefaultSudoKeyArchive tests', () => {
51
- const mockKeyManager1 = mock<SudoKeyManager>()
52
- const mockKeyManager2 = mock<SudoKeyManager>()
53
- const keyManager1Namespace = 'key-manager-1'
54
- const keyManager2Namespace = 'key-manager-2'
55
- const password = BufferUtil.fromString('password')
56
-
57
- beforeEach(() => {
58
- reset(mockKeyManager1)
59
- reset(mockKeyManager2)
60
-
61
- when(mockKeyManager1.namespace).thenReturn(keyManager1Namespace)
62
- when(mockKeyManager1.addPassword(anything(), anything())).thenResolve()
63
- when(mockKeyManager1.addPrivateKey(anything(), anything())).thenResolve()
64
- when(mockKeyManager1.addPublicKey(anything(), anything())).thenResolve()
65
- when(mockKeyManager1.addSymmetricKey(anything(), anything())).thenResolve()
66
-
67
- when(mockKeyManager2.namespace).thenReturn(keyManager2Namespace)
68
- when(mockKeyManager2.addPassword(anything(), anything())).thenResolve()
69
- when(mockKeyManager2.addPrivateKey(anything(), anything())).thenResolve()
70
- when(mockKeyManager2.addPublicKey(anything(), anything())).thenResolve()
71
- when(mockKeyManager2.addSymmetricKey(anything(), anything())).thenResolve()
72
- })
73
-
74
- const iv = BufferUtil.fromString('iv')
75
- const ivB64 = Base64.encode(iv)
76
- const salt = BufferUtil.fromString('salt')
77
- const saltB64 = Base64.encode(salt)
78
- const symmetricKey = BufferUtil.fromString('symmetric-key')
79
-
80
- describe('constructor', () => {
81
- describe('with no options parameter and one key manager', () => {
82
- it('should succeed', () => {
83
- new DefaultSudoKeyArchive(instance(mockKeyManager1))
84
- verify(mockKeyManager1.namespace).atLeast(1)
85
- })
86
-
87
- it('should create a sudo key archive with no meta info', () => {
88
- const sudoKeyArchive = new DefaultSudoKeyArchive(
89
- instance(mockKeyManager1),
90
- )
91
- expect(sudoKeyArchive.getMetaInfo()).toEqual(new Map<string, string>())
92
- verify(mockKeyManager1.namespace).atLeast(1)
93
- })
94
-
95
- it('should create a sudo key archive with no excluded keys', () => {
96
- const sudoKeyArchive = new DefaultSudoKeyArchive(
97
- instance(mockKeyManager1),
98
- )
99
- expect(sudoKeyArchive.getExcludedKeys()).toEqual(new Set<string>())
100
- verify(mockKeyManager1.namespace).atLeast(1)
101
- })
102
-
103
- it('should create a sudo key archive with no excluded key types', () => {
104
- const sudoKeyArchive = new DefaultSudoKeyArchive(
105
- instance(mockKeyManager1),
106
- )
107
- expect(sudoKeyArchive.getExcludedKeyTypes()).toEqual(
108
- new Set<KeyArchiveKeyType>(),
109
- )
110
- verify(mockKeyManager1.namespace).atLeast(1)
111
- })
112
- })
113
-
114
- describe('with no options parameter and array of key managers', () => {
115
- it('should succeed', () => {
116
- new DefaultSudoKeyArchive([
117
- instance(mockKeyManager1),
118
- instance(mockKeyManager2),
119
- ])
120
- verify(mockKeyManager1.namespace).atLeast(1)
121
- verify(mockKeyManager2.namespace).atLeast(1)
122
- })
123
-
124
- it('should throw an IllegalArgumentError if key manager array is empty', () => {
125
- expect(() => new DefaultSudoKeyArchive([])).toThrowErrorMatching(
126
- new IllegalArgumentError('Must provide at least one key manager'),
127
- )
128
- })
129
-
130
- it('should throw an IllegalArgumentError if key manager array has key managers with same namespace', () => {
131
- expect(
132
- () =>
133
- new DefaultSudoKeyArchive([
134
- instance(mockKeyManager1),
135
- instance(mockKeyManager1),
136
- ]),
137
- ).toThrowErrorMatching(
138
- new IllegalArgumentError(
139
- `Multiple key managers provided with namespace ${keyManager1Namespace}`,
140
- ),
141
- )
142
- })
143
- })
144
-
145
- describe('with fully populated options parameter but no archive', () => {
146
- let metaInfo: ReadonlyMap<string, string>
147
- let excludedKeyTypes: ReadonlySet<KeyArchiveKeyType>
148
- let excludedKeys: ReadonlySet<string>
149
-
150
- beforeAll(() => {
151
- const newMetaInfo = new Map<string, string>()
152
- newMetaInfo.set('meta-1', 'value-1')
153
- newMetaInfo.set('meta-2', 'value-2')
154
- metaInfo = newMetaInfo
155
-
156
- const newExcludedKeyTypes = new Set<KeyArchiveKeyType>()
157
- newExcludedKeyTypes.add(KeyArchiveKeyType.PublicKey)
158
- excludedKeyTypes = newExcludedKeyTypes
159
-
160
- const newExcludedKeys = new Set<string>()
161
- newExcludedKeys.add('excluded-key-1')
162
- excludedKeys = newExcludedKeys
163
- })
164
-
165
- it('should succeed', () => {
166
- const keyArchive = new DefaultSudoKeyArchive(
167
- instance(mockKeyManager1),
168
- {
169
- metaInfo,
170
- excludedKeys,
171
- excludedKeyTypes,
172
- },
173
- )
174
- verify(mockKeyManager1.namespace).once()
175
-
176
- expect(keyArchive.getExcludedKeys()).toEqual(excludedKeys)
177
- expect(keyArchive.getExcludedKeyTypes()).toEqual(excludedKeyTypes)
178
- expect(keyArchive.getMetaInfo()).toEqual(metaInfo)
179
- })
180
- })
181
-
182
- describe('with archiveData provided', () => {
183
- it('throws KeyArchiveDecodingError if archive data is not gzip data', () => {
184
- expect(
185
- () =>
186
- new DefaultSudoKeyArchive(instance(mockKeyManager1), {
187
- archiveData: BufferUtil.fromString('not gzipped'),
188
- }),
189
- ).toThrowErrorMatching(new KeyArchiveDecodingError())
190
- })
191
-
192
- it('throws KeyArchiveDecodingError if archive data is not gzipped JSON data', () => {
193
- expect(
194
- () =>
195
- new DefaultSudoKeyArchive(instance(mockKeyManager1), {
196
- archiveData: gzipSync(BufferUtil.fromString('not JSON')),
197
- }),
198
- ).toThrowErrorMatching(new KeyArchiveDecodingError())
199
- })
200
-
201
- it('throws KeyArchiveDecodingError if archive data is gzipped JSON data without a Type or Version field', () => {
202
- expect(
203
- () =>
204
- new DefaultSudoKeyArchive(instance(mockKeyManager1), {
205
- archiveData: gzipSync(
206
- BufferUtil.fromString(JSON.stringify({ Some: 'JSON' })),
207
- ),
208
- }),
209
- ).toThrowErrorMatching(new KeyArchiveDecodingError())
210
- })
211
-
212
- it('throws KeyArchiveTypeError if archive data is gzipped JSON data with Type property of unrecognized value', () => {
213
- const unsupportedType = 'Unsupported'
214
- expect(
215
- () =>
216
- new DefaultSudoKeyArchive(instance(mockKeyManager1), {
217
- archiveData: gzipSync(
218
- BufferUtil.fromString(
219
- JSON.stringify({ Type: unsupportedType }),
220
- ),
221
- ),
222
- }),
223
- ).toThrowErrorMatching(new KeyArchiveTypeError(unsupportedType))
224
- })
225
-
226
- it('throws KeyArchiveVersionError if archive data is gzipped JSON data with Type property of unrecognized value', () => {
227
- const unsupportedVersion =
228
- DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION + 1
229
- expect(
230
- () =>
231
- new DefaultSudoKeyArchive(instance(mockKeyManager1), {
232
- archiveData: gzipSync(
233
- BufferUtil.fromString(
234
- JSON.stringify({ Version: unsupportedVersion }),
235
- ),
236
- ),
237
- }),
238
- ).toThrowErrorMatching(new KeyArchiveVersionError(unsupportedVersion))
239
- })
240
- })
241
- })
242
-
243
- describe('unarchive', () => {
244
- const keys: KeyArchiveKeyInfo[] = [
245
- {
246
- Name: 'key-1-password',
247
- NameSpace: keyManager1Namespace,
248
- Data: Base64.encode(BufferUtil.fromString('key-1-password-data')),
249
- Exportable: true,
250
- Synchronizable: false,
251
- Type: KeyArchiveKeyType.Password,
252
- },
253
- {
254
- Name: 'key-2-key-pair',
255
- NameSpace: keyManager1Namespace,
256
- Data: Base64.encode(BufferUtil.fromString('key-2-public-key-data')),
257
- Exportable: true,
258
- Synchronizable: false,
259
- Type: KeyArchiveKeyType.PublicKey,
260
- },
261
- {
262
- Name: 'key-2-key-pair',
263
- NameSpace: keyManager1Namespace,
264
- Data: Base64.encode(BufferUtil.fromString('key-2-private-key-data')),
265
- Exportable: true,
266
- Synchronizable: false,
267
- Type: KeyArchiveKeyType.PrivateKey,
268
- },
269
- {
270
- Name: 'key-3-symmetric',
271
- NameSpace: keyManager1Namespace,
272
- Data: Base64.encode(BufferUtil.fromString('key-3-symmetric-data')),
273
- Exportable: true,
274
- Synchronizable: false,
275
- Type: KeyArchiveKeyType.SymmetricKey,
276
- },
277
- ]
278
-
279
- it('throws KeyArchiveMissingError if constructed without archive data', async () => {
280
- const keyArchive = new DefaultSudoKeyArchive(instance(mockKeyManager1))
281
- await expect(keyArchive.unarchive(undefined)).rejects.toMatchError(
282
- new KeyArchiveMissingError(),
283
- )
284
- })
285
-
286
- it('throws KeyArchiveDecodingError if key data cannot be decoded', async () => {
287
- const keyArchive = new DefaultSudoKeyArchive(instance(mockKeyManager1), {
288
- archiveData: gzipSync(
289
- BufferUtil.fromString(
290
- JSON.stringify({
291
- Type: 'Insecure',
292
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
293
- Keys: [
294
- {
295
- Data: 'not base64',
296
- Type: KeyArchiveKeyType.Password,
297
- Name: 'not-base64',
298
- NameSpace: keyManager1Namespace,
299
- },
300
- ],
301
- }),
302
- ),
303
- ),
304
- })
305
-
306
- await expect(keyArchive.unarchive(undefined)).rejects.toMatchError(
307
- new KeyArchiveDecodingError(
308
- `Unable to decode key ${keyManager1Namespace}:${KeyArchiveKeyType.Password}:not-base64`,
309
- ),
310
- )
311
- })
312
-
313
- describe('with insecure archive', () => {
314
- it('throws KeyArchiveNoPasswordRequiredError if a password is provided', async () => {
315
- const insecureArchive: InsecureKeyArchive = {
316
- Type: 'Insecure',
317
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
318
- Keys: [],
319
- MetaInfo: {},
320
- }
321
-
322
- const keyArchive = new DefaultSudoKeyArchive(
323
- instance(mockKeyManager1),
324
- {
325
- archiveData: gzipSync(
326
- BufferUtil.fromString(JSON.stringify(insecureArchive)),
327
- ),
328
- },
329
- )
330
-
331
- await expect(keyArchive.unarchive(password)).rejects.toMatchError(
332
- new KeyArchiveNoPasswordRequiredError(),
333
- )
334
- })
335
-
336
- it('succeeds with no keys', async () => {
337
- const insecureArchive: InsecureKeyArchive = {
338
- Type: 'Insecure',
339
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
340
- Keys: [],
341
- MetaInfo: {},
342
- }
343
-
344
- const keyArchive = new DefaultSudoKeyArchive(
345
- instance(mockKeyManager1),
346
- {
347
- archiveData: gzipSync(
348
- BufferUtil.fromString(JSON.stringify(insecureArchive)),
349
- ),
350
- },
351
- )
352
-
353
- await expect(keyArchive.unarchive(undefined)).resolves.toBeUndefined()
354
-
355
- verify(mockKeyManager1.addPassword(anything(), anything())).never()
356
- verify(mockKeyManager1.addPrivateKey(anything(), anything())).never()
357
- verify(mockKeyManager1.addPublicKey(anything(), anything())).never()
358
- verify(mockKeyManager1.addSymmetricKey(anything(), anything())).never()
359
- })
360
-
361
- it('succeeds with keys of different types', async () => {
362
- const insecureArchive: InsecureKeyArchive = {
363
- Type: 'Insecure',
364
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
365
- Keys: keys,
366
- MetaInfo: {},
367
- }
368
-
369
- const keyArchive = new DefaultSudoKeyArchive(
370
- instance(mockKeyManager1),
371
- {
372
- archiveData: gzipSync(
373
- BufferUtil.fromString(JSON.stringify(insecureArchive)),
374
- ),
375
- },
376
- )
377
-
378
- await expect(keyArchive.unarchive(undefined)).resolves.toBeUndefined()
379
-
380
- keys.forEach((Key) =>
381
- expect(
382
- keyArchive.getKeyData(keyManager1Namespace, Key.Name, Key.Type),
383
- ).toEqual(Base64.decode(Key.Data)),
384
- )
385
- })
386
- })
387
-
388
- describe('with secure archive', () => {
389
- const emptyKeys: KeyArchiveKeyInfo[] = []
390
- const serializedEmptyKeys = JSON.stringify(emptyKeys)
391
- const compressedSerializedEmptyKeys = gzipSync(
392
- BufferUtil.fromString(serializedEmptyKeys),
393
- )
394
- const serializedKeys = JSON.stringify(keys)
395
- const compressedSerializedKeys = gzipSync(
396
- BufferUtil.fromString(serializedKeys),
397
- )
398
- const encryptedEmptyKeys = BufferUtil.fromString('encrypted-empty-keys')
399
- const encryptedEmptyKeysB64 = Base64.encode(encryptedEmptyKeys)
400
- const encryptedKeys = BufferUtil.fromString('encrypted-keys')
401
- const encryptedKeysB64 = Base64.encode(encryptedKeys)
402
-
403
- beforeEach(() => {
404
- when(
405
- mockKeyManager1.generateSymmetricKeyFromPassword(
406
- anything(),
407
- anything(),
408
- anything(),
409
- ),
410
- ).thenResolve(symmetricKey)
411
- when(
412
- mockKeyManager1.decryptWithSymmetricKey(
413
- anything(),
414
- deepEqual(encryptedEmptyKeys),
415
- anything(),
416
- ),
417
- ).thenResolve(compressedSerializedEmptyKeys)
418
- when(
419
- mockKeyManager1.decryptWithSymmetricKey(
420
- anything(),
421
- deepEqual(encryptedKeys),
422
- anything(),
423
- ),
424
- ).thenResolve(compressedSerializedKeys)
425
- })
426
-
427
- it('throws KeyArchivePasswordRequiredError if no password is provided', async () => {
428
- const secureArchive: SecureKeyArchive = {
429
- Type: 'Secure',
430
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
431
- IV: ivB64,
432
- Salt: saltB64,
433
- Rounds: 1,
434
- Keys: encryptedEmptyKeysB64,
435
- MetaInfo: {},
436
- }
437
-
438
- const keyArchive = new DefaultSudoKeyArchive(
439
- instance(mockKeyManager1),
440
- {
441
- archiveData: gzipSync(
442
- BufferUtil.fromString(JSON.stringify(secureArchive)),
443
- ),
444
- },
445
- )
446
-
447
- await expect(keyArchive.unarchive(undefined)).rejects.toMatchError(
448
- new KeyArchivePasswordRequiredError(),
449
- )
450
-
451
- verify(
452
- mockKeyManager1.generateSymmetricKeyFromPassword(
453
- anything(),
454
- anything(),
455
- anything(),
456
- ),
457
- ).never()
458
- verify(
459
- mockKeyManager1.decryptWithSymmetricKey(
460
- anything(),
461
- anything(),
462
- anything(),
463
- ),
464
- ).never()
465
- })
466
-
467
- it('throws KeyArchiveDecodingError if Salt is not decodable as base 64', async () => {
468
- const secureArchive: SecureKeyArchive = {
469
- Type: 'Secure',
470
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
471
- IV: ivB64,
472
- Salt: 'not base64',
473
- Rounds: 1,
474
- Keys: encryptedEmptyKeysB64,
475
- MetaInfo: {},
476
- }
477
-
478
- const keyArchive = new DefaultSudoKeyArchive(
479
- instance(mockKeyManager1),
480
- {
481
- archiveData: gzipSync(
482
- BufferUtil.fromString(JSON.stringify(secureArchive)),
483
- ),
484
- },
485
- )
486
-
487
- await expect(keyArchive.unarchive(password)).rejects.toMatchError(
488
- new KeyArchiveDecodingError(),
489
- )
490
-
491
- verify(
492
- mockKeyManager1.generateSymmetricKeyFromPassword(
493
- anything(),
494
- anything(),
495
- anything(),
496
- ),
497
- ).never()
498
- verify(
499
- mockKeyManager1.decryptWithSymmetricKey(
500
- anything(),
501
- anything(),
502
- anything(),
503
- ),
504
- ).never()
505
- })
506
-
507
- it('throws KeyArchiveDecodingError if IV is not decodable as base 64', async () => {
508
- const secureArchive: SecureKeyArchive = {
509
- Type: 'Secure',
510
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
511
- IV: 'not base64',
512
- Salt: saltB64,
513
- Rounds: 1,
514
- Keys: encryptedEmptyKeysB64,
515
- MetaInfo: {},
516
- }
517
-
518
- const keyArchive = new DefaultSudoKeyArchive(
519
- instance(mockKeyManager1),
520
- {
521
- archiveData: gzipSync(
522
- BufferUtil.fromString(JSON.stringify(secureArchive)),
523
- ),
524
- },
525
- )
526
-
527
- await expect(keyArchive.unarchive(password)).rejects.toMatchError(
528
- new KeyArchiveDecodingError(),
529
- )
530
-
531
- verify(
532
- mockKeyManager1.generateSymmetricKeyFromPassword(
533
- anything(),
534
- anything(),
535
- anything(),
536
- ),
537
- ).never()
538
- verify(
539
- mockKeyManager1.decryptWithSymmetricKey(
540
- anything(),
541
- anything(),
542
- anything(),
543
- ),
544
- ).never()
545
- })
546
-
547
- it('throws KeyArchiveDecodingError if Keys is not decodable as base 64', async () => {
548
- const secureArchive: SecureKeyArchive = {
549
- Type: 'Secure',
550
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
551
- IV: ivB64,
552
- Salt: saltB64,
553
- Rounds: 1,
554
- Keys: 'not base64',
555
- MetaInfo: {},
556
- }
557
-
558
- const keyArchive = new DefaultSudoKeyArchive(
559
- instance(mockKeyManager1),
560
- {
561
- archiveData: gzipSync(
562
- BufferUtil.fromString(JSON.stringify(secureArchive)),
563
- ),
564
- },
565
- )
566
-
567
- await expect(keyArchive.unarchive(password)).rejects.toMatchError(
568
- new KeyArchiveDecodingError(),
569
- )
570
-
571
- verify(
572
- mockKeyManager1.generateSymmetricKeyFromPassword(
573
- anything(),
574
- anything(),
575
- anything(),
576
- ),
577
- ).never()
578
- verify(
579
- mockKeyManager1.decryptWithSymmetricKey(
580
- anything(),
581
- anything(),
582
- anything(),
583
- ),
584
- ).never()
585
- })
586
-
587
- it('throws KeyArchiveDecodingError if symmetric key is unable to be generated', async () => {
588
- const secureArchive: SecureKeyArchive = {
589
- Type: 'Secure',
590
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
591
- IV: ivB64,
592
- Salt: saltB64,
593
- Rounds: 1,
594
- Keys: encryptedEmptyKeysB64,
595
- MetaInfo: {},
596
- }
597
-
598
- const keyArchive = new DefaultSudoKeyArchive(
599
- instance(mockKeyManager1),
600
- {
601
- archiveData: gzipSync(
602
- BufferUtil.fromString(JSON.stringify(secureArchive)),
603
- ),
604
- },
605
- )
606
-
607
- when(
608
- mockKeyManager1.generateSymmetricKeyFromPassword(
609
- anything(),
610
- anything(),
611
- anything(),
612
- ),
613
- ).thenReject(new Error('symmetric key generation failed'))
614
-
615
- await expect(keyArchive.unarchive(password)).rejects.toMatchError(
616
- new KeyArchiveDecodingError(),
617
- )
618
-
619
- verify(
620
- mockKeyManager1.generateSymmetricKeyFromPassword(
621
- anything(),
622
- anything(),
623
- anything(),
624
- ),
625
- ).once()
626
- const [actualPassword, actualSalt, actualOptions] = capture(
627
- mockKeyManager1.generateSymmetricKeyFromPassword,
628
- ).first()
629
- expect(actualPassword).toEqual(password)
630
- expect(actualSalt).toEqual(salt)
631
- expect(actualOptions).toEqual({ rounds: secureArchive.Rounds })
632
-
633
- verify(
634
- mockKeyManager1.decryptWithSymmetricKey(
635
- anything(),
636
- anything(),
637
- anything(),
638
- ),
639
- ).never()
640
- })
641
-
642
- it('throws KeyArchiveIncorrectPasswordError if encrypted compressed serialized keys are unable to be decrypted', async () => {
643
- const secureArchive: SecureKeyArchive = {
644
- Type: 'Secure',
645
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
646
- IV: ivB64,
647
- Salt: saltB64,
648
- Rounds: 1,
649
- Keys: encryptedEmptyKeysB64,
650
- MetaInfo: {},
651
- }
652
-
653
- const keyArchive = new DefaultSudoKeyArchive(
654
- instance(mockKeyManager1),
655
- {
656
- archiveData: gzipSync(
657
- BufferUtil.fromString(JSON.stringify(secureArchive)),
658
- ),
659
- },
660
- )
661
-
662
- when(
663
- mockKeyManager1.decryptWithSymmetricKey(
664
- anything(),
665
- anything(),
666
- anything(),
667
- ),
668
- ).thenReject(new Error('decryption failed'))
669
-
670
- await expect(keyArchive.unarchive(password)).rejects.toMatchError(
671
- new KeyArchiveIncorrectPasswordError(),
672
- )
673
-
674
- verify(
675
- mockKeyManager1.generateSymmetricKeyFromPassword(
676
- anything(),
677
- anything(),
678
- anything(),
679
- ),
680
- ).once()
681
- const [actualPassword, actualSalt, actualOptions] = capture(
682
- mockKeyManager1.generateSymmetricKeyFromPassword,
683
- ).first()
684
- expect(actualPassword).toEqual(password)
685
- expect(actualSalt).toEqual(salt)
686
- expect(actualOptions).toEqual({ rounds: secureArchive.Rounds })
687
-
688
- verify(
689
- mockKeyManager1.decryptWithSymmetricKey(
690
- anything(),
691
- anything(),
692
- anything(),
693
- ),
694
- ).once()
695
- const [actualKey, actualData, symmetricOptions] = capture(
696
- mockKeyManager1.decryptWithSymmetricKey,
697
- ).first()
698
- expect(actualKey).toEqual(symmetricKey)
699
- expect(actualData).toEqual(encryptedEmptyKeys)
700
- expect(symmetricOptions).toBeDefined()
701
- expect(symmetricOptions.iv).toEqual(iv)
702
- })
703
-
704
- it('throws KeyArchiveDecodingError if compressed serialized keys are unable to be uncompressed', async () => {
705
- const secureArchive: SecureKeyArchive = {
706
- Type: 'Secure',
707
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
708
- IV: ivB64,
709
- Salt: saltB64,
710
- Rounds: 1,
711
- Keys: encryptedEmptyKeysB64,
712
- MetaInfo: {},
713
- }
714
-
715
- const keyArchive = new DefaultSudoKeyArchive(
716
- instance(mockKeyManager1),
717
- {
718
- archiveData: gzipSync(
719
- BufferUtil.fromString(JSON.stringify(secureArchive)),
720
- ),
721
- },
722
- )
723
-
724
- when(
725
- mockKeyManager1.decryptWithSymmetricKey(
726
- anything(),
727
- anything(),
728
- anything(),
729
- ),
730
- ).thenResolve(BufferUtil.fromString('not compressed'))
731
-
732
- await expect(keyArchive.unarchive(password)).rejects.toMatchError(
733
- new KeyArchiveDecodingError(),
734
- )
735
-
736
- verify(
737
- mockKeyManager1.generateSymmetricKeyFromPassword(
738
- anything(),
739
- anything(),
740
- anything(),
741
- ),
742
- ).once()
743
- const [actualPassword, actualSalt, actualOptions] = capture(
744
- mockKeyManager1.generateSymmetricKeyFromPassword,
745
- ).first()
746
- expect(actualPassword).toEqual(password)
747
- expect(actualSalt).toEqual(salt)
748
- expect(actualOptions).toEqual({ rounds: secureArchive.Rounds })
749
-
750
- verify(
751
- mockKeyManager1.decryptWithSymmetricKey(
752
- anything(),
753
- anything(),
754
- anything(),
755
- ),
756
- ).once()
757
- const [actualKey, actualData, symmetricOptions] = capture(
758
- mockKeyManager1.decryptWithSymmetricKey,
759
- ).first()
760
- expect(actualKey).toEqual(symmetricKey)
761
- expect(actualData).toEqual(encryptedEmptyKeys)
762
- expect(symmetricOptions).toBeDefined()
763
- expect(symmetricOptions.iv).toEqual(iv)
764
- })
765
-
766
- it('throws KeyArchiveDecodingError if serialized keys are unable to be deserialized', async () => {
767
- const secureArchive: SecureKeyArchive = {
768
- Type: 'Secure',
769
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
770
- IV: ivB64,
771
- Salt: saltB64,
772
- Rounds: 1,
773
- Keys: encryptedEmptyKeysB64,
774
- MetaInfo: {},
775
- }
776
-
777
- const keyArchive = new DefaultSudoKeyArchive(
778
- instance(mockKeyManager1),
779
- {
780
- archiveData: gzipSync(
781
- BufferUtil.fromString(JSON.stringify(secureArchive)),
782
- ),
783
- },
784
- )
785
-
786
- when(
787
- mockKeyManager1.decryptWithSymmetricKey(
788
- anything(),
789
- anything(),
790
- anything(),
791
- ),
792
- ).thenResolve(gzipSync(BufferUtil.fromString('not JSON')))
793
-
794
- await expect(keyArchive.unarchive(password)).rejects.toMatchError(
795
- new KeyArchiveDecodingError(),
796
- )
797
-
798
- verify(
799
- mockKeyManager1.generateSymmetricKeyFromPassword(
800
- anything(),
801
- anything(),
802
- anything(),
803
- ),
804
- ).once()
805
- const [actualPassword, actualSalt, actualOptions] = capture(
806
- mockKeyManager1.generateSymmetricKeyFromPassword,
807
- ).first()
808
- expect(actualPassword).toEqual(password)
809
- expect(actualSalt).toEqual(salt)
810
- expect(actualOptions).toEqual({ rounds: secureArchive.Rounds })
811
-
812
- verify(
813
- mockKeyManager1.decryptWithSymmetricKey(
814
- anything(),
815
- anything(),
816
- anything(),
817
- ),
818
- ).once()
819
- const [actualKey, actualData, symmetricOptions] = capture(
820
- mockKeyManager1.decryptWithSymmetricKey,
821
- ).first()
822
- expect(actualKey).toEqual(symmetricKey)
823
- expect(actualData).toEqual(encryptedEmptyKeys)
824
- expect(symmetricOptions).toBeDefined()
825
- expect(symmetricOptions.iv).toEqual(iv)
826
- })
827
-
828
- it('succeeds with an empty key array', async () => {
829
- const secureArchive: SecureKeyArchive = {
830
- Type: 'Secure',
831
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
832
- IV: ivB64,
833
- Salt: saltB64,
834
- Rounds: 1,
835
- Keys: encryptedEmptyKeysB64,
836
- MetaInfo: {},
837
- }
838
-
839
- const keyArchive = new DefaultSudoKeyArchive(
840
- instance(mockKeyManager1),
841
- {
842
- archiveData: gzipSync(
843
- BufferUtil.fromString(JSON.stringify(secureArchive)),
844
- ),
845
- },
846
- )
847
-
848
- await expect(keyArchive.unarchive(password)).resolves.toBeUndefined()
849
-
850
- verify(
851
- mockKeyManager1.generateSymmetricKeyFromPassword(
852
- anything(),
853
- anything(),
854
- anything(),
855
- ),
856
- ).once()
857
- const [actualPassword, actualSalt, actualOptions] = capture(
858
- mockKeyManager1.generateSymmetricKeyFromPassword,
859
- ).first()
860
- expect(actualPassword).toEqual(password)
861
- expect(actualSalt).toEqual(salt)
862
- expect(actualOptions).toEqual({ rounds: secureArchive.Rounds })
863
-
864
- verify(
865
- mockKeyManager1.decryptWithSymmetricKey(
866
- anything(),
867
- anything(),
868
- anything(),
869
- ),
870
- ).once()
871
- const [actualKey, actualData, symmetricOptions] = capture(
872
- mockKeyManager1.decryptWithSymmetricKey,
873
- ).first()
874
- expect(actualKey).toEqual(symmetricKey)
875
- expect(actualData).toEqual(encryptedEmptyKeys)
876
- expect(symmetricOptions.iv).toEqual(iv)
877
- })
878
-
879
- it('succeeds with an non-empty key array', async () => {
880
- const secureArchive: SecureKeyArchive = {
881
- Type: 'Secure',
882
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
883
- IV: ivB64,
884
- Salt: saltB64,
885
- Rounds: 1,
886
- Keys: encryptedKeysB64,
887
- MetaInfo: {},
888
- }
889
-
890
- const keyArchive = new DefaultSudoKeyArchive(
891
- instance(mockKeyManager1),
892
- {
893
- archiveData: gzipSync(
894
- BufferUtil.fromString(JSON.stringify(secureArchive)),
895
- ),
896
- },
897
- )
898
-
899
- await expect(keyArchive.unarchive(password)).resolves.toBeUndefined()
900
-
901
- verify(
902
- mockKeyManager1.generateSymmetricKeyFromPassword(
903
- anything(),
904
- anything(),
905
- anything(),
906
- ),
907
- ).once()
908
- const [actualPassword, actualSalt, actualOptions] = capture(
909
- mockKeyManager1.generateSymmetricKeyFromPassword,
910
- ).first()
911
- expect(actualPassword).toEqual(password)
912
- expect(actualSalt).toEqual(salt)
913
- expect(actualOptions).toEqual({ rounds: secureArchive.Rounds })
914
-
915
- verify(
916
- mockKeyManager1.decryptWithSymmetricKey(
917
- anything(),
918
- anything(),
919
- anything(),
920
- ),
921
- ).once()
922
- const [actualKey, actualData, symmetricOptions] = capture(
923
- mockKeyManager1.decryptWithSymmetricKey,
924
- ).first()
925
- expect(actualKey).toEqual(symmetricKey)
926
- expect(actualData).toEqual(encryptedKeys)
927
- expect(symmetricOptions.iv).toEqual(iv)
928
-
929
- keys.forEach((key) =>
930
- expect(
931
- keyArchive.getKeyData(keyManager1Namespace, key.Name, key.Type),
932
- ).toEqual(Base64.decode(key.Data)),
933
- )
934
- })
935
- it('succeeds with an non-empty key array', async () => {
936
- const secureArchive: SecureKeyArchive = {
937
- Type: 'Secure',
938
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
939
- IV: ivB64,
940
- Salt: saltB64,
941
- Rounds: 1,
942
- Keys: encryptedKeysB64,
943
- MetaInfo: {},
944
- }
945
-
946
- const keyArchive = new DefaultSudoKeyArchive(
947
- instance(mockKeyManager1),
948
- {
949
- archiveData: gzipSync(
950
- BufferUtil.fromString(JSON.stringify(secureArchive)),
951
- ),
952
- },
953
- )
954
-
955
- await expect(keyArchive.unarchive(password)).resolves.toBeUndefined()
956
-
957
- verify(
958
- mockKeyManager1.generateSymmetricKeyFromPassword(
959
- anything(),
960
- anything(),
961
- anything(),
962
- ),
963
- ).once()
964
- const [actualPassword, actualSalt, actualOptions] = capture(
965
- mockKeyManager1.generateSymmetricKeyFromPassword,
966
- ).first()
967
- expect(actualPassword).toEqual(password)
968
- expect(actualSalt).toEqual(salt)
969
- expect(actualOptions).toEqual({ rounds: secureArchive.Rounds })
970
-
971
- verify(
972
- mockKeyManager1.decryptWithSymmetricKey(
973
- anything(),
974
- anything(),
975
- anything(),
976
- ),
977
- ).once()
978
- const [actualKey, actualData, symmetricOptions] = capture(
979
- mockKeyManager1.decryptWithSymmetricKey,
980
- ).first()
981
- expect(actualKey).toEqual(symmetricKey)
982
- expect(actualData).toEqual(encryptedKeys)
983
- expect(symmetricOptions.iv).toEqual(iv)
984
-
985
- keys.forEach((key) =>
986
- expect(
987
- keyArchive.getKeyData(keyManager1Namespace, key.Name, key.Type),
988
- ).toEqual(Base64.decode(key.Data)),
989
- )
990
- })
991
- })
992
- })
993
-
994
- type AddFn = (data: ArrayBuffer, name: string) => Promise<void>
995
- function getAddFn(key: KeyArchiveKeyInfo): AddFn {
996
- switch (key.Type) {
997
- case KeyArchiveKeyType.Password:
998
- return key.NameSpace === keyManager1Namespace
999
- ? mockKeyManager1.addPassword
1000
- : mockKeyManager2.addPassword
1001
- case KeyArchiveKeyType.PublicKey:
1002
- return key.NameSpace === keyManager1Namespace
1003
- ? mockKeyManager1.addPublicKey
1004
- : mockKeyManager2.addPublicKey
1005
- case KeyArchiveKeyType.PrivateKey:
1006
- return key.NameSpace === keyManager1Namespace
1007
- ? mockKeyManager1.addPrivateKey
1008
- : mockKeyManager2.addPrivateKey
1009
- case KeyArchiveKeyType.SymmetricKey:
1010
- return key.NameSpace === keyManager1Namespace
1011
- ? mockKeyManager1.addSymmetricKey
1012
- : mockKeyManager2.addSymmetricKey
1013
- }
1014
- }
1015
-
1016
- const password1: KeyArchiveKeyInfo = {
1017
- Name: 'key-1-password',
1018
- NameSpace: keyManager1Namespace,
1019
- Data: Base64.encode(BufferUtil.fromString('1-key-1-password-data')),
1020
- Exportable: true,
1021
- Synchronizable: false,
1022
- Type: KeyArchiveKeyType.Password,
1023
- }
1024
- const publicKey1: KeyArchiveKeyInfo = {
1025
- Name: 'key-2-key-pair',
1026
- NameSpace: keyManager1Namespace,
1027
- Data: Base64.encode(BufferUtil.fromString('1-key-2-public-key-data')),
1028
- Exportable: true,
1029
- Synchronizable: false,
1030
- Type: KeyArchiveKeyType.PublicKey,
1031
- }
1032
- const privateKey1: KeyArchiveKeyInfo = {
1033
- Name: 'key-2-key-pair',
1034
- NameSpace: keyManager1Namespace,
1035
- Data: Base64.encode(BufferUtil.fromString('1-key-2-private-key-data')),
1036
- Exportable: true,
1037
- Synchronizable: false,
1038
- Type: KeyArchiveKeyType.PrivateKey,
1039
- }
1040
- const symmetricKey1: KeyArchiveKeyInfo = {
1041
- Name: 'key-3-symmetric',
1042
- NameSpace: keyManager1Namespace,
1043
- Data: Base64.encode(BufferUtil.fromString('1-key-3-symmetric-data')),
1044
- Exportable: true,
1045
- Synchronizable: false,
1046
- Type: KeyArchiveKeyType.SymmetricKey,
1047
- }
1048
- const password2: KeyArchiveKeyInfo = {
1049
- Name: 'key-1-password',
1050
- NameSpace: keyManager2Namespace,
1051
- Data: Base64.encode(BufferUtil.fromString('2-key-1-password-data')),
1052
- Exportable: true,
1053
- Synchronizable: false,
1054
- Type: KeyArchiveKeyType.Password,
1055
- }
1056
- const publicKey2: KeyArchiveKeyInfo = {
1057
- Name: 'key-2-key-pair',
1058
- NameSpace: keyManager2Namespace,
1059
- Data: Base64.encode(BufferUtil.fromString('2-key-2-public-key-data')),
1060
- Exportable: true,
1061
- Synchronizable: false,
1062
- Type: KeyArchiveKeyType.PublicKey,
1063
- }
1064
- const privateKey2: KeyArchiveKeyInfo = {
1065
- Name: 'key-2-key-pair',
1066
- NameSpace: keyManager2Namespace,
1067
- Data: Base64.encode(BufferUtil.fromString('2-key-2-private-key-data')),
1068
- Exportable: true,
1069
- Synchronizable: false,
1070
- Type: KeyArchiveKeyType.PrivateKey,
1071
- }
1072
-
1073
- const symmetricKey2: KeyArchiveKeyInfo = {
1074
- Name: 'key-3-symmetric',
1075
- NameSpace: keyManager2Namespace,
1076
- Data: Base64.encode(BufferUtil.fromString('2-key-3-symmetric-data')),
1077
- Exportable: true,
1078
- Synchronizable: false,
1079
- Type: KeyArchiveKeyType.SymmetricKey,
1080
- }
1081
- const keys: KeyArchiveKeyInfo[] = [
1082
- password1,
1083
- publicKey1,
1084
- privateKey1,
1085
- symmetricKey1,
1086
- password2,
1087
- publicKey2,
1088
- privateKey2,
1089
- symmetricKey2,
1090
- ]
1091
-
1092
- function keyArchiveKeyTypeToKeyDataKeyType(
1093
- keyArchiveInfoKeyType: KeyArchiveKeyType,
1094
- ): KeyDataKeyType {
1095
- switch (keyArchiveInfoKeyType) {
1096
- case KeyArchiveKeyType.Password:
1097
- return KeyDataKeyType.Password
1098
- case KeyArchiveKeyType.PrivateKey:
1099
- return KeyDataKeyType.RSAPrivateKey
1100
- case KeyArchiveKeyType.PublicKey:
1101
- return KeyDataKeyType.RSAPublicKey
1102
- case KeyArchiveKeyType.SymmetricKey:
1103
- return KeyDataKeyType.SymmetricKey
1104
- }
1105
- }
1106
- function keyArchiveInfoToKeyData(keyInfo: KeyArchiveKeyInfo): KeyData {
1107
- let format: KeyDataKeyFormat
1108
- switch (keyInfo.Type) {
1109
- case KeyArchiveKeyType.Password:
1110
- format = KeyDataKeyFormat.Raw
1111
- break
1112
- case KeyArchiveKeyType.PublicKey:
1113
- format = KeyDataKeyFormat.SPKI
1114
- break
1115
- case KeyArchiveKeyType.PrivateKey:
1116
- format = KeyDataKeyFormat.PKCS8
1117
- break
1118
- case KeyArchiveKeyType.SymmetricKey:
1119
- format = KeyDataKeyFormat.Raw
1120
- break
1121
- }
1122
- return {
1123
- namespace: keyInfo.NameSpace,
1124
- name: keyInfo.Name,
1125
- type: keyArchiveKeyTypeToKeyDataKeyType(keyInfo.Type),
1126
- data: Base64.decode(keyInfo.Data),
1127
- format,
1128
- }
1129
- }
1130
-
1131
- describe('saveKeys', () => {
1132
- let insecureKeyArchiveData: ArrayBuffer
1133
-
1134
- beforeEach(() => {
1135
- const insecureArchive: InsecureKeyArchive = {
1136
- Type: 'Insecure',
1137
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
1138
- Keys: keys,
1139
- MetaInfo: {},
1140
- }
1141
-
1142
- insecureKeyArchiveData = gzipSync(
1143
- BufferUtil.fromString(JSON.stringify(insecureArchive)),
1144
- )
1145
- })
1146
-
1147
- it('should save keys to correct key manager in correct way', async () => {
1148
- const keyArchive = new DefaultSudoKeyArchive(
1149
- [instance(mockKeyManager1), instance(mockKeyManager2)],
1150
- { archiveData: insecureKeyArchiveData },
1151
- )
1152
- await expect(keyArchive.unarchive(undefined)).resolves.toBeUndefined()
1153
- await expect(keyArchive.saveKeys()).resolves.toBeUndefined()
1154
-
1155
- verify(mockKeyManager1.addSymmetricKey(anything(), anything())).once()
1156
- verify(mockKeyManager1.addPublicKey(anything(), anything())).once()
1157
- verify(mockKeyManager1.addPrivateKey(anything(), anything())).once()
1158
- verify(mockKeyManager1.addPassword(anything(), anything())).once()
1159
- verify(mockKeyManager2.addSymmetricKey(anything(), anything())).once()
1160
- verify(mockKeyManager2.addPublicKey(anything(), anything())).once()
1161
- verify(mockKeyManager2.addPrivateKey(anything(), anything())).once()
1162
- verify(mockKeyManager2.addPassword(anything(), anything())).once()
1163
-
1164
- for (const key of keys) {
1165
- const addFn = getAddFn(key)
1166
- const [actualData, actualName] = capture(addFn).first()
1167
- expect(actualData).toEqual(Base64.decode(key.Data))
1168
- expect(actualName).toEqual(key.Name)
1169
- }
1170
- })
1171
-
1172
- it('should omit excluded key types', async () => {
1173
- const keyArchive = new DefaultSudoKeyArchive(
1174
- [instance(mockKeyManager1), instance(mockKeyManager2)],
1175
- {
1176
- archiveData: insecureKeyArchiveData,
1177
- excludedKeyTypes: new Set([KeyArchiveKeyType.PublicKey]),
1178
- },
1179
- )
1180
- await expect(keyArchive.unarchive(undefined)).resolves.toBeUndefined()
1181
- await expect(keyArchive.saveKeys()).resolves.toBeUndefined()
1182
-
1183
- verify(mockKeyManager1.addPublicKey(anything(), anything())).never()
1184
- verify(mockKeyManager2.addPublicKey(anything(), anything())).never()
1185
-
1186
- verify(mockKeyManager1.addSymmetricKey(anything(), anything())).once()
1187
- verify(mockKeyManager1.addPrivateKey(anything(), anything())).once()
1188
- verify(mockKeyManager1.addPassword(anything(), anything())).once()
1189
- verify(mockKeyManager2.addSymmetricKey(anything(), anything())).once()
1190
- verify(mockKeyManager2.addPrivateKey(anything(), anything())).once()
1191
- verify(mockKeyManager2.addPassword(anything(), anything())).once()
1192
-
1193
- for (const key of keys) {
1194
- if (key.Type === KeyArchiveKeyType.PublicKey) continue
1195
-
1196
- const addFn = getAddFn(key)
1197
- const [actualData, actualName] = capture(addFn).first()
1198
- expect(actualData).toEqual(Base64.decode(key.Data))
1199
- expect(actualName).toEqual(key.Name)
1200
- }
1201
- })
1202
-
1203
- it('should omit excluded key names', async () => {
1204
- const keyArchive = new DefaultSudoKeyArchive(
1205
- [instance(mockKeyManager1), instance(mockKeyManager2)],
1206
- {
1207
- archiveData: insecureKeyArchiveData,
1208
- excludedKeys: new Set([password1.Name]),
1209
- },
1210
- )
1211
- await expect(keyArchive.unarchive(undefined)).resolves.toBeUndefined()
1212
- await expect(keyArchive.saveKeys()).resolves.toBeUndefined()
1213
-
1214
- verify(mockKeyManager1.addPassword(anything(), anything())).never()
1215
- verify(mockKeyManager2.addPassword(anything(), anything())).never()
1216
-
1217
- verify(mockKeyManager1.addSymmetricKey(anything(), anything())).once()
1218
- verify(mockKeyManager1.addPublicKey(anything(), anything())).once()
1219
- verify(mockKeyManager1.addPrivateKey(anything(), anything())).once()
1220
- verify(mockKeyManager2.addSymmetricKey(anything(), anything())).once()
1221
- verify(mockKeyManager2.addPublicKey(anything(), anything())).once()
1222
- verify(mockKeyManager2.addPrivateKey(anything(), anything())).once()
1223
-
1224
- for (const key of keys) {
1225
- if (key.Name === password1.Name) continue
1226
-
1227
- const addFn = getAddFn(key)
1228
- const [actualData, actualName] = capture(addFn).first()
1229
- expect(actualData).toEqual(Base64.decode(key.Data))
1230
- expect(actualName).toEqual(key.Name)
1231
- }
1232
- })
1233
-
1234
- it('should omit keys without a matching key manager namespace', async () => {
1235
- const keyArchive = new DefaultSudoKeyArchive(
1236
- [instance(mockKeyManager1)],
1237
- {
1238
- archiveData: insecureKeyArchiveData,
1239
- },
1240
- )
1241
- await expect(keyArchive.unarchive(undefined)).resolves.toBeUndefined()
1242
- await expect(keyArchive.saveKeys()).resolves.toBeUndefined()
1243
-
1244
- verify(mockKeyManager1.addPassword(anything(), anything())).once()
1245
- verify(mockKeyManager1.addSymmetricKey(anything(), anything())).once()
1246
- verify(mockKeyManager1.addPublicKey(anything(), anything())).once()
1247
- verify(mockKeyManager1.addPrivateKey(anything(), anything())).once()
1248
-
1249
- verify(mockKeyManager2.addPassword(anything(), anything())).never()
1250
- verify(mockKeyManager2.addSymmetricKey(anything(), anything())).never()
1251
- verify(mockKeyManager2.addPublicKey(anything(), anything())).never()
1252
- verify(mockKeyManager2.addPrivateKey(anything(), anything())).never()
1253
-
1254
- for (const key of keys) {
1255
- if (key.NameSpace === keyManager2Namespace) continue
1256
-
1257
- const addFn = getAddFn(key)
1258
- const [actualData, actualName] = capture(addFn).first()
1259
- expect(actualData).toEqual(Base64.decode(key.Data))
1260
- expect(actualName).toEqual(key.Name)
1261
- }
1262
- })
1263
- })
1264
-
1265
- describe('loadKeys', () => {
1266
- it('should load keys from all key managers', async () => {
1267
- when(mockKeyManager1.exportKeys()).thenResolve(
1268
- keys
1269
- .filter((key) => key.NameSpace === keyManager1Namespace)
1270
- .map(keyArchiveInfoToKeyData),
1271
- )
1272
- when(mockKeyManager2.exportKeys()).thenResolve(
1273
- keys
1274
- .filter((key) => key.NameSpace === keyManager2Namespace)
1275
- .map(keyArchiveInfoToKeyData),
1276
- )
1277
-
1278
- const keyArchive = new DefaultSudoKeyArchive([
1279
- instance(mockKeyManager1),
1280
- instance(mockKeyManager2),
1281
- ])
1282
-
1283
- await expect(keyArchive.loadKeys()).resolves.toBeUndefined()
1284
-
1285
- keys.forEach((key) =>
1286
- expect(
1287
- keyArchive.containsKey(key.NameSpace, key.Name, key.Type),
1288
- ).toEqual(true),
1289
- )
1290
-
1291
- verify(mockKeyManager1.exportKeys()).once()
1292
- verify(mockKeyManager2.exportKeys()).once()
1293
- })
1294
-
1295
- it('should omit keys from excluded key types', async () => {
1296
- when(mockKeyManager1.exportKeys()).thenResolve(
1297
- keys
1298
- .filter((key) => key.NameSpace === keyManager1Namespace)
1299
- .map(keyArchiveInfoToKeyData),
1300
- )
1301
- when(mockKeyManager2.exportKeys()).thenResolve(
1302
- keys
1303
- .filter((key) => key.NameSpace === keyManager2Namespace)
1304
- .map(keyArchiveInfoToKeyData),
1305
- )
1306
-
1307
- const keyArchive = new DefaultSudoKeyArchive(
1308
- [instance(mockKeyManager1), instance(mockKeyManager2)],
1309
- {
1310
- excludedKeyTypes: new Set([KeyArchiveKeyType.PublicKey]),
1311
- },
1312
- )
1313
-
1314
- await expect(keyArchive.loadKeys()).resolves.toBeUndefined()
1315
-
1316
- keys.forEach((key) =>
1317
- expect(
1318
- keyArchive.containsKey(key.NameSpace, key.Name, key.Type),
1319
- ).toEqual(key.Type !== KeyArchiveKeyType.PublicKey),
1320
- )
1321
-
1322
- verify(mockKeyManager1.exportKeys()).once()
1323
- verify(mockKeyManager2.exportKeys()).once()
1324
- })
1325
-
1326
- it('should omit keys with excluded names', async () => {
1327
- when(mockKeyManager1.exportKeys()).thenResolve(
1328
- keys
1329
- .filter((key) => key.NameSpace === keyManager1Namespace)
1330
- .map(keyArchiveInfoToKeyData),
1331
- )
1332
- when(mockKeyManager2.exportKeys()).thenResolve(
1333
- keys
1334
- .filter((key) => key.NameSpace === keyManager2Namespace)
1335
- .map(keyArchiveInfoToKeyData),
1336
- )
1337
-
1338
- const keyArchive = new DefaultSudoKeyArchive(
1339
- [instance(mockKeyManager1), instance(mockKeyManager2)],
1340
- {
1341
- excludedKeys: new Set([password1.Name]),
1342
- },
1343
- )
1344
-
1345
- await expect(keyArchive.loadKeys()).resolves.toBeUndefined()
1346
-
1347
- keys.forEach((key) =>
1348
- expect(
1349
- keyArchive.containsKey(key.NameSpace, key.Name, key.Type),
1350
- ).toEqual(key.Name !== password1.Name),
1351
- )
1352
-
1353
- verify(mockKeyManager1.exportKeys()).once()
1354
- verify(mockKeyManager2.exportKeys()).once()
1355
- })
1356
- })
1357
-
1358
- describe('archive', () => {
1359
- const metaInfoRecord = { some: 'meta', info: 'provided' }
1360
- const metaInfo = new Map<string, string>(
1361
- Object.entries(metaInfoRecord).map(([k, v]) => [k, v]),
1362
- )
1363
-
1364
- beforeEach(() => {
1365
- when(mockKeyManager1.exportKeys()).thenResolve(
1366
- keys
1367
- .filter((key) => key.NameSpace === keyManager1Namespace)
1368
- .map(keyArchiveInfoToKeyData),
1369
- )
1370
- when(mockKeyManager2.exportKeys()).thenResolve(
1371
- keys
1372
- .filter((key) => key.NameSpace === keyManager2Namespace)
1373
- .map(keyArchiveInfoToKeyData),
1374
- )
1375
- })
1376
-
1377
- describe('without password', () => {
1378
- it.each`
1379
- name | withMetaInfo
1380
- ${'with MetaInfo'} | ${true}
1381
- ${'without MetaInfo'} | ${false}
1382
- `(
1383
- 'should produce an insecure archive $name',
1384
- async ({ withMetaInfo }) => {
1385
- const keyArchive = new DefaultSudoKeyArchive(
1386
- [instance(mockKeyManager1), instance(mockKeyManager2)],
1387
- { metaInfo: withMetaInfo ? metaInfo : undefined },
1388
- )
1389
-
1390
- await expect(keyArchive.loadKeys()).resolves.toBeUndefined()
1391
-
1392
- const archive = await keyArchive.archive(undefined)
1393
- const unzipped = gunzipSync(new Uint8Array(archive))
1394
- const string = BufferUtil.toString(unzipped)
1395
- const deserialized = JSON.parse(string)
1396
- const decoded = InsecureKeyArchiveCodec.decode(deserialized)
1397
- expect(isRight(decoded)).toEqual(true)
1398
- if (!isRight(decoded)) throw new Error('decoded unexpectedly lefty')
1399
- const insecureKeyArchive = decoded.right
1400
- expect(insecureKeyArchive).toMatchObject({
1401
- Type: 'Insecure',
1402
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
1403
- MetaInfo: withMetaInfo ? metaInfoRecord : {},
1404
- })
1405
- expect(insecureKeyArchive.Keys).toHaveLength(keys.length)
1406
- keys.forEach((key) =>
1407
- expect(insecureKeyArchive.Keys).toContainEqual(key),
1408
- )
1409
- },
1410
- )
1411
- })
1412
-
1413
- describe('with password', () => {
1414
- const encryptedKeys = BufferUtil.fromString('encrypted-keys')
1415
-
1416
- it.each`
1417
- name | withMetaInfo
1418
- ${'with MetaInfo'} | ${true}
1419
- ${'without MetaInfo'} | ${false}
1420
- `(
1421
- 'should produce an insecure archive $name',
1422
- async ({ withMetaInfo }) => {
1423
- const keyArchive = new DefaultSudoKeyArchive(
1424
- [instance(mockKeyManager1), instance(mockKeyManager2)],
1425
- { metaInfo: withMetaInfo ? metaInfo : undefined },
1426
- )
1427
-
1428
- await expect(keyArchive.loadKeys()).resolves.toBeUndefined()
1429
-
1430
- when(mockKeyManager1.generateRandomData(anything())).thenResolve(
1431
- salt,
1432
- iv,
1433
- )
1434
- when(
1435
- mockKeyManager1.generateSymmetricKeyFromPassword(
1436
- anything(),
1437
- anything(),
1438
- anything(),
1439
- ),
1440
- ).thenResolve(symmetricKey)
1441
- when(
1442
- mockKeyManager1.encryptWithSymmetricKey(
1443
- anything(),
1444
- anything(),
1445
- anything(),
1446
- ),
1447
- ).thenResolve(encryptedKeys)
1448
-
1449
- const archive = await keyArchive.archive(password)
1450
-
1451
- const unzipped = gunzipSync(new Uint8Array(archive))
1452
- const string = BufferUtil.toString(unzipped)
1453
- const deserialized = JSON.parse(string)
1454
- const decoded = SecureKeyArchiveCodec.decode(deserialized)
1455
- expect(isRight(decoded)).toEqual(true)
1456
- if (!isRight(decoded)) throw new Error('decoded unexpectedly lefty')
1457
- const secureKeyArchive = decoded.right
1458
- expect(secureKeyArchive).toEqual({
1459
- Type: 'Secure',
1460
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
1461
- IV: ivB64,
1462
- Salt: saltB64,
1463
- Rounds: SudoCryptoProviderDefaults.pbkdfRounds,
1464
- Keys: Base64.encode(encryptedKeys),
1465
- MetaInfo: withMetaInfo ? metaInfoRecord : {},
1466
- })
1467
-
1468
- verify(mockKeyManager1.exportKeys()).once()
1469
- verify(mockKeyManager2.exportKeys()).once()
1470
-
1471
- verify(mockKeyManager1.generateRandomData(anything())).twice()
1472
- const [actualSaltSize] = capture(
1473
- mockKeyManager1.generateRandomData,
1474
- ).first()
1475
- expect(actualSaltSize).toEqual(
1476
- SudoCryptoProviderDefaults.pbkdfSaltSize,
1477
- )
1478
- const [actualIVSize] = capture(
1479
- mockKeyManager1.generateRandomData,
1480
- ).second()
1481
- expect(actualIVSize).toEqual(SudoCryptoProviderDefaults.aesIVSize)
1482
-
1483
- verify(
1484
- mockKeyManager1.generateSymmetricKeyFromPassword(
1485
- anything(),
1486
- anything(),
1487
- anything(),
1488
- ),
1489
- ).once()
1490
- const [actualPassword, actualSalt, actualOptions] = capture(
1491
- mockKeyManager1.generateSymmetricKeyFromPassword,
1492
- ).first()
1493
- expect(actualPassword).toEqual(password)
1494
- expect(actualSalt).toEqual(salt)
1495
- expect(actualOptions).toEqual({
1496
- rounds: SudoCryptoProviderDefaults.pbkdfRounds,
1497
- })
1498
-
1499
- verify(
1500
- mockKeyManager1.encryptWithSymmetricKey(
1501
- anything(),
1502
- anything(),
1503
- anything(),
1504
- ),
1505
- ).once()
1506
- const [actualKey, actualData, symmetricOptions] = capture(
1507
- mockKeyManager1.encryptWithSymmetricKey,
1508
- ).first()
1509
- expect(actualKey).toEqual(symmetricKey)
1510
- expect(symmetricOptions.iv).toEqual(iv)
1511
-
1512
- const uncompressedData = gunzipSync(new Uint8Array(actualData))
1513
- const deserializedData = JSON.parse(
1514
- BufferUtil.toString(uncompressedData),
1515
- )
1516
- const decodedData = t
1517
- .array(KeyArchiveKeyInfoCodec)
1518
- .decode(deserializedData)
1519
- expect(isRight(decodedData)).toEqual(true)
1520
- if (isLeft(decodedData)) {
1521
- throw new Error('decodedData unexpectedly lefty')
1522
- }
1523
- const actualKeys = decodedData.right
1524
- expect(actualKeys).toHaveLength(keys.length)
1525
- keys.forEach((key) => expect(actualKeys).toContainEqual(key))
1526
- },
1527
- )
1528
- })
1529
- })
1530
-
1531
- describe('getKeyData', () => {
1532
- it('should throw a KeyNotFoundError if archive does not contain requested key', () => {
1533
- const insecureArchive: InsecureKeyArchive = {
1534
- Type: 'Insecure',
1535
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
1536
- Keys: [],
1537
- MetaInfo: {},
1538
- }
1539
-
1540
- const keyArchive = new DefaultSudoKeyArchive(instance(mockKeyManager1), {
1541
- archiveData: gzipSync(
1542
- BufferUtil.fromString(JSON.stringify(insecureArchive)),
1543
- ),
1544
- })
1545
-
1546
- expect(() =>
1547
- keyArchive.getKeyData(
1548
- keyManager1Namespace,
1549
- 'not-found',
1550
- KeyArchiveKeyType.Password,
1551
- ),
1552
- ).toThrowErrorMatching(new KeyNotFoundError())
1553
- })
1554
-
1555
- it('should return keys from the archive', async () => {
1556
- const insecureArchive: InsecureKeyArchive = {
1557
- Type: 'Insecure',
1558
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
1559
- Keys: keys,
1560
- MetaInfo: {},
1561
- }
1562
-
1563
- const keyArchive = new DefaultSudoKeyArchive(instance(mockKeyManager1), {
1564
- archiveData: gzipSync(
1565
- BufferUtil.fromString(JSON.stringify(insecureArchive)),
1566
- ),
1567
- })
1568
-
1569
- await keyArchive.unarchive(undefined)
1570
-
1571
- keys.forEach((key) =>
1572
- expect(
1573
- keyArchive.getKeyData(key.NameSpace, key.Name, key.Type),
1574
- ).toEqual(Base64.decode(key.Data)),
1575
- )
1576
- })
1577
- })
1578
-
1579
- describe('reset', () => {
1580
- it('should clear out keys from the archive', async () => {
1581
- const insecureArchive: InsecureKeyArchive = {
1582
- Type: 'Insecure',
1583
- Version: DefaultSudoKeyArchive.CURRENT_ARCHIVE_VERSION,
1584
- Keys: keys,
1585
- MetaInfo: {},
1586
- }
1587
-
1588
- const keyArchive = new DefaultSudoKeyArchive(instance(mockKeyManager1), {
1589
- archiveData: gzipSync(
1590
- BufferUtil.fromString(JSON.stringify(insecureArchive)),
1591
- ),
1592
- })
1593
-
1594
- await keyArchive.unarchive(undefined)
1595
-
1596
- keys.forEach((key) =>
1597
- expect(
1598
- keyArchive.containsKey(key.NameSpace, key.Name, key.Type),
1599
- ).toEqual(true),
1600
- )
1601
- keyArchive.reset()
1602
- keys.forEach((key) =>
1603
- expect(
1604
- keyArchive.containsKey(key.NameSpace, key.Name, key.Type),
1605
- ).toEqual(false),
1606
- )
1607
- })
1608
- })
1609
- })