Skip to content

Commit bab59c5

Browse files
committed
refactor!: fixed eslint warnings and refactored crypto layer provider to be more readable
BREAKING CHANGE: * Renamed `CryptoLayerProviderConfig` to `CryptoLayerProviderFilter`. * Renamed `providers` key of `CryptoLayerConfig` to `providersToBeInitialized`. * Refactored `CryptoLayerConfig` to be an interface.
1 parent 23dab29 commit bab59c5

File tree

4 files changed

+172
-55
lines changed

4 files changed

+172
-55
lines changed

src/CryptoLayerConfig.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
12
import { AdditionalConfig, ProviderConfig, ProviderFactoryFunctions, SecurityLevel } from "@nmshd/rs-crypto-types";
23

34
/**
4-
* Type holding functions for listing and creating providers and configuration for initializing the key meta data store.
5+
* Interface holding functions for listing and creating providers and configuration for initializing the key meta data store.
56
*
67
* @property factoryFunctions - Functions that list providers or create providers.
78
* @property keyMetadataStoreConfig - Configuration needed for saving key metadata.
89
* @property keyMetadataStoreAuth - ~~Optional~~ configuration for authenticating key metadata.
9-
* @property providers - Array of providers to initalize.
10+
* @property providersToBeInitialized - Array of providers to initalize.
1011
*/
11-
export type CryptoLayerConfig = {
12+
export interface CryptoLayerConfig {
1213
factoryFunctions: ProviderFactoryFunctions;
1314
keyMetadataStoreConfig: Extract<AdditionalConfig, { KVStoreConfig: any } | { FileStoreConfig: any }>;
1415
keyMetadataStoreAuth?: Extract<
1516
AdditionalConfig,
1617
{ StorageConfigHMAC: any } | { StorageConfigDSA: any } | { StorageConfigPass: any }
1718
>;
18-
providers: CryptoLayerProviderConfig[];
19-
};
19+
providersToBeInitialized: CryptoLayerProviderFilter[];
20+
}
2021

21-
export type CryptoLayerProviderConfig =
22+
/**
23+
* Reference to a specific provider, if a name is supplied, or any provider that fullfills the other requirements.
24+
*/
25+
export type CryptoLayerProviderFilter =
2226
| {
2327
providerName: string;
2428
}

src/CryptoLayerProviders.ts

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
import { Provider, ProviderConfig, ProviderImplConfig, SecurityLevel } from "@nmshd/rs-crypto-types";
1+
/* eslint-disable @typescript-eslint/naming-convention */
2+
import {
3+
Provider,
4+
ProviderConfig,
5+
ProviderFactoryFunctions,
6+
ProviderImplConfig,
7+
SecurityLevel
8+
} from "@nmshd/rs-crypto-types";
29

310
import { defaults } from "lodash";
411
import { CryptoError } from "./CryptoError";
512
import { CryptoErrorCode } from "./CryptoErrorCode";
6-
import { CryptoLayerConfig } from "./CryptoLayerConfig";
13+
import { CryptoLayerConfig, CryptoLayerProviderFilter } from "./CryptoLayerConfig";
714

815
let PROVIDERS_BY_SECURITY: Map<SecurityLevel, Provider[]> | undefined = undefined;
916
let PROVIDERS_BY_NAME: Map<string, Provider> | undefined = undefined;
@@ -16,6 +23,56 @@ const DEFAULT_PROVIDER_CONFIG: ProviderConfig = {
1623
supported_hashes: ["Sha2_256", "Sha2_512"]
1724
};
1825

26+
async function providerBySecurityMapFromProviderByNameMap(
27+
providersByName: Map<string, Provider>
28+
): Promise<Map<SecurityLevel, Provider[]>> {
29+
const providersBySecurity = new Map();
30+
for (const [_key, value] of providersByName) {
31+
const caps = await value.getCapabilities();
32+
if (!caps?.min_security_level) {
33+
continue;
34+
}
35+
const securityLevel = caps.min_security_level;
36+
37+
if (!providersBySecurity.has(securityLevel)) {
38+
providersBySecurity.set(securityLevel, []);
39+
}
40+
41+
providersBySecurity.get(securityLevel)!.push(value);
42+
}
43+
return providersBySecurity;
44+
}
45+
46+
/**
47+
* Creates a provider if possible with the given provider filter. This means, that the provider created must adhere to the filter.
48+
*
49+
* If a `SecurityLevel` is given, the default provider config (`DEFAULT_PROVIDER_CONFIG`) will be used to fill in the rest for the selection.
50+
*/
51+
async function createProviderFromProviderFilter(
52+
providerToBeInitialized: CryptoLayerProviderFilter,
53+
factoryFunctions: ProviderFactoryFunctions,
54+
providerImplConfig: ProviderImplConfig
55+
): Promise<Provider | undefined> {
56+
if ("providerName" in providerToBeInitialized) {
57+
return await factoryFunctions.createProviderFromName(providerToBeInitialized.providerName, providerImplConfig);
58+
}
59+
if ("securityLevel" in providerToBeInitialized) {
60+
const providerConfig: ProviderConfig = defaults(
61+
{
62+
max_security_level: providerToBeInitialized.securityLevel,
63+
min_security_level: providerToBeInitialized.securityLevel
64+
},
65+
DEFAULT_PROVIDER_CONFIG
66+
);
67+
return await factoryFunctions.createProvider(providerConfig, providerImplConfig);
68+
}
69+
if ("providerConfig" in providerToBeInitialized) {
70+
return await factoryFunctions.createProvider(providerToBeInitialized.providerConfig, providerImplConfig);
71+
}
72+
73+
throw new CryptoError(CryptoErrorCode.WrongParameters);
74+
}
75+
1976
/**
2077
* Intializes global providers with the given configuration.
2178
*
@@ -28,37 +85,19 @@ export async function initCryptoLayerProviders(config: CryptoLayerConfig): Promi
2885
return;
2986
}
3087

31-
let providerImplConfig: ProviderImplConfig = { additional_config: [config.keyMetadataStoreConfig] };
88+
const providerImplConfig: ProviderImplConfig = { additional_config: [config.keyMetadataStoreConfig] };
3289
if (config.keyMetadataStoreAuth) {
3390
providerImplConfig.additional_config.push(config.keyMetadataStoreAuth);
3491
}
3592

36-
let providers: Map<string, Provider> = new Map();
37-
38-
for (const providerInitalizationConfig of config.providers) {
39-
let provider: Provider | undefined;
40-
if ("providerName" in providerInitalizationConfig) {
41-
provider = await config.factoryFunctions.createProviderFromName(
42-
providerInitalizationConfig.providerName,
43-
providerImplConfig
44-
);
45-
} else if ("securityLevel" in providerInitalizationConfig) {
46-
let providerConfig: ProviderConfig = defaults(
47-
{
48-
max_security_level: providerInitalizationConfig.securityLevel,
49-
min_security_level: providerInitalizationConfig.securityLevel
50-
},
51-
DEFAULT_PROVIDER_CONFIG
52-
);
53-
provider = await config.factoryFunctions.createProvider(providerConfig, providerImplConfig);
54-
} else if ("providerConfig" in providerInitalizationConfig) {
55-
provider = await config.factoryFunctions.createProvider(
56-
providerInitalizationConfig.providerConfig,
57-
providerImplConfig
58-
);
59-
} else {
60-
throw new CryptoError(CryptoErrorCode.WrongParameters);
61-
}
93+
const providers: Map<string, Provider> = new Map();
94+
95+
for (const providerFilter of config.providersToBeInitialized) {
96+
const provider = await createProviderFromProviderFilter(
97+
providerFilter,
98+
config.factoryFunctions,
99+
providerImplConfig
100+
);
62101

63102
if (!provider) {
64103
throw new CryptoError(CryptoErrorCode.CalFailedLoadingProvider, `Failed loading provider.`);
@@ -68,23 +107,7 @@ export async function initCryptoLayerProviders(config: CryptoLayerConfig): Promi
68107
}
69108

70109
PROVIDERS_BY_NAME = providers;
71-
72-
let providers_by_security = new Map();
73-
for (const [key, value] of providers) {
74-
let caps = await value.getCapabilities();
75-
if (!caps?.min_security_level) {
76-
continue;
77-
}
78-
let securityLevel = caps.min_security_level;
79-
80-
if (!providers_by_security.has(securityLevel)) {
81-
providers_by_security.set(securityLevel, []);
82-
}
83-
84-
providers_by_security.get(securityLevel)!.push(value);
85-
}
86-
87-
PROVIDERS_BY_SECURITY = providers_by_security;
110+
PROVIDERS_BY_SECURITY = await providerBySecurityMapFromProviderByNameMap(PROVIDERS_BY_NAME);
88111
}
89112

90113
function isSecurityLevel(value: string): value is SecurityLevel {
@@ -113,7 +136,7 @@ export function getProvider(key: string | SecurityLevel | undefined): Provider |
113136
return undefined;
114137
}
115138

116-
let provider = isSecurityLevel(key) ? PROVIDERS_BY_SECURITY.get(key)?.[0] : PROVIDERS_BY_NAME.get(key);
139+
const provider = isSecurityLevel(key) ? PROVIDERS_BY_SECURITY.get(key)?.[0] : PROVIDERS_BY_NAME.get(key);
117140

118141
if (!provider) {
119142
throw new CryptoError(CryptoErrorCode.WrongParameters, `No such provider with name or security level: ${key}`);

src/CryptoPrivateKeyHandle.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { serialize, type, validate } from "@js-soft/ts-serval";
2+
import { CoreBuffer, Encoding, ICoreBuffer } from "./CoreBuffer";
3+
import { CryptoSerializable } from "./CryptoSerializable";
4+
import { CryptoExchangeAlgorithm } from "./exchange/CryptoExchange";
5+
import { CryptoSignatureAlgorithm } from "./signature/CryptoSignatureAlgorithm";
6+
7+
export interface ICryptoPrivateKeyHandle {
8+
privateKey: ICoreBuffer;
9+
algorithm: CryptoExchangeAlgorithm | CryptoSignatureAlgorithm;
10+
toString(): string;
11+
toPEM(): string;
12+
}
13+
14+
export interface ICryptoPrivateKeyHandleStatic {
15+
new (): ICryptoPrivateKeyHandle;
16+
fromPEM(
17+
pem: string,
18+
algorithm: CryptoExchangeAlgorithm | CryptoSignatureAlgorithm
19+
): Promise<ICryptoPrivateKeyHandle>;
20+
fromString(
21+
value: string,
22+
algorithm: CryptoExchangeAlgorithm | CryptoSignatureAlgorithm,
23+
encoding: Encoding
24+
): Promise<ICryptoPrivateKeyHandle>;
25+
fromNativeKey(
26+
key: any,
27+
algorithm: CryptoExchangeAlgorithm | CryptoSignatureAlgorithm
28+
): Promise<ICryptoPrivateKeyHandle>;
29+
}
30+
31+
@type("CryptoPrivateKeyHandle")
32+
export class CryptoPrivateKeyHandle extends CryptoSerializable implements ICryptoPrivateKeyHandle {
33+
@validate()
34+
@serialize()
35+
public algorithm: CryptoExchangeAlgorithm | CryptoSignatureAlgorithm;
36+
37+
@validate()
38+
@serialize()
39+
public privateKey: CoreBuffer;
40+
41+
public toPEM(): string {
42+
return this.privateKey.toString(Encoding.Pem, "PRIVATE KEY");
43+
}
44+
45+
public override toString(): string {
46+
return this.privateKey.toString(Encoding.Base64_UrlSafe_NoPadding);
47+
}
48+
49+
protected static stripPEM(pem: string): string {
50+
pem = pem.replace(/-----BEGIN [\w ]* KEY-----/, "");
51+
pem = pem.replace(/-----END [\w ]* KEY-----/, "");
52+
pem = pem.replace(/----- BEGIN [\w ]* KEY -----/, "");
53+
pem = pem.replace(/----- END [\w ]* KEY -----/, "");
54+
pem = pem.replace(/(?:\r\n|\r|\n)/g, "");
55+
return pem;
56+
}
57+
58+
public static fromString(
59+
value: string,
60+
algorithm: CryptoExchangeAlgorithm | CryptoSignatureAlgorithm,
61+
encoding: Encoding = Encoding.Base64_UrlSafe_NoPadding
62+
): CryptoPrivateKeyHandle {
63+
const buffer: CoreBuffer = CoreBuffer.fromString(value, encoding);
64+
return this.fromAny({ algorithm, privateKey: buffer });
65+
}
66+
67+
public static fromObject(
68+
value: any,
69+
algorithm: CryptoExchangeAlgorithm | CryptoSignatureAlgorithm
70+
): CryptoPrivateKeyHandle {
71+
const buffer: ICoreBuffer = CoreBuffer.fromObject(value);
72+
73+
return this.fromAny({ algorithm, privateKey: buffer });
74+
}
75+
76+
public static fromPEM(
77+
pem: string,
78+
algorithm: CryptoExchangeAlgorithm | CryptoSignatureAlgorithm
79+
): CryptoPrivateKeyHandle {
80+
const value = this.stripPEM(pem);
81+
return this.fromString(value, algorithm, Encoding.Base64);
82+
}
83+
84+
public static from(value: any): CryptoPrivateKeyHandle {
85+
return this.fromAny(value);
86+
}
87+
88+
public static fromBase64(value: string): CryptoPrivateKeyHandle {
89+
return this.deserialize(CoreBuffer.base64_utf8(value));
90+
}
91+
}

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ export * from "./CryptoDerivation";
55
export * from "./CryptoError";
66
export * from "./CryptoErrorCode";
77
export * from "./CryptoLayerConfig";
8-
//export * from "./CryptoLayerProviders";
98
export * from "./CryptoPrivateKey";
9+
export * from "./CryptoPrivateKeyHandle";
1010
export * from "./CryptoPublicKey";
1111
export * from "./CryptoValidation";
1212
export * from "./encryption/CryptoCipher";
@@ -42,4 +42,3 @@ export * from "./state/CryptoStateType";
4242
export * from "./stream/CryptoStream";
4343
export * from "./stream/CryptoStreamAddress";
4444
export * from "./stream/CryptoStreamState";
45-

0 commit comments

Comments
 (0)