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.
Files changed (87) hide show
  1. hive_nectar-0.2.9.dist-info/METADATA +194 -0
  2. hive_nectar-0.2.9.dist-info/RECORD +87 -0
  3. hive_nectar-0.2.9.dist-info/WHEEL +4 -0
  4. hive_nectar-0.2.9.dist-info/entry_points.txt +2 -0
  5. hive_nectar-0.2.9.dist-info/licenses/LICENSE.txt +23 -0
  6. nectar/__init__.py +37 -0
  7. nectar/account.py +5076 -0
  8. nectar/amount.py +553 -0
  9. nectar/asciichart.py +303 -0
  10. nectar/asset.py +122 -0
  11. nectar/block.py +574 -0
  12. nectar/blockchain.py +1242 -0
  13. nectar/blockchaininstance.py +2590 -0
  14. nectar/blockchainobject.py +263 -0
  15. nectar/cli.py +5937 -0
  16. nectar/comment.py +1552 -0
  17. nectar/community.py +854 -0
  18. nectar/constants.py +95 -0
  19. nectar/discussions.py +1437 -0
  20. nectar/exceptions.py +152 -0
  21. nectar/haf.py +381 -0
  22. nectar/hive.py +630 -0
  23. nectar/imageuploader.py +114 -0
  24. nectar/instance.py +113 -0
  25. nectar/market.py +876 -0
  26. nectar/memo.py +542 -0
  27. nectar/message.py +379 -0
  28. nectar/nodelist.py +309 -0
  29. nectar/price.py +603 -0
  30. nectar/profile.py +74 -0
  31. nectar/py.typed +0 -0
  32. nectar/rc.py +333 -0
  33. nectar/snapshot.py +1024 -0
  34. nectar/storage.py +62 -0
  35. nectar/transactionbuilder.py +659 -0
  36. nectar/utils.py +630 -0
  37. nectar/version.py +3 -0
  38. nectar/vote.py +722 -0
  39. nectar/wallet.py +472 -0
  40. nectar/witness.py +728 -0
  41. nectarapi/__init__.py +12 -0
  42. nectarapi/exceptions.py +126 -0
  43. nectarapi/graphenerpc.py +596 -0
  44. nectarapi/node.py +194 -0
  45. nectarapi/noderpc.py +79 -0
  46. nectarapi/openapi.py +107 -0
  47. nectarapi/py.typed +0 -0
  48. nectarapi/rpcutils.py +98 -0
  49. nectarapi/version.py +3 -0
  50. nectarbase/__init__.py +15 -0
  51. nectarbase/ledgertransactions.py +106 -0
  52. nectarbase/memo.py +242 -0
  53. nectarbase/objects.py +521 -0
  54. nectarbase/objecttypes.py +21 -0
  55. nectarbase/operationids.py +102 -0
  56. nectarbase/operations.py +1357 -0
  57. nectarbase/py.typed +0 -0
  58. nectarbase/signedtransactions.py +89 -0
  59. nectarbase/transactions.py +11 -0
  60. nectarbase/version.py +3 -0
  61. nectargraphenebase/__init__.py +27 -0
  62. nectargraphenebase/account.py +1121 -0
  63. nectargraphenebase/aes.py +49 -0
  64. nectargraphenebase/base58.py +197 -0
  65. nectargraphenebase/bip32.py +575 -0
  66. nectargraphenebase/bip38.py +110 -0
  67. nectargraphenebase/chains.py +15 -0
  68. nectargraphenebase/dictionary.py +2 -0
  69. nectargraphenebase/ecdsasig.py +309 -0
  70. nectargraphenebase/objects.py +130 -0
  71. nectargraphenebase/objecttypes.py +8 -0
  72. nectargraphenebase/operationids.py +5 -0
  73. nectargraphenebase/operations.py +25 -0
  74. nectargraphenebase/prefix.py +13 -0
  75. nectargraphenebase/py.typed +0 -0
  76. nectargraphenebase/signedtransactions.py +221 -0
  77. nectargraphenebase/types.py +557 -0
  78. nectargraphenebase/unsignedtransactions.py +288 -0
  79. nectargraphenebase/version.py +3 -0
  80. nectarstorage/__init__.py +57 -0
  81. nectarstorage/base.py +317 -0
  82. nectarstorage/exceptions.py +15 -0
  83. nectarstorage/interfaces.py +244 -0
  84. nectarstorage/masterpassword.py +237 -0
  85. nectarstorage/py.typed +0 -0
  86. nectarstorage/ram.py +27 -0
  87. 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,3 @@
1
+ """THIS FILE IS GENERATED FROM nectar PYPROJECT.TOML."""
2
+
3
+ version = "0.2.9"
@@ -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