示例#1
0
    def __getitem__(self, index: Union[SchemaKey, int, str]) -> dict:
        """
        Get schema by schema key, sequence number, or schema identifier. Raise CacheIndex for no such schema.

        Raise CacheIndex for no such index in schema store.

        :param index: schema key, sequence number, or schema identifier
        :return: corresponding schema or None
        """

        LOGGER.debug('SchemaCache.__getitem__ >>> index: %s', index)

        rv = None
        if isinstance(index, SchemaKey):
            rv = self._schema_key2schema[index]
        elif isinstance(index, int) or (isinstance(index, str)
                                        and not ok_schema_id(index)):
            try:
                rv = self._schema_key2schema[self._seq_no2schema_key[int(
                    index)]]
            except KeyError:
                LOGGER.debug(
                    'SchemaCache.__getitem__: <!< index %s not present', index)
                raise CacheIndex('{}'.format(index))
        elif isinstance(index, str):
            rv = self._schema_key2schema[schema_key(index)]
        else:
            LOGGER.debug(
                'SchemaCache.__getitem__: <!< index %s must be int SchemaKey, or schema id',
                index)
            raise CacheIndex(
                '{} must be int, SchemaKey, or schema id'.format(index))

        LOGGER.debug('SchemaCache.__getitem__ <<< %s', rv)
        return rv
示例#2
0
    async def get_schema(self, index: Union[SchemaKey, int, str]) -> str:
        """
        Get schema from ledger by SchemaKey namedtuple (origin DID, name, version),
        sequence number, or schema identifier.

        Raise AbsentSchema for no such schema, logging any error condition and raising
        BadLedgerTxn on bad request.

        Retrieve the schema from the anchor's schema cache if it has it; cache it
        en passant if it does not (and there is a corresponding schema on the ledger).

        :param index: schema key (origin DID, name, version), sequence number, or schema identifier
        :return: schema json, parsed from ledger
        """

        LOGGER.debug('BaseAnchor.get_schema >>> index: %s', index)

        rv_json = json.dumps({})
        with SCHEMA_CACHE.lock:
            if SCHEMA_CACHE.contains(index):
                LOGGER.info('BaseAnchor.get_schema: got schema %s from cache', index)
                rv_json = SCHEMA_CACHE[index]
                LOGGER.debug('BaseAnchor.get_schema <<< %s', rv_json)
                return json.dumps(rv_json)

            if isinstance(index, SchemaKey) or (isinstance(index, str) and ok_schema_id(index)):
                s_id = schema_id(*index) if isinstance(index, SchemaKey) else index
                s_key = schema_key(s_id)
                req_json = await ledger.build_get_schema_request(self.did, s_id)
                resp_json = await self._submit(req_json)
                resp = json.loads(resp_json)

                if not ('result' in resp and resp['result'].get('data', {}).get('attr_names', None)):
                    LOGGER.debug('BaseAnchor.get_schema <!< no schema exists on %s', index)
                    raise AbsentSchema('No schema exists on {}'.format(index))
                try:
                    (_, rv_json) = await ledger.parse_get_schema_response(resp_json)
                except IndyError:  # ledger replied, but there is no such schema
                    LOGGER.debug('BaseAnchor.get_schema <!< no schema exists on %s', index)
                    raise AbsentSchema('No schema exists on {}'.format(index))
                SCHEMA_CACHE[s_key] = json.loads(rv_json)  # cache indexes by both txn# and schema key en passant
                LOGGER.info('BaseAnchor.get_schema: got schema %s from ledger', index)

            elif isinstance(index, (int, str)):  # index is not a schema id: it's a stringified int txn# if it's a str
                txn_json = await self.get_txn(int(index))  # raises AbsentPool if anchor has no pool
                txn = json.loads(txn_json)
                if txn.get('type', None) == '101':  # {} for no such txn; 101 marks indy-sdk schema txn type
                    rv_json = await self.get_schema(self.pool.protocol.txn_data2schema_key(txn))
                else:
                    LOGGER.debug('BaseAnchor.get_schema <!< no schema at seq #%s on ledger', index)
                    raise AbsentSchema('No schema at seq #{} on ledger'.format(index))

            else:
                LOGGER.debug('BaseAnchor.get_schema <!< bad schema index type')
                raise AbsentSchema('Attempt to get schema on ({}) {} , must use schema key or an int'.format(
                    type(index),
                    index))

        LOGGER.debug('BaseAnchor.get_schema <<< %s', rv_json)
        return rv_json
示例#3
0
    def feed(self, schemata: list) -> None:
        """
        Take schemata from incoming list representation as schemata() returns, unless
        cache already has schema for an incoming schema sequence number.

        :param schemata: list of schema objects
        """

        LOGGER.debug('SchemaCache.feed >>> schemata: %s', schemata)

        for schema in schemata:
            seq_no = schema['seqNo']
            s_id = schema['id']
            if not ok_schema_id(s_id):
                LOGGER.warning(
                    'Abstaining from feeding schema cache from bad id %s',
                    s_id)
            elif self.contains(seq_no):
                LOGGER.warning(
                    'Schema cache already has schema at seq no %s: skipping',
                    seq_no)
            else:
                self[seq_no] = schema
                LOGGER.info(
                    'Schema cache imported schema on id %s at seq no %s', s_id,
                    seq_no)

        LOGGER.debug('SchemaCache.feed <<<')
示例#4
0
    async def load_cache_for_verification(self, archive: bool = False) -> int:
        """
        Load schema, cred def, revocation caches; optionally archive enough to go
        offline and be able to verify proof on content marked of interest in configuration.

        Return timestamp (epoch seconds) of cache load event, also used as subdirectory
        for cache archives.

        :param archive: True to archive now or False to demur (subclasses may still
            need to augment archivable caches further)
        :return: cache load event timestamp (epoch seconds)
        """

        LOGGER.debug('Verifier.load_cache_for_verification >>> archive: %s',
                     archive)

        rv = int(time())
        for s_id in self.config.get('archive-verifier-caches-on-close',
                                    {}).get('schema_id', {}):
            if ok_schema_id(s_id):
                with SCHEMA_CACHE.lock:
                    await self.get_schema(s_id)
            else:
                LOGGER.info('Not archiving schema for specified bad id %s',
                            s_id)
        for cd_id in self.config.get('archive-verifier-caches-on-close',
                                     {}).get('cred_def_id', {}):
            if ok_cred_def_id(cd_id):
                with CRED_DEF_CACHE.lock:
                    await self.get_cred_def(cd_id)
            else:
                LOGGER.info('Not archiving cred def for specified bad id %s',
                            cd_id)
        for rr_id in self.config.get('archive-verifier-caches-on-close',
                                     {}).get('rev_reg_id', {}):
            if ok_rev_reg_id(rr_id):
                await self.get_rev_reg_def(rr_id)
                with REVO_CACHE.lock:
                    revo_cache_entry = REVO_CACHE.get(rr_id, None)
                    if revo_cache_entry:
                        try:
                            await revo_cache_entry.get_state_json(
                                self._build_rr_state_json, rv, rv)
                        except ClosedPool:
                            LOGGER.warning(
                                'Verifier %s is offline from pool %s, cannot update revo cache reg state for %s to %s',
                                self.name, self.pool.name, rr_id, rv)
                        except AbsentPool:
                            LOGGER.warning(
                                'Verifier %s has no pool, cannot update revo cache reg state for %s to %s',
                                self.name, rr_id, rv)
            else:
                LOGGER.info('Not archiving rev reg for specified bad id %s',
                            rr_id)

        if archive:
            ArchivableCaches.archive(self.dir_cache)
        LOGGER.debug('Verifier.load_cache_for_verification <<< %s', rv)
        return rv
示例#5
0
async def test_box_ids():
    print(Ink.YELLOW('\n\n== Testing Box Identifier Checks =='))
    
    assert ok_did('Q4zqM7aXqm7gDQkUVLng9h')  # quibble: not technically a box id
    assert not ok_did('Q4zqM7aXqm7gDQkUVLng9I')
    assert not ok_did('Q4zqM7aXqm7gDQkUVLng')

    assert Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9h')
    assert Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9h')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9hx')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng90')

    assert ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:3:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h::bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2::1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:1.0a')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9I:2:bc-reg:1.0')  # I is not in base58

    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag')  # protocol >= 1.4
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:4:CL:18:0')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h::CL:18:0')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9I:3:CL:18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3::18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18z:tag')
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18')  # protocol == 1.3

    assert ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1')  # protocol >= 1.4
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:5:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:4:CL:20:0:CL_ACCUM:1')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL::CL:20:0:CL_ACCUM:1')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:NOT_CL:20:tag:CL_ACCUM:1')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20z:tag:CL_ACCUM:1')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20::CL_ACCUM:1')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag::1')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:1')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:')
    assert not ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM')
    assert ok_rev_reg_id('LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1')  # protocol == 1.3
示例#6
0
 async def _set_schema(s_id: str) -> None:
     nonlocal s_id2schema
     if not ok_schema_id(s_id):
         LOGGER.debug('Verifier.verify_proof <!< Bad schema id %s', s_id)
         raise BadIdentifier('Bad schema id {}'.format(s_id))
     if s_id not in s_id2schema:
         schema = json.loads(await self.get_schema(s_id))  # add to cache en passant
         if not schema:
             LOGGER.debug(
                 'Verifier.verify_proof <!< absent schema %s, proof req may be for another ledger',
                 s_id)
             raise AbsentSchema('Absent schema {}, proof req may be for another ledger'.format(s_id))
         s_id2schema[s_id] = schema
示例#7
0
    def contains(self, index: Union[SchemaKey, int, str]) -> bool:
        """
        Return whether the cache contains a schema for the input key, sequence number, or schema identifier.

        :param index: schema key, sequence number, or sequence identifier
        :return: whether the cache contains a schema for the input index
        """

        LOGGER.debug('SchemaCache.contains >>> index: %s', index)

        rv = None
        if isinstance(index, SchemaKey):
            rv = (index in self._schema_key2schema)
        elif isinstance(index, int) or (isinstance(index, str)
                                        and not ok_schema_id(index)):
            rv = (int(index) in self._seq_no2schema_key)
        elif isinstance(index, str):
            rv = (schema_key(index) in self._schema_key2schema)
        else:
            rv = False

        LOGGER.debug('SchemaCache.contains <<< %s', rv)
        return rv
示例#8
0
    async def send_cred_def(self,
                            s_id: str,
                            revocation: bool = True,
                            rr_size: int = None) -> str:
        """
        Create a credential definition as Issuer, store it in its wallet, and send it to the ledger.

        Raise CorruptWallet for wallet not pertaining to current ledger, BadLedgerTxn on failure
        to send credential definition to ledger if need be, or IndyError for any other failure
        to create and store credential definition in wallet.

        :param s_id: schema identifier
        :param revocation: whether to support revocation for cred def
        :param rr_size: size of initial revocation registry (default as per _create_rev_reg()), if revocation supported
        :return: json credential definition as it appears on ledger
        """

        LOGGER.debug(
            'Issuer.send_cred_def >>> s_id: %s, revocation: %s, rr_size: %s',
            s_id, revocation, rr_size)

        if not ok_schema_id(s_id):
            LOGGER.debug('Issuer.send_cred_def <!< Bad schema id %s', s_id)
            raise BadIdentifier('Bad schema id {}'.format(s_id))

        rv_json = json.dumps({})
        schema_json = await self.get_schema(schema_key(s_id))
        schema = json.loads(schema_json)

        cd_id = cred_def_id(self.did, schema['seqNo'], self.pool.protocol)
        private_key_ok = True
        with CRED_DEF_CACHE.lock:
            try:
                rv_json = await self.get_cred_def(cd_id)
                LOGGER.info(
                    'Cred def on schema %s version %s already exists on ledger; Issuer %s not sending another',
                    schema['name'], schema['version'], self.wallet.name)
            except AbsentCredDef:
                pass  # OK - about to create, store, and send it

            try:
                (_, cred_def_json
                 ) = await anoncreds.issuer_create_and_store_credential_def(
                     self.wallet.handle,
                     self.did,  # issuer DID
                     schema_json,
                     self.pool.protocol.cd_id_tag(
                         False
                     ),  # expect only one cred def per schema and issuer
                     'CL',
                     json.dumps({'support_revocation': revocation}))
                if json.loads(rv_json):
                    private_key_ok = False
                    LOGGER.warning(
                        'New cred def on %s in wallet shadows existing one on ledger: private key not usable',
                        cd_id)
                    # carry on though, this anchor may have other roles so public key may be good enough
            except IndyError as x_indy:
                if x_indy.error_code == ErrorCode.AnoncredsCredDefAlreadyExistsError:
                    if json.loads(rv_json):
                        LOGGER.info(
                            'Issuer wallet %s reusing existing cred def on schema %s version %s',
                            self.wallet.name, schema['name'],
                            schema['version'])
                    else:
                        LOGGER.debug(
                            'Issuer.send_cred_def: <!< corrupt wallet %s',
                            self.wallet.name)
                        raise CorruptWallet(
                            'Corrupt Issuer wallet {} has cred def on schema {} version {} not on ledger'
                            .format(self.wallet.name, schema['name'],
                                    schema['version']))
                else:
                    LOGGER.debug(
                        'Issuer.send_cred_def: <!< cannot store cred def in wallet %s: indy error code %s',
                        self.wallet.name, x_indy.error_code)
                    raise

            if not json.loads(
                    rv_json
            ):  # checking the ledger returned no cred def: send it
                req_json = await ledger.build_cred_def_request(
                    self.did, cred_def_json)
                await self._sign_submit(req_json)

                for _ in range(16):  # reasonable timeout
                    try:
                        rv_json = await self.get_cred_def(cd_id
                                                          )  # adds to cache
                        break
                    except AbsentCredDef:
                        await sleep(1)
                        LOGGER.info(
                            'Sent cred def %s to ledger, waiting 1s for its appearance',
                            cd_id)

                if not rv_json:
                    LOGGER.debug(
                        'Issuer.send_cred_def <!< timed out waiting on sent cred_def %s',
                        cd_id)
                    raise BadLedgerTxn(
                        'Timed out waiting on sent cred_def {}'.format(cd_id))

                if revocation:
                    await self._sync_revoc(
                        rev_reg_id(cd_id, 0),
                        rr_size)  # create new rev reg, tails file for tag 0

        if revocation and private_key_ok:
            for tag in [
                    str(t) for t in range(
                        int(Tails.next_tag(self._dir_tails, cd_id)[0]))
            ]:  # '0' to str(next-1)
                await self._sync_revoc(rev_reg_id(cd_id, tag),
                                       rr_size if tag == 0 else None)

        makedirs(join(self._dir_tails, cd_id), exist_ok=True
                 )  # make sure dir exists for box id collection, revo or not

        LOGGER.debug('Issuer.send_cred_def <<< %s', rv_json)
        return rv_json
示例#9
0
    async def verify_proof(self, proof_req: dict, proof: dict) -> str:
        """
        Verify proof as Verifier. Raise AbsentRevReg if a proof cites a revocation registry
        that does not exist on the distributed ledger.

        :param proof_req: proof request as Verifier creates, as per proof_req_json above
        :param proof: proof as HolderProver creates
        :return: json encoded True if proof is valid; False if not
        """

        LOGGER.debug('Verifier.verify_proof >>> proof_req: %s, proof: %s',
                     proof_req, proof)

        s_id2schema = {}
        cd_id2cred_def = {}
        rr_id2rr_def = {}
        rr_id2rr = {}
        proof_ids = proof['identifiers']

        for proof_id in proof_ids:
            # schema
            s_id = proof_id['schema_id']
            if not ok_schema_id(s_id):
                LOGGER.debug('Verifier.verify_proof: <!< Bad schema id %s',
                             s_id)
                raise BadIdentifier('Bad schema id {}'.format(s_id))

            if s_id not in s_id2schema:
                schema = json.loads(
                    await self.get_schema(s_id))  # add to cache en passant
                if not schema:
                    LOGGER.debug(
                        'Verifier.verify_proof: <!< absent schema %s, proof req may be for another ledger',
                        s_id)
                    raise AbsentSchema(
                        'Absent schema {}, proof req may be for another ledger'
                        .format(s_id))
                s_id2schema[s_id] = schema

            # cred def
            cd_id = proof_id['cred_def_id']
            if not ok_cred_def_id(cd_id):
                LOGGER.debug('Verifier.verify_proof: <!< Bad cred def id %s',
                             cd_id)
                raise BadIdentifier('Bad cred def id {}'.format(cd_id))

            if cd_id not in cd_id2cred_def:
                cred_def = json.loads(
                    await self.get_cred_def(cd_id))  # add to cache en passant
                cd_id2cred_def[cd_id] = cred_def

            # rev reg def
            rr_id = proof_id['rev_reg_id']
            if not rr_id:
                continue
            if not ok_rev_reg_id(rr_id):
                LOGGER.debug('Verifier.verify_proof: <!< Bad rev reg id %s',
                             rr_id)
                raise BadIdentifier('Bad rev reg id {}'.format(rr_id))

            rr_def_json = await self._get_rev_reg_def(rr_id)
            rr_id2rr_def[rr_id] = json.loads(rr_def_json)

            # timestamp
            timestamp = proof_id['timestamp']
            with REVO_CACHE.lock:
                revo_cache_entry = REVO_CACHE.get(rr_id, None)
                (rr_json, _) = await revo_cache_entry.get_state_json(
                    self._build_rr_state_json, timestamp, timestamp)
                if rr_id not in rr_id2rr:
                    rr_id2rr[rr_id] = {}
                rr_id2rr[rr_id][timestamp] = json.loads(rr_json)

        rv = json.dumps(await anoncreds.verifier_verify_proof(
            json.dumps(proof_req), json.dumps(proof), json.dumps(s_id2schema),
            json.dumps(cd_id2cred_def), json.dumps(rr_id2rr_def),
            json.dumps(rr_id2rr)))

        LOGGER.debug('Verifier.verify_proof <<< %s', rv)
        return rv
示例#10
0
async def test_ids():
    print(Ink.YELLOW('\n\n== Testing Identifier Checks =='))

    assert ok_wallet_reft('49ad0727-8663-45ae-a115-12b09860f9c6')
    assert not ok_wallet_reft('Q4zqM7aXqm7gDQkUVLng9I')
    assert not ok_wallet_reft('49ad0727-45ae-a115-12b09860f9c6')
    print('\n\n== 1 == Wallet referent identifier checks pass OK')

    assert ok_did('Q4zqM7aXqm7gDQkUVLng9h')
    assert not ok_did('Q4zqM7aXqm7gDQkUVLng9I')  # 'I' not a base58 char
    assert not ok_did('Q4zqM7aXqm7gDQkUVLng')  # too short
    print('\n\n== 2 == Distributed identifier checks pass OK')

    for value in (None, 'TRUSTEE', 'STEWARD', 'TRUST_ANCHOR', ''):
        assert ok_role(value)
    for value in (123, 'TRUSTY', 'STEW', 'ANCHOR', ' '):
        assert not ok_role(value)
    print('\n\n== 3 == Role identifier checks pass OK')

    assert Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9h')
    assert Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9h')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9hx')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng90')
    print('\n\n== 4 == Tails hash identifier checks pass OK')

    assert ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:3:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h::bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2::1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:1.0a')
    assert not ok_schema_id(
        'Q4zqM7aXqm7gDQkUVLng9I:2:bc-reg:1.0')  # I is not in base58
    print('\n\n== 5 == Schema identifier checks pass OK')

    assert ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag')  # protocol >= 1.4
    assert ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:Q4zqM7aXqm7gDQkUVLng9h:2:schema_name:1.0:tag'
    )  # long form
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag',
                          'Q4zqM7aXqm7gDQkUVLng9h')  # issuer-did
    assert ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:Q999999999999999999999:2:schema_name:1.0:tag',
        'Q4zqM7aXqm7gDQkUVLng9h')  # long form, issuer-did
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag',
                              'Xxxxxxxxxxxxxxxxxxxxxx')
    assert not ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:Q4zqM7aXqm7gDQkUVLng9h:2:schema_name:1.0:tag',
        'Xxxxxxxxxxxxxxxxxxxxxx')  # long form, issuer-did
    assert ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:Q4zqM7aXqm7gDQkUVLng9h:2:schema_name:1.0:tag'
    )  # long form
    assert not ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:Q4zqM7aXqm7gDQkUVLng9h:schema_name:1.0:tag'
    )  # no :2:
    assert not ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:QIIIIIIIII7gDQkUVLng9h:schema_name:1.0:tag'
    )  # I not base58
    assert not ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:QIIIIIIIII7gDQkUVLng9h:schema_name:v1.0:tag'
    )  # bad version
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:4:CL:18:0')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h::CL:18:0')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9I:3:CL:18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3::18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18z:tag')
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18')  # protocol == 1.3
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18',
                          'Q4zqM7aXqm7gDQkUVLng9h')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18',
                              'Xxxxxxxxxxxxxxxxxxxxxx')
    assert ok_cred_def_id(
        rev_reg_id2cred_def_id(
            'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:Q4zqM7aXqm7gDQkUVLng9h:2:schema_name:1.0:tag:CL_ACCUM:1'
        ))
    print('\n\n== 6 == Credential definition identifier checks pass OK')

    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1'
    )  # protocol >= 1.4
    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1',
        'LjgpST2rjsoxYegQDRm7EL')
    assert ok_rev_reg_id(  # long form
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:Q4zqM7aXqm7gDQkUVLng9h:2:schema_name:1.0:tag:CL_ACCUM:1'
    )
    assert ok_rev_reg_id(  # long form
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:Q4zqM7aXqm7gDQkUVLng9h:2:schema_name:1.0:tag:CL_ACCUM:1',
        'LjgpST2rjsoxYegQDRm7EL')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1',
        'Xxxxxxxxxxxxxxxxxxxxxx')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:5:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:4:CL:20:0:CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL::CL:20:0:CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:NOT_CL:20:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20z:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20::CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag::1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM')
    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1'
    )  # protocol == 1.3
    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1',
        'LjgpST2rjsoxYegQDRm7EL')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1',
        'Xxxxxxxxxxxxxxxxxxxxxx')
    print('\n\n== 7 == Revocation registry identifier checks pass OK')
示例#11
0
    async def send_cred_def(self,
                            s_id: str,
                            revo: bool = True,
                            rr_size: int = None) -> str:
        """
        Create a credential definition as Issuer, store it in its wallet, and send it to the ledger.

        Raise CorruptWallet for wallet not pertaining to current ledger, BadLedgerTxn on failure
        to send credential definition to ledger if need be, WalletState for closed wallet,
        or IndyError for any other failure to create and store credential definition in wallet.

        :param s_id: schema identifier
        :param revo: whether to support revocation for cred def
        :param rr_size: size of initial revocation registry (default as per RevRegBuilder.create_rev_reg()),
            if revocation supported
        :return: json credential definition as it appears on ledger
        """

        LOGGER.debug(
            'Issuer.send_cred_def >>> s_id: %s, revo: %s, rr_size: %s', s_id,
            revo, rr_size)

        if not ok_schema_id(s_id):
            LOGGER.debug('Issuer.send_cred_def <!< Bad schema id %s', s_id)
            raise BadIdentifier('Bad schema id {}'.format(s_id))

        if not self.wallet.handle:
            LOGGER.debug('Issuer.send_cred_def <!< Wallet %s is closed',
                         self.name)
            raise WalletState('Wallet {} is closed'.format(self.name))

        if not self.pool:
            LOGGER.debug('Issuer.send_cred_def <!< issuer %s has no pool',
                         self.name)
            raise AbsentPool(
                'Issuer {} has no pool: cannot send cred def'.format(
                    self.name))

        rv_json = json.dumps({})
        schema_json = await self.get_schema(schema_key(s_id))
        schema = json.loads(schema_json)

        cd_id = cred_def_id(self.did, schema['seqNo'], self.pool.protocol)
        private_key_ok = True
        with CRED_DEF_CACHE.lock:
            try:
                rv_json = await self.get_cred_def(cd_id)
                LOGGER.info(
                    'Cred def on schema %s version %s already exists on ledger; Issuer %s not sending another',
                    schema['name'], schema['version'], self.name)
            except AbsentCredDef:
                pass  # OK - about to create, store, and send it

            (cred_def_json, private_key_ok) = await self._create_cred_def(
                schema, json.loads(rv_json), revo)

            if not json.loads(
                    rv_json
            ):  # checking the ledger returned no cred def: send it
                req_json = await ledger.build_cred_def_request(
                    self.did, cred_def_json)
                await self._sign_submit(req_json)

                for _ in range(16):  # reasonable timeout
                    try:
                        rv_json = await self.get_cred_def(cd_id
                                                          )  # adds to cache
                        break
                    except AbsentCredDef:
                        await asyncio.sleep(1)
                        LOGGER.info(
                            'Sent cred def %s to ledger, waiting 1s for its appearance',
                            cd_id)

                if not rv_json:
                    LOGGER.debug(
                        'Issuer.send_cred_def <!< timed out waiting on sent cred_def %s',
                        cd_id)
                    raise BadLedgerTxn(
                        'Timed out waiting on sent cred_def {}'.format(cd_id))

                if revo:  # create new rev reg for tag '0'
                    if self.rrbx:
                        (_, rr_size_suggested) = Tails.next_tag(
                            self.dir_tails, cd_id)
                        self.rrb.mark_in_progress(rev_reg_id(cd_id, '0'),
                                                  rr_size or rr_size_suggested)

                    await self._sync_revoc_for_issue(rev_reg_id(
                        cd_id, '0'), rr_size)  # sync rev reg on tag '0'

        if revo and private_key_ok:
            for tag in [
                    str(t) for t in range(
                        1, int(Tails.next_tag(self.dir_tails, cd_id)[0]))
            ]:  # '1' to next-1
                await self._sync_revoc_for_issue(
                    rev_reg_id(cd_id, tag), rr_size if tag == '0' else None)

        makedirs(
            join(self.dir_tails, cd_id),
            exist_ok=True)  # dir required for box id collection, revo or not

        LOGGER.debug('Issuer.send_cred_def <<< %s', rv_json)
        return rv_json
示例#12
0
async def test_box_ids():
    print(Ink.YELLOW('\n\n== Testing Identifier Checks =='))

    assert ok_wallet_reft('49ad0727-8663-45ae-a115-12b09860f9c6')
    assert not ok_wallet_reft('Q4zqM7aXqm7gDQkUVLng9I')
    assert not ok_wallet_reft('49ad0727-45ae-a115-12b09860f9c6')

    assert ok_did(
        'Q4zqM7aXqm7gDQkUVLng9h')  # quibble: not technically a box id
    assert not ok_did('Q4zqM7aXqm7gDQkUVLng9I')
    assert not ok_did('Q4zqM7aXqm7gDQkUVLng')

    for value in (None, 'TRUSTEE', 'STEWARD', 'TRUST_ANCHOR', ''):
        assert ok_role(value)
    for value in (123, 'TRUSTY', 'STEW', 'ANCHOR', ' '):
        assert not ok_role(value)

    assert Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9h')
    assert Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9h')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9hx')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng90')

    assert ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:3:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h::bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2::1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:1.0a')
    assert not ok_schema_id(
        'Q4zqM7aXqm7gDQkUVLng9I:2:bc-reg:1.0')  # I is not in base58

    assert ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag')  # protocol >= 1.4
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag',
                          'Q4zqM7aXqm7gDQkUVLng9h')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag',
                              'Xxxxxxxxxxxxxxxxxxxxxx')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:4:CL:18:0')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h::CL:18:0')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9I:3:CL:18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3::18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18z:tag')
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18')  # protocol == 1.3
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18',
                          'Q4zqM7aXqm7gDQkUVLng9h')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18',
                              'Xxxxxxxxxxxxxxxxxxxxxx')

    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1'
    )  # protocol >= 1.4
    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1',
        'LjgpST2rjsoxYegQDRm7EL')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1',
        'Xxxxxxxxxxxxxxxxxxxxxx')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:5:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:4:CL:20:0:CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL::CL:20:0:CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:NOT_CL:20:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20z:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20::CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag::1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM')

    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1'
    )  # protocol == 1.3
    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1',
        'LjgpST2rjsoxYegQDRm7EL')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1',
        'Xxxxxxxxxxxxxxxxxxxxxx')

    assert ok_endpoint('10.0.0.2:9702')
    assert ok_endpoint('0.0.0.0:0')
    assert not ok_endpoint('canada.gc.ca:8088')
    assert not ok_endpoint(':37')
    assert not ok_endpoint('http://url-wrong')
    assert not ok_endpoint('2.3.4.5')
    assert not ok_endpoint('2.3.4:8080')
    assert not ok_endpoint('1.2.3.4:abc')
    assert not ok_endpoint('1.2.3.4:1234.56')
示例#13
0
async def test_ids():
    print(Ink.YELLOW('\n\n== Testing Identifier Checks =='))

    assert ok_wallet_reft('49ad0727-8663-45ae-a115-12b09860f9c6')
    assert not ok_wallet_reft('Q4zqM7aXqm7gDQkUVLng9I')
    assert not ok_wallet_reft('49ad0727-45ae-a115-12b09860f9c6')
    print('\n\n== 1 == Wallet referent identifier checks pass OK')

    assert ok_did('Q4zqM7aXqm7gDQkUVLng9h')
    assert not ok_did('Q4zqM7aXqm7gDQkUVLng9I')  # 'I' not a base58 char
    assert not ok_did('Q4zqM7aXqm7gDQkUVLng')  # too short
    print('\n\n== 2 == Distributed identifier checks pass OK')

    for value in (None, 'TRUSTEE', 'STEWARD', 'TRUST_ANCHOR', ''):
        assert ok_role(value)
    for value in (123, 'TRUSTY', 'STEW', 'ANCHOR', ' '):
        assert not ok_role(value)
    print('\n\n== 3 == Role identifier checks pass OK')

    assert Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9h')
    assert Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9h')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng9hx')
    assert not Tails.ok_hash('Q4zqM7aXqm7gDQkUVLng9hQ4zqM7aXqm7gDQkUVLng90')
    print('\n\n== 4 == Tails hash identifier checks pass OK')

    assert ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:3:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h::bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:bc-reg:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2::1.0')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:')
    assert not ok_schema_id('Q4zqM7aXqm7gDQkUVLng9h:2:bc-reg:1.0a')
    assert not ok_schema_id(
        'Q4zqM7aXqm7gDQkUVLng9I:2:bc-reg:1.0')  # I is not in base58
    print('\n\n== 5 == Schema identifier checks pass OK')

    assert ok_cred_def_id(
        'Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag')  # protocol >= 1.4
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag',
                          'Q4zqM7aXqm7gDQkUVLng9h')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18:tag',
                              'Xxxxxxxxxxxxxxxxxxxxxx')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:4:CL:18:0')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h::CL:18:0')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9I:3:CL:18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3::18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:18:tag')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18z:tag')
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18')  # protocol == 1.3
    assert ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18',
                          'Q4zqM7aXqm7gDQkUVLng9h')
    assert not ok_cred_def_id('Q4zqM7aXqm7gDQkUVLng9h:3:CL:18',
                              'Xxxxxxxxxxxxxxxxxxxxxx')
    print('\n\n== 6 == Credential definition identifier checks pass OK')

    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1'
    )  # protocol >= 1.4
    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1',
        'LjgpST2rjsoxYegQDRm7EL')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1',
        'Xxxxxxxxxxxxxxxxxxxxxx')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:5:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:4:CL:20:0:CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL::CL:20:0:CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:NOT_CL:20:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20z:tag:CL_ACCUM:1'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20::CL_ACCUM:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag::1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:1')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM:'
    )
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:tag:CL_ACCUM')
    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1'
    )  # protocol == 1.3
    assert ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1',
        'LjgpST2rjsoxYegQDRm7EL')
    assert not ok_rev_reg_id(
        'LjgpST2rjsoxYegQDRm7EL:4:LjgpST2rjsoxYegQDRm7EL:3:CL:20:CL_ACCUM:1',
        'Xxxxxxxxxxxxxxxxxxxxxx')
    print('\n\n== 7 == Revocation registry identifier checks pass OK')

    assert ok_endpoint('10.0.0.2:9702')
    assert ok_endpoint('0.0.0.0:0')
    assert not ok_endpoint('canada.gc.ca:8088')
    assert not ok_endpoint(':37')
    assert not ok_endpoint('http://url-wrong')
    assert not ok_endpoint('2.3.4.5')
    assert not ok_endpoint('2.3.4:8080')
    assert not ok_endpoint('1.2.3.4:abc')
    assert not ok_endpoint('1.2.3.4:1234.56')
    print('\n\n== 8 == Endpoint checks pass OK')