-
Notifications
You must be signed in to change notification settings - Fork 370
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
plugin:adding did plugin support in indy-plenum
Signed-off-by: Atharva Amritkar <[email protected]>
- Loading branch information
1 parent
78d3ad3
commit 456dcef
Showing
27 changed files
with
1,849 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import json | ||
import base64 | ||
from nacl.signing import VerifyKey | ||
from nacl.exceptions import BadSignatureError | ||
|
||
""" | ||
1. The function wil recieve REQUEST_BODY somehow | ||
2. The REQUEST_BODY will have `DIDDocment`which will have all the info.... | ||
3. I will get `publicKeyMultibase` for verification purposes. | ||
4. Now get the `VerificationKey` and `Signature` from REQUEST_BODY. | ||
5. Then tried to verify it.... | ||
""" | ||
|
||
request = { | ||
"identifier": "EbP4aYNeTHL6q385GuVpRV", | ||
"operation": { | ||
"dest": "Vzfdscz6YG6n1EuNJV4ob1", | ||
"type": "20226", | ||
"data": { | ||
"DIDDocument": { | ||
"id": "did:exampleiin:org1", | ||
"verificationMethod": [ | ||
{ | ||
"id": "did:exampleiin:org1#key1", | ||
"type": "Ed25519VerificationKey2020", | ||
"controller": "did:exampleiin:org1", | ||
"publicKeyMultibase": "zH3C2AVvLMv6gmMNam3uVAjZpfkcJCwDwnZn6z3wXmqPV" | ||
} | ||
], | ||
"authentication": ["did:exampleiin:org1"] | ||
}, | ||
"signature": { | ||
"verificationMethod": "did:exampleiin:org1#key1", | ||
"sigbase64": "sdfsdfsdf" | ||
} | ||
}, | ||
"verkey": "~HFPBKb7S7ocrTzxakNbcao" | ||
}, | ||
"protocolVersion": 2, | ||
"reqId": 1704282737760629997 | ||
} | ||
|
||
# Get DID document | ||
did_doc = json.loads(request["operation"]["data"]["DIDDocument"]) | ||
|
||
# Get public key from DID document | ||
key_id = "did:exampleiin:org1#key1" | ||
public_key = did_doc["verificationMethod"][0]["publicKeyMultibase"] | ||
|
||
# Load public key | ||
verify_key = VerifyKey(base64.standard_b64decode(public_key)) | ||
|
||
# Get signature | ||
signature = base64.standard_b64decode(request["operation"]["data"]["signature"]["sigbase64"]) | ||
|
||
# Get signed data | ||
signed_data = json.dumps(did_doc) | ||
|
||
try: | ||
verify_key.verify(signed_data.encode(), signature) | ||
print("Signature is valid!") | ||
except BadSignatureError: | ||
print("Invalid signature!") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from plenum.common.messages.fields import FixedLengthField | ||
from plenum.server.plugin.did_plugin.transactions import DemoTransactions | ||
from plenum.server.plugin.did_plugin.constants import DID_PLUGIN_LEDGER_ID | ||
|
||
|
||
dummy_field_length = 10 | ||
LEDGER_IDS = {DID_PLUGIN_LEDGER_ID, } | ||
CLIENT_REQUEST_FIELDS = {'fix_length_dummy': | ||
FixedLengthField(dummy_field_length, | ||
optional=True, nullable=True)} | ||
|
||
AcceptableWriteTypes = {DemoTransactions.CREATE_DID.value, | ||
DemoTransactions.CREATE_NETWORK_DID.value, | ||
DemoTransactions.UPDATE_DID.value, | ||
DemoTransactions.UPDATE_NETWORK_DID.value, | ||
DemoTransactions.DEACTIVATE_DID.value, | ||
DemoTransactions.OUDID.value | ||
} | ||
|
||
AcceptableQueryTypes = {DemoTransactions.FETCH_DID.value, } |
Empty file.
16 changes: 16 additions & 0 deletions
16
plenum/server/plugin/did_plugin/batch_handlers/did_plugin_batch_handler.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from plenum.common.constants import DOMAIN_LEDGER_ID | ||
from plenum.server.batch_handlers.batch_request_handler import BatchRequestHandler | ||
from plenum.server.database_manager import DatabaseManager | ||
from plenum.server.plugin.did_plugin import DID_PLUGIN_LEDGER_ID | ||
|
||
|
||
class DIDBatchHandler(BatchRequestHandler): | ||
|
||
def __init__(self, database_manager: DatabaseManager): | ||
super().__init__(database_manager, DID_PLUGIN_LEDGER_ID) | ||
|
||
def post_batch_applied(self, three_pc_batch, prev_handler_result=None): | ||
pass | ||
|
||
def post_batch_rejected(self, ledger_id, prev_handler_result=None): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
import json | ||
import libnacl | ||
import libnacl.encode | ||
from plenum.common.exceptions import InvalidSignature | ||
|
||
def libnacl_validate(vk_base64, signature_base64, originalhash): | ||
vk = libnacl.encode.base64_decode(vk_base64) | ||
signature = libnacl.encode.base64_decode(signature_base64) | ||
verifiedhash = libnacl.crypto_sign_open(signature, vk) | ||
if signature == originalhash: | ||
raise InvalidSignature("The hash of the DIDDocument did not match.") | ||
# | ||
def libnacl_validate2(vk_base64, signature_base64): | ||
print("vk_base64", vk_base64) | ||
print("signature_base64", signature_base64) | ||
# vk = libnacl.encode.base64_decode(vk_base64) | ||
# signature = libnacl.encode.base64_decode(signature_base64) | ||
# verifiedhash = libnacl.crypto_sign_open(signature, vk) | ||
return signature_base64 | ||
|
||
def did_id_from_url(did_url: str) -> str: | ||
return did_url.split("#")[0] | ||
|
||
|
||
class DID: | ||
did = None | ||
id = None | ||
verification_methods = None | ||
authentication_methods = None | ||
|
||
def __init__(self, did_json) -> None: | ||
self.did = json.loads(did_json) | ||
self.id = self.did["id"] | ||
|
||
# populate verification methods: | ||
self.verification_methods = {} | ||
for method in self.did["verificationMethod"]: | ||
self.verification_methods[method["id"]] = method | ||
|
||
# populate authentication methods: | ||
self.authentication_methods = {} | ||
for method in self.did["authentication"]: | ||
if isinstance(method, dict): | ||
# fully specified method | ||
self.authentication_methods[method["id"]] = method | ||
elif isinstance(method, str): | ||
# id points to a verification method | ||
# TODO: if it points to a different did -> resolve that did and fetch method | ||
if method in self.verification_methods: | ||
self.authentication_methods[method] = self.verification_methods[method] | ||
# [{'controller': 'did:exampleiin:org1', 'id': 'did:exampleiin:org1#key1', 'publicKeyMultibase': '4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA', 'type': 'libnacl'}]} | ||
def fetch_authentication_method(self, authentication_method_id: str) -> dict: | ||
# if authentication_method_id in self.authentication_methods: | ||
# return self.authentication_methods[authentication_method_id] | ||
return authentication_method_id[0] | ||
|
||
def fetch_authentication(self, authentication_method_id: str) -> dict: | ||
if authentication_method_id in self.authentication_methods: | ||
return self.authentication_methods[authentication_method_id] | ||
return None | ||
|
||
|
||
|
||
class NetworkDID: | ||
did = None | ||
id = None | ||
verification_methods = None | ||
authentication_methods = None | ||
network_participants: list = None | ||
|
||
def __init__(self, did_json) -> None: | ||
self.did = json.loads(did_json) | ||
self.id = self.did["id"] | ||
self.network_participants = self.did["networkMembers"] | ||
|
||
assert(len(self.network_participants) > 0) | ||
|
||
# populate verification methods: | ||
self.verification_methods = {} | ||
for method in self.did["verificationMethod"]: | ||
self.verification_methods[method["id"]] = method | ||
|
||
# populate authentication methods: | ||
self.authentication_methods = {} | ||
for method in self.did["authentication"]: | ||
if isinstance(method, dict): | ||
# fully specified method | ||
self.authentication_methods[method["id"]] = method | ||
elif isinstance(method, str): | ||
# id points to a verification method | ||
# TODO: if it points to a different did -> resolve that did and fetch method | ||
if method in self.verification_methods: | ||
self.authentication_methods[method] = self.verification_methods[method] | ||
|
||
# ensure atleast one authentication method of type GroupMultiSig | ||
group_multisig_auth_support = False | ||
for method_id, method in self.authentication_methods.items(): | ||
if method["type"] == "BlockchainNetworkMultiSig": | ||
group_multisig_auth_support = True | ||
if not group_multisig_auth_support: | ||
raise Exception("Network DID does not have BlockchainNetworkMultiSig authentication method") | ||
|
||
# Get any one authentication method of type GroupMultiSig | ||
def fetch_authentication_method(self) -> dict: | ||
for method_id, method in self.authentication_methods.items(): | ||
if method["type"] == "BlockchainNetworkMultiSig": | ||
return method | ||
|
||
def fetch_signature(self) -> dict: | ||
|
||
|
||
|
||
|
||
class OUDID: | ||
did = None | ||
id = None | ||
verification_methods = None | ||
authentication_methods = None | ||
|
||
def __init__(self, did_json) -> None: | ||
self.did = json.loads(did_json) | ||
self.id = self.did["id"] | ||
|
||
# populate verification methods: | ||
self.verification_methods = {} | ||
for method in self.did["verificationMethod"]: | ||
self.verification_methods[method["id"]] = method | ||
|
||
# "authentication": ["did:<method-name>:<method-specific-id>"] | ||
# populate authentication methods: | ||
self.authentication_methods = {} | ||
for method in self.did["authentication"]: | ||
if isinstance(method, dict): | ||
# fully specified method | ||
self.authentication_methods[method["id"]] = method | ||
elif isinstance(method, str): | ||
# id points to a verification method | ||
# TODO: if it points to a different did -> resolve that did and fetch method | ||
if method in self.verification_methods: | ||
self.authentication_methods[method] = self.verification_methods[method] | ||
|
||
def fetch_authentication_method(self) -> dict: | ||
if authentication_method_id in self.authentication_methods: | ||
return self.authentication_methods[authentication_method_id] | ||
return None | ||
|
||
|
||
class SDDID: | ||
did = None | ||
id = None | ||
verification_methods = None | ||
authentication_methods = None | ||
network_participants: list = None | ||
|
||
def __init__(self, did_json) -> None: | ||
self.did = json.loads(did_json) | ||
self.id = self.did["id"] | ||
self.network_participants = self.did["networkMembers"] | ||
|
||
assert(len(self.network_participants) > 0) | ||
|
||
# populate verification methods: | ||
self.verification_methods = {} | ||
for method in self.did["verificationMethod"]: | ||
self.verification_methods[method["id"]] = method | ||
|
||
# populate authentication methods: | ||
self.authentication_methods = {} | ||
for method in self.did["authentication"]: | ||
if isinstance(method, dict): | ||
# fully specified method | ||
self.authentication_methods[method["id"]] = method | ||
elif isinstance(method, str): | ||
# id points to a verification method | ||
# TODO: if it points to a different did -> resolve that did and fetch method | ||
if method in self.verification_methods: | ||
self.authentication_methods[method] = self.verification_methods[method] | ||
|
||
# ensure atleast one authentication method of type BlockchainNetworkMultiSig | ||
group_multisig_auth_support = False | ||
for method_id, method in self.authentication_methods.items(): | ||
if method["type"] == "BlockchainNetworkMultiSig": | ||
group_multisig_auth_support = True | ||
if not group_multisig_auth_support: | ||
raise Exception("Network DID does not have BlockchainNetworkMultiSig authentication method") | ||
|
||
# Get any one authentication method of type BlockchainNetworkMultiSig | ||
def fetch_authentication_method(self) -> dict: | ||
for method_id, method in self.authentication_methods.items(): | ||
if method["type"] == "BlockchainNetworkMultiSig": | ||
return method |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from plenum.common.constants import KeyValueStorageType | ||
|
||
|
||
def get_config(config): | ||
config.didPluginTransactionsFile = 'did_plugin_transactions' | ||
config.didPluginStateStorage = KeyValueStorageType.Leveldb | ||
config.didPluginStateDbName = 'did_plugin_state' | ||
return config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import importlib | ||
|
||
import pytest | ||
from copy import deepcopy | ||
|
||
from plenum import setup_plugins, PLUGIN_LEDGER_IDS, PLUGIN_CLIENT_REQUEST_FIELDS | ||
from plenum.common.pkg_util import update_module_vars | ||
from plenum.server.plugin.did_plugin import AUCTION_LEDGER_ID | ||
from plenum.server.plugin.did_plugin.main import integrate_plugin_in_node | ||
|
||
|
||
def do_plugin_initialisation_for_tests(): | ||
# The next imports and reloading are needed only in tests, since in | ||
# production none of these modules would be loaded before plugins are | ||
# setup (not initialised) | ||
import plenum.server | ||
import plenum.common | ||
|
||
importlib.reload(plenum.server.replica) | ||
importlib.reload(plenum.server.consensus.view_change_trigger_service) | ||
importlib.reload(plenum.server.consensus.view_change_service) | ||
importlib.reload(plenum.server.consensus.view_change_storages) | ||
importlib.reload(plenum.server.consensus.ordering_service) | ||
importlib.reload(plenum.server.consensus.ordering_service_msg_validator) | ||
importlib.reload(plenum.server.node) | ||
importlib.reload(plenum.server.catchup.utils) | ||
importlib.reload(plenum.server.catchup.catchup_rep_service) | ||
importlib.reload(plenum.server.catchup.cons_proof_service) | ||
importlib.reload(plenum.server.catchup.ledger_leecher_service) | ||
importlib.reload(plenum.server.catchup.node_leecher_service) | ||
importlib.reload(plenum.server.catchup.seeder_service) | ||
importlib.reload(plenum.server.message_handlers) | ||
importlib.reload(plenum.server.observer.observable) | ||
importlib.reload(plenum.common.ledger_manager) | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def tconf(tconf, request): | ||
global PLUGIN_LEDGER_IDS, PLUGIN_CLIENT_REQUEST_FIELDS | ||
|
||
orig_plugin_root = deepcopy(tconf.PLUGIN_ROOT) | ||
orig_enabled_plugins = deepcopy(tconf.ENABLED_PLUGINS) | ||
orig_plugin_ledger_ids = deepcopy(PLUGIN_LEDGER_IDS) | ||
orig_plugin_client_req_fields = deepcopy(PLUGIN_CLIENT_REQUEST_FIELDS) | ||
|
||
update_module_vars('plenum.config', | ||
**{ | ||
'PLUGIN_ROOT': 'plenum.test.plugin', | ||
'ENABLED_PLUGINS': ['demo_plugin', ], | ||
}) | ||
PLUGIN_LEDGER_IDS = {AUCTION_LEDGER_ID} | ||
PLUGIN_CLIENT_REQUEST_FIELDS = {} | ||
setup_plugins() | ||
do_plugin_initialisation_for_tests() | ||
|
||
def reset(): | ||
global PLUGIN_LEDGER_IDS, PLUGIN_CLIENT_REQUEST_FIELDS | ||
update_module_vars('plenum.config', | ||
**{ | ||
'PLUGIN_ROOT': orig_plugin_root, | ||
'ENABLED_PLUGINS': orig_enabled_plugins, | ||
}) | ||
PLUGIN_LEDGER_IDS = orig_plugin_ledger_ids | ||
PLUGIN_CLIENT_REQUEST_FIELDS = orig_plugin_client_req_fields | ||
setup_plugins() | ||
|
||
request.addfinalizer(reset) | ||
return tconf | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def do_post_node_creation(): | ||
# Integrate plugin into each node. | ||
def _post_node_creation(node): | ||
integrate_plugin_in_node(node) | ||
|
||
return _post_node_creation | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def txn_pool_node_set_post_creation(tconf, do_post_node_creation, txnPoolNodeSet): | ||
return txnPoolNodeSet |
Oops, something went wrong.