Coverage for admin/misc.py: 62%
96 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-07-10 13:43 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-07-10 13:43 +0000
1# The MIT License (MIT)
2#
3# Copyright (c) 2021 RSK Labs Ltd
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy of
6# this software and associated documentation files (the "Software"), to deal in
7# the Software without restriction, including without limitation the rights to
8# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9# of the Software, and to permit persons to whom the Software is furnished to do
10# so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
23import sys
24import time
25from getpass import getpass
26from ledger.hsm2dongle import HSM2Dongle
27from sgx.hsm2dongle import HSM2DongleSGX
28from ledger.pin import BasePin
29from .dongle_admin import DongleAdmin
30from .dongle_eth import DongleEth
31from comm.platform import Platform
32from .utils import is_hex_string_of_length, normalize_hex_string
33from .rsk_client import RskClient, RskClientError
36PIN_ERROR_MESSAGE = ("Invalid pin given. It must be exactly 8 alphanumeric "
37 "characters with at least one alphabetic character.")
38PIN_ERROR_MESSAGE_ANYCHARS = (
39 "Invalid pin given. It must be composed only of alphanumeric characters.")
41SIGNER_WAIT_TIME = 3 # seconds
43ATTESTATION_UD_VALUE_LENGTH = 32 # bytes
44DEFAULT_ATT_UD_SOURCE = "https://public-node.rsk.co"
47class AdminError(RuntimeError):
48 pass
51def info(s, nl=True):
52 newline = "\n" if nl else ""
53 sys.stdout.write(f"{s}{newline}")
54 sys.stdout.flush()
57def head(ss, fill="*", nl=True):
58 if type(ss) == str:
59 ss = [ss]
61 maxl = max(map(len, ss))
62 info(fill*maxl)
63 for s in ss:
64 info(s)
65 info(fill*maxl, nl=nl)
68def bls(b):
69 return "Yes" if b else "No"
72def not_implemented(options):
73 info(f"Operation {options.operation} not yet implemented")
74 return 1
77def get_hsm(debug):
78 info("Connecting to HSM... ", False)
79 if Platform.is_ledger():
80 hsm = HSM2Dongle(debug)
81 elif Platform.is_sgx():
82 hsm = get_sgx_hsm(Platform.options("sgx_host"),
83 Platform.options("sgx_port"), debug)
84 else:
85 raise AdminError("Platform not set or unknown platform")
86 hsm.connect()
87 info("OK")
88 return hsm
91def get_sgx_hsm(host, port, debug):
92 hsm = HSM2DongleSGX(host, port, debug)
93 hsm.connect()
94 info("OK")
95 return hsm
98def get_admin_hsm(debug):
99 info("Connecting to HSM... ", False)
100 hsm = DongleAdmin(debug)
101 hsm.connect()
102 info("OK")
103 return hsm
106def dispose_hsm(hsm):
107 if hsm is None:
108 return
110 info("Disconnecting from HSM... ", False)
111 hsm.disconnect()
112 info("OK")
115def get_eth_dongle(debug):
116 info("Connecting to Ethereum App... ", False)
117 eth = DongleEth(debug)
118 eth.connect()
119 info("OK")
120 return eth
123def dispose_eth_dongle(eth):
124 if eth is None:
125 return
127 info("Disconnecting from Ethereum App... ", False)
128 eth.disconnect()
129 info("OK")
132def ask_for_pin(any_pin):
133 pin = None
134 while pin is None or not BasePin.is_valid(pin, any_pin):
135 pin = getpass("> ").encode()
136 if not BasePin.is_valid(pin, any_pin):
137 info(PIN_ERROR_MESSAGE if not any_pin else PIN_ERROR_MESSAGE_ANYCHARS)
138 return pin
141def wait_for_reconnection():
142 # This is only ever needed for Ledger
143 if Platform.is_ledger():
144 time.sleep(SIGNER_WAIT_TIME)
147def get_ud_value_for_attestation(user_provided_ud_source):
148 if is_hex_string_of_length(user_provided_ud_source,
149 ATTESTATION_UD_VALUE_LENGTH,
150 allow_prefix=True):
151 # Final value provided by user
152 ud_value = normalize_hex_string(user_provided_ud_source)
153 else:
154 # Final value taken from a specific Rootstock node
155 try:
156 rsk_client = RskClient(user_provided_ud_source)
157 best_block = rsk_client.get_block_by_number(
158 rsk_client.get_best_block_number())
159 ud_value = best_block["hash"][2:]
160 if not is_hex_string_of_length(ud_value, ATTESTATION_UD_VALUE_LENGTH):
161 raise ValueError("Got invalid best block from "
162 f"Rootstock server: {ud_value}")
163 except RskClientError as e:
164 raise AdminError(f"While fetching the best Rootstock block hash: {str(e)}")
166 return ud_value