hive-nectar 0.2.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hive_nectar-0.2.9.dist-info/METADATA +194 -0
- hive_nectar-0.2.9.dist-info/RECORD +87 -0
- hive_nectar-0.2.9.dist-info/WHEEL +4 -0
- hive_nectar-0.2.9.dist-info/entry_points.txt +2 -0
- hive_nectar-0.2.9.dist-info/licenses/LICENSE.txt +23 -0
- nectar/__init__.py +37 -0
- nectar/account.py +5076 -0
- nectar/amount.py +553 -0
- nectar/asciichart.py +303 -0
- nectar/asset.py +122 -0
- nectar/block.py +574 -0
- nectar/blockchain.py +1242 -0
- nectar/blockchaininstance.py +2590 -0
- nectar/blockchainobject.py +263 -0
- nectar/cli.py +5937 -0
- nectar/comment.py +1552 -0
- nectar/community.py +854 -0
- nectar/constants.py +95 -0
- nectar/discussions.py +1437 -0
- nectar/exceptions.py +152 -0
- nectar/haf.py +381 -0
- nectar/hive.py +630 -0
- nectar/imageuploader.py +114 -0
- nectar/instance.py +113 -0
- nectar/market.py +876 -0
- nectar/memo.py +542 -0
- nectar/message.py +379 -0
- nectar/nodelist.py +309 -0
- nectar/price.py +603 -0
- nectar/profile.py +74 -0
- nectar/py.typed +0 -0
- nectar/rc.py +333 -0
- nectar/snapshot.py +1024 -0
- nectar/storage.py +62 -0
- nectar/transactionbuilder.py +659 -0
- nectar/utils.py +630 -0
- nectar/version.py +3 -0
- nectar/vote.py +722 -0
- nectar/wallet.py +472 -0
- nectar/witness.py +728 -0
- nectarapi/__init__.py +12 -0
- nectarapi/exceptions.py +126 -0
- nectarapi/graphenerpc.py +596 -0
- nectarapi/node.py +194 -0
- nectarapi/noderpc.py +79 -0
- nectarapi/openapi.py +107 -0
- nectarapi/py.typed +0 -0
- nectarapi/rpcutils.py +98 -0
- nectarapi/version.py +3 -0
- nectarbase/__init__.py +15 -0
- nectarbase/ledgertransactions.py +106 -0
- nectarbase/memo.py +242 -0
- nectarbase/objects.py +521 -0
- nectarbase/objecttypes.py +21 -0
- nectarbase/operationids.py +102 -0
- nectarbase/operations.py +1357 -0
- nectarbase/py.typed +0 -0
- nectarbase/signedtransactions.py +89 -0
- nectarbase/transactions.py +11 -0
- nectarbase/version.py +3 -0
- nectargraphenebase/__init__.py +27 -0
- nectargraphenebase/account.py +1121 -0
- nectargraphenebase/aes.py +49 -0
- nectargraphenebase/base58.py +197 -0
- nectargraphenebase/bip32.py +575 -0
- nectargraphenebase/bip38.py +110 -0
- nectargraphenebase/chains.py +15 -0
- nectargraphenebase/dictionary.py +2 -0
- nectargraphenebase/ecdsasig.py +309 -0
- nectargraphenebase/objects.py +130 -0
- nectargraphenebase/objecttypes.py +8 -0
- nectargraphenebase/operationids.py +5 -0
- nectargraphenebase/operations.py +25 -0
- nectargraphenebase/prefix.py +13 -0
- nectargraphenebase/py.typed +0 -0
- nectargraphenebase/signedtransactions.py +221 -0
- nectargraphenebase/types.py +557 -0
- nectargraphenebase/unsignedtransactions.py +288 -0
- nectargraphenebase/version.py +3 -0
- nectarstorage/__init__.py +57 -0
- nectarstorage/base.py +317 -0
- nectarstorage/exceptions.py +15 -0
- nectarstorage/interfaces.py +244 -0
- nectarstorage/masterpassword.py +237 -0
- nectarstorage/py.typed +0 -0
- nectarstorage/ram.py +27 -0
- nectarstorage/sqlite.py +343 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
from binascii import hexlify, unhexlify
|
|
5
|
+
from collections import OrderedDict
|
|
6
|
+
from typing import Any, Dict, List, Optional, Union
|
|
7
|
+
|
|
8
|
+
import ecdsa
|
|
9
|
+
from asn1crypto.core import OctetString
|
|
10
|
+
|
|
11
|
+
from .bip32 import parse_path
|
|
12
|
+
from .chains import known_chains
|
|
13
|
+
from .objects import Operation, isArgsThisClass
|
|
14
|
+
from .types import (
|
|
15
|
+
Array,
|
|
16
|
+
JsonObj,
|
|
17
|
+
PointInTime,
|
|
18
|
+
Set,
|
|
19
|
+
Signature,
|
|
20
|
+
String,
|
|
21
|
+
Uint16,
|
|
22
|
+
Uint32,
|
|
23
|
+
Varint32,
|
|
24
|
+
)
|
|
25
|
+
from .types import (
|
|
26
|
+
Optional as GrapheneOptional,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
log = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class GrapheneObjectASN1:
|
|
33
|
+
"""Core abstraction class
|
|
34
|
+
|
|
35
|
+
This class is used for any JSON reflected object in Graphene.
|
|
36
|
+
|
|
37
|
+
* ``instance.__json__()``: encodes data into json format
|
|
38
|
+
* ``bytes(instance)``: encodes data into wire format
|
|
39
|
+
* ``str(instances)``: dumps json object as string
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, data: Any = None) -> None:
|
|
44
|
+
self.data = data
|
|
45
|
+
|
|
46
|
+
def __bytes__(self) -> bytes:
|
|
47
|
+
if self.data is None:
|
|
48
|
+
return b""
|
|
49
|
+
b = b""
|
|
50
|
+
output = b""
|
|
51
|
+
for name, value in list(self.data.items()):
|
|
52
|
+
if name == "operations":
|
|
53
|
+
for operation in value:
|
|
54
|
+
if isinstance(value, str):
|
|
55
|
+
b = bytes(operation, "utf-8")
|
|
56
|
+
else:
|
|
57
|
+
b = bytes(operation)
|
|
58
|
+
output += OctetString(b).dump()
|
|
59
|
+
elif name != "signatures":
|
|
60
|
+
if isinstance(value, str):
|
|
61
|
+
b = bytes(value, "utf-8")
|
|
62
|
+
else:
|
|
63
|
+
b = bytes(value)
|
|
64
|
+
output += OctetString(b).dump()
|
|
65
|
+
return output
|
|
66
|
+
|
|
67
|
+
def __json__(self) -> Dict[str, Any]:
|
|
68
|
+
if self.data is None:
|
|
69
|
+
return {}
|
|
70
|
+
d = {} # JSON output is *not* ordered
|
|
71
|
+
for name, value in list(self.data.items()):
|
|
72
|
+
if isinstance(value, GrapheneOptional) and value.isempty():
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
if isinstance(value, String):
|
|
76
|
+
d.update({name: str(value)})
|
|
77
|
+
else:
|
|
78
|
+
try:
|
|
79
|
+
d.update({name: JsonObj(value)})
|
|
80
|
+
except Exception:
|
|
81
|
+
d.update({name: value.__str__()})
|
|
82
|
+
return d
|
|
83
|
+
|
|
84
|
+
def __str__(self) -> str:
|
|
85
|
+
return json.dumps(self.__json__())
|
|
86
|
+
|
|
87
|
+
def toJson(self) -> Dict[str, Any]:
|
|
88
|
+
return self.__json__()
|
|
89
|
+
|
|
90
|
+
def json(self) -> Dict[str, Any]:
|
|
91
|
+
return self.__json__()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Unsigned_Transaction(GrapheneObjectASN1):
|
|
95
|
+
"""Create an unsigned transaction with ASN1 encoder for using it with ledger
|
|
96
|
+
|
|
97
|
+
:param num ref_block_num:
|
|
98
|
+
:param num ref_block_prefix:
|
|
99
|
+
:param str expiration: expiration date
|
|
100
|
+
:param array operations: array of operations
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
104
|
+
if isArgsThisClass(self, args):
|
|
105
|
+
self.data = args[0].data
|
|
106
|
+
else:
|
|
107
|
+
if len(args) == 1 and len(kwargs) == 0:
|
|
108
|
+
kwargs = args[0]
|
|
109
|
+
kwargs.pop("prefix", "STM")
|
|
110
|
+
if "extensions" not in kwargs:
|
|
111
|
+
kwargs["extensions"] = Set([])
|
|
112
|
+
elif not kwargs.get("extensions"):
|
|
113
|
+
kwargs["extensions"] = Set([])
|
|
114
|
+
if "signatures" not in kwargs:
|
|
115
|
+
kwargs["signatures"] = Array([])
|
|
116
|
+
else:
|
|
117
|
+
kwargs["signatures"] = Array(
|
|
118
|
+
[Signature(unhexlify(a)) for a in kwargs["signatures"]]
|
|
119
|
+
)
|
|
120
|
+
operations_count = 0
|
|
121
|
+
if "operations" in kwargs:
|
|
122
|
+
operations_count = len(kwargs["operations"])
|
|
123
|
+
# opklass = self.getOperationKlass()
|
|
124
|
+
# if all([not isinstance(a, opklass) for a in kwargs["operations"]]):
|
|
125
|
+
# kwargs['operations'] = Array([opklass(a, ) for a in kwargs["operations"]])
|
|
126
|
+
# else:
|
|
127
|
+
# kwargs['operations'] = (kwargs["operations"])
|
|
128
|
+
|
|
129
|
+
super().__init__(
|
|
130
|
+
OrderedDict(
|
|
131
|
+
[
|
|
132
|
+
("ref_block_num", Uint16(kwargs["ref_block_num"])),
|
|
133
|
+
("ref_block_prefix", Uint32(kwargs["ref_block_prefix"])),
|
|
134
|
+
("expiration", PointInTime(kwargs["expiration"])),
|
|
135
|
+
("operations_count", Varint32(operations_count)),
|
|
136
|
+
("operations", kwargs["operations"]),
|
|
137
|
+
("extensions", kwargs["extensions"]),
|
|
138
|
+
("signatures", kwargs["signatures"]),
|
|
139
|
+
]
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def id(self) -> str:
|
|
145
|
+
"""The transaction id of this transaction"""
|
|
146
|
+
# Store signatures temporarily since they are not part of
|
|
147
|
+
# transaction id
|
|
148
|
+
sigs = self.data["signatures"]
|
|
149
|
+
self.data.pop("signatures", None)
|
|
150
|
+
|
|
151
|
+
# Generage Hash of the seriliazed version
|
|
152
|
+
h = hashlib.sha256(bytes(self)).digest()
|
|
153
|
+
|
|
154
|
+
# recover signatures
|
|
155
|
+
self.data["signatures"] = sigs
|
|
156
|
+
|
|
157
|
+
# Return properly truncated tx hash
|
|
158
|
+
return hexlify(h[:20]).decode("ascii")
|
|
159
|
+
|
|
160
|
+
def getOperationKlass(self) -> type[Operation]:
|
|
161
|
+
return Operation
|
|
162
|
+
|
|
163
|
+
def derSigToHexSig(self, s: bytes) -> str:
|
|
164
|
+
"""Format DER to HEX signature"""
|
|
165
|
+
s, junk = ecdsa.der.remove_sequence(unhexlify(s))
|
|
166
|
+
if junk:
|
|
167
|
+
log.debug("JUNK: %s", hexlify(junk).decode("ascii"))
|
|
168
|
+
if not (junk == b""):
|
|
169
|
+
raise AssertionError()
|
|
170
|
+
x, s = ecdsa.der.remove_integer(s)
|
|
171
|
+
y, s = ecdsa.der.remove_integer(s)
|
|
172
|
+
return "{:064x}{:064x}".format(x, y)
|
|
173
|
+
|
|
174
|
+
def getKnownChains(self) -> Dict[str, Any]:
|
|
175
|
+
return known_chains
|
|
176
|
+
|
|
177
|
+
def getChainParams(self, chain: Union[str, Dict[str, Any]]) -> Dict[str, Any]:
|
|
178
|
+
# Which network are we on:
|
|
179
|
+
chains = self.getKnownChains()
|
|
180
|
+
if isinstance(chain, str) and chain in chains:
|
|
181
|
+
chain_params = chains[chain]
|
|
182
|
+
elif isinstance(chain, dict):
|
|
183
|
+
chain_params = chain
|
|
184
|
+
else:
|
|
185
|
+
raise Exception("sign() only takes a string or a dict as chain!")
|
|
186
|
+
if "chain_id" not in chain_params:
|
|
187
|
+
raise Exception("sign() needs a 'chain_id' in chain params!")
|
|
188
|
+
return chain_params
|
|
189
|
+
|
|
190
|
+
def deriveDigest(self, chain: Union[str, Dict[str, Any]]) -> None:
|
|
191
|
+
chain_params = self.getChainParams(chain)
|
|
192
|
+
# Chain ID
|
|
193
|
+
self.chainid = chain_params["chain_id"]
|
|
194
|
+
|
|
195
|
+
# Do not serialize signatures
|
|
196
|
+
sigs = self.data["signatures"]
|
|
197
|
+
self.data["signatures"] = []
|
|
198
|
+
|
|
199
|
+
# Get message to sign
|
|
200
|
+
# bytes(self) will give the wire formated data according to
|
|
201
|
+
# GrapheneObject and the data given in __init__()
|
|
202
|
+
self.message = OctetString(unhexlify(self.chainid)).dump()
|
|
203
|
+
for name, value in list(self.data.items()):
|
|
204
|
+
if name == "operations":
|
|
205
|
+
for operation in value:
|
|
206
|
+
if isinstance(value, str):
|
|
207
|
+
b = bytes(operation, "utf-8")
|
|
208
|
+
else:
|
|
209
|
+
b = bytes(operation)
|
|
210
|
+
self.message += OctetString(b).dump()
|
|
211
|
+
elif name != "signatures":
|
|
212
|
+
if isinstance(value, str):
|
|
213
|
+
b = bytes(value, "utf-8")
|
|
214
|
+
else:
|
|
215
|
+
b = bytes(value)
|
|
216
|
+
self.message += OctetString(b).dump()
|
|
217
|
+
|
|
218
|
+
self.digest = hashlib.sha256(self.message).digest()
|
|
219
|
+
|
|
220
|
+
# restore signatures
|
|
221
|
+
self.data["signatures"] = sigs
|
|
222
|
+
|
|
223
|
+
def build_path(self, role: str, account_index: int, key_index: int) -> str:
|
|
224
|
+
if role == "owner":
|
|
225
|
+
return "48'/13'/0'/%d'/%d'" % (account_index, key_index)
|
|
226
|
+
elif role == "active":
|
|
227
|
+
return "48'/13'/1'/%d'/%d'" % (account_index, key_index)
|
|
228
|
+
elif role == "posting":
|
|
229
|
+
return "48'/13'/4'/%d'/%d'" % (account_index, key_index)
|
|
230
|
+
elif role == "memo":
|
|
231
|
+
return "48'/13'/3'/%d'/%d'" % (account_index, key_index)
|
|
232
|
+
else:
|
|
233
|
+
raise ValueError(f"Unknown role: {role}")
|
|
234
|
+
|
|
235
|
+
def build_apdu(
|
|
236
|
+
self, path: str = "48'/13'/0'/0'/0'", chain: Optional[Union[str, Dict[str, Any]]] = None
|
|
237
|
+
) -> List[bytes]:
|
|
238
|
+
if chain is None:
|
|
239
|
+
raise ValueError("chain parameter is required for build_apdu")
|
|
240
|
+
self.deriveDigest(chain)
|
|
241
|
+
parsed_path = parse_path(path, as_bytes=True)
|
|
242
|
+
path_bytes = unhexlify(bytes(parsed_path))
|
|
243
|
+
|
|
244
|
+
message = self.message
|
|
245
|
+
path_size = int(len(path_bytes) / 4)
|
|
246
|
+
message_size = len(message)
|
|
247
|
+
|
|
248
|
+
offset = 0
|
|
249
|
+
first = True
|
|
250
|
+
result = []
|
|
251
|
+
while offset < message_size:
|
|
252
|
+
chunk = message[offset : offset + 255]
|
|
253
|
+
total_size = len(chunk)
|
|
254
|
+
if first:
|
|
255
|
+
apdu = (
|
|
256
|
+
unhexlify("d4040000")
|
|
257
|
+
+ bytes([total_size])
|
|
258
|
+
+ bytes([path_size])
|
|
259
|
+
+ path_bytes
|
|
260
|
+
+ chunk
|
|
261
|
+
)
|
|
262
|
+
first = False
|
|
263
|
+
else:
|
|
264
|
+
total_size = len(chunk)
|
|
265
|
+
apdu = unhexlify("d4048000") + bytes([total_size]) + chunk
|
|
266
|
+
result.append(apdu)
|
|
267
|
+
offset += len(chunk)
|
|
268
|
+
return result
|
|
269
|
+
|
|
270
|
+
def build_apdu_pubkey(
|
|
271
|
+
self, path: str = "48'/13'/0'/0'/0'", request_screen_approval: bool = False
|
|
272
|
+
) -> bytes:
|
|
273
|
+
parsed_path = parse_path(path, as_bytes=True)
|
|
274
|
+
path_bytes = unhexlify(bytes(parsed_path))
|
|
275
|
+
if not request_screen_approval:
|
|
276
|
+
return (
|
|
277
|
+
unhexlify("d4020001")
|
|
278
|
+
+ bytes([int(len(path_bytes)) + 1])
|
|
279
|
+
+ bytes([int(len(path_bytes) / 4)])
|
|
280
|
+
+ path_bytes
|
|
281
|
+
)
|
|
282
|
+
else:
|
|
283
|
+
return (
|
|
284
|
+
unhexlify("d4020101")
|
|
285
|
+
+ bytes([int(len(path_bytes)) + 1])
|
|
286
|
+
+ bytes([int(len(path_bytes) / 4)])
|
|
287
|
+
+ path_bytes
|
|
288
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Load modules from other classes
|
|
2
|
+
# # Inspired by https://raw.githubusercontent.com/xeroc/python-graphenelib/master/graphenestorage/__init__.py
|
|
3
|
+
from .base import (
|
|
4
|
+
InRamConfigurationStore,
|
|
5
|
+
InRamEncryptedKeyStore,
|
|
6
|
+
InRamEncryptedTokenStore,
|
|
7
|
+
InRamPlainKeyStore,
|
|
8
|
+
InRamPlainTokenStore,
|
|
9
|
+
SqliteConfigurationStore,
|
|
10
|
+
SqliteEncryptedKeyStore,
|
|
11
|
+
SqliteEncryptedTokenStore,
|
|
12
|
+
SqlitePlainKeyStore,
|
|
13
|
+
SqlitePlainTokenStore,
|
|
14
|
+
)
|
|
15
|
+
from .sqlite import SQLiteCommon, SQLiteFile
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
# submodules
|
|
19
|
+
"interfaces",
|
|
20
|
+
"masterpassword",
|
|
21
|
+
"base",
|
|
22
|
+
"sqlite",
|
|
23
|
+
"ram",
|
|
24
|
+
# store classes re-exported for convenience
|
|
25
|
+
"InRamConfigurationStore",
|
|
26
|
+
"InRamEncryptedKeyStore",
|
|
27
|
+
"InRamEncryptedTokenStore",
|
|
28
|
+
"InRamPlainKeyStore",
|
|
29
|
+
"InRamPlainTokenStore",
|
|
30
|
+
"SqliteConfigurationStore",
|
|
31
|
+
"SqliteEncryptedKeyStore",
|
|
32
|
+
"SqliteEncryptedTokenStore",
|
|
33
|
+
"SqlitePlainKeyStore",
|
|
34
|
+
"SqlitePlainTokenStore",
|
|
35
|
+
"SQLiteCommon",
|
|
36
|
+
"SQLiteFile",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_default_config_store(*args, **kwargs):
|
|
41
|
+
"""This method returns the default **configuration** store
|
|
42
|
+
that uses an SQLite database internally.
|
|
43
|
+
:params str appname: The appname that is used internally to distinguish
|
|
44
|
+
different SQLite files
|
|
45
|
+
"""
|
|
46
|
+
kwargs["appname"] = kwargs.get("appname", "nectar")
|
|
47
|
+
return SqliteConfigurationStore(*args, **kwargs)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_default_key_store(*args, config, **kwargs):
|
|
51
|
+
"""This method returns the default **key** store
|
|
52
|
+
that uses an SQLite database internally.
|
|
53
|
+
:params str appname: The appname that is used internally to distinguish
|
|
54
|
+
different SQLite files
|
|
55
|
+
"""
|
|
56
|
+
kwargs["appname"] = kwargs.get("appname", "nectar")
|
|
57
|
+
return SqliteEncryptedKeyStore(config=config, **kwargs)
|
nectarstorage/base.py
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Inspired by https://raw.githubusercontent.com/xeroc/python-graphenelib/master/graphenestorage/base.py
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from .exceptions import KeyAlreadyInStoreException
|
|
5
|
+
from .interfaces import (
|
|
6
|
+
ConfigInterface,
|
|
7
|
+
EncryptedKeyInterface,
|
|
8
|
+
EncryptedTokenInterface,
|
|
9
|
+
KeyInterface,
|
|
10
|
+
TokenInterface,
|
|
11
|
+
)
|
|
12
|
+
from .masterpassword import MasterPassword
|
|
13
|
+
from .ram import InRamStore
|
|
14
|
+
from .sqlite import SQLiteStore
|
|
15
|
+
|
|
16
|
+
log = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Configuration
|
|
20
|
+
class InRamConfigurationStore(InRamStore, ConfigInterface):
|
|
21
|
+
"""A simple example that stores configuration in RAM.
|
|
22
|
+
|
|
23
|
+
Internally, this works by simply inheriting
|
|
24
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
25
|
+
:class:`nectarstorage.interfaces.ConfigInterface`.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SqliteConfigurationStore(SQLiteStore, ConfigInterface):
|
|
32
|
+
"""This is the configuration storage that stores key/value
|
|
33
|
+
pairs in the `config` table of the SQLite3 database.
|
|
34
|
+
|
|
35
|
+
Internally, this works by simply inheriting
|
|
36
|
+
:class:`nectarstorage.sqlite.SQLiteStore`. The interface is defined
|
|
37
|
+
in :class:`nectarstorage.interfaces.ConfigInterface`.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
#: The table name for the configuration
|
|
41
|
+
__tablename__ = "config"
|
|
42
|
+
#: The name of the 'key' column
|
|
43
|
+
__key__ = "key"
|
|
44
|
+
#: The name of the 'value' column
|
|
45
|
+
__value__ = "value"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Keys
|
|
49
|
+
class InRamPlainKeyStore(InRamStore, KeyInterface):
|
|
50
|
+
"""A simple in-RAM Store that stores keys unencrypted in RAM
|
|
51
|
+
|
|
52
|
+
Internally, this works by simply inheriting
|
|
53
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
54
|
+
:class:`nectarstorage.interfaces.KeyInterface`.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def getPublicKeys(self):
|
|
58
|
+
return [k for k, v in self.items()]
|
|
59
|
+
|
|
60
|
+
def getPrivateKeyForPublicKey(self, pub):
|
|
61
|
+
return self.get(str(pub), None)
|
|
62
|
+
|
|
63
|
+
def add(self, wif, pub=None):
|
|
64
|
+
if pub is None:
|
|
65
|
+
raise ValueError("pub key required")
|
|
66
|
+
if str(pub) in self:
|
|
67
|
+
raise KeyAlreadyInStoreException
|
|
68
|
+
self[str(pub)] = str(wif)
|
|
69
|
+
|
|
70
|
+
def delete(self, key):
|
|
71
|
+
InRamStore.delete(self, str(key))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class SqlitePlainKeyStore(SQLiteStore, KeyInterface):
|
|
75
|
+
"""This is the key storage that stores the public key and the
|
|
76
|
+
**unencrypted** private key in the `keys` table in the SQLite3
|
|
77
|
+
database.
|
|
78
|
+
|
|
79
|
+
Internally, this works by simply inheriting
|
|
80
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
81
|
+
:class:`nectarstorage.interfaces.KeyInterface`.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
#: The table name for the configuration
|
|
85
|
+
__tablename__ = "keys"
|
|
86
|
+
#: The name of the 'key' column
|
|
87
|
+
__key__ = "pub"
|
|
88
|
+
#: The name of the 'value' column
|
|
89
|
+
__value__ = "wif"
|
|
90
|
+
|
|
91
|
+
def getPublicKeys(self):
|
|
92
|
+
return [k for k, v in self.items()]
|
|
93
|
+
|
|
94
|
+
def getPrivateKeyForPublicKey(self, pub):
|
|
95
|
+
return self.get(str(pub), None)
|
|
96
|
+
|
|
97
|
+
def add(self, wif, pub=None):
|
|
98
|
+
if pub is None:
|
|
99
|
+
raise ValueError("pub key required")
|
|
100
|
+
if str(pub) in self:
|
|
101
|
+
raise KeyAlreadyInStoreException
|
|
102
|
+
self[str(pub)] = str(wif)
|
|
103
|
+
|
|
104
|
+
def delete(self, key):
|
|
105
|
+
SQLiteStore.delete(self, str(key))
|
|
106
|
+
|
|
107
|
+
def is_encrypted(self):
|
|
108
|
+
"""Returns False, as we are not encrypted here"""
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class KeyEncryption(MasterPassword, EncryptedKeyInterface):
|
|
113
|
+
"""This is an interface class that provides the methods required for
|
|
114
|
+
EncryptedKeyInterface and links them to the MasterPassword-provided
|
|
115
|
+
functionatlity, accordingly.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
def __init__(self, *args, **kwargs):
|
|
119
|
+
EncryptedKeyInterface.__init__(self, *args, **kwargs)
|
|
120
|
+
MasterPassword.__init__(self, *args, **kwargs)
|
|
121
|
+
|
|
122
|
+
# Interface to deal with encrypted keys
|
|
123
|
+
def getPublicKeys(self):
|
|
124
|
+
return [k for k, v in self.items()]
|
|
125
|
+
|
|
126
|
+
def getPrivateKeyForPublicKey(self, pub):
|
|
127
|
+
wif = self.get(str(pub), None)
|
|
128
|
+
if wif:
|
|
129
|
+
return self.decrypt(wif) # From Masterpassword
|
|
130
|
+
|
|
131
|
+
def add(self, wif, pub=None):
|
|
132
|
+
if pub is None:
|
|
133
|
+
raise ValueError("pub key required")
|
|
134
|
+
if str(pub) in self:
|
|
135
|
+
raise KeyAlreadyInStoreException
|
|
136
|
+
self[str(pub)] = self.encrypt(str(wif)) # From Masterpassword
|
|
137
|
+
|
|
138
|
+
def is_encrypted(self):
|
|
139
|
+
return True
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class InRamEncryptedKeyStore(InRamStore, KeyEncryption):
|
|
143
|
+
"""An in-RAM Store that stores keys **encrypted** in RAM.
|
|
144
|
+
|
|
145
|
+
Internally, this works by simply inheriting
|
|
146
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
147
|
+
:class:`nectarstorage.interfaces.KeyInterface`.
|
|
148
|
+
|
|
149
|
+
.. note:: This module also inherits
|
|
150
|
+
:class:`nectarstorage.masterpassword.MasterPassword` which offers
|
|
151
|
+
additional methods and deals with encrypting the keys.
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
def __init__(self, *args, **kwargs):
|
|
155
|
+
InRamStore.__init__(self, *args, **kwargs)
|
|
156
|
+
KeyEncryption.__init__(self, *args, **kwargs)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class SqliteEncryptedKeyStore(SQLiteStore, KeyEncryption):
|
|
160
|
+
"""This is the key storage that stores the public key and the
|
|
161
|
+
**encrypted** private key in the `keys` table in the SQLite3 database.
|
|
162
|
+
|
|
163
|
+
Internally, this works by simply inheriting
|
|
164
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
165
|
+
:class:`nectarstorage.interfaces.KeyInterface`.
|
|
166
|
+
|
|
167
|
+
.. note:: This module also inherits
|
|
168
|
+
:class:`nectarstorage.masterpassword.MasterPassword` which offers
|
|
169
|
+
additional methods and deals with encrypting the keys.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
__tablename__ = "keys"
|
|
173
|
+
__key__ = "pub"
|
|
174
|
+
__value__ = "wif"
|
|
175
|
+
|
|
176
|
+
def __init__(self, *args, **kwargs):
|
|
177
|
+
SQLiteStore.__init__(self, *args, **kwargs)
|
|
178
|
+
KeyEncryption.__init__(self, *args, **kwargs)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# Token
|
|
182
|
+
class InRamPlainTokenStore(InRamStore, TokenInterface):
|
|
183
|
+
"""A simple in-RAM Store that stores token unencrypted in RAM
|
|
184
|
+
|
|
185
|
+
Internally, this works by simply inheriting
|
|
186
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
187
|
+
:class:`nectarstorage.interfaces.TokenInterface`.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
def getPublicNames(self):
|
|
191
|
+
return [k for k, v in self.items()]
|
|
192
|
+
|
|
193
|
+
def getPrivateKeyForPublicKey(self, pub):
|
|
194
|
+
return self.get(str(pub), None)
|
|
195
|
+
|
|
196
|
+
def add(self, token, name=None):
|
|
197
|
+
if name is None:
|
|
198
|
+
raise ValueError("name required")
|
|
199
|
+
if str(name) in self:
|
|
200
|
+
raise KeyAlreadyInStoreException
|
|
201
|
+
self[str(name)] = str(token)
|
|
202
|
+
|
|
203
|
+
def delete(self, key):
|
|
204
|
+
InRamStore.delete(self, str(key))
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class SqlitePlainTokenStore(SQLiteStore, TokenInterface):
|
|
208
|
+
"""This is the token storage that stores the public key and the
|
|
209
|
+
**unencrypted** private key in the `tokens` table in the SQLite3
|
|
210
|
+
database.
|
|
211
|
+
|
|
212
|
+
Internally, this works by simply inheriting
|
|
213
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
214
|
+
:class:`nectarstorage.interfaces.TokenInterface`.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
#: The table name for the configuration
|
|
218
|
+
__tablename__ = "token"
|
|
219
|
+
#: The name of the 'key' column
|
|
220
|
+
__key__ = "name"
|
|
221
|
+
#: The name of the 'value' column
|
|
222
|
+
__value__ = "token"
|
|
223
|
+
|
|
224
|
+
def getPublicNames(self):
|
|
225
|
+
return [k for k, v in self.items()]
|
|
226
|
+
|
|
227
|
+
def getPrivateKeyForPublicKey(self, pub):
|
|
228
|
+
return self[str(pub)]
|
|
229
|
+
|
|
230
|
+
def add(self, token, name=None):
|
|
231
|
+
if name is None:
|
|
232
|
+
raise ValueError("name required")
|
|
233
|
+
if str(name) in self:
|
|
234
|
+
raise KeyAlreadyInStoreException
|
|
235
|
+
self[str(name)] = str(token)
|
|
236
|
+
|
|
237
|
+
def updateToken(self, name, token):
|
|
238
|
+
self[str(name)] = str(token) # From Masterpassword
|
|
239
|
+
|
|
240
|
+
def delete(self, key):
|
|
241
|
+
SQLiteStore.delete(self, str(key))
|
|
242
|
+
|
|
243
|
+
def is_encrypted(self):
|
|
244
|
+
"""Returns False, as we are not encrypted here"""
|
|
245
|
+
return False
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class TokenEncryption(MasterPassword, EncryptedTokenInterface):
|
|
249
|
+
"""This is an interface class that provides the methods required for
|
|
250
|
+
EncryptedTokenInterface and links them to the MasterPassword-provided
|
|
251
|
+
functionatlity, accordingly.
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
def __init__(self, *args, **kwargs):
|
|
255
|
+
EncryptedTokenInterface.__init__(self, *args, **kwargs)
|
|
256
|
+
MasterPassword.__init__(self, *args, **kwargs)
|
|
257
|
+
|
|
258
|
+
# Interface to deal with encrypted keys
|
|
259
|
+
def getPublicNames(self):
|
|
260
|
+
return [k for k, v in self.items()]
|
|
261
|
+
|
|
262
|
+
def getPrivateKeyForPublicKey(self, pub):
|
|
263
|
+
token = self.get(str(pub), None)
|
|
264
|
+
if token:
|
|
265
|
+
return self.decrypt_text(token) # From Masterpassword
|
|
266
|
+
|
|
267
|
+
def add(self, token, name=None):
|
|
268
|
+
if name is None:
|
|
269
|
+
raise ValueError("name required")
|
|
270
|
+
if str(name) in self:
|
|
271
|
+
raise KeyAlreadyInStoreException
|
|
272
|
+
self[str(name)] = self.encrypt_text(str(token)) # From Masterpassword
|
|
273
|
+
|
|
274
|
+
def updateToken(self, name, token):
|
|
275
|
+
self[str(name)] = self.encrypt_text(str(token)) # From Masterpassword
|
|
276
|
+
|
|
277
|
+
def is_encrypted(self):
|
|
278
|
+
return True
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class InRamEncryptedTokenStore(InRamStore, TokenEncryption):
|
|
282
|
+
"""An in-RAM Store that stores token **encrypted** in RAM.
|
|
283
|
+
|
|
284
|
+
Internally, this works by simply inheriting
|
|
285
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
286
|
+
:class:`nectarstorage.interfaces.TokenInterface`.
|
|
287
|
+
|
|
288
|
+
.. note:: This module also inherits
|
|
289
|
+
:class:`nectarstorage.masterpassword.MasterPassword` which offers
|
|
290
|
+
additional methods and deals with encrypting the keys.
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
def __init__(self, *args, **kwargs):
|
|
294
|
+
InRamStore.__init__(self, *args, **kwargs)
|
|
295
|
+
TokenEncryption.__init__(self, *args, **kwargs)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class SqliteEncryptedTokenStore(SQLiteStore, TokenEncryption):
|
|
299
|
+
"""This is the key storage that stores the account name and the
|
|
300
|
+
**encrypted** token in the `token` table in the SQLite3 database.
|
|
301
|
+
|
|
302
|
+
Internally, this works by simply inheriting
|
|
303
|
+
:class:`nectarstorage.ram.InRamStore`. The interface is defined in
|
|
304
|
+
:class:`nectarstorage.interfaces.TokenInterface`.
|
|
305
|
+
|
|
306
|
+
.. note:: This module also inherits
|
|
307
|
+
:class:`nectarstorage.masterpassword.MasterPassword` which offers
|
|
308
|
+
additional methods and deals with encrypting the token.
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
__tablename__ = "token"
|
|
312
|
+
__key__ = "name"
|
|
313
|
+
__value__ = "token"
|
|
314
|
+
|
|
315
|
+
def __init__(self, *args, **kwargs):
|
|
316
|
+
SQLiteStore.__init__(self, *args, **kwargs)
|
|
317
|
+
TokenEncryption.__init__(self, *args, **kwargs)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Inspired by https://raw.githubusercontent.com/xeroc/python-graphenelib/master/graphenestorage/exceptions.py
|
|
2
|
+
class WalletLocked(Exception):
|
|
3
|
+
pass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class WrongMasterPasswordException(Exception):
|
|
7
|
+
"""The password provided could not properly unlock the wallet"""
|
|
8
|
+
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class KeyAlreadyInStoreException(Exception):
|
|
13
|
+
"""The key of a key/value pair is already in the store"""
|
|
14
|
+
|
|
15
|
+
pass
|