diff --git a/src/keri/app/cli/commands/escrow.py b/src/keri/app/cli/commands/escrow.py deleted file mode 100644 index 24d78f335..000000000 --- a/src/keri/app/cli/commands/escrow.py +++ /dev/null @@ -1,159 +0,0 @@ -# -*- encoding: utf-8 -*- -""" -KERI -keri.kli.commands module - -""" -import argparse -import json - -from hio import help -from hio.base import doing - -from keri.core import eventing -from keri.app.cli.common import existing -from keri.db import dbing -from keri.kering import ConfigurationError -from keri.vdr import viring - -logger = help.ogler.getLogger() - -parser = argparse.ArgumentParser(description='Initialize a prefix') -parser.set_defaults(handler=lambda args: handler(args), - transferable=True) -parser.add_argument('--name', '-n', help='keystore name and file location of KERI keystore', required=True) -parser.add_argument('--base', '-b', help='additional optional prefix to file location of KERI keystore', - required=False, default="") -parser.add_argument('--passcode', '-p', help='22 character encryption passcode for keystore (is not saved)', - dest="bran", default=None) # passcode => bran - -parser.add_argument("--escrow", "-e", help="show values for one specific escrow", default=None) - - -def handler(args): - """ Command line escrow handler - - """ - kwa = dict(args=args) - return [doing.doify(escrows, **kwa)] - - -def escrows(tymth, tock=0.0, **opts): - _ = (yield tock) - - args = opts["args"] - name = args.name - base = args.base - bran = args.bran - escrow = args.escrow - - try: - with existing.existingHby(name=name, base=base, bran=bran) as hby: - reger = viring.Reger(name=hby.name, db=hby.db, temp=False) - - escrows = dict() - if (not escrow) or escrow == "out-of-order-events": - oots = list() - key = ekey = b'' # both start same. when not same means escrows found - while True: - for ekey, edig in hby.db.getOoeItemsNextIter(key=key): - pre, sn = dbing.splitKeySN(ekey) # get pre and sn from escrow item - - try: - oots.append(eventing.loadEvent(hby.db, pre, edig)) - except ValueError as e: - raise e - - if ekey == key: # still same so no escrows found on last while iteration - break - key = ekey # setup next while iteration, with key after ekey - - escrows["out-of-order-events"] = oots - - if (not escrow) or escrow == "partially-witnessed-events": - pwes = list() - key = ekey = b'' # both start same. when not same means escrows found - while True: # break when done - for ekey, edig in hby.db.getPweItemsNextIter(key=key): - pre, sn = dbing.splitKeySN(ekey) # get pre and sn from escrow item - - try: - pwes.append(eventing.loadEvent(hby.db, pre, edig)) - except ValueError as e: - raise e - - if ekey == key: # still same so no escrows found on last while iteration - break - key = ekey # setup next while iteration, with key after ekey - - escrows["partially-witnessed-events"] = pwes - - if (not escrow) or escrow == "partially-signed-events": - pses = list() - key = ekey = b'' # both start same. when not same means escrows found - while True: # break when done - for ekey, edig in hby.db.getPseItemsNextIter(key=key): - pre, sn = dbing.splitKeySN(ekey) # get pre and sn from escrow item - - try: - pses.append(eventing.loadEvent(hby.db, pre, edig)) - except ValueError as e: - raise e - - if ekey == key: # still same so no escrows found on last while iteration - break - key = ekey # setup next while iteration, with key after ekey - - escrows["partially-signed-events"] = pses - - if (not escrow) or escrow == "likely-duplicitous-events": - ldes = list() - key = ekey = b'' # both start same. when not same means escrows found - while True: # break when done - for ekey, edig in hby.db.getLdeItemsNextIter(key=key): - pre, sn = dbing.splitKeySN(ekey) # get pre and sn from escrow item - - try: - ldes.append(eventing.loadEvent(hby.db, pre, edig)) - except ValueError as e: - raise e - - if ekey == key: # still same so no escrows found on last while iteration - break - key = ekey # setup next while iteration, with key after ekey - - escrows["likely-duplicitous-events"] = ldes - - if (not escrow) or escrow == "missing-registry-escrow": - creds = list() - for (said,), dater in reger.mre.getItemIter(): - creder, *_ = reger.cloneCred(said) - creds.append(creder.sad) - - escrows["missing-registry-escrow"] = creds - - if (not escrow) or escrow == "broken-chain-escrow": - creds = list() - for (said,), dater in reger.mce.getItemIter(): - creder, *_ = reger.cloneCred(said) - creds.append(creder.sad) - - escrows["broken-chain-escrow"] = creds - - if (not escrow) or escrow == "missing-schema-escrow": - creds = list() - for (said,), dater in reger.mse.getItemIter(): - creder, *_ = reger.cloneCred(said) - creds.append(creder.sad) - - escrows["missing-schema-escrow"] = creds - - print(json.dumps(escrows, indent=2)) - - if not(escrow) or escrow == 'tel-partial-witness-escrow': - for (regk, snq), (prefixer, seqner, saider) in reger.tpwe.getItemIter(): - pass - - except ConfigurationError as e: - print(f"identifier prefix for {name} does not exist, incept must be run first", ) - return -1 diff --git a/src/keri/app/cli/commands/escrow/list.py b/src/keri/app/cli/commands/escrow/list.py index 06fe76617..4e647c3d9 100644 --- a/src/keri/app/cli/commands/escrow/list.py +++ b/src/keri/app/cli/commands/escrow/list.py @@ -63,7 +63,7 @@ def escrows(tymth, tock=0.0, **opts): pses = list() key = ekey = b'' # both start same. when not same means escrows found while True: # break when done - for ekey, edig in hby.db.getPseItemIter(key=key): + for ekey, edig in hby.db.getPseItemsNextIter(key=key): pre, sn = dbing.splitSnKey(ekey) # get pre and sn from escrow item try: @@ -138,7 +138,7 @@ def escrows(tymth, tock=0.0, **opts): escrows["query-not-found"] = sum(1 for key, _ in hby.db.getQnfItemsNextIter()) if (not escrow) or escrow == "partially-delegated-events": - escrows["partially-delegated-events"] = sum(1 for key, _ in hby.db.getPdesItemsNextIter()) + escrows["partially-delegated-events"] = sum(1 for key, _ in hby.db.getPdeItemsNextIter()) if (not escrow) or escrow == "reply": escrows["reply"] = sum(1 for key, _ in hby.db.rpes.getItemIter()) diff --git a/src/keri/app/cli/commands/vc/create.py b/src/keri/app/cli/commands/vc/create.py index e30b632dc..daac5dd2b 100644 --- a/src/keri/app/cli/commands/vc/create.py +++ b/src/keri/app/cli/commands/vc/create.py @@ -1,5 +1,6 @@ import argparse import json +from typing import Optional from hio import help from hio.base import doing @@ -36,6 +37,10 @@ parser.add_argument('--alias', '-a', help='human readable alias for the new identifier prefix', required=True) parser.add_argument("--private", help="flag to indicate if this credential needs privacy preserving features", action="store_true") +parser.add_argument("--private-credential-nonce", help="nonce for vc", + action="store_true") +parser.add_argument("--private-subject-nonce", help="nonce for subject", + action="store_true") parser.add_argument('--passcode', '-p', help='22 character encryption passcode for keystore (is not saved)', dest="bran", default=None) # passcode => bran parser.add_argument("--time", help="timestamp for the credential creation", required=False, default=None) @@ -99,7 +104,10 @@ def issueCredential(args): rules=rules, credential=credential, timestamp=args.time, - private=args.private) + private=args.private, + private_credential_nonce=args.private_credential_nonce, + private_subject_nonce=args.private_subject_nonce, + ) doers = [issueDoer] return doers @@ -112,7 +120,8 @@ class CredentialIssuer(doing.DoDoer): """ def __init__(self, name, alias, base, bran, registryName=None, schema=None, edges=None, recipient=None, data=None, - rules=None, credential=None, timestamp=None, private=False): + rules=None, credential=None, timestamp=None, private:bool=False, private_credential_nonce:Optional[str]=None, + private_subject_nonce:Optional[str]=None,): """ Create DoDoer for issuing a credential and managing the processes needed to complete issuance Parameters: @@ -124,7 +133,9 @@ def __init__(self, name, alias, base, bran, registryName=None, schema=None, edge data: (dict) credential data dict credential: (dict) full credential to issue when joining a multisig issuance out (str): Filename for credential output - private: (bool) privacy preserving + private (bool): apply nonce used for privacy preserving ACDC + private_credential_nonce (Optional[str]): nonce used for privacy vc + private_subject_nonce (Optional[str]): nonce used for subject """ self.name = name @@ -173,7 +184,9 @@ def __init__(self, name, alias, base, bran, registryName=None, schema=None, edge source=edges, rules=rules, data=data, - private=private) + private=private, + private_credential_nonce=private_credential_nonce, + private_subject_nonce=private_subject_nonce) else: self.creder = serdering.SerderACDC(sad=credential) # proving.Creder(ked=credential) self.credentialer.validate(creder=self.creder) diff --git a/src/keri/db/basing.py b/src/keri/db/basing.py index e119b9edf..eddb93047 100644 --- a/src/keri/db/basing.py +++ b/src/keri/db/basing.py @@ -1173,7 +1173,7 @@ def clearEscrows(self): logger.info(f"KEL: Cleared {count} verified receipt escrows") count = 0 - for (k, _) in self.getPseItemIter(): + for (k, _) in self.getPseItemsNextIter(): count += 1 self.delPses(key=k) logger.info(f"KEL: Cleared {count} partially signed escrows") @@ -1203,14 +1203,12 @@ def clearEscrows(self): logger.info(f"KEL: Cleared {count} likely duplicitous escrows") count = 0 - for ekey, edig in self.getQnfItemsNextIter(): - count += 1 - pre, _ = splitKey(ekey) - self.delQnf(dgKey(pre, edig), edig) + for k, _ in self.getQnfItemsNextIter(): + self.delQnfs(key=k) logger.info(f"KEL: Cleared {count} query not found escrows") count = 0 - for (key, on, val) in self.getPdesItemsNextIter(): + for (key, _) in self.getPdeItemsNextIter(): count += 1 self.delPde(key=key) logger.info(f"KEL: Cleared {count} partially delegated key event escrows") @@ -1228,8 +1226,8 @@ def clearEscrows(self): for (k, _) in escrow.getItemIter(): count += 1 escrow.trim() - # logger.info(f"KEL: Cleared {count} escrows from ({name.ljust(5)}): {desc}") - logger.info(f"Cleared all escrows") + logger.info(f"KEL: Cleared {count} escrows from ({name.ljust(5)}): {desc}") + logger.info("Cleared KEL escrows") @property def current(self): @@ -2640,18 +2638,6 @@ def getPseLast(self, key): """ return self.getIoValLast(self.pses, key) - def getPseItemIter(self, key=b''): - """ - Use sgKey() - Return iterator of partial signed escrowed event dig items at next key after key. - Items is (key, val) where proem has already been stripped from val - If key is b'' empty then returns dup items at first key. - If skip is False and key is not b'' empty then returns dup items at key - Raises StopIteration Error when empty - Duplicates are retrieved in insertion order. - """ - return self.getTopIoDupItemIter(self.pses, key) - def getPseItemsNext(self, key=b'', skip=True): """ Use snKey() @@ -2731,6 +2717,24 @@ def getPde(self, key): """ return self.getVal(self.pdes, key) + def getPdes(self, key): + """ + Use dgKey() + Return list of out of order escrow event dig vals at key + Returns empty list if no entry at key + Duplicates are retrieved in insertion order. + """ + return self.getIoVals(self.pdes, key) + + def getPdeItemsNextIter(self, key=b'', skip=True): + """ + Use dgKey() + Return list of witnessed signed escrowed event dig vals at key + Returns empty list if no entry at key + Duplicates are retrieved in insertion order. + """ + return self.getIoItemsNextIter(self.pdes, key, skip) + def delPde(self, key): """ Use dgKey() @@ -3137,9 +3141,6 @@ def getQnfItemsNextIter(self, key=b'', skip=True): """ return self.getIoItemsNextIter(self.qnfs, key, skip) - def getPdesItemsNextIter(self, key=b'', skip=True): - return self.getOnIoDupItemIter(self.pdes, key, skip) - def cntQnfs(self, key): """ Use snKey() diff --git a/src/keri/vc/proving.py b/src/keri/vc/proving.py index e724648a5..ae097fb7e 100644 --- a/src/keri/vc/proving.py +++ b/src/keri/vc/proving.py @@ -4,15 +4,13 @@ """ -from collections.abc import Iterable -from typing import Union +from typing import Optional from .. import help from ..core import coring, serdering from ..core.coring import (Serials, versify) -from ..db import subing -from ..kering import Version from ..help import helping +from ..kering import Version KERI_REGISTRY_TYPE = "KERICredentialRegistry" @@ -23,8 +21,9 @@ def credential(schema, issuer, data, recipient=None, - private=False, - salt=None, + private:bool=False, + private_credential_nonce:Optional[str]=None, + private_subject_nonce:Optional[str]=None, status=None, source=None, rules=None, @@ -40,7 +39,8 @@ def credential(schema, recipient (Option[str|None]): qb64 identifier prefix of the recipient data (dict): of the values being assigned to the subject of this credential private (bool): apply nonce used for privacy preserving ACDC - salt (string): salt for nonce + private_credential_nonce (Optional[str]): nonce used for privacy vc + private_subject_nonce (Optional[str]): nonce used for subject source (dict | list): of source credentials to which this credential is chained rules (dict | list): ACDC rules section for credential version (Version): version instance @@ -62,8 +62,8 @@ def credential(schema, ) if private: - vc["u"] = salt if salt is not None else coring.Salter().qb64 - subject["u"] = salt if salt is not None else coring.Salter().qb64 + vc["u"] = private_credential_nonce if private_credential_nonce is not None else coring.Salter().qb64 + subject["u"] = private_subject_nonce if private_subject_nonce is not None else coring.Salter().qb64 if recipient is not None: subject['i'] = recipient diff --git a/src/keri/vdr/credentialing.py b/src/keri/vdr/credentialing.py index 8a85c8e54..ec3d87506 100644 --- a/src/keri/vdr/credentialing.py +++ b/src/keri/vdr/credentialing.py @@ -5,6 +5,8 @@ VC issuer support """ +from typing import Optional + from hio.base import doing from hio.help import decking @@ -770,7 +772,8 @@ def __init__(self, hby, rgy, registrar, verifier): super(Credentialer, self).__init__(doers=doers) - def create(self, regname, recp: str, schema, source, rules, data, private=False): + def create(self, regname, recp: str, schema, source, rules, data, private: bool = False, + private_credential_nonce: Optional[str] = None, private_subject_nonce: Optional[str] = None): """ Create and validate a credential returning the fully populated Creder Parameters: @@ -780,7 +783,9 @@ def create(self, regname, recp: str, schema, source, rules, data, private=False) source: rules: data: - private: add nonce for privacy preserving + private (bool): apply nonce used for privacy preserving ACDC + private_credential_nonce (Optional[str]): nonce used for privacy vc + private_subject_nonce (Optional[str]): nonce used for subject Returns: Creder: Creder class for the issued credential @@ -801,6 +806,8 @@ def create(self, regname, recp: str, schema, source, rules, data, private=False) data=data, source=source, private=private, + private_credential_nonce=private_credential_nonce, + private_subject_nonce=private_subject_nonce, rules=rules, status=registry.regk) self.validate(creder) diff --git a/src/keri/vdr/viring.py b/src/keri/vdr/viring.py index bafc2b749..409b510c2 100644 --- a/src/keri/vdr/viring.py +++ b/src/keri/vdr/viring.py @@ -416,13 +416,11 @@ def clearEscrows(self): ('cmse', self.cmse, 'missing signature escrows'), ('tpwe', self.tpwe, 'partial witness escrows'), ('tmse', self.tmse, 'multisig escrows'), - ('tede', self.tede, 'event dissemination escrows'), + ('tede', self.tede, 'event dissemination escrows') ]: - count = 0 - for (k, _) in sub.getItemIter(): - count += 1 sub.trim() - logger.info(f"TEL: Cleared {count} escrows from ({name.ljust(5)}): {desc}") + logger.info(f"TEL: Cleared escrow ({name.ljust(5)}): {desc}") + logger.info("Cleared TEL escrows") def cloneCreds(self, saids, db): """ Returns fully expanded credential with chained credentials attached. diff --git a/tests/app/cli/test_kli_commands.py b/tests/app/cli/test_kli_commands.py index afb021102..39281becf 100644 --- a/tests/app/cli/test_kli_commands.py +++ b/tests/app/cli/test_kli_commands.py @@ -3,7 +3,7 @@ import multicommand import pytest -from keri.app import directing, habbing +from keri.app import directing from keri.app.cli import commands from keri.app.cli.common import existing from keri.core import coring diff --git a/tests/db/test_basing.py b/tests/db/test_basing.py index b067985dc..df04d7345 100644 --- a/tests/db/test_basing.py +++ b/tests/db/test_basing.py @@ -11,6 +11,7 @@ import pytest from hio.base import doing +from keri.core.serdering import Serder from tests.app import openMultiSig from keri.kering import Versionage from keri.app import habbing @@ -21,7 +22,7 @@ from keri.core.eventing import incept, rotate, interact, Kever from keri.db import basing from keri.db import dbing -from keri.db.basing import openDB, Baser, KeyStateRecord +from keri.db.basing import openDB, Baser, KeyStateRecord, OobiRecord from keri.db.dbing import (dgKey, onKey, snKey) from keri.db.dbing import openLMDB from keri.help.helping import datify, dictify @@ -2274,6 +2275,76 @@ def test_group_members(): """End Test""" +def test_clear_escrows(): + with openDB() as db: + key = b'A.a' + vals = [b"z", b"m", b"x", b"a"] + + db.putUres(key, vals) + db.putVres(key, vals) + db.putPses(key, vals) + db.putPwes(key, vals) + db.putUwes(key, vals) + db.putOoes(key, vals) + db.putLdes(key, vals) + db.putQnfs(key, vals) + + preb = 'DAzwEHHzq7K0gzQPYGGwTmuupUhPx5_yZ-Wk1x4ejhcc'.encode("utf-8") + digb = 'EGAPkzNZMtX-QiVgbRbyAIZGoXvbGv9IPb0foWTZvI_4'.encode("utf-8") + key = dgKey(preb, digb) + ssnu1 = b'0AAAAAAAAAAAAAAAAAAAAAAB' + sdig1 = b'EALkveIFUPvt38xhtgYYJRCCpAGO7WjjHVR37Pawv67E' + val1 = ssnu1 + sdig1 + + db.putPde(key, val1) + + pre = 'k' + saider = coring.Saider(qb64b='EGAPkzNZMtX-QiVgbRbyAIZGoXvbGv9IPb0foWTZvI_4') + db.rpes.put(keys=('route',), vals=[saider]) + assert db.rpes.cnt(keys=('route',)) == 1 + + db.eoobi.pin(keys=('url',), val=OobiRecord()) + assert db.eoobi.cntAll() == 1 + + db.gpwe.add(keys=(pre,), val=(coring.Seqner(qb64b=b'0AAAAAAAAAAAAAAAAAAAAAAB'), saider)) + assert db.gpwe.cnt(keys=(pre,)) == 1 + + db.gdee.add(keys=(pre,), val=(coring.Seqner(qb64b=b'0AAAAAAAAAAAAAAAAAAAAAAB'), saider)) + assert db.gdee.cnt(keys=(pre,)) == 1 + + serder = Serder(raw=b'{"v":"KERI10JSON0000cb_","t":"ixn","d":"EG8WAmM29ZBdoXbnb87yiPxQw4Y7gcQjqZS74vBAKsRm","i":"DApYGFaqnrALTyejaJaGAVhNpSCtqyerPqWVK9ZBNZk0","s":"4","p":"EAskHI462CuIMS_gNkcl_QewzrRSKH2p9zHQIO132Z30","a":[]}') + db.dpwe.pin(keys=(pre, 'said'), val=serder) + assert db.dpwe.get(keys=(pre, 'said')) is not None + + db.gpse.add(keys=('qb64',), val=(coring.Seqner(qb64b=b'0AAAAAAAAAAAAAAAAAAAAAAB'), saider)) + assert db.gpse.cnt(keys=('qb64',)) == 1 + + db.epse.put(keys=('dig',), val=serder) + assert db.epse.get(keys=('dig',)) is not None + + db.dune.pin(keys=(pre, 'said'), val=serder) + assert db.dune.get(keys=(pre, 'said')) is not None + + db.clearEscrows() + + assert db.getUres(key) == [] + assert db.getVres(key) == [] + assert db.getPses(key) == [] + assert db.getPwes(key) == [] + assert db.getUwes(key) == [] + assert db.getOoes(key) == [] + assert db.getLdes(key) == [] + assert db.getQnfs(key) == [] + assert db.getPdes(key) == [] + assert db.rpes.cnt(keys=('route',)) == 0 + assert db.eoobi.cntAll() == 0 + assert db.gpwe.cnt(keys=(pre,)) == 0 + assert db.gdee.cnt(keys=(pre,)) == 0 + assert db.dpwe.get(keys=(pre, 'said')) is None + assert db.gpse.cnt(keys=('qb64',)) == 0 + assert db.epse.get(keys=('dig',)) is None + assert db.dune.get(keys=(pre, 'said')) is None + if __name__ == "__main__": test_baser() test_clean_baser() diff --git a/tests/vc/test_proving.py b/tests/vc/test_proving.py index bdb273be1..def769b0c 100644 --- a/tests/vc/test_proving.py +++ b/tests/vc/test_proving.py @@ -244,22 +244,22 @@ def test_privacy_preserving_credential(mockHelpingNowIso8601): engagementContextRole="Project Manager", ) - salt = coring.Salter(raw=b'0123456789abcdef').qb64 cred = credential(schema="EZllThM1rLBSMZ_ozM1uAnFvSfC0N1jaQ42aKU5sCZ5Q", recipient="EM_S2MdMaKgP6P2Yyno6-flV6GqrwPencTIw8tCMR7iB", private=True, - salt=salt, + private_credential_nonce=coring.Salter(raw=b'0123456789abcdef').qb64, + private_subject_nonce=coring.Salter(raw=b'abcdef0123456789').qb64, issuer="EMZeK1yLZd1JV6Ktdq_YUt-YbyoTWB9UMcFzuiDly2Y6", data=d, status="ETQoH02zJRCTNz-Wl3nnkUD_RVSzSwcoNvmfa18AWt3M") assert cred.size == len(cred.raw) assert "u" in cred.sad print(cred.raw) - assert cred.raw == (b'{"v":"ACDC10JSON00021c_","d":"ELFOCm58xUlId994cS6m6bsfYOkNHEKoe15Cav-Sj8__",' + assert cred.raw == (b'{"v":"ACDC10JSON00021c_","d":"EMMDzhHHlpQP0XNMRThDeIFkYD1WkDHF7Tp-8kt8X5pn",' b'"u":"0AAwMTIzNDU2Nzg5YWJjZGVm","i":"EMZeK1yLZd1JV6Ktdq_YUt-YbyoTWB9UMcFzuiDl' b'y2Y6","ri":"ETQoH02zJRCTNz-Wl3nnkUD_RVSzSwcoNvmfa18AWt3M","s":"EZllThM1rLBSM' - b'Z_ozM1uAnFvSfC0N1jaQ42aKU5sCZ5Q","a":{"d":"EFwWs1d_fe_VeLZ0vQQKO-gkRvGrpfWAR' - b'bI4e9tzcqlV","u":"0AAwMTIzNDU2Nzg5YWJjZGVm","i":"EM_S2MdMaKgP6P2Yyno6-flV6Gq' + b'Z_ozM1uAnFvSfC0N1jaQ42aKU5sCZ5Q","a":{"d":"EK3MRnlg-bMUnHtYKyZ8HD_IbBeI0v4N8' + b'YB4UnNVBqrv","u":"0ABhYmNkZWYwMTIzNDU2Nzg5","i":"EM_S2MdMaKgP6P2Yyno6-flV6Gq' b'rwPencTIw8tCMR7iB","dt":"2021-06-27T21:26:21.233257+00:00","LEI":"254900OPPU' b'84GM83MG36","personLegalName":"John Doe","engagementContextRole":"Project Ma' b'nager"}}')