aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xexample-dht.py22
-rwxr-xr-xexample-gns.py15
-rw-r--r--gnunet/__init__.py31
-rw-r--r--gnunet/_dbus_utils.py65
-rw-r--r--gnunet/block.py16
-rw-r--r--gnunet/crypto.py10
-rw-r--r--gnunet/dht.py105
-rw-r--r--gnunet/gns.py48
-rw-r--r--gnunet/gnsrecord.py36
-rw-r--r--gnunet/strings.py97
10 files changed, 445 insertions, 0 deletions
diff --git a/example-dht.py b/example-dht.py
new file mode 100755
index 0000000..726e0be
--- /dev/null
+++ b/example-dht.py
@@ -0,0 +1,22 @@
1#!/usr/bin/python3
2
3import gnunet.dht
4import time
5
6key = gnunet.HashCode("RMKN0U1JNA3PVCL148D6JI0STVG94A8A65INOK849CF1RT6BGF26AMMT14GMDMNRDFSJRJME6IKJ3LDFBUL2R1TPQJE64I55I32QN5G")
7
8gnunet.dht.put(key, 1, "test", b"hello")
9
10def result_callback(block_type, key, data, expiry, get_path, put_path):
11 print("Got result from DHT")
12 print(" block_type == %s" % repr(block_type))
13 print(" key == %s" % repr(key))
14 print(" expiry == %s" % repr(expiry))
15 print(" get_path == %s" % repr(get_path))
16 print(" put_path == %s" % repr(put_path))
17 print(" data == %s" % repr(data))
18
19gnunet.dht.get_start(result_callback, "test", key, 1, record_route=True)
20
21time.sleep(1)
22
diff --git a/example-gns.py b/example-gns.py
new file mode 100755
index 0000000..4b3ea10
--- /dev/null
+++ b/example-gns.py
@@ -0,0 +1,15 @@
1#!/usr/bin/python3
2
3import gnunet.gns
4
5results = gnunet.gns.lookup("www.gnu", "JK55QA8JLAL64MBO8UM209KE93M9JBBO7M2UB8M3M03FKRFSUOMG", "A", True)
6
7for r in results:
8 print("Got result from gns")
9 print(" record_type == %s" % repr(r.record_type))
10 print(" data == %s" % repr(r.data))
11 print(" expiration_time == %s" % repr(r.expiration_time))
12 print(" private == %s" % repr(r.private))
13 print(" pending == %s" % repr(r.pending))
14 print(" shadow == %s" % repr(r.shadow))
15
diff --git a/gnunet/__init__.py b/gnunet/__init__.py
new file mode 100644
index 0000000..425ab86
--- /dev/null
+++ b/gnunet/__init__.py
@@ -0,0 +1,31 @@
1import gnunet.strings as strings
2
3class GNUNetDaemonError(Exception):
4 pass
5
6class _Key:
7 def __init__(self, arg, subtype, bits):
8 if isinstance(arg, subtype):
9 self._data = arg.data
10 elif isinstance(arg, str):
11 self._data = strings.string_to_data(arg)
12 else:
13 try:
14 self._data = bytearray(arg)
15 except:
16 raise TypeError("'arg' must be a " + type(subtype).__name__ + ", a string or an array of bytes. Not a '" + type(arg).__name__ + "'.")
17
18 if len(self._data) * 8 != bits:
19 raise ValueError("'arg' must be a " + bits + " bit hash. Got " + len(self._data) + " bits.")
20
21 def __str__(self):
22 return strings.data_to_string(self._data)
23
24
25class HashCode(_Key):
26 def __init__(self, arg):
27 _Key.__init__(self, arg, HashCode, 512)
28
29 def __repr__(self):
30 return "gnunet.HashCode('" + str(self) + "')"
31
diff --git a/gnunet/_dbus_utils.py b/gnunet/_dbus_utils.py
new file mode 100644
index 0000000..4e08c2a
--- /dev/null
+++ b/gnunet/_dbus_utils.py
@@ -0,0 +1,65 @@
1import dbus
2import threading
3import datetime
4from gi.repository import Gtk
5
6from dbus.mainloop.glib import DBusGMainLoop, threads_init
7threads_init()
8DBusGMainLoop(set_as_default=True)
9sysbus = dbus.SystemBus()
10
11class MainLoop(threading.Thread):
12 def __init__(self):
13 threading.Thread.__init__(self)
14 self.daemon = True
15 self.start()
16
17 def run(self):
18 Gtk.main()
19
20MainLoop()
21
22from gnunet import _Key, GNUNetDaemonError
23import gnunet.strings as strings
24
25def pythonize(arg, argtype):
26 if argtype is datetime.datetime:
27 if isinstance(arg, str):
28 return strings.string_to_absolute_time(arg)
29 if isinstance(arg. dbus.UInt64):
30 return datetime.datetime(1970, 1, 1) + datetime.timedelta(microseconds=arg)
31 return datatime.datetime(arg)
32
33def dbusize(arg, pretty):
34 if isinstance(arg, _Key):
35 if pretty:
36 return dbus.String(arg, variant_level=1)
37 else:
38 return dbus.Array(arg._data[:], variant_level=1, signature="y")
39
40 #if type(arg) is gnsrecord.Data:
41 #return dbus.Struct([arg._recordtype,
42
43 if isinstance(arg, datetime.datetime):
44 if pretty:
45 return dbus.String(strings.absolute_time_to_string(arg), variant_level=1)
46 else:
47 return dbus.UInt64((arg - datetime.datetime(1970, 1, 1)).total_seconds() * 1000000, variant_level=1)
48
49def handle_exception(e, daemon, daemon_address):
50 name = e.get_dbus_name()
51 message = e.get_dbus_message()
52 if not name.startswith("org.freedesktop.DBus.Error."):
53 raise e
54 name = name[len("org.freedesktop.DBus.Error."):]
55
56 if name == "Failed" or name == "InvalidArgs":
57 raise GNUNetDaemonError(message)
58 if name == "NoMemory":
59 raise MemoryError(message)
60 if name == "ServiceUnknown" or name == "NameHasNoOwner":
61 raise GNUNetDaemonError("Failed to contact " + daemon + " daemon at " + daemon_address)
62 if name == "NoReply" or name == "Timeout":
63 raise GNUNetDaemonError("Did not receive reply from " + daemon + " daemon at " + daemon_address + ". Daemon might of crashed")
64 raise e
65
diff --git a/gnunet/block.py b/gnunet/block.py
new file mode 100644
index 0000000..2a2dfec
--- /dev/null
+++ b/gnunet/block.py
@@ -0,0 +1,16 @@
1types = set([
2 "any",
3 "fs_dblock",
4 "fs_iblock",
5 "fs_kblock",
6 "fs_sblock",
7 "fs_nblock",
8 "fs_ondemand",
9 "dht_hello",
10 "test",
11 "fs_ublock",
12 "dns",
13 "gns_namerecord",
14 "regex",
15 "regex_accept"])
16
diff --git a/gnunet/crypto.py b/gnunet/crypto.py
new file mode 100644
index 0000000..b81b49d
--- /dev/null
+++ b/gnunet/crypto.py
@@ -0,0 +1,10 @@
1from gnunet import _Key
2import gnunet.strings as strings
3
4class EcdsaPublicKey(_Key):
5 def __init__(self, arg):
6 _Key.__init__(self, arg, EcdsaPublicKey, 256)
7
8 def __repr__(self):
9 return "gnunet.crypto.EcdsaPublicKey('" + str(self) + "')"
10
diff --git a/gnunet/dht.py b/gnunet/dht.py
new file mode 100644
index 0000000..d26b7f2
--- /dev/null
+++ b/gnunet/dht.py
@@ -0,0 +1,105 @@
1import dbus
2
3import datetime
4
5from gnunet import *
6from gnunet._dbus_utils import *
7
8import gnunet.block as block
9
10get_requests = {}
11requests_lock = threading.Lock()
12
13class GetResult(threading.Thread):
14 def __init__(self, expiry, key, get_path, put_path, block_type, data, path):
15 threading.Thread.__init__(self)
16 self.expiry = expiry
17 self.key = key
18 self.get_path = get_path
19 self.put_path = put_path
20 self.block_type = block_type
21 self.data = data
22 self.path = path
23 self.daemon = True
24 self.start()
25
26 def run(self):
27 request = None
28 with requests_lock:
29 request = get_requests[self.path]
30
31 if request:
32 if request.record_route:
33 request.callback(self.block_type, self.key, self.data, self.expiry, get_path=self.get_path, put_path=self.put_path)
34 else:
35 request.callback(self.block_type, self.key, self.data, self.expiry)
36
37def _result(expiry, key, get_path, put_path, block_type, data, path):
38 expiry = pythonize(expiry, datetime.datetime)
39 key = HashCode(key)
40 get_path = list(get_path)
41 put_path = list(put_path)
42 block_type = str(block_type)
43 data = bytearray(data)
44 GetResult(expiry, key, get_path, put_path, block_type, data, path)
45
46sysbus.add_signal_receiver(_result, "result", "gnu.gnunet.dht.get", "gnu.gnunet.dht", path_keyword="path")
47
48class GetRequest:
49 def __init__(self, path, callback, record_route):
50 self._path = path
51 self.callback = callback
52 self.record_route = record_route
53
54def put(key, desired_replication_level, block_type, data, expiry=None, demultiplex_everywhere=False, record_route=False, bart=False):
55 key = dbusize(HashCode(key), True)
56 desired_replication_level = dbus.UInt32(desired_replication_level)
57 if block_type not in block.types:
58 raise ValueError("'block_type' must be one of %s" % block.types)
59 block_type = dbus.String(block_type, variant_level=1)
60 if expiry is not None:
61 if not isinstance(expiry, datetime.datetime):
62 raise TypeError("'expiry' must be a datetime.datetime")
63 expiry = dbusize(expiry)
64 else:
65 expiry = dbus.String("end of time", variant_level=1)
66 options = dbus.Array([], variant_level=1, signature="s")
67 if demultiplex_everywhere:
68 options += ["demultiplex_everywhere"]
69 if record_route:
70 options += ["record_route"]
71 if bart:
72 options += ["bart"]
73 data = dbus.Array(bytearray(data), signature="y")
74
75 try:
76 sysbus.get_object("gnu.gnunet.dht", "/").put(key, desired_replication_level, options, block_type, data, expiry)
77 except dbus.DBusException as e:
78 handle_exception(e, "dht", "gnu.gnunet.dht")
79
80def get_start(callback, block_type, key, desired_replication_level, demultiplex_everywhere=False, record_route=False, bart=False):
81 if block_type not in block.types:
82 raise ValueError("'block_type' must be one of %s" % block.types)
83 block_type = dbus.String(block_type, variant_level=1)
84 key = dbusize(HashCode(key), True)
85 desired_replication_level = dbus.UInt32(desired_replication_level)
86 options = dbus.Array([], variant_level=1, signature="s")
87 if demultiplex_everywhere:
88 options += ["demultiplex_everywhere"]
89 if record_route:
90 options += ["record_route"]
91 if bart:
92 options += ["bart"]
93
94 ret = None
95 try:
96 with requests_lock:
97 path = sysbus.get_object("gnu.gnunet.dht", "/").get_start(block_type, key, desired_replication_level, options)
98 ret = GetRequest(path, callback, record_route)
99 get_requests[path] = ret
100 except dbus.DBusException as e:
101 handle_exception(e, "dht", "gnu.gnunet.dht")
102
103 return ret
104
105
diff --git a/gnunet/gns.py b/gnunet/gns.py
new file mode 100644
index 0000000..57c1bd9
--- /dev/null
+++ b/gnunet/gns.py
@@ -0,0 +1,48 @@
1import dbus
2
3from gnunet._dbus_utils import *
4
5from gnunet import *
6import gnunet.crypto as crypto
7import gnunet.gnsrecord as gnsrecord
8
9def lookup(name, zone, record_type, only_cached):
10 name = str(name)
11 zone = dbusize(crypto.EcdsaPublicKey(zone), True)
12 if record_type not in gnsrecord.types:
13 raise ValueError("'record_type' must be one of %s" % gnsrecord.types)
14 #record_type = dbus.UInt32(gnsrecord.types[record_type], variant_level=1)
15 record_type = dbus.String(record_type, variant_level=1)
16 only_cached = dbus.Boolean(only_cached)
17
18 try:
19 results = sysbus.get_object("gnu.gnunet.gns", "/").lookup(name, zone, record_type, only_cached)
20 except dbus.DBusException as e:
21 handle_exception(e, "gns", "gnu.gnunet.gns")
22
23 ret = []
24 for r in results:
25 record_type = str(r[0])
26 private = False
27 pending = False
28 shadow = False
29 relative = False
30 for f in r[1]:
31 if f == "private":
32 private = True
33 if f == "pending":
34 pending = True
35 if f == "shadow":
36 shadow = True
37 if f == "relative_expiration":
38 relative = True
39 data = str(r[2])
40 expiration_time = None
41 if relative:
42 expiration_time = pythonize(r[3], datetime.timedelta)
43 else:
44 expiration_time = pythonize(r[3], datetime.datetime)
45 ret.append(gnsrecord.Data(record_type, data, expiration_time, private, pending, shadow))
46
47 return ret
48
diff --git a/gnunet/gnsrecord.py b/gnunet/gnsrecord.py
new file mode 100644
index 0000000..4d00139
--- /dev/null
+++ b/gnunet/gnsrecord.py
@@ -0,0 +1,36 @@
1import datetime
2
3dns_types = {
4 "A": 1,
5 "NS": 2,
6 "CNAME": 5,
7 "SOA": 6,
8 "PTR": 12,
9 "MX": 15,
10 "TXT": 16,
11 "AAAA": 28,
12 "TLSA": 52}
13
14gns_types = {
15 "PKEY": 65536,
16 "NICK": 65537,
17 "LEHO": 65538,
18 "VPN": 65539,
19 "GNS2DNS": 65540}
20
21types = dict(list(dns_types.items()) + list(gns_types.items()))
22
23class Data:
24 def __init__(self, record_type, data, expiration_time=None, private=None, pending=None, shadow=None):
25 self.record_type = str(record_type)
26 if record_type not in types:
27 raise ValueError("'record_type' must be one of %s" % types)
28 #self.data = bytearray(data)
29 self.data = str(data)
30 if expiration_time is not None and not isinstance(expiration_time, datetime.datetime) or isinstance(expiration_time, datetime.timedelta):
31 raise TypeError("'expiration_time' must be a datetime.datetime or a datetime.timedelta")
32 self.expiration_time = expiration_time
33 self.private = private
34 self.pending = pending
35 self.shadow = shadow
36
diff --git a/gnunet/strings.py b/gnunet/strings.py
new file mode 100644
index 0000000..cfbdaa5
--- /dev/null
+++ b/gnunet/strings.py
@@ -0,0 +1,97 @@
1import datetime
2
3from gnunet import *
4
5encTable = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
6
7def data_to_string(data):
8 data = bytearray(data)
9 size = len(data)
10 bits = 0
11 rpos = 0
12 vbit = 0
13 ret = ""
14 while rpos < size:
15 while rpos < size and vbit < 5:
16 bits = (bits << 8) | data[rpos]
17 rpos += 1
18 vbit += 8
19 while vbit >= 5:
20 vbit -= 5
21 ret += encTable[(bits >> vbit) & 31]
22 if vbit > 0:
23 ret += encTable[(bits << (5 - vbit)) & 31]
24 return ret
25
26def string_to_data(s):
27 s = str(s)
28 size = len(s)
29 bits = 0
30 rpos = 0
31 vbit = 0
32 ret = bytearray([])
33 try:
34 while rpos < size:
35 while rpos < size and vbit < 8:
36 bits = (bits << 5) | int(s[rpos], 32)
37 rpos += 1
38 vbit += 5
39 while vbit >= 8:
40 vbit -= 8
41 ret.append((bits >> vbit) & 255)
42 if vbit > 0:
43 if bits & ((1 << vbit) - 1) != 0:
44 raise ValueError("")
45 except ValueError:
46 raise ValueError("'" + s + "' is not a valid data-encoding string")
47 return ret
48
49def absolute_time_to_string(t):
50 return t.strftime("%a %b %d %H:%M:%S %Y")
51
52def string_to_absolute_time(s):
53 if s == "end of time":
54 return None
55 try:
56 return datetime.datetime.strptime(s, "%a %b %d %H:%M:%S %Y")
57 except ValueError:
58 pass
59 try:
60 return datetime.datetime.strptime(s, "%c")
61 except ValueError:
62 pass
63 try:
64 return datetime.datetime.strptime(s, "%Ec")
65 except ValueError:
66 pass
67 try:
68 return datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
69 except ValueError:
70 pass
71 try:
72 return datetime.datetime.strptime(s, "%Y-%m-%d %H:%M")
73 except ValueError:
74 pass
75 try:
76 return datetime.datetime.strptime(s, "%x")
77 except ValueError:
78 pass
79 try:
80 return datetime.datetime.strptime(s, "%Ex")
81 except ValueError:
82 pass
83 try:
84 return datetime.datetime.strptime(s, "%Y-%m-%d")
85 except ValueError:
86 pass
87 try:
88 return datetime.datetime.strptime(s, "%Y-%m")
89 except ValueError:
90 pass
91 try:
92 return datetime.datetime.strptime(s, "%Y")
93 except ValueError:
94 pass
95 raise ValueError("%s is not a properly formatted time string" % s)
96
97