@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.
- package/lib/configurationManager/defaultConfigurationManager.js +3 -5
- package/package.json +2 -3
- package/.babelrc +0 -10
- package/.eslintrc.js +0 -91
- package/.gitignore +0 -14
- package/.gitlab-ci.yml +0 -101
- package/.npmignore +0 -1
- package/.prettierignore +0 -3
- package/.prettierrc.js +0 -7
- package/.publisher.json +0 -7
- package/.vscode/settings.json +0 -5
- package/.yarn/releases/yarn-1.22.19.cjs +0 -147529
- package/.yarnrc +0 -5
- package/bin/outdated-with-suppression.sh +0 -203
- package/bin/suppress-audit.sh +0 -15
- package/bin/suppress-outdated.sh +0 -60
- package/bin/yarn-audit-with-suppression.sh +0 -19
- package/dependencies-report.json +0 -640
- package/docs/.nojekyll +0 -1
- package/docs/assets/highlight.css +0 -57
- package/docs/assets/main.js +0 -54
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1224
- package/docs/assets/widgets.png +0 -0
- package/docs/assets/widgets@2x.png +0 -0
- package/docs/classes/AccountLockedError.html +0 -163
- package/docs/classes/AuthenticationError.html +0 -169
- package/docs/classes/Base64.html +0 -245
- package/docs/classes/Buffer.html +0 -158
- package/docs/classes/ConfigurationNotSetError.html +0 -164
- package/docs/classes/ConfigurationSetNotFoundError.html +0 -168
- package/docs/classes/DecodeError.html +0 -168
- package/docs/classes/DefaultConfigurationManager.html +0 -213
- package/docs/classes/DefaultLogger.html +0 -291
- package/docs/classes/DefaultSudoKeyArchive.html +0 -363
- package/docs/classes/DefaultSudoKeyManager.html +0 -814
- package/docs/classes/FatalError.html +0 -169
- package/docs/classes/IllegalArgumentError.html +0 -168
- package/docs/classes/IllegalStateError.html +0 -169
- package/docs/classes/InsufficientEntitlementsError.html +0 -164
- package/docs/classes/InvalidOwnershipProofError.html +0 -163
- package/docs/classes/InvalidTokenError.html +0 -163
- package/docs/classes/KeyArchiveDecodingError.html +0 -168
- package/docs/classes/KeyArchiveIncorrectPasswordError.html +0 -168
- package/docs/classes/KeyArchiveMissingError.html +0 -168
- package/docs/classes/KeyArchiveNoPasswordRequiredError.html +0 -168
- package/docs/classes/KeyArchivePasswordRequiredError.html +0 -168
- package/docs/classes/KeyArchiveTypeError.html +0 -168
- package/docs/classes/KeyArchiveUnknownKeyTypeError.html +0 -168
- package/docs/classes/KeyArchiveVersionError.html +0 -168
- package/docs/classes/KeyNotFoundError.html +0 -168
- package/docs/classes/KeyStoreNotExportableError.html +0 -168
- package/docs/classes/LimitExceededError.html +0 -164
- package/docs/classes/NoEntitlementsError.html +0 -163
- package/docs/classes/NotAuthorizedError.html +0 -169
- package/docs/classes/NotRegisteredError.html +0 -168
- package/docs/classes/NotSignedInError.html +0 -164
- package/docs/classes/OperationNotImplementedError.html +0 -168
- package/docs/classes/RegisterError.html +0 -169
- package/docs/classes/RequestFailedError.html +0 -189
- package/docs/classes/ServiceError.html +0 -170
- package/docs/classes/SignOutError.html +0 -168
- package/docs/classes/SudoCryptoProviderDefaults.html +0 -106
- package/docs/classes/UnknownGraphQLError.html +0 -169
- package/docs/classes/UnrecognizedAlgorithmError.html +0 -168
- package/docs/classes/UserNotConfirmedError.html +0 -164
- package/docs/classes/VersionMismatchError.html +0 -166
- package/docs/enums/CachePolicy.html +0 -72
- package/docs/enums/EncryptionAlgorithm.html +0 -80
- package/docs/enums/KeyArchiveKeyType.html +0 -86
- package/docs/enums/KeyDataKeyFormat.html +0 -92
- package/docs/enums/KeyDataKeyType.html +0 -85
- package/docs/enums/ListOperationResultStatus.html +0 -85
- package/docs/enums/PublicKeyFormat.html +0 -68
- package/docs/functions/isAppSyncNetworkError.html +0 -147
- package/docs/functions/isInsecureKeyArchive.html +0 -147
- package/docs/functions/isSecureKeyArchive.html +0 -147
- package/docs/functions/isUnrecognizedKeyArchive.html +0 -147
- package/docs/functions/keyArchiveInfoFromKeyData.html +0 -147
- package/docs/functions/keyArchiveKeyTypeFromKeyDataKeyType.html +0 -147
- package/docs/functions/mapGraphQLToClientError.html +0 -154
- package/docs/functions/mapNetworkErrorToClientError.html +0 -154
- package/docs/index.html +0 -146
- package/docs/interfaces/AsymmetricEncryptionOptions.html +0 -68
- package/docs/interfaces/BooleanFilter.html +0 -75
- package/docs/interfaces/ConfigurationManager.html +0 -200
- package/docs/interfaces/KeyData.html +0 -106
- package/docs/interfaces/ListOperationFailureResult.html +0 -76
- package/docs/interfaces/ListOperationPartialResult.html +0 -102
- package/docs/interfaces/ListOperationSuccessResult.html +0 -90
- package/docs/interfaces/ListOutput.html +0 -80
- package/docs/interfaces/Logger.html +0 -251
- package/docs/interfaces/Owner.html +0 -72
- package/docs/interfaces/PublicKey.html +0 -72
- package/docs/interfaces/ServiceCompatibilityInfo.html +0 -110
- package/docs/interfaces/StringFilter.html +0 -82
- package/docs/interfaces/SudoCryptoProvider.html +0 -865
- package/docs/interfaces/SudoKeyArchive.html +0 -257
- package/docs/interfaces/SudoKeyManager.html +0 -848
- package/docs/interfaces/SymmetricEncryptionOptions.html +0 -75
- package/docs/interfaces/ValidationResult.html +0 -83
- package/docs/modules.html +0 -248
- package/docs/types/AppSyncError.html +0 -138
- package/docs/types/AppSyncNetworkError.html +0 -138
- package/docs/types/InsecureKeyArchive.html +0 -138
- package/docs/types/KeyArchive.html +0 -138
- package/docs/types/KeyArchiveKeyInfo.html +0 -154
- package/docs/types/KeyArchiveKeyInfoDecoded.html +0 -138
- package/docs/types/ListOperationResult.html +0 -148
- package/docs/types/SecureKeyArchive.html +0 -138
- package/docs/types/Subset.html +0 -144
- package/docs/types/UnrecognizedKeyArchive.html +0 -138
- package/docs/variables/CURRENT_ARCHIVE_VERSION.html +0 -138
- package/docs/variables/InsecureKeyArchiveCodec.html +0 -138
- package/docs/variables/InsecureKeyArchiveType.html +0 -138
- package/docs/variables/KeyArchiveCodec.html +0 -138
- package/docs/variables/KeyArchiveKeyInfoArrayCodec.html +0 -138
- package/docs/variables/KeyArchiveKeyInfoCodec.html +0 -138
- package/docs/variables/KeyArchiveKeyTypeCodec.html +0 -138
- package/docs/variables/SecureKeyArchiveCodec.html +0 -138
- package/docs/variables/SecureKeyArchiveType.html +0 -138
- package/docs/variables/UnrecognizedKeyArchiveCodec.html +0 -138
- package/github/.babelrc +0 -10
- package/github/.eslintrc.js +0 -91
- package/github/.gitignore +0 -14
- package/github/.gitlab-ci.yml +0 -101
- package/github/.npmignore +0 -1
- package/github/.prettierignore +0 -3
- package/github/.prettierrc.js +0 -7
- package/github/.publisher.json +0 -7
- package/github/.vscode/settings.json +0 -5
- package/github/.yarn/releases/yarn-1.22.19.cjs +0 -147529
- package/github/.yarnrc +0 -5
- package/github/CHANGELOG.md +0 -51
- package/github/README.md +0 -8
- package/github/bin/outdated-with-suppression.sh +0 -203
- package/github/bin/suppress-audit.sh +0 -15
- package/github/bin/suppress-outdated.sh +0 -60
- package/github/bin/yarn-audit-with-suppression.sh +0 -19
- package/github/docs/.nojekyll +0 -1
- package/github/docs/assets/highlight.css +0 -57
- package/github/docs/assets/main.js +0 -54
- package/github/docs/assets/search.js +0 -1
- package/github/docs/assets/style.css +0 -1224
- package/github/docs/assets/widgets.png +0 -0
- package/github/docs/assets/widgets@2x.png +0 -0
- package/github/docs/classes/AccountLockedError.html +0 -163
- package/github/docs/classes/AuthenticationError.html +0 -169
- package/github/docs/classes/Base64.html +0 -245
- package/github/docs/classes/Buffer.html +0 -158
- package/github/docs/classes/ConfigurationNotSetError.html +0 -164
- package/github/docs/classes/ConfigurationSetNotFoundError.html +0 -168
- package/github/docs/classes/DecodeError.html +0 -168
- package/github/docs/classes/DefaultConfigurationManager.html +0 -213
- package/github/docs/classes/DefaultLogger.html +0 -291
- package/github/docs/classes/DefaultSudoKeyArchive.html +0 -363
- package/github/docs/classes/DefaultSudoKeyManager.html +0 -814
- package/github/docs/classes/FatalError.html +0 -169
- package/github/docs/classes/IllegalArgumentError.html +0 -168
- package/github/docs/classes/IllegalStateError.html +0 -169
- package/github/docs/classes/InsufficientEntitlementsError.html +0 -164
- package/github/docs/classes/InvalidOwnershipProofError.html +0 -163
- package/github/docs/classes/InvalidTokenError.html +0 -163
- package/github/docs/classes/KeyArchiveDecodingError.html +0 -168
- package/github/docs/classes/KeyArchiveIncorrectPasswordError.html +0 -168
- package/github/docs/classes/KeyArchiveMissingError.html +0 -168
- package/github/docs/classes/KeyArchiveNoPasswordRequiredError.html +0 -168
- package/github/docs/classes/KeyArchivePasswordRequiredError.html +0 -168
- package/github/docs/classes/KeyArchiveTypeError.html +0 -168
- package/github/docs/classes/KeyArchiveUnknownKeyTypeError.html +0 -168
- package/github/docs/classes/KeyArchiveVersionError.html +0 -168
- package/github/docs/classes/KeyNotFoundError.html +0 -168
- package/github/docs/classes/KeyStoreNotExportableError.html +0 -168
- package/github/docs/classes/LimitExceededError.html +0 -164
- package/github/docs/classes/NoEntitlementsError.html +0 -163
- package/github/docs/classes/NotAuthorizedError.html +0 -169
- package/github/docs/classes/NotRegisteredError.html +0 -168
- package/github/docs/classes/NotSignedInError.html +0 -164
- package/github/docs/classes/OperationNotImplementedError.html +0 -168
- package/github/docs/classes/RegisterError.html +0 -169
- package/github/docs/classes/RequestFailedError.html +0 -189
- package/github/docs/classes/ServiceError.html +0 -170
- package/github/docs/classes/SignOutError.html +0 -168
- package/github/docs/classes/SudoCryptoProviderDefaults.html +0 -106
- package/github/docs/classes/UnknownGraphQLError.html +0 -169
- package/github/docs/classes/UnrecognizedAlgorithmError.html +0 -168
- package/github/docs/classes/UserNotConfirmedError.html +0 -164
- package/github/docs/classes/VersionMismatchError.html +0 -166
- package/github/docs/enums/CachePolicy.html +0 -72
- package/github/docs/enums/EncryptionAlgorithm.html +0 -80
- package/github/docs/enums/KeyArchiveKeyType.html +0 -86
- package/github/docs/enums/KeyDataKeyFormat.html +0 -92
- package/github/docs/enums/KeyDataKeyType.html +0 -85
- package/github/docs/enums/ListOperationResultStatus.html +0 -85
- package/github/docs/enums/PublicKeyFormat.html +0 -68
- package/github/docs/functions/isAppSyncNetworkError.html +0 -147
- package/github/docs/functions/isInsecureKeyArchive.html +0 -147
- package/github/docs/functions/isSecureKeyArchive.html +0 -147
- package/github/docs/functions/isUnrecognizedKeyArchive.html +0 -147
- package/github/docs/functions/keyArchiveInfoFromKeyData.html +0 -147
- package/github/docs/functions/keyArchiveKeyTypeFromKeyDataKeyType.html +0 -147
- package/github/docs/functions/mapGraphQLToClientError.html +0 -154
- package/github/docs/functions/mapNetworkErrorToClientError.html +0 -154
- package/github/docs/index.html +0 -146
- package/github/docs/interfaces/AsymmetricEncryptionOptions.html +0 -68
- package/github/docs/interfaces/BooleanFilter.html +0 -75
- package/github/docs/interfaces/ConfigurationManager.html +0 -200
- package/github/docs/interfaces/KeyData.html +0 -106
- package/github/docs/interfaces/ListOperationFailureResult.html +0 -76
- package/github/docs/interfaces/ListOperationPartialResult.html +0 -102
- package/github/docs/interfaces/ListOperationSuccessResult.html +0 -90
- package/github/docs/interfaces/ListOutput.html +0 -80
- package/github/docs/interfaces/Logger.html +0 -251
- package/github/docs/interfaces/Owner.html +0 -72
- package/github/docs/interfaces/PublicKey.html +0 -72
- package/github/docs/interfaces/ServiceCompatibilityInfo.html +0 -110
- package/github/docs/interfaces/StringFilter.html +0 -82
- package/github/docs/interfaces/SudoCryptoProvider.html +0 -865
- package/github/docs/interfaces/SudoKeyArchive.html +0 -257
- package/github/docs/interfaces/SudoKeyManager.html +0 -848
- package/github/docs/interfaces/SymmetricEncryptionOptions.html +0 -75
- package/github/docs/interfaces/ValidationResult.html +0 -83
- package/github/docs/modules.html +0 -248
- package/github/docs/types/AppSyncError.html +0 -138
- package/github/docs/types/AppSyncNetworkError.html +0 -138
- package/github/docs/types/InsecureKeyArchive.html +0 -138
- package/github/docs/types/KeyArchive.html +0 -138
- package/github/docs/types/KeyArchiveKeyInfo.html +0 -154
- package/github/docs/types/KeyArchiveKeyInfoDecoded.html +0 -138
- package/github/docs/types/ListOperationResult.html +0 -148
- package/github/docs/types/SecureKeyArchive.html +0 -138
- package/github/docs/types/Subset.html +0 -144
- package/github/docs/types/UnrecognizedKeyArchive.html +0 -138
- package/github/docs/variables/CURRENT_ARCHIVE_VERSION.html +0 -138
- package/github/docs/variables/InsecureKeyArchiveCodec.html +0 -138
- package/github/docs/variables/InsecureKeyArchiveType.html +0 -138
- package/github/docs/variables/KeyArchiveCodec.html +0 -138
- package/github/docs/variables/KeyArchiveKeyInfoArrayCodec.html +0 -138
- package/github/docs/variables/KeyArchiveKeyInfoCodec.html +0 -138
- package/github/docs/variables/KeyArchiveKeyTypeCodec.html +0 -138
- package/github/docs/variables/SecureKeyArchiveCodec.html +0 -138
- package/github/docs/variables/SecureKeyArchiveType.html +0 -138
- package/github/docs/variables/UnrecognizedKeyArchiveCodec.html +0 -138
- package/github/jest.config.json +0 -14
- package/github/package.json +0 -91
- package/github/src/configurationManager/defaultConfigurationManager.ts +0 -281
- package/github/src/errors/error.ts +0 -469
- package/github/src/index.ts +0 -8
- package/github/src/logging/bunyanLogger.ts +0 -47
- package/github/src/logging/logger.ts +0 -164
- package/github/src/sudoKeyArchive/index.ts +0 -4
- package/github/src/sudoKeyArchive/keyArchive.ts +0 -120
- package/github/src/sudoKeyArchive/keyInfo.ts +0 -47
- package/github/src/sudoKeyArchive/keyType.ts +0 -50
- package/github/src/sudoKeyArchive/sudoKeyArchive.ts +0 -591
- package/github/src/sudoKeyManager/index.ts +0 -4
- package/github/src/sudoKeyManager/keyData.ts +0 -60
- package/github/src/sudoKeyManager/publicKey.ts +0 -9
- package/github/src/sudoKeyManager/sudoCryptoProvider.ts +0 -416
- package/github/src/sudoKeyManager/sudoKeyManager.ts +0 -609
- package/github/src/types/types.ts +0 -129
- package/github/src/utils/base64.ts +0 -75
- package/github/src/utils/buffer.ts +0 -39
- package/github/test/integration/defaultConfigurationManager.spec.ts +0 -85
- package/github/test/matchers.ts +0 -122
- package/github/test/unit/configurationManager/defaultConfigurationManager.spec.ts +0 -506
- package/github/test/unit/errors/error.spec.ts +0 -115
- package/github/test/unit/keyType.spec.ts +0 -54
- package/github/test/unit/logging/logger.spec.ts +0 -182
- package/github/test/unit/sudoKeyArchive.spec.ts +0 -1609
- package/github/test/unit/sudoKeyManager.spec.ts +0 -1045
- package/github/test/unit/utils/base64.spec.ts +0 -45
- package/github/test/unit/utils/buffer.spec.ts +0 -45
- package/github/test/unit/utils/listOperationResult.spec.ts +0 -84
- package/github/tsconfig.json +0 -20
- package/github/tsconfig.test.json +0 -7
- package/github/yarn.lock +0 -5922
- package/jest.config.json +0 -14
- package/src/configurationManager/defaultConfigurationManager.ts +0 -281
- package/src/errors/error.ts +0 -469
- package/src/index.ts +0 -8
- package/src/logging/bunyanLogger.ts +0 -47
- package/src/logging/logger.ts +0 -164
- package/src/sudoKeyArchive/index.ts +0 -4
- package/src/sudoKeyArchive/keyArchive.ts +0 -120
- package/src/sudoKeyArchive/keyInfo.ts +0 -47
- package/src/sudoKeyArchive/keyType.ts +0 -50
- package/src/sudoKeyArchive/sudoKeyArchive.ts +0 -591
- package/src/sudoKeyManager/index.ts +0 -4
- package/src/sudoKeyManager/keyData.ts +0 -60
- package/src/sudoKeyManager/publicKey.ts +0 -9
- package/src/sudoKeyManager/sudoCryptoProvider.ts +0 -416
- package/src/sudoKeyManager/sudoKeyManager.ts +0 -609
- package/src/types/types.ts +0 -129
- package/src/utils/base64.ts +0 -75
- package/src/utils/buffer.ts +0 -39
- package/test/integration/defaultConfigurationManager.spec.ts +0 -85
- package/test/matchers.ts +0 -122
- package/test/unit/configurationManager/defaultConfigurationManager.spec.ts +0 -506
- package/test/unit/errors/error.spec.ts +0 -115
- package/test/unit/keyType.spec.ts +0 -54
- package/test/unit/logging/logger.spec.ts +0 -182
- package/test/unit/sudoKeyArchive.spec.ts +0 -1609
- package/test/unit/sudoKeyManager.spec.ts +0 -1045
- package/test/unit/utils/base64.spec.ts +0 -45
- package/test/unit/utils/buffer.spec.ts +0 -45
- package/test/unit/utils/listOperationResult.spec.ts +0 -84
- package/tsconfig.json +0 -20
- package/tsconfig.test.json +0 -7
- 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
|
-
})
|