From af90ba55bc272a69c3d152457a286d0fdd46e1ad Mon Sep 17 00:00:00 2001 From: s1fr0 <28568419+s1fr0@users.noreply.github.com> Date: Mon, 6 Feb 2023 01:16:59 +0100 Subject: [PATCH] feat(credentials): use appInfo --- tests/v2/test_utils_credentials.nim | 42 +++++++++-------- tests/v2/test_waku_rln_relay.nim | 8 +--- waku/v2/protocol/waku_rln_relay/constants.nim | 7 +-- waku/v2/protocol/waku_rln_relay/utils.nim | 8 +--- waku/v2/utils/credentials.nim | 45 +++++++++---------- 5 files changed, 49 insertions(+), 61 deletions(-) diff --git a/tests/v2/test_utils_credentials.nim b/tests/v2/test_utils_credentials.nim index ce40e28228..56c9599d68 100644 --- a/tests/v2/test_utils_credentials.nim +++ b/tests/v2/test_utils_credentials.nim @@ -1,7 +1,7 @@ {.used.} import - std/[algorithm, options, os], + std/[algorithm, json, options, os], testutils/unittests, chronos, stint, ../../waku/v2/utils/credentials, ../test_helpers @@ -12,6 +12,7 @@ procSuite "Credentials test suite": # We initialize the RNG in test_helpers let rng = rng() + let testAppInfo = AppInfo(application: "test", appIdentifier: "1234", version: "0.1") asyncTest "Create keystore": @@ -19,9 +20,7 @@ procSuite "Credentials test suite": defer: removeFile(filepath) let keystoreRes = createAppKeystore(path = filepath, - application = "test", - appIdentifier = "1234", - version = "0.1") + appInfo = testAppInfo) check: keystoreRes.isOk() @@ -31,14 +30,23 @@ procSuite "Credentials test suite": let filepath = "./testAppKeystore.txt" defer: removeFile(filepath) + # If no keystore exists at filepath, a new one is created for appInfo and empty credentials let keystoreRes = loadAppKeystore(path = filepath, - application = "test", - appIdentifier = "1234", - version = "0.1") + appInfo = testAppInfo) check: keystoreRes.isOk() + let keystore = keystoreRes.get() + + check: + keystore.hasKeys(["application", "appIdentifier", "version", "credentials"]) + keystore["application"].getStr() == testAppInfo.application + keystore["appIdentifier"].getStr() == testAppInfo.appIdentifier + keystore["version"].getStr() == testAppInfo.version + # We assume the loaded keystore to not have credentials set (previous tests delete the keystore at filepath) + keystore["credentials"].getElems().len() == 0 + asyncTest "Add credentials to keystore": let filepath = "./testAppKeystore.txt" @@ -79,9 +87,7 @@ procSuite "Credentials test suite": let keystoreRes = addMembershipCredentials(path = filepath, credentials = @[membershipCredentials1, membershipCredentials2], password = password, - application = "test", - appIdentifier = "1234", - version = "0.1") + appInfo = testAppInfo) check: keystoreRes.isOk() @@ -135,9 +141,7 @@ procSuite "Credentials test suite": let keystoreRes = addMembershipCredentials(path = filepath, credentials = @[membershipCredentials1, membershipCredentials2, membershipCredentials3, membershipCredentials4], password = password, - application = "test", - appIdentifier = "1234", - version = "0.1") + appInfo = testAppInfo) check: keystoreRes.isOk() @@ -158,9 +162,7 @@ procSuite "Credentials test suite": # We retrieve all credentials stored under password (no filter) var recoveredCredentialsRes = getMembershipCredentials(path = filepath, password = password, - application = "test", - appIdentifier = "1234", - version = "0.1") + appInfo = testAppInfo) check: recoveredCredentialsRes.isOk() @@ -171,9 +173,7 @@ procSuite "Credentials test suite": recoveredCredentialsRes = getMembershipCredentials(path = filepath, password = password, filterIdentityCredentials = @[idCredential1], - application = "test", - appIdentifier = "1234", - version = "0.1") + appInfo = testAppInfo) check: recoveredCredentialsRes.isOk() @@ -183,9 +183,7 @@ procSuite "Credentials test suite": recoveredCredentialsRes = getMembershipCredentials(path = filepath, password = password, filterIdentityCredentials = @[idCredential1, idCredential2], - application = "test", - appIdentifier = "1234", - version = "0.1") + appInfo = testAppInfo) check: recoveredCredentialsRes.isOk() diff --git a/tests/v2/test_waku_rln_relay.nim b/tests/v2/test_waku_rln_relay.nim index 7960c42a13..1dac46fa74 100644 --- a/tests/v2/test_waku_rln_relay.nim +++ b/tests/v2/test_waku_rln_relay.nim @@ -1059,16 +1059,12 @@ suite "Waku rln relay": addMembershipCredentials(path = filepath, credentials = @[rlnMembershipCredentials], password = password, - application = RLNKeystoreApplication, - appIdentifier = RLNKeystoreAppIdentifier, - version = RLNKeystoreVersion).isOk() + appInfo = RLNAppInfo).isOk() let readCredentialsResult = getMembershipCredentials(path = filepath, password = password, filterMembershipContracts = @[rlnMembershipContract], - application = RLNKeystoreApplication, - appIdentifier = RLNKeystoreAppIdentifier, - version = RLNKeystoreVersion) + appInfo = RLNAppInfo) require: readCredentialsResult.isOk() diff --git a/waku/v2/protocol/waku_rln_relay/constants.nim b/waku/v2/protocol/waku_rln_relay/constants.nim index 43a2eb15db..d68ff73eb6 100644 --- a/waku/v2/protocol/waku_rln_relay/constants.nim +++ b/waku/v2/protocol/waku_rln_relay/constants.nim @@ -1,6 +1,9 @@ import stint +import + ../../utils/credentials + # Acceptable roots for merkle root validation of incoming messages const AcceptableRootWindowSize* = 5 @@ -51,8 +54,6 @@ const MaxEpochGap* = uint64(MaxClockGapSeconds/EpochUnitSeconds) # RLN Keystore defaults const - RLNKeystoreApplication* = "nwaku-rln-relay" - RLNKeystoreAppIdentifier* = "01234567890abcdef" - RLNKeystoreVersion* = "0.1" + RLNAppInfo* = AppInfo(application: "nwaku-rln-relay", appIdentifier: "01234567890abcdef", version: "0.1") # NOTE: 256-bytes long credentials are due to the use of BN254 in RLN. Other implementations/curves might have a different byte size CredentialByteSize* = 256 \ No newline at end of file diff --git a/waku/v2/protocol/waku_rln_relay/utils.nim b/waku/v2/protocol/waku_rln_relay/utils.nim index a579a0c942..cc70fd9dc5 100644 --- a/waku/v2/protocol/waku_rln_relay/utils.nim +++ b/waku/v2/protocol/waku_rln_relay/utils.nim @@ -937,9 +937,7 @@ proc mount(wakuRelay: WakuRelay, password = conf.rlnRelayCredentialsPassword, filterMembershipContracts = @[rlnMembershipContract], # TODO: the following can be embedded in conf - application = RLNKeystoreApplication, - appIdentifier = RLNKeystoreAppIdentifier, - version = RLNKeystoreVersion) + appInfo = RLNAppInfo) if readCredentialsRes.isErr(): return err("RLN credentials cannot be read") @@ -1011,9 +1009,7 @@ proc mount(wakuRelay: WakuRelay, credentials = @[credentials.get()], password = conf.rlnRelayCredentialsPassword, # TODO: the following can be embedded in conf - application = RLNKeystoreApplication, - appIdentifier = RLNKeystoreAppIdentifier, - version = RLNKeystoreVersion).isErr(): + appInfo = RLNAppInfo).isErr(): return err("error in storing rln credentials") return ok(wakuRlnRelay) diff --git a/waku/v2/utils/credentials.nim b/waku/v2/utils/credentials.nim index 991be8be82..a78f3a94cf 100644 --- a/waku/v2/utils/credentials.nim +++ b/waku/v2/utils/credentials.nim @@ -4,7 +4,7 @@ else: {.push raises: [].} import - chronicles, options, json, strutils, + options, json, strutils, stew/byteutils, std/[algorithm, os, sequtils, sets], ./keyfile @@ -42,6 +42,11 @@ type MembershipCredentials* = object identityCredential*: IdentityCredential membershipGroups*: seq[MembershipGroup] +type AppInfo* = object + application*: string + appIdentifier*: string + version*: string + type AppKeystore* = object application*: string appIdentifier*: string @@ -84,12 +89,12 @@ proc decode*(encodedCredential: seq[byte]): KeystoreResult[MembershipCredentials return err(OsError) # Checks if a JsonNode has all keys contained in "keys" -proc hasKeys(data: JsonNode, keys: openArray[string]): bool = +proc hasKeys*(data: JsonNode, keys: openArray[string]): bool = return all(keys, proc (key: string): bool = return data.hasKey(key)) # Safely saves a JsonNode to disk. # If exists, the destination file is renamed with extension .bkp; the file is written at its destination and the .bkp file is removed if write is successful, otherwise is restored -proc save(json: JsonNode, path: string, separator: string): KeystoreResult[void] = +proc save*(json: JsonNode, path: string, separator: string): KeystoreResult[void] = # We first backup the current keystore if fileExists(path): @@ -137,15 +142,13 @@ proc sortMembershipGroup*(a,b: MembershipGroup): int = # This proc creates an empty keystore (i.e. with no credentials) proc createAppKeystore*(path: string, - application: string, - appIdentifier: string, - version: string, + appInfo: AppInfo, separator: string = "\n"): KeystoreResult[void] = - let keystore = AppKeystore(application: application, - appIdentifier: appIdentifier, + let keystore = AppKeystore(application: appInfo.application, + appIdentifier: appInfo.appIdentifier, credentials: @[], - version: version) + version: appInfo.version) var jsonKeystore: string jsonKeystore.toUgly(%keystore) @@ -169,9 +172,7 @@ proc createAppKeystore*(path: string, # This proc load a keystore based on the application, appIdentifier and version filters. # If none is found, it automatically creates an empty keystore for the passed parameters proc loadAppKeystore*(path: string, - application: string, - appIdentifier: string, - version: string, + appInfo: AppInfo, separator: string = "\n"): KeystoreResult[JsonNode] = ## Load and decode JSON keystore from pathname @@ -180,7 +181,7 @@ proc loadAppKeystore*(path: string, # If no keystore exists at path we create a new empty one with passed keystore parameters if fileExists(path) == false: - let newKeystore = createAppKeystore(path, application, appIdentifier, version, separator) + let newKeystore = createAppKeystore(path, appInfo, separator) if newKeystore.isErr(): return err(CreateKeystoreError) @@ -209,9 +210,9 @@ proc loadAppKeystore*(path: string, # We check if parsed json contains the relevant keystore credentials fields and if these are set to the passed parameters # (note that "if" is lazy, so if one of the .contains() fails, the json fields contents will not be checked and no ResultDefect will be raised due to accessing unavailable fields) if data.hasKeys(["application", "appIdentifier", "credentials", "version"]) and - data["application"].getStr() == application and - data["appIdentifier"].getStr() == appIdentifier and - data["version"].getStr() == version: + data["application"].getStr() == appInfo.application and + data["appIdentifier"].getStr() == appInfo.appIdentifier and + data["version"].getStr() == appInfo.version: # We return the first json keystore that matches the passed app parameters # We assume a unique kesytore with such parameters is present in the file matchingAppKeystore = data @@ -236,14 +237,12 @@ proc loadAppKeystore*(path: string, proc addMembershipCredentials*(path: string, credentials: seq[MembershipCredentials], password: string, - application: string, - appIdentifier: string, - version: string, + appInfo: AppInfo, separator: string = "\n"): KeystoreResult[void] = # We load the keystore corresponding to the desired parameters # This call ensures that JSON has all required fields - let jsonKeystoreRes = loadAppKeystore(path, application, appIdentifier, version, separator) + let jsonKeystoreRes = loadAppKeystore(path, appInfo, separator) if jsonKeystoreRes.isErr(): return err(LoadKeystoreError) @@ -359,15 +358,13 @@ proc getMembershipCredentials*(path: string, password: string, filterIdentityCredentials: seq[IdentityCredential] = @[], filterMembershipContracts: seq[MembershipContract] = @[], - application: string, - appIdentifier: string, - version: string): KeystoreResult[seq[MembershipCredentials]] = + appInfo: AppInfo): KeystoreResult[seq[MembershipCredentials]] = var outputMembershipCredentials: seq[MembershipCredentials] = @[] # We load the keystore corresponding to the desired parameters # This call ensures that JSON has all required fields - let jsonKeystoreRes = loadAppKeystore(path, application, appIdentifier, version) + let jsonKeystoreRes = loadAppKeystore(path, appInfo) if jsonKeystoreRes.isErr(): return err(LoadKeystoreError)