Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(credentials): store and processing generic app credentials #1466

Merged
merged 23 commits into from
Feb 8, 2023

Conversation

s1fr0
Copy link
Contributor

@s1fr0 s1fr0 commented Dec 15, 2022

This PR adds a dynamic keystore for membership credential storage and management. The credentials are thought to be generic membership credentials, i.e. associated to a membership contract and membership Merkle tree, and the implementation is not tied to RLN credentials only.

The keystore JSON schema implemented is the one proposed in #1238 (comment).

In short, a keystore is uniquely identified by an application name, app identifier and version strings. Multiple keystores can co-exist in the same file.
Each keystore can contain none or more Membership credentials. Each Membership Credential contains a unique Identity Credential (made of identity trapdoor, nullifier, secret hash and commitment) and none or more Membership Groups. Each Membership Group contains a Membership contract and a membership tree index position. A Membership Contract contains the chain ID and the membership contract address information.

When a Membership credential is added to a certain keystore:

  • if its Identity Credential was present in the keystore (it decrypts with the same password used to add the new credential), only the new Membership Groups (i.e. not already present in the keystore) will be added;
  • if not present, the whole credential is added.
    When one or more credentials are added, the keystore is automatically updated to disk (with a backup mechanism to mitigate credentials loss in case of IO errors).

Membership credentials in a certain keystore can be retrieved by none or more filters. These allow to return:

  • all Membership credentials decrypting under a certain password;
  • Membership credentials corresponding to one or more Identity credentials;
  • Membership credentials corresponding to one or more Membership Groups (non-matching groups are stripped);
  • Membership credentials corresponding to one or more Identity credentials and Membership Groups (non-matching groups are stripped).

This PR addresses the issues:

@rymnc rymnc added this to the Release 0.14.0 milestone Dec 15, 2022
@rymnc rymnc added the track:rln RLN Track (Secure Messaging/Applied ZK), e.g. relay and applications label Dec 15, 2022
@status-im-auto
Copy link
Collaborator

status-im-auto commented Dec 15, 2022

Jenkins Builds

Click to see older builds (7)
Commit #️⃣ Finished (UTC) Duration Platform Result
✔️ b6466f6 #1 2022-12-15 23:17:24 ~30 min macos 📦bin
✔️ 287b10a #3 2023-01-11 22:58:16 ~10 min macos 📦bin
cc75811 #4 2023-01-23 22:55:30 ~8 min macos 📄log
cc75811 #1 2023-01-24 09:55:38 ~6 min linux 📄log
7566cad #5 2023-01-24 22:53:38 ~6 min macos 📄log
58724d7 #6 2023-01-25 23:13:26 ~26 min macos 📄log
✔️ 1acb693 #7 2023-01-27 23:01:37 ~14 min macos 📦bin
Commit #️⃣ Finished (UTC) Duration Platform Result
1fcf016 #8 2023-01-31 23:04:04 ~16 min macos 📄log
✔️ af90ba5 #9 2023-02-06 15:20:38 ~33 min macos 📦bin

@jm-clius
Copy link
Contributor

@s1fr0 @rymnc I notice this draft PR has a release milestone attached - should we remove the milestone (not required for PRs, but rather for issues), or bump it to a next milestone?

@s1fr0 s1fr0 modified the milestones: Release 0.14.0, Release 0.15.0 Jan 12, 2023
@s1fr0
Copy link
Contributor Author

s1fr0 commented Jan 12, 2023

Thanks @Hanno! We moved delivery of this PR to next release, hence I bumped it.

@rymnc rymnc added track:rlnp2p and removed track:rln RLN Track (Secure Messaging/Applied ZK), e.g. relay and applications labels Jan 19, 2023
@s1fr0 s1fr0 requested review from rymnc and LNSD January 31, 2023 01:50
@s1fr0 s1fr0 marked this pull request as ready for review January 31, 2023 01:50
Copy link
Contributor

@rymnc rymnc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few queries, looks great!

Maybe we should decide if we plan to merge this, or #1496 first. There would be non-trivial refactoring both ways.

waku/v2/node/waku_node.nim Show resolved Hide resolved
waku/v2/utils/credentials.nim Outdated Show resolved Hide resolved
waku/v2/utils/credentials.nim Outdated Show resolved Hide resolved
waku/v2/utils/credentials.nim Outdated Show resolved Hide resolved
waku/v2/utils/credentials.nim Outdated Show resolved Hide resolved
waku/v2/utils/credentials.nim Outdated Show resolved Hide resolved
@LNSD
Copy link
Contributor

LNSD commented Jan 31, 2023

Wow! +696 new lines! 😨 I will need a couple of days to review this.

Please, let's keep the PR sizes manageable. Smaller PRs will help us be more agile in reviewing and merging code changes.

@s1fr0 s1fr0 requested a review from rymnc February 6, 2023 00:32
Copy link
Contributor

@rymnc rymnc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, maybe we should have instructions for operators to use this feature :)

Copy link
Contributor

@LNSD LNSD left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the code a little convoluted. Please, check my comments.

@@ -0,0 +1,401 @@
when (NimMajor, NimMinor) < (1, 4):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am against adding more stuff under the utils module.

Please, move the utils/keyfile and utils/credentials modules under the waku_rln_relay module given that at this moment it is the only user of this code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed to move all keyfile/keystore implementation under a new waku_keystore module in protocol. Done in 082043c

Comment on lines 50 to 67
type AppKeystore* = object
application*: string
appIdentifier*: string
credentials*: seq[MembershipCredentials]
version*: string

type
AppKeystoreError = enum
OsError = "keystore error: OS specific error"
IoError = "keystore error: IO specific error"
JsonKeyError = "keystore error: fields not present in JSON"
JsonError = "keystore error: JSON encoder/decoder error"
KeystoreDoesNotExist = "keystore error: file does not exist"
CreateKeystoreError = "Error while creating application keystore"
LoadKeystoreError = "Error while loading application keystore"
CreateKeyfileError = "Error while creating keyfile for credentials"
SaveKeyfileError = "Error while saving keyfile for credentials"
ReadKeyfileError = "Error while reading keyfile for credentials"
Copy link
Contributor

@LNSD LNSD Feb 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you separate the AppKeystore related code into another module and import and use it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 082043c

Comment on lines 71 to 93
# Encodes a Membership credential to a byte sequence
proc encode*(credential: MembershipCredentials): seq[byte] =
# TODO: use custom encoding, avoid wordy json
var stringCredential: string
# NOTE: toUgly appends to the string, doesn't replace its contents
stringCredential.toUgly(%credential)
return toBytes(stringCredential)

# Decodes a byte sequence to a Membership credential
proc decode*(encodedCredential: seq[byte]): KeystoreResult[MembershipCredentials] =
# TODO: use custom decoding, avoid wordy json
try:
# we parse the json decrypted keystoreCredential
let jsonObject = parseJson(string.fromBytes(encodedCredential))
return ok(to(jsonObject, MembershipCredentials))
except JsonParsingError:
return err(JsonError)
except Exception: #parseJson raises Exception
return err(OsError)

# Checks if a JsonNode has all keys contained in "keys"
proc hasKeys*(data: JsonNode, keys: openArray[string]): bool =
return all(keys, proc (key: string): bool = return data.hasKey(key))
Copy link
Contributor

@LNSD LNSD Feb 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the JSON serialization-related code should be in a separate module. Is that possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Separated encoding/decoding of keystore relevant data structures from more general "utils". Done in 082043c

@s1fr0 s1fr0 requested a review from LNSD February 7, 2023 15:49
Copy link
Contributor

@LNSD LNSD left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding it inside the waku_keystore. I like the new module layout.

There are minor/nitpick details, but in general, LGreatTM ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

5 participants