Closed robertmin1 closed 5 months ago
For validation that isn't reliant on Qt, I'd prefer that the functions be added to names.py
rather than a gui
subfolder; this way they can be reused in the CLI and the Kivy GUI later.
I think I'd prefer that the validation functions raise an Exception on rejection rather than returning a bool
. Seems harder to misuse.
What's the origin of the regex patterns used in this PR? (Knowing this would make auditing a lot easier.)
Most of the patterns are generated from regex-generator.olafneumann.org
I think I'd prefer that the validation functions raise an Exception on rejection rather than returning a
bool
. Seems harder to misuse. For validation that isn't reliant on Qt, I'd prefer that the functions be added to names.py rather than a gui subfolder; this way they can be reused in the CLI and the Kivy GUI later.
Alright! I will make the changes.
Most of the patterns are generated from regex-generator.olafneumann.org
I think for most of these, we should be able to find more canonical validation mechanisms. For example, Electrum deals with IP addresses already, presumably there should be some library function available to validate an IP address? Similarly, ZeroNet addresses are P2PKH Bitcoin addresses; presumably we already have a library function to validate those? For cases where we don't already have a function available in an existing dependency, it might be preferable to validate according to the spec (e.g. a Tor spec for onion service addresses), with each rule in the spec corresponding to one line of Python code. This would make it a lot easier to audit. Alternatively, if there's a high-quality library available (e.g. Stem for onion addresses), we could maybe add that as a dependency, or just copy a Python function from them. I think in the case of onion addresses, probably there's something in Stem that we could copy verbatim rather than adding Stem as a full dependency.
A longer version of the current func for validating ZeroNet addresses. (Comapring cheksum)
def validate_p2pkh_address(address):
# Step 1: Check the length
if not (27 <= len(address) <= 36):
return False
try:
# Step 2: Base58 decoding
decoded_address = base58.b58decode(address)
# Step 3: Check the version byte
if decoded_address[0] != 0x00:
return False
# Step 4: Double SHA-256 checksum
checksum = hashlib.sha256(hashlib.sha256(decoded_address[:-4]).digest()).digest()
# Step 5: Compare checksum
if decoded_address[-4:] == checksum[:4]:
return True
except base58.Base58Error:
return False
return False
The current idea for IP2 is something similar to this.
The current idea on validating onion addresses, to mitigate using stem module. From the suggested Rust Code.
import base64
import hashlib
V3_ONION_SERVICE_ID_RAW_SIZE= 35
V3_ONION_SERVICE_ID_VERSION_OFFSET = 34
ED25519_PUBLIC_KEY_SIZE = 32
V3_ONION_SERVICE_ID_CHECKSUM_OFFSET = 32
def validate_onion_address(service_id):
try:
# Initialize the bytearray to hold the decoded service ID
decoded_service_id = bytearray([0] * V3_ONION_SERVICE_ID_RAW_SIZE)
# Decode the service ID from base32 into the decoded_service_id bytearray
decoded_service_id = base64.b32decode(service_id.encode(), decoded_service_id)
# Check decoded service ID has the expected length
if len(decoded_service_id) != V3_ONION_SERVICE_ID_RAW_SIZE:
raise ValueError("Invalid service ID length")
# Check the version byte
version_byte = decoded_service_id[V3_ONION_SERVICE_ID_VERSION_OFFSET]
if version_byte > 0x03:
raise ValueError(f"Warning: Unknown version byte {version_byte}")
if version_byte != 0x03:
raise ValueError("Invalid version byte")
# Extract the public key from the decoded service ID
public_key = bytearray(decoded_service_id[:ED25519_PUBLIC_KEY_SIZE])
# Calculate the truncated checksum
truncated_checksum = calc_truncated_checksum(public_key)
# Check if the truncated checksum matches the corresponding bytes in the decoded service ID
if truncated_checksum[0] != decoded_service_id[V3_ONION_SERVICE_ID_CHECKSUM_OFFSET] or \
truncated_checksum[1] != decoded_service_id[V3_ONION_SERVICE_ID_CHECKSUM_OFFSET + 1]:
raise ValueError("Invalid checksum")
except Exception as e:
# Raise an exception if an error occurs
raise ValueError("Invalid service ID: " + str(e))
def calc_truncated_checksum(public_key):
# Define the size of the hash in bytes
SHA256_BYTES = 256 // 8
hash_bytes = bytearray(SHA256_BYTES)
hasher = hashlib.sha3_256()
assert SHA256_BYTES == hasher.digest_size
# Calculate the checksum
hasher.update(b".onion checksum")
hasher.update(public_key)
hasher.update(bytes([0x03]))
hash_bytes = bytearray(hasher.digest())
return [hash_bytes[0], hash_bytes[1]]
Made changes to handling the version byte
The UI element that shows onion errors seems to be user-editable, which is not desirable. Not sure if maybe you accidentally used a line edit widget instead of a label widget?
Also if I type blah.onion
in IPv4 mode, and then switch the drop-down to Tor, validation doesn't happen until I edit the address again.
For validating IP addresses, the ipaddress
module in the Python standard library looks like what you want.
What's the origin of the regex patterns used in this PR? (Knowing this would make auditing a lot easier.)