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

[WiP] - plugin:adding did plugin support in indy-plenum #1654

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions plenum/server/plugin/did_plugin/Functionalities/OU_DID.py
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!")
20 changes: 20 additions & 0 deletions plenum/server/plugin/did_plugin/__init__.py
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.
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
191 changes: 191 additions & 0 deletions plenum/server/plugin/did_plugin/common.py
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
8 changes: 8 additions & 0 deletions plenum/server/plugin/did_plugin/config.py
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
82 changes: 82 additions & 0 deletions plenum/server/plugin/did_plugin/conftest.py
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
Loading