11import json
2- from typing import Union
2+ import logging
3+ from pathlib import Path
4+ from typing import Optional , Union
35
6+ from sr25519 import verify
47from substrateinterface import Keypair
8+ from substrateinterface .utils .ss58 import ss58_decode
59
610from ..conf import settings
7- from .common import BaseAccount , get_verification_buffer
11+ from ..exceptions import BadSignatureError
12+ from .common import BaseAccount , bytes_from_hex , get_verification_buffer
13+
14+ logger = logging .getLogger (__name__ )
815
916
1017class DOTAccount (BaseAccount ):
1118 CHAIN = "DOT"
1219 CURVE = "sr25519"
1320
14- def __init__ (self , mnemonics = None , address_type = 42 ):
21+ def __init__ (self , mnemonics : str , address_type = 42 ):
1522 self .mnemonics = mnemonics
1623 self .address_type = address_type
1724 self ._account = Keypair .create_from_mnemonic (
18- self .mnemonics , address_type = address_type
25+ self .mnemonics , ss58_format = address_type
1926 )
2027
2128 async def sign_message (self , message ):
2229 message = self ._setup_sender (message )
2330 verif = get_verification_buffer (message ).decode ("utf-8" )
24- sig = {"curve" : self .CURVE , "data" : self ._account .sign (verif )}
31+ signature = await self .sign_raw (verif .encode ("utf-8" ))
32+ sig = {"curve" : self .CURVE , "data" : signature .hex ()}
2533 message ["signature" ] = json .dumps (sig )
2634 return message
2735
28- def get_address (self ):
36+ async def sign_raw (self , buffer : bytes ) -> bytes :
37+ return self ._account .sign (buffer )
38+
39+ def get_address (self ) -> str :
2940 return self ._account .ss58_address
3041
31- def get_public_key (self ):
32- return self ._account .public_key
42+ def get_public_key (self ) -> str :
43+ return "0x" + self ._account .public_key . hex ()
3344
3445
35- def get_fallback_account () :
36- return DOTAccount (mnemonics = get_fallback_mnemonics ())
46+ def get_fallback_account (path : Optional [ Path ] = None ) -> DOTAccount :
47+ return DOTAccount (mnemonics = get_fallback_mnemonics (path ))
3748
3849
39- def get_fallback_mnemonics ():
40- try :
41- mnemonic = settings .PRIVATE_KEY_FILE .read_text ()
42- except OSError :
50+ def get_fallback_mnemonics (path : Optional [Path ] = None ) -> str :
51+ path = path or settings .PRIVATE_MNEMONIC_FILE
52+ if path .exists () and path .stat ().st_size > 0 :
53+ mnemonic = path .read_text ()
54+ else :
4355 mnemonic = Keypair .generate_mnemonic ()
44- settings .PRIVATE_KEY_FILE .write_text (mnemonic )
56+ path .parent .mkdir (exist_ok = True , parents = True )
57+ path .write_text (mnemonic )
58+ default_mnemonic_path = path .parent / "default.mnemonic"
59+
60+ # If the symlink exists but does not point to a file, delete it.
61+ if (
62+ default_mnemonic_path .is_symlink ()
63+ and not default_mnemonic_path .resolve ().exists ()
64+ ):
65+ default_mnemonic_path .unlink ()
66+ logger .warning ("The symlink to the mnemonic is broken" )
67+
68+ # Create a symlink to use this mnemonic by default
69+ if not default_mnemonic_path .exists ():
70+ default_mnemonic_path .symlink_to (path )
4571
4672 return mnemonic
4773
@@ -50,6 +76,26 @@ def verify_signature(
5076 signature : Union [bytes , str ],
5177 public_key : Union [bytes , str ],
5278 message : Union [bytes , str ],
53- ) -> bool :
54- """TODO: Implement this"""
55- raise NotImplementedError ("Not implemented yet" )
79+ ) -> None :
80+ if isinstance (signature , str ):
81+ signature = bytes_from_hex (signature )
82+ if isinstance (public_key , str ):
83+ public_key = bytes_from_hex (public_key )
84+ if isinstance (message , str ):
85+ message = message .encode ()
86+
87+ try :
88+ # Another attempt with the data wrapped, as discussed in https://github.com/polkadot-js/extension/pull/743
89+ if not verify (signature , message , public_key ) or verify (
90+ signature , b"<Bytes>" + message + b"</Bytes>" , public_key
91+ ):
92+ raise BadSignatureError
93+ except Exception as e :
94+ raise BadSignatureError from e
95+
96+
97+ def verify_signature_with_ss58_address (
98+ signature : Union [bytes , str ], address : str , message : Union [bytes , str ]
99+ ) -> None :
100+ address_bytes = ss58_decode (address )
101+ return verify_signature (signature , address_bytes , message )
0 commit comments