Compare commits
1054 Commits
upload-fix
...
wot
Author | SHA1 | Date | |
---|---|---|---|
|
61051d5711 | ||
|
59ad2731ba | ||
|
560a20e90a | ||
|
ce3a548c70 | ||
|
8712a1c401 | ||
|
8511fb42b6 | ||
|
9eb2e5d413 | ||
|
39c01fdbc5 | ||
|
7bcef03592 | ||
|
2b224cae84 | ||
|
7895442b51 | ||
|
474ef21163 | ||
|
8e35a79864 | ||
|
8e730cef98 | ||
|
738fa0c361 | ||
|
b3eb0caffd | ||
|
446662cc60 | ||
|
180116a55d | ||
|
bc3d6571bb | ||
|
30d50ceacf | ||
|
e84ad93de7 | ||
|
84e16e5b82 | ||
|
cd3a7cd7b2 | ||
|
24e0157e15 | ||
|
c2db671a85 | ||
|
9501d73546 | ||
|
4572f255fb | ||
|
20393a547e | ||
|
015a072b0b | ||
|
5ae5897703 | ||
|
e9efffff34 | ||
|
2eea681e98 | ||
|
3852b15c89 | ||
|
3643e4f8d7 | ||
|
8676a18c87 | ||
|
97d8662f15 | ||
|
a517ad3aee | ||
|
d915a2aaed | ||
|
25e705c0b2 | ||
|
6f3e5aebd9 | ||
|
584bc6b73f | ||
|
171ea25f46 | ||
|
2c9836c54f | ||
|
a036c1839f | ||
|
6ad36bf4e5 | ||
|
cdeaa403af | ||
|
fae9521d8f | ||
|
05e04ef557 | ||
|
5bb43326e7 | ||
|
9058f7bee5 | ||
|
08d8fda857 | ||
|
650e943182 | ||
|
e3d06ff0f5 | ||
|
83007cb28d | ||
|
57b1e07715 | ||
|
bddddd7c5b | ||
|
85b6f468fd | ||
|
5ca2c8d329 | ||
|
c0d3b367dc | ||
|
86615305d7 | ||
|
69a31d1d83 | ||
|
954f5d793d | ||
|
c95d4b2685 | ||
|
736549c1dc | ||
|
2deb9271dc | ||
|
189645d560 | ||
|
b59e79a21f | ||
|
3b8644fa8f | ||
|
b2ebc56419 | ||
|
bc71d12b77 | ||
|
264eeaa988 | ||
|
c880b6fa7a | ||
|
228d3cbe35 | ||
|
9864fa5040 | ||
|
3a7e378d8b | ||
|
f220e398f1 | ||
|
8bd4a4c524 | ||
|
c663be30f1 | ||
|
90176e43fb | ||
|
9b6d1f5dbd | ||
|
e7daaf576f | ||
|
84c13ade51 | ||
|
d2b5298bc6 | ||
|
d11d12b67f | ||
|
1eadb4bf6e | ||
|
64a88118bd | ||
|
b25e376349 | ||
|
b9fa446cb0 | ||
|
6b6d357a13 | ||
|
ac88e0a1da | ||
|
cdccde2d9d | ||
|
7b0c761dd1 | ||
|
911d8118bc | ||
|
ac17b53663 | ||
|
946fdbd06d | ||
|
9088d931c9 | ||
|
421c6da25a | ||
|
158178d6fc | ||
|
85626d6642 | ||
|
9f25291c3a | ||
|
15a4744a70 | ||
|
1b21e25f7e | ||
|
0b4e264877 | ||
|
12d4ed7638 | ||
|
2be0175326 | ||
|
5bdfbd7c43 | ||
|
93fc1827b5 | ||
|
3a26d053fe | ||
|
7b7d6a03d3 | ||
|
50f0cfa6f4 | ||
|
91df7507f4 | ||
|
c065be0145 | ||
|
4edbde82cc | ||
|
1b37264eb7 | ||
|
e6b61c5f59 | ||
|
ca2344c72c | ||
|
237cdde4e5 | ||
|
6a6460ef31 | ||
|
4caee50ce7 | ||
|
a61cd273a8 | ||
|
c7ba974264 | ||
|
9d2c2641f4 | ||
|
996bff267b | ||
|
dae99dc2f7 | ||
|
5858b0aca3 | ||
|
df02bdb826 | ||
|
c215d4decd | ||
|
b07c176f5c | ||
|
9c44069248 | ||
|
5b5e5ef764 | ||
|
fd9e6f5ede | ||
|
8b2b6a613e | ||
|
be1dde95a6 | ||
|
9ef6f46a5c | ||
|
e985966e7c | ||
|
f740d475c4 | ||
|
a53c31fda7 | ||
|
511803f565 | ||
|
1b77c60346 | ||
|
568a192c97 | ||
|
2544579363 | ||
|
6c2b1e49a2 | ||
|
9bf16c5758 | ||
|
19159ffa06 | ||
|
4c54677387 | ||
|
747b7d70a8 | ||
|
fefec8bdc8 | ||
|
9d17c7bd64 | ||
|
17b268d9e4 | ||
|
4f3da58a60 | ||
|
1a7ce7d386 | ||
|
44f6b90777 | ||
|
5337b0aba4 | ||
|
34f9ffbf6b | ||
|
8d394c76a7 | ||
|
df3568fc15 | ||
|
850468dc39 | ||
|
d6b1c98cbd | ||
|
8eec2167c8 | ||
|
d48af45210 | ||
|
81a0d83b53 | ||
|
15875d26c6 | ||
|
2bcfbf0d79 | ||
|
e5b396fc11 | ||
|
713aeb199d | ||
|
026f39b680 | ||
|
ebb75b136d | ||
|
ed6e2d05b4 | ||
|
d388bba646 | ||
|
cbd9a3cbec | ||
|
e55beec18c | ||
|
4fba79950c | ||
|
cedd01c98f | ||
|
df686b3995 | ||
|
9c3ed5bb10 | ||
|
29b28accf1 | ||
|
79639ba0af | ||
|
061e2d1e01 | ||
|
eb763cf293 | ||
|
ff9eb13579 | ||
|
844723cea9 | ||
|
bb34f9042e | ||
|
44d5eeab2a | ||
|
15931ccc32 | ||
|
21d1f69bbe | ||
|
fd93f6151e | ||
|
1d22b43ef9 | ||
|
e99056afac | ||
|
cb647daa85 | ||
|
4bd9bd6e9d | ||
|
2352e066cc | ||
|
6a8ab46815 | ||
|
8f784f208b | ||
|
de18cdfd55 | ||
|
06907a80fa | ||
|
aecd9ad9ef | ||
|
3e17cf7c0b | ||
|
735220d8da | ||
|
914b505dfa | ||
|
8659fa613e | ||
|
7fa320cfc5 | ||
|
9306143e4c | ||
|
7303cf041e | ||
|
4e96d18396 | ||
|
133b3ea699 | ||
|
3a98183fa0 | ||
|
8083489110 | ||
|
cb2e29ad6e | ||
|
6b6a698370 | ||
|
d10ccd2e13 | ||
|
513b758c7a | ||
|
5a9594074e | ||
|
ba8b9b49ed | ||
|
8c9a24b227 | ||
|
c28e5dea74 | ||
|
07d9207808 | ||
|
ad91a3222f | ||
|
a032782d26 | ||
|
1042676f26 | ||
|
9bf27b345d | ||
|
8a2d0a635a | ||
|
5a0231653f | ||
|
e71935fcef | ||
|
87685fd728 | ||
|
d0df62770f | ||
|
e95b75b193 | ||
|
59090b4a03 | ||
|
ab41282fba | ||
|
d1e4ae6032 | ||
|
b6b941bf9b | ||
|
509e8a290b | ||
|
b267d3028e | ||
|
76f1d164e7 | ||
|
54f6e3bdc6 | ||
|
fd440b8b91 | ||
|
8797bce4fa | ||
|
b42dc8fbc6 | ||
|
e950f3242e | ||
|
eefcb8ccbe | ||
|
f4e37bbf4e | ||
|
7dce969eaa | ||
|
79b46b62eb | ||
|
314bec0909 | ||
|
fcc3bd656d | ||
|
4b7be71102 | ||
|
8a722a0911 | ||
|
797da0aaea | ||
|
52bffa0aae | ||
|
d7bcd2b4a8 | ||
|
0fb5e5df10 | ||
|
ae84d09e8e | ||
|
80e4562029 | ||
|
427957b9e8 | ||
|
9d55c62d68 | ||
|
e36f44f9a1 | ||
|
57638e73f7 | ||
|
2dc11303d7 | ||
|
9345d27d6a | ||
|
5afbed63cf | ||
|
c44d6624ff | ||
|
ae359de562 | ||
|
2bd58945da | ||
|
b1ef248ee9 | ||
|
416e43e7bb | ||
|
1eb6140811 | ||
|
700bde4bd8 | ||
|
71b511382b | ||
|
67f5c30d85 | ||
|
9684585432 | ||
|
9d6216e16b | ||
|
2a6f6bb1aa | ||
|
7820c87b79 | ||
|
93d176badc | ||
|
968f468027 | ||
|
86fd936d52 | ||
|
e34b499044 | ||
|
01ed4d49d0 | ||
|
9db9c495c8 | ||
|
dcc304be9d | ||
|
eaf61c280a | ||
|
e831a27ae3 | ||
|
de271794fd | ||
|
21df88fdaa | ||
|
9d4afc4b3a | ||
|
28044f2bd7 | ||
|
adba4be099 | ||
|
30a4285b92 | ||
|
59330149e1 | ||
|
a775f3b26d | ||
|
cc703fc404 | ||
|
ecd2cc54da | ||
|
bbd76da333 | ||
|
04105a2b70 | ||
|
8d839f62c9 | ||
|
a0ae62d0a3 | ||
|
a9d0524ccc | ||
|
130e9de5e9 | ||
|
f0cd2fb2b9 | ||
|
44112750ec | ||
|
f2d7075b3a | ||
|
256c402223 | ||
|
2601263b87 | ||
|
3ab8681b24 | ||
|
2837210cf4 | ||
|
d0e6f6c4af | ||
|
67054446ae | ||
|
f7f4732789 | ||
|
f80d58e5b8 | ||
|
4a831a4a4d | ||
|
57ec04eff5 | ||
|
da11c74f6c | ||
|
c4be08bd23 | ||
|
299980f126 | ||
|
b5fe4453ed | ||
|
77de7e318d | ||
|
eec8c356ad | ||
|
6a4744997c | ||
|
cf0507b82d | ||
|
862b39c217 | ||
|
b424ef6674 | ||
|
4847d9bddf | ||
|
51c3078b90 | ||
|
8a4c138eed | ||
|
5dddeb3f10 | ||
|
fb85856f76 | ||
|
5c61708c61 | ||
|
183e6491d0 | ||
|
3ca05e2390 | ||
|
88ec98c92a | ||
|
8f52fa4669 | ||
|
60c7e6cb37 | ||
|
c23b286540 | ||
|
723d004e5c | ||
|
989692c6ac | ||
|
fcfecaff7e | ||
|
895b4fe4fd | ||
|
cf669024bf | ||
|
a9096dc048 | ||
|
1e7d7840b1 | ||
|
57225f57f0 | ||
|
fbcb95be9e | ||
|
c2b7246048 | ||
|
e0f59784b1 | ||
|
2291d5a5f2 | ||
|
d067a343e6 | ||
|
3ef29077e7 | ||
|
835c2e527e | ||
|
1c44a514a5 | ||
|
5baa048a4e | ||
|
0338cd64b6 | ||
|
fc7db42deb | ||
|
503bf65cbe | ||
|
da57dc373f | ||
|
f0bb41daac | ||
|
2dc706a894 | ||
|
d0baa7fd12 | ||
|
10689f24d7 | ||
|
b010fa8326 | ||
|
b5b7c756ea | ||
|
99371cfec5 | ||
|
10ba2be93f | ||
|
45940b2dba | ||
|
092233027c | ||
|
5abe4cf704 | ||
|
ab9726a41a | ||
|
6370d07f90 | ||
|
fa0318802b | ||
|
366295f09c | ||
|
48f988877d | ||
|
68a557daf5 | ||
|
02cdbc75ce | ||
|
843f1c1a8e | ||
|
50f0ff8da6 | ||
|
60d6aa0510 | ||
|
0c315c3181 | ||
|
e9dbc9fa09 | ||
|
499981ed52 | ||
|
60c1ec07e9 | ||
|
fd0f13cf63 | ||
|
3199f93d4b | ||
|
646a7c0b80 | ||
|
5b3d76067a | ||
|
c0ebfec034 | ||
|
c19797bb2e | ||
|
1f067f614a | ||
|
b4d80da3ff | ||
|
43d3e687d7 | ||
|
4bc2bf5db5 | ||
|
c7e0b6c1b2 | ||
|
247b1f616d | ||
|
b4ddf343fc | ||
|
196d02a751 | ||
|
a5b6805b5f | ||
|
e11c3d2733 | ||
|
97708e5875 | ||
|
41e57cb5b9 | ||
|
79a5e6ca3e | ||
|
2ce5f48c90 | ||
|
17ef138c21 | ||
|
cb88ff8c3f | ||
|
d40bd85368 | ||
|
d7e7d4499b | ||
|
104f71c0c3 | ||
|
16cdd6d877 | ||
|
b7091d2062 | ||
|
f8fcd6d4e5 | ||
|
15a66c7fb4 | ||
|
37e5dbab4b | ||
|
3df1859df5 | ||
|
14f2d03ebf | ||
|
3422ca43ff | ||
|
a83351a73c | ||
|
39650a4ca0 | ||
|
8d54519771 | ||
|
9f1f1435ce | ||
|
78e533952c | ||
|
e19e23022b | ||
|
68aac2153b | ||
|
15379a7c2f | ||
|
61bc5fd34b | ||
|
b66e1d852e | ||
|
02fde0ad70 | ||
|
308fca7c22 | ||
|
72653c1e93 | ||
|
cd0b69b03f | ||
|
bbc9646a25 | ||
|
fd73f63ecd | ||
|
2cf7a8c8b3 | ||
|
6089cc3c98 | ||
|
05127dd3b7 | ||
|
d39c12ab4d | ||
|
ce0e60c4ea | ||
|
0938bf0692 | ||
|
fb4dd07ba4 | ||
|
6f242298fe | ||
|
0b2658374b | ||
|
2a7c933321 | ||
|
c9af24392d | ||
|
272d7d7f74 | ||
|
ce63c4cd3b | ||
|
e900d597d8 | ||
|
2ddeab8788 | ||
|
a24086da62 | ||
|
8389ed190c | ||
|
87b8655b83 | ||
|
feb8004c95 | ||
|
a01b645a79 | ||
|
3473c5e36a | ||
|
e14955cb6b | ||
|
504c53edb3 | ||
|
5e00bb930f | ||
|
6976dcf8f3 | ||
|
552e7427d8 | ||
|
661a4ee3d2 | ||
|
96af4e8db0 | ||
|
bff2595ac9 | ||
|
522cd2c462 | ||
|
2f5c1311be | ||
|
077f530b72 | ||
|
5930f3bfad | ||
|
ab10cea8b6 | ||
|
086f2f718c | ||
|
4cf17ffe62 | ||
|
0b34aa7385 | ||
|
6f1daf50d3 | ||
|
5bde99967b | ||
|
f28d469e56 | ||
|
080f33bf1f | ||
|
fad5e8547e | ||
|
dde10b7005 | ||
|
10c1cd7803 | ||
|
97a5f50271 | ||
|
e00d41f8a9 | ||
|
6a6718c9fd | ||
|
0e4e7bb050 | ||
|
0460d3380f | ||
|
e3b1eaad17 | ||
|
6ecb62356a | ||
|
47013431d2 | ||
|
b4be481f81 | ||
|
f4d1739e4a | ||
|
8b5c87d356 | ||
|
ac279c1cef | ||
|
82b1121ad5 | ||
|
9fe74d1f9b | ||
|
9fc741106a | ||
|
9424f1d6a0 | ||
|
782c980b69 | ||
|
714b3a3c33 | ||
|
a887efe3d2 | ||
|
7931f514b6 | ||
|
c46e9590c6 | ||
|
08d2dee18a | ||
|
3a6322c6c6 | ||
|
d6422801a2 | ||
|
63e676ed6f | ||
|
e174b4a636 | ||
|
3f13cd84ea | ||
|
25485e6aa4 | ||
|
1aa707cea5 | ||
|
049956544e | ||
|
7f8e63f19b | ||
|
6738eaf222 | ||
|
0d58d57467 | ||
|
95c4050142 | ||
|
27adbbb199 | ||
|
e9bbd38aab | ||
|
cc41ad793e | ||
|
b878faeb4c | ||
|
c5fd39c762 | ||
|
7780093898 | ||
|
0358ce91f0 | ||
|
57a18999ac | ||
|
91c95ac32e | ||
|
ee28aba792 | ||
|
4a647b4cb1 | ||
|
e07c70057c | ||
|
b2068fc6b5 | ||
|
22c4a2e8cd | ||
|
1aea6c3362 | ||
|
1bf365aff4 | ||
|
03608960c0 | ||
|
8d33e1a188 | ||
|
ca1f9eb44b | ||
|
5bcb5a759d | ||
|
5419cb431a | ||
|
817f0263db | ||
|
6c75c525d2 | ||
|
7d8c3f75e4 | ||
|
a24c87c5b0 | ||
|
3ed2ac2d63 | ||
|
1b90458b19 | ||
|
34416c07fe | ||
|
c41592de0a | ||
|
dafa4b6117 | ||
|
c81df9093d | ||
|
c9a6769be7 | ||
|
7205189d62 | ||
|
5751468e8a | ||
|
eeab5ef2c2 | ||
|
9ad20c069c | ||
|
bae8b38f08 | ||
|
c0b72f9007 | ||
|
1f2c116b4b | ||
|
5b9bb2e5e2 | ||
|
1e76990d1e | ||
|
529da22cc4 | ||
|
ac665f5872 | ||
|
0c7afa89f1 | ||
|
a10a32fafb | ||
|
88824b7913 | ||
|
3c7b090a4e | ||
|
a401f49da3 | ||
|
3d0f1d9337 | ||
|
2a65f605f5 | ||
|
33896d9c91 | ||
|
7c5359c39e | ||
|
eefc0e28e1 | ||
|
05f65c1f89 | ||
|
db8fdc4999 | ||
|
f35db0a3cf | ||
|
b5d5c77516 | ||
|
57fe06ff11 | ||
|
d7b9b507a1 | ||
|
6a1cd02477 | ||
|
2c4b012d90 | ||
|
2a34218391 | ||
|
e1fd4daa8e | ||
|
6047ae842f | ||
|
935220bd69 | ||
|
c15e7b7cf3 | ||
|
5f54c9ec56 | ||
|
7cc86057f3 | ||
|
13acff9db7 | ||
|
ca8f139c2f | ||
|
30351a1343 | ||
|
4a155c5c11 | ||
|
1a189a85ba | ||
|
1270628155 | ||
|
f2290d48d2 | ||
|
249c62a515 | ||
|
1618e2988d | ||
|
76daf89565 | ||
|
fc17dda993 | ||
|
05ec520f0e | ||
|
9605c9db73 | ||
|
6a23c13cc4 | ||
|
b863a8cab0 | ||
|
9f61a93397 | ||
|
a6baa8ac00 | ||
|
026901ce90 | ||
|
039d791b90 | ||
|
eb37325222 | ||
|
5d496ee3b1 | ||
|
a52465a54f | ||
|
a5983d32a4 | ||
|
b2a581823f | ||
|
b35d5be8db | ||
|
3bc54086a3 | ||
|
9959ec0d57 | ||
|
12137d3c00 | ||
|
d13d9a3039 | ||
|
ae8d1fc5ea | ||
|
4cd2302bc9 | ||
|
7bedae48a4 | ||
|
aa729d862c | ||
|
653954714f | ||
|
da1940cc8e | ||
|
d47c546620 | ||
|
39d0be32ac | ||
|
919ab12b76 | ||
|
a8ab5d20f1 | ||
|
37913d544b | ||
|
eea8b39b0f | ||
|
dee5d8ceed | ||
|
5be4df1276 | ||
|
b23343e7cb | ||
|
46ce27cbe8 | ||
|
8804c13225 | ||
|
8d372cccfb | ||
|
0da27a78c7 | ||
|
b2f630e4f9 | ||
|
09134eaba4 | ||
|
1bd0aa9419 | ||
|
d2746c21b4 | ||
|
160469f50f | ||
|
7bb4a7680a | ||
|
018f6692a9 | ||
|
b256db2698 | ||
|
70a26598fb | ||
|
825c576ce3 | ||
|
179ec4a3be | ||
|
2c848a4caf | ||
|
309f98d640 | ||
|
418881fc32 | ||
|
3b939b4598 | ||
|
d50e6db1d2 | ||
|
012ee33499 | ||
|
16ae16f042 | ||
|
b8a8cfd3f6 | ||
|
62b4f5eb0e | ||
|
922f2be235 | ||
|
d5c9b01b53 | ||
|
db9cd3eb60 | ||
|
71c7ad4545 | ||
|
d24fd41c53 | ||
|
8e31d51740 | ||
|
1be08e09ef | ||
|
0825f2dd01 | ||
|
427a5355bc | ||
|
83a1c09af7 | ||
|
2aa8cdbaa0 | ||
|
b5e57da191 | ||
|
2c8f1fdf99 | ||
|
eec7efd38d | ||
|
d77f802fdd | ||
|
3c6b3652c6 | ||
|
77b24d022f | ||
|
c7b8f9bed6 | ||
|
42a8d71ebf | ||
|
acabeab7c4 | ||
|
9369a22841 | ||
|
361853cc95 | ||
|
481cb5aeff | ||
|
4696e7be3f | ||
|
05ea54cd28 | ||
|
2a104d7459 | ||
|
a52a17ac25 | ||
|
3e4a39016f | ||
|
e6181bdd1f | ||
|
022fbaa1af | ||
|
b2f4dae226 | ||
|
b5ac1ed7d8 | ||
|
fe3b6c01c4 | ||
|
d4f4487fb6 | ||
|
e90d7e96f4 | ||
|
1ffc899695 | ||
|
6fed37a237 | ||
|
69bb257166 | ||
|
24284e058f | ||
|
62a01b6dba | ||
|
76118a2e4a | ||
|
68678177ed | ||
|
9575352e3e | ||
|
3aec35ef33 | ||
|
92c4109572 | ||
|
2732b2feea | ||
|
18aca5aeea | ||
|
d4652e1107 | ||
|
7bb95c3b87 | ||
|
a8290e2ac3 | ||
|
4e053f1b30 | ||
|
e4d4091e66 | ||
|
c106d5881f | ||
|
25766e02fc | ||
|
a5c733469f | ||
|
159585a292 | ||
|
04133035ba | ||
|
901b7fa064 | ||
|
eb081d1f3d | ||
|
46c8c99fa1 | ||
|
dfc42953f7 | ||
|
008e16c11f | ||
|
61d60c13d2 | ||
|
6c82632469 | ||
|
4516cdee24 | ||
|
60d2ebfaed | ||
|
665cb0c732 | ||
|
c0def6fb7e | ||
|
1322352fa2 | ||
|
02fa6dd558 | ||
|
b62e613e8e | ||
|
862c6f2ea4 | ||
|
6f0ef390a7 | ||
|
56e86460d1 | ||
|
b8348be65a | ||
|
34a55f63f9 | ||
|
6b5e6a9ad0 | ||
|
59376135f9 | ||
|
38e2ecb8ca | ||
|
e5d64bb164 | ||
|
6f2f2c89a3 | ||
|
3e6811bea6 | ||
|
bdf838e48f | ||
|
aaa7251d56 | ||
|
c1472ecfaa | ||
|
1b52a957dc | ||
|
d342bb3e5b | ||
|
4dae995eaa | ||
|
3e0919f12d | ||
|
d0fb035572 | ||
|
20debf5c9e | ||
|
080933639c | ||
|
6fe2da7b09 | ||
|
bf73dedd64 | ||
|
9f1790a601 | ||
|
83ef9dc3ca | ||
|
aea4815fbd | ||
|
23782dcb8f | ||
|
6bb4347f61 | ||
|
47eef04643 | ||
|
d149f351d2 | ||
|
59a1ad1235 | ||
|
353b2f1c63 | ||
|
3bb51a16e1 | ||
|
6f7406e82c | ||
|
26ddee54ce | ||
|
559f6bed49 | ||
|
dee531fd51 | ||
|
982ac88a72 | ||
|
572e29f5d5 | ||
|
e77d422fc2 | ||
|
b8c288259b | ||
|
2319ff8344 | ||
|
7c7e5de091 | ||
|
938e1bddd3 | ||
|
3456fae533 | ||
|
4487bf2806 | ||
|
c8f0427f45 | ||
|
b305380447 | ||
|
d91480104b | ||
|
52e3600ae1 | ||
|
e7fd0d1d66 | ||
|
6960d9209d | ||
|
fe36b87c57 | ||
|
8e1eaa2b42 | ||
|
b86eb821ce | ||
|
583ce92065 | ||
|
b08e95d752 | ||
|
f0ffbb63e7 | ||
|
68074d4dd8 | ||
|
09617dc563 | ||
|
246ba6eb7b | ||
|
6500229000 | ||
|
c58bbbb10f | ||
|
d4dd964069 | ||
|
5b78a8810d | ||
|
79a3f725be | ||
|
5c3fb5bec3 | ||
|
912c2c832b | ||
|
74be4dee01 | ||
|
8a82e76182 | ||
|
8e5152a14e | ||
|
567af997d7 | ||
|
88146a5690 | ||
|
cd671feb92 | ||
|
ea47ae456b | ||
|
8bf1389a48 | ||
|
840563f75c | ||
|
bffef46e89 | ||
|
95599003e5 | ||
|
d2dca0f94d | ||
|
1556339ab2 | ||
|
6707af2c9a | ||
|
927071533f | ||
|
4484489690 | ||
|
940272136c | ||
|
a934fbd006 | ||
|
e0b8b3fcef | ||
|
f17d56341b | ||
|
b1eb9a1338 | ||
|
d0bdeca7c4 | ||
|
8649231860 | ||
|
d4c1dc2bf2 | ||
|
6f557d0aef | ||
|
8a3f84097a | ||
|
6624a80c68 | ||
|
68ebb2f0df | ||
|
cffe74d310 | ||
|
2bc14b5c63 | ||
|
d0291c2fb3 | ||
|
cb108cb990 | ||
|
7f8aa64fa4 | ||
|
a958b99fef | ||
|
c636e87b2c | ||
|
d612fbf5c5 | ||
|
2732c3a149 | ||
|
d303b8252b | ||
|
85be8f76e5 | ||
|
787c733785 | ||
|
d65d9c79c0 | ||
|
c8e215341d | ||
|
0059c91b06 | ||
|
2bc996f660 | ||
|
2388c80a3d | ||
|
a1fd5f2648 | ||
|
0e013df9d4 | ||
|
70d94c6ba9 | ||
|
73993a67e5 | ||
|
ef25377e15 | ||
|
b17834d814 | ||
|
11d97a12d0 | ||
|
b1a7641db9 | ||
|
5c636246fb | ||
|
66d24e3535 | ||
|
57f233d856 | ||
|
48d19b277c | ||
|
dd0ebd9238 | ||
|
07ab85698d | ||
|
3aeb305994 | ||
|
c7bbd054e4 | ||
|
4afa3d87e5 | ||
|
f3b22dad56 | ||
|
7db8193bf6 | ||
|
1c6893e297 | ||
|
abddeecda7 | ||
|
0cd533db60 | ||
|
3fc11657e8 | ||
|
828f7682b8 | ||
|
29421d678e | ||
|
1c5fe29baf | ||
|
f78809fa2a | ||
|
2e31155a5d | ||
|
27ef1d9ce4 | ||
|
88fe605762 | ||
|
a801960179 | ||
|
c975d27906 | ||
|
1ba8b4c707 | ||
|
6529d3e622 | ||
|
d7be2ca16d | ||
|
ee7b68c844 | ||
|
66aafb6deb | ||
|
a4762ccf9a | ||
|
a9bc826930 | ||
|
34b1abddb7 | ||
|
e9f0e60608 | ||
|
01f9b9b470 | ||
|
87ea8d137b | ||
|
9329b07e3b | ||
|
f71f2f6246 | ||
|
c469c5d871 | ||
|
b5a8f295c9 | ||
|
1019ff0773 | ||
|
9571ea519d | ||
|
e5f3866f9e | ||
|
9fbee668aa | ||
|
eb294dd9ae | ||
|
0484655e2e | ||
|
f5a98fba13 | ||
|
906219fe30 | ||
|
6d123b93fc | ||
|
4b6fdbdd0a | ||
|
ef794b18cf | ||
|
e77e213589 | ||
|
027abd3f13 | ||
|
c1dd2a7213 | ||
|
00e20c54b0 | ||
|
f7e2a94502 | ||
|
9707d5e320 | ||
|
aa51a2fea6 | ||
|
a1c68fabe7 | ||
|
f42e777408 | ||
|
abe1dde57e | ||
|
8f1df8c371 | ||
|
a36885c806 | ||
|
9af3f06b56 | ||
|
70408b828b | ||
|
743e735c48 | ||
|
9790785c08 | ||
|
ae416bc650 | ||
|
47e69bab99 | ||
|
bb87bc192e | ||
|
6b0c88aff9 | ||
|
15872f8f7c | ||
|
63c0c51f38 | ||
|
fd6096a93c | ||
|
1eb7880de9 | ||
|
1eb47a4584 | ||
|
3816e64da7 | ||
|
3c1fd87fd4 | ||
|
fa3b1c5d22 | ||
|
8a4102cbd1 | ||
|
68ead2ae85 | ||
|
9b2aa63846 | ||
|
1de668a9e5 | ||
|
fb975dc52c | ||
|
158510e9fb | ||
|
316b01ea85 | ||
|
13c34a1c04 | ||
|
f401518d24 | ||
|
00baf30141 | ||
|
d4ae6255d6 | ||
|
e7c826d4c6 | ||
|
6f8a843e49 | ||
|
d1f9911fd4 | ||
|
e41487f80c | ||
|
ee5f4409af | ||
|
a4a0d240ac | ||
|
54a35a452a | ||
|
720efe4fca | ||
|
2b996da17f | ||
|
8126e6490e | ||
|
d27ebd7f19 | ||
|
b4225d3750 | ||
|
6cc01fa240 | ||
|
15b3d506ff | ||
|
1166c9155a | ||
|
534bf138cc | ||
|
0cce0f4318 | ||
|
57e750a15a | ||
|
348904c97a | ||
|
5bb4cc7179 | ||
|
ce761f6ec0 | ||
|
54c7b807c7 | ||
|
95a5ad0668 | ||
|
5ce1ea6774 | ||
|
ba8e9ebfc8 | ||
|
38a9be9a2e | ||
|
bf74a4eb20 | ||
|
9e4e6a6e53 | ||
|
209b3e4323 | ||
|
0b4b075802 | ||
|
adcb3f31a9 | ||
|
aa07d50eed | ||
|
bc37fc0e95 | ||
|
56c901eb8b | ||
|
9fa05d6e1f | ||
|
ff9bdc690e | ||
|
027ce4f45b | ||
|
9ccbcf6c1d | ||
|
bc71e3f693 | ||
|
40eed73ff7 | ||
|
49ecffb245 | ||
|
304df0fbb4 | ||
|
df57e2300e | ||
|
c237efd523 | ||
|
9a35619a0b | ||
|
9c1cb1a7e1 | ||
|
e0c53ee118 | ||
|
b3ee096e49 | ||
|
c60dfdcea3 | ||
|
08d5d9e425 | ||
|
4eeed15ecb | ||
|
bfd25ab706 | ||
|
9fd8bd8bd0 | ||
|
265e2c181b | ||
|
d034072704 | ||
|
560e828c8a | ||
|
cea6840588 | ||
|
aea5b5ecfd | ||
|
bb7817076d | ||
|
811538601f | ||
|
18e317c820 | ||
|
2d5fc6cf54 | ||
|
63fced9cff | ||
|
e5fc15acc2 | ||
|
f0c72ef1c8 | ||
|
a704eaaf60 | ||
|
47e81a4bb5 | ||
|
7145cf6f7d | ||
|
2ab2597e00 | ||
|
b10bbe7c52 | ||
|
7f60560cbe | ||
|
8195ffbeb6 | ||
|
c4c4fb70d5 | ||
|
695f334297 | ||
|
31825bfad7 | ||
|
c22f084315 | ||
|
dbb306d7ee | ||
|
e75adb3d48 | ||
|
7e9fe03235 | ||
|
578a238f2e | ||
|
f4d7a2acb9 | ||
|
e2832afacb | ||
|
215c8d2c3a | ||
|
14334e7197 | ||
|
37db4b514e | ||
|
991c79b350 | ||
|
48e956c27c | ||
|
86ae8327c3 | ||
|
ec6cda7de9 | ||
|
f0e7810342 | ||
|
d49811bc2e | ||
|
6d515f7a60 | ||
|
1ca0402660 | ||
|
b077f72e5f | ||
|
b42c0a79a1 | ||
|
0067bd36b5 | ||
|
e310ffc4e2 | ||
|
e3b8e12dfb | ||
|
c709c8e030 | ||
|
4c208d54e8 | ||
|
0fc33e30ff | ||
|
7006c7e63d | ||
|
631510f4fe | ||
|
4df69b7842 | ||
|
60f0ef0fef | ||
|
71c9337ab7 | ||
|
24d682860f | ||
|
f14239db6c | ||
|
6d2ae36f38 | ||
|
e91c9da714 | ||
|
386b64da10 | ||
|
09f6735961 | ||
|
e4df34ef29 | ||
|
2a6782f88d | ||
|
f980c26aa7 | ||
|
7e75089eaa | ||
|
6322306273 | ||
|
0d4ab54ceb | ||
|
6d4b35c5e3 | ||
|
ec4ff3158e | ||
|
292cae9822 | ||
|
921bf36a3f | ||
|
edd9bf6d3b | ||
|
e49f311192 | ||
|
22836f068e | ||
|
021954c86b | ||
|
586ce58894 | ||
|
ccc30f68d6 | ||
|
4187aba570 | ||
|
a7a5f88142 | ||
|
fbe1766aea | ||
|
0405eda30e |
@ -1,4 +1,6 @@
|
|||||||
onionr/data/**/*
|
onionr/data/**/*
|
||||||
onionr/data
|
onionr/data
|
||||||
RUN-WINDOWS.bat
|
|
||||||
MY-RUN.sh
|
MY-RUN.sh
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
.git
|
||||||
|
7
.github/stale.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 0
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 0
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: wontfix
|
||||||
|
closeComment: false
|
13
.github/workflows/greetings.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
name: Greetings
|
||||||
|
|
||||||
|
on: [pull_request, issues]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
greeting:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/first-interaction@v1
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
issue-message: 'Message that will be displayed on users'' first issue'
|
||||||
|
pr-message: 'Hi, please make the PR at https://gitlab.com/beardog/Onionr'' first pr'
|
55
.gitignore
vendored
@ -1,39 +1,44 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
onionr/data/config.ini
|
src/data/config.ini
|
||||||
onionr/data/*.db
|
src/data/*.db
|
||||||
onionr/data-old/*
|
src/data-old/*
|
||||||
onionr/data*
|
src/data*
|
||||||
onionr/tor
|
src/tor
|
||||||
onionr/tor.exe
|
src/tor.exe
|
||||||
onionr/testdata
|
src/testdata
|
||||||
onionr/*.pyc
|
src/*.pyc
|
||||||
onionr/*.log
|
src/*.log
|
||||||
onionr/data/hs/hostname
|
src/data/hs/hostname
|
||||||
onionr/data/*
|
src/data/*
|
||||||
onionr/data-backup/*
|
src/data-backup/*
|
||||||
onionr/gnupg/*
|
|
||||||
run.sh
|
run.sh
|
||||||
onionr/data-encrypted.dat
|
src/.onionr-lock
|
||||||
onionr/.onionr-lock
|
daemon-true.txt
|
||||||
core
|
.vscode/tags
|
||||||
.vscode/*
|
.vscode/settings.json
|
||||||
venv/*
|
|
||||||
onionr/fs*
|
venv*
|
||||||
onionr/tmp/*
|
src/fs*
|
||||||
|
src/tmp/*
|
||||||
testdata/*
|
testdata/*
|
||||||
*.dll
|
*.dll
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
|
.mypy_cache/
|
||||||
|
|
||||||
|
dist/*
|
||||||
|
|
||||||
# log files
|
# log files
|
||||||
output.log
|
output.log
|
||||||
*.log
|
*.log
|
||||||
onionr/output.log
|
src/output.log
|
||||||
onionr/*.log
|
src/*.log
|
||||||
onionr/data/output.log
|
src/data/output.log
|
||||||
onionr/data/*.log
|
src/data/*.log
|
||||||
|
|
||||||
# package files
|
# package files
|
||||||
onionr-*.pkg.tar.gz
|
onionr-*.pkg.tar.gz
|
||||||
pkg/
|
pkg/
|
||||||
src/
|
|
||||||
spawnnodes.py
|
spawnnodes.py
|
||||||
|
|
||||||
|
static-data/tor-node-list.dat
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
test:
|
test:
|
||||||
image: ubuntu:disco
|
image: python
|
||||||
script:
|
script:
|
||||||
- apt-get update -qy
|
- apt-get update -qy
|
||||||
- apt-get install -y python3-pip tor
|
- apt-get install -y tor
|
||||||
|
- apt-get install -y firefox-esr
|
||||||
- pip3 install --require-hashes -r requirements.txt
|
- pip3 install --require-hashes -r requirements.txt
|
||||||
|
- pip3 install --require-hashes -r requirements-dev.txt
|
||||||
|
- pip3 install --require-hashes -r requirements-notifications.txt
|
||||||
- python3 --version
|
- python3 --version
|
||||||
- make test
|
- make test
|
||||||
|
23
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Onionr: init",
|
||||||
|
"type": "python",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/src/__init__.py",
|
||||||
|
"cwd": "${workspaceFolder}/src/",
|
||||||
|
"args" : ["start"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Python: Current File",
|
||||||
|
"type": "python",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${file}",
|
||||||
|
"cwd": "${workspaceFolder}/src/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
58
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Make new test",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "cp tests/test_template.py tests/new-test.py",
|
||||||
|
"group": "test",
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "new"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run tests",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "source venv/bin/activate; make test",
|
||||||
|
"group": "test",
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "new"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Run test by name",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "source venv/bin/activate; scripts/run-unit-test-by-name.py",
|
||||||
|
"group": "test",
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "new"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Enable dev config",
|
||||||
|
"type": "process",
|
||||||
|
"command": "scripts/enable-dev-config.py",
|
||||||
|
"group": "dev",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Disable dev config",
|
||||||
|
"type": "process",
|
||||||
|
"command": "scripts/disable-dev-config.py",
|
||||||
|
"group": "dev",
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Format default config",
|
||||||
|
"type": "process",
|
||||||
|
"command": "scripts/pretty-default-config.py",
|
||||||
|
"group": "dev",
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
12
AUTHORS.MD
@ -1,12 +0,0 @@
|
|||||||
# Incomplete List of Contributors
|
|
||||||
|
|
||||||
Onionr is created by a team of hard working volunteers.
|
|
||||||
|
|
||||||
In no order of importance, these people make Onionr happen:
|
|
||||||
|
|
||||||
* [Beardog (Kevin Froman)](https://www.chaoswebs.net/) - Project founder, owner and core developer
|
|
||||||
* [InvisaMage](https://invisamage.com/) - Web UI Bulma design
|
|
||||||
* [Arinerron](https://arinerron.com/) - Logger and config modules, testing and other contributions
|
|
||||||
* [Anhar Ismail](https://github.com/anharismail) - Created Onionr's logo
|
|
||||||
|
|
||||||
+ Other contributors and testers
|
|
48
CHANGELOG.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [8.0.1] - 2020-12-22
|
||||||
|
|
||||||
|
* Fix subprocess in 3.9x with dumb hack
|
||||||
|
* Dependency bumps
|
||||||
|
|
||||||
|
## [8.0.0] - 2020-12-04
|
||||||
|
|
||||||
|
* Decrease PoW until better implementation is made
|
||||||
|
|
||||||
|
|
||||||
|
## [7.2.0] - 2020-12-03
|
||||||
|
|
||||||
|
* Purge blocks not meeting current pow on startup
|
||||||
|
* Check block POW before LAN sync
|
||||||
|
* WSL fixes
|
||||||
|
|
||||||
|
## [7.1.0] - 2020-11-23
|
||||||
|
|
||||||
|
* Check for ownership of existing dirs in createdirs, this prevents the rare edge case where a user might use a home directory in a location an attacker could write (allowing arbitrary code execution via plugins). This was already partially mitigated by the chmod of the home directory in any case, but this further fixes the issue.
|
||||||
|
|
||||||
|
## [7.0.0] - 2020-11-22
|
||||||
|
|
||||||
|
* Removed communicator timers
|
||||||
|
* Removed direct connections and chat (these will be either plugins or separate programs/processes in the future)
|
||||||
|
|
||||||
|
|
||||||
|
## [5.1.0] - 2020-09-07
|
||||||
|
|
||||||
|
* Moved plugin web files to be in the plugin folder to reduce staticfiles blueprint coupling
|
||||||
|
* Added basic sidebar on index page
|
||||||
|
* Many bug fixes
|
||||||
|
|
||||||
|
|
||||||
|
## [5.0.1] - 2020-08-08
|
||||||
|
|
||||||
|
* bumped deadsimplekv to 0.3.2
|
||||||
|
* bumped urllib3 to 1.25.10
|
||||||
|
|
||||||
|
## [5.0.0] - 2020-07-23
|
||||||
|
|
||||||
|
- Removed single-process POW support (was only needed on Windows)
|
35
Dockerfile
@ -1,28 +1,31 @@
|
|||||||
FROM ubuntu:disco
|
FROM python:3.10
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
#Base settings
|
USER root
|
||||||
ENV HOME /root
|
|
||||||
|
RUN mkdir /app
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV ONIONR_DOCKER=true
|
||||||
|
|
||||||
#Install needed packages
|
#Install needed packages
|
||||||
RUN apt update && apt install -y python3 python3-dev python3-pip tor locales nano sqlite3
|
RUN apt-get update && apt-get install -y tor locales
|
||||||
|
|
||||||
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
|
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
|
||||||
locale-gen
|
locale-gen
|
||||||
ENV LANG en_US.UTF-8
|
ENV LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8
|
||||||
ENV LANGUAGE en_US:en
|
|
||||||
ENV LC_ALL en_US.UTF-8
|
|
||||||
|
|
||||||
WORKDIR /srv/
|
ADD ./requirements-x86-all-plugins.txt /app/requirements.txt
|
||||||
ADD ./requirements.txt /srv/requirements.txt
|
|
||||||
RUN pip3 install --require-hashes -r requirements.txt
|
RUN pip3 install --require-hashes -r requirements.txt
|
||||||
|
|
||||||
WORKDIR /root/
|
|
||||||
#Add Onionr source
|
#Add Onionr source
|
||||||
COPY . /root/
|
COPY . /app/
|
||||||
VOLUME /root/data/
|
|
||||||
|
|
||||||
#Set upstart command
|
VOLUME /app/data/
|
||||||
CMD bash
|
|
||||||
|
|
||||||
#Expose ports
|
#Default to running as nonprivileged user
|
||||||
EXPOSE 8080
|
RUN chmod g=u -R /app
|
||||||
|
USER 1000
|
||||||
|
ENV HOME=/app
|
||||||
|
|
||||||
|
CMD ["bash", "./onionr.sh", "start"]
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
# Steps to Reproduce
|
# Steps to Reproduce
|
||||||
|
|
||||||
# Version Information
|
# Version Information
|
||||||
Onionr:
|
|
||||||
OS:
|
* Onionr:
|
||||||
Python:
|
* OS:
|
||||||
Tor:
|
* Python:
|
||||||
I2P:
|
* Tor:
|
||||||
|
* CPU:
|
||||||
|
2
Makefile
@ -30,7 +30,7 @@ soft-reset:
|
|||||||
|
|
||||||
reset:
|
reset:
|
||||||
@echo "Hard-resetting Onionr..."
|
@echo "Hard-resetting Onionr..."
|
||||||
rm -rf onionr/$(ONIONR_HOME)/ | true > /dev/null 2>&1
|
rm -rf $(ONIONR_HOME)/ | true > /dev/null 2>&1
|
||||||
cd onionr/static-data/www/ui/; rm -rf ./dist; python compile.py
|
cd onionr/static-data/www/ui/; rm -rf ./dist; python compile.py
|
||||||
#@./onionr.sh version | grep -v "Failed" --color=always
|
#@./onionr.sh version | grep -v "Failed" --color=always
|
||||||
|
|
||||||
|
133
README.md
@ -5,107 +5,107 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Private P2P Communication Network 📡
|
Privacy Respecting Communication Network 📡
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
WIP anonymous social platform, mail, file sharing and marketplace
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<img src='https://img.shields.io/github/license/beardog108/onionr'> <img src='https://gitlab.com/beardog/Onionr/badges/master/build.svg'> <img src='https://img.shields.io/badge/docker%20%F0%9F%90%8B-supported-success'> <img src='https://img.shields.io/badge/python%20version%20%F0%9F%90%8D-3.6+-blue'> <img src='https://img.shields.io/github/commit-activity/m/beardog108/onionr'>
|
<img src="https://img.shields.io/badge/License-aGPLv3-yellow"> <img src='https://img.shields.io/badge/python%20version%20%F0%9F%90%8D-3.10+-blue'>
|
||||||
|
|
||||||
<img src='https://onionr.net/block-count.svg' alt='current stored block count'>
|
<a href='https://twitter.com/onionrnet'><img src='https://img.shields.io/twitter/follow/onionrnet?style=social'></a> - [Discord](https://discord.gg/DVF2bEAzrt) - Matrix: #onionr:amorgan.xyz
|
||||||
|
|
||||||
<a href='https://www.reddit.com/r/onionr'><img src = 'https://img.shields.io/reddit/subreddit-subscribers/onionr?style=social'></a> <a href='https://twitter.com/onionrnet'><img src='https://img.shields.io/twitter/follow/onionrnet?style=social'></a>
|
|
||||||
|
|
||||||
| | | |
|
| | | |
|
||||||
| ----------- | ----------- | ----------- |
|
| ----------- | ----------- | ----------- |
|
||||||
| [Install](#install-and-run-on-linux) | [Features](#main-features) | [Screenshots](#screenshots)|
|
| [Install](#install-and-run-on-linux) | [Features](#main-features) | [Screenshots](#screenshots)|
|
||||||
| [Docs](#documentation) | [Get involved](#help-out) | [Onionr.net](https://onionr.net/)/[.onion](http://onionr.onionkvc5ibm37bmxwr56bdxcdnb6w3wm4bdghh5qo6f6za7gn7styid.onion/) |
|
| [Docs](#documentation) | [Get involved](#help-out) | [Onionr.net](https://onionr.net/)/[.onion](http://onionrbak72t5zhbzuey2fdkpczlvhowgcpqc6uoyrd3uxztzxwz5cyd.onion/) |
|
||||||
|
|
||||||
|
|
||||||
<hr>
|
---
|
||||||
|
|
||||||
**The main repository for this software is at https://GitLab.com/beardog/Onionr/**
|
**The main repository for this software is at https://gitlab.com/beardog/onionr/**
|
||||||
|
|
||||||
**The [GitHub repository](https://github.com/beardog108/onionr/) is a mirror, do not submit PRs or issues there.**
|
***Note that this README reflects the state of the rewrite, and not the original alpha network***
|
||||||
|
|
||||||
# About
|
Mirrors [Gitea](https://git.voidnet.tech/kev/onionr)
|
||||||
|
|
||||||
Onionr ("Onion Relay") is a decentralized, peer-to-peer communication network, designed to be anonymous and resistant to (meta)data analysis, spam, and corruption.
|
|
||||||
|
|
||||||
Onionr stores data in independent packages referred to as 'blocks'. The blocks are synced to all other nodes in the network. Blocks and user IDs cannot be easily proven to have been created by a particular user. Even if there is enough evidence to believe that a specific user created a block, nodes still operate behind Tor or I2P and as such cannot be trivially unmasked.
|
Onionr ("Onion Relay") is a decentralized/distributed peer-to-peer communication network, designed to be anonymous and resistant to (meta)data analysis, spam, and corruption.
|
||||||
|
|
||||||
|
Onionr gives the individual the ability to speak freely, without fear of surveillance and censorship.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Onionr internals
|
||||||
|
|
||||||
|
## Blocks
|
||||||
|
|
||||||
|
At the core, Onionr is an anonymous Distributed Hash Table (DHT) syncing prepackaged blocks using a simple Gossip protocol with Dandelion++ as an overlay network on top of Tor and I2P.
|
||||||
|
|
||||||
|
Onionr stores data in independent packages referred to as 'blocks'. The blocks are distributed to all nodes, but are not required to be stored. Blocks and user IDs cannot be easily proven to have been created by a particular user. Even if Dandelion++ is defeated and there is enough evidence to believe that a specific node is linked to a block's creation, nodes still operate behind Tor or I2P and as such cannot be trivially unmasked. Anonymity is achieved by a stateless network, with no given indication of what node a block originates from. In fact, since one is not required to participate in routing or storage to insert a message, blocks often do not originate from any identifiable node, similar to how Bitcoin transactions do not necessarily originate from a wallet directly associated with a node.
|
||||||
|
|
||||||
|
## Onionr Gossip
|
||||||
|
|
||||||
|
Onionr works via epidemic/gossip style routing, with message delivery taking roughly log<sub>C</sub>(N) cycles where C is the number of nodes to send a message to each cycle and N is the number of connected nodes. So a network of 100 million nodes can deliver messages in a few minutes even with high packet loss and malfunctioning nodes.
|
||||||
|
|
||||||
|
Through Dandelion++ message forwarding and key privacy, it is intended to be nigh impossible to discover the identity of a message creator or recipient. Via long-term traffic analysis, a well funded adversary may discover the most probable node(s) to be creating a set of related blocks, however doing so would only lead them to a node behind Tor. As the first node that a block appears on is almost always not the creator of the block, there is plausible deniability regarding the true creator of the block.
|
||||||
|
|
||||||
Users are identified by ed25519/curve25519 public keys, which can be used to sign blocks or send encrypted data.
|
Users are identified by ed25519/curve25519 public keys, which can be used to sign blocks or send encrypted data.
|
||||||
|
|
||||||
Onionr can be used for mail, as a social network, instant messenger, file sharing software, or for encrypted group discussion.
|
Onionr can be used for mail, as a social network, instant messenger, file sharing software, or for encrypted group discussion.
|
||||||
|
|
||||||
The whitepaper (subject to change prior to alpha release) is available [here](docs/whitepaper.md).
|
Since Onionr is technically just a data format, any routing scheme can technically be used to pass messages.
|
||||||
|
|
||||||
![Tor stinks slide image](docs/tor-stinks-02.png)
|
The whitepaper is available [here](docs/whitepaper.md).
|
||||||
|
|
||||||
## Main Features
|
---
|
||||||
|
|
||||||
|
# Main Features
|
||||||
|
|
||||||
* [X] 🌐 Fully p2p/decentralized, no trackers or other single points of failure
|
* [X] 🌐 Fully p2p/decentralized, no trackers or other single points of failure
|
||||||
* [X] 🔒 End to end encryption of user data
|
|
||||||
* [X] 📢 Optional non-encrypted blocks, useful for blog posts or public file sharing
|
|
||||||
* [X] 💻 Easy HTTP API for integration to websites
|
|
||||||
* [X] 🕵️ Metadata analysis resistance and anonymity
|
* [X] 🕵️ Metadata analysis resistance and anonymity
|
||||||
* [X] 📡 Transport agnosticism (no internet required)
|
* [X] 📡 Transport agnosticism (no internet required)
|
||||||
|
|
||||||
Onionr ships with various application plugins ready for use out of the box:
|
|
||||||
|
|
||||||
Currently usable:
|
# Roadmap
|
||||||
|
|
||||||
* Mail
|
See [ROADMAP.md](ROADMAP.md)
|
||||||
* Public anonymous chat/message board
|
|
||||||
* Simple webpage hosting - Will be greatly extended
|
|
||||||
* File sharing (Work in progress)
|
|
||||||
|
|
||||||
Not yet usable:
|
|
||||||
|
|
||||||
* Instant messaging
|
|
||||||
|
|
||||||
**Onionr API and functionality is subject to non-backwards compatible change during pre-alpha development**
|
|
||||||
|
|
||||||
# Screenshots
|
|
||||||
|
|
||||||
<img alt='Node statistics page screenshot' src='docs/onionr-1.png' width=600>
|
|
||||||
|
|
||||||
Home screen
|
|
||||||
|
|
||||||
<img alt='Friend/contact manager screenshot' src='docs/onionr-2.png' width=600>
|
|
||||||
|
|
||||||
Friend/contact manager
|
|
||||||
|
|
||||||
<img alt='Encrypted, metadata-masking mail application screenshot' src='docs/onionr-3.png' width=600>
|
|
||||||
|
|
||||||
Encrypted, metadata-masking mail application. One of the first distributed mail systems to have basic forward secrecy.
|
|
||||||
|
|
||||||
# Documentation
|
# Documentation
|
||||||
|
|
||||||
More docs coming soon.
|
More docs coming soon.
|
||||||
|
|
||||||
* [Block specification](docs/specs/block-spec.md)
|
|
||||||
* [HTTP API](docs/http-api.md)
|
|
||||||
|
|
||||||
# Install and Run on Linux
|
# Install and Run on Linux
|
||||||
|
|
||||||
The following applies to Ubuntu Bionic. Other distros may have different package or command names.
|
The following applies to Ubuntu Bionic. Other distributions may have different package or command names.
|
||||||
|
|
||||||
|
Master may be unstable, you should use the latest release tag. (checkout via git: `$ git checkout release-latest`)
|
||||||
|
|
||||||
`$ sudo apt install python3-pip python3-dev tor`
|
`$ sudo apt install python3-pip python3-dev tor`
|
||||||
|
|
||||||
* Have python3.6+, python3-pip, Tor (daemon, not browser) installed. python3-dev is recommended.
|
* Have python3.10, python3-pip, Tor (daemon, not browser) installed. python3-dev is recommended.
|
||||||
* Clone the git repo: `$ git clone https://gitlab.com/beardog/onionr`
|
* You may need build-essentials or the equivalent of your platform
|
||||||
|
* Clone the git repo: `$ git clone https://gitlab.com/beardog/onionr --tags`
|
||||||
* cd into install direction: `$ cd onionr/`
|
* cd into install direction: `$ cd onionr/`
|
||||||
* Install the Python dependencies ([virtualenv strongly recommended](https://virtualenv.pypa.io/en/stable/userguide/)): `$ pip3 install --require-hashes -r requirements.txt`
|
* Install the Python dependencies ([virtualenv strongly recommended](https://virtualenv.pypa.io/en/stable/userguide/)): `$ pip3 install --require-hashes -r requirements-x86-all-plugins.txt`
|
||||||
* (Optional): Install desktop notification dependencies: `$ pip3 install --require-hashes -r requirements-notifications.txt`
|
|
||||||
|
|
||||||
(--require-hashes is intended to prevent exploitation via compromise of PyPi/CA certificates)
|
Require-hashes is suggested for supply-chain security but is optional. The hashes are not correct for ARM machines. If you are just running a node or want a bare-bones install you can use requirements-base-x86.txt and selectively install the requirements.txt files in static-data/official-plugins/ subdirectories
|
||||||
|
|
||||||
## Run Onionr
|
## Run Onionr
|
||||||
|
|
||||||
* Run Onionr normally: `$ ./onionr.sh start`
|
* Run Onionr normally: `$ ./onionr.sh start`
|
||||||
* Run Onionr in background as daemon: `$ ./start-daemon.sh`
|
* Run Onionr in background as daemon: `$ ./start-daemon.sh`
|
||||||
* Open Onionr web interface `$ ./onionr.sh openhome`
|
|
||||||
* Gracefully stop Onionr from CLI `$ ./onionr.sh stop`
|
* Gracefully stop Onionr from CLI `$ ./onionr.sh stop`
|
||||||
|
|
||||||
|
|
||||||
|
# Contact/Community
|
||||||
|
|
||||||
|
* Email: onionr [ at ] voidnet.tech
|
||||||
|
* Twitter: [@onionrnet](https://twitter.com/onionrnet)
|
||||||
|
* Matrix: #onionr:amorgan.xyz
|
||||||
|
* Discord: https://discord.gg/DVF2bEAzrt (Discord is bad for freedom and privacy, this is only provided for convenience)
|
||||||
|
|
||||||
# Help out
|
# Help out
|
||||||
|
|
||||||
Everyone is welcome to contribute. Help is wanted for the following:
|
Everyone is welcome to contribute. Help is wanted for the following:
|
||||||
@ -113,36 +113,41 @@ Everyone is welcome to contribute. Help is wanted for the following:
|
|||||||
* Development (Get in touch first)
|
* Development (Get in touch first)
|
||||||
* Creation of a shared lib for use from other languages and faster proof-of-work
|
* Creation of a shared lib for use from other languages and faster proof-of-work
|
||||||
* Android and IOS development
|
* Android and IOS development
|
||||||
* Windows and Mac support (already partially supported, testers needed)
|
* Mac support (testers needed)
|
||||||
* Bug fixes and development of new features
|
* Bug fixes and development of new features
|
||||||
* Testing
|
* Testing
|
||||||
* Translations/localizations
|
* Translations/localizations
|
||||||
* UI/UX design
|
* UI/UX design
|
||||||
* Running stable nodes
|
* Running stable nodes
|
||||||
* Security review/audit
|
* Security review/audit
|
||||||
* Automatic I2P setup
|
* I2P support
|
||||||
|
|
||||||
|
## Watch the talk from BSidesPDX 2019
|
||||||
|
|
||||||
|
<a href="https://www.youtube.com/watch?v=mrULtmSkKxg">
|
||||||
|
<img src="docs/talk.png" alt="improving anonymous networking talk link" width="600">
|
||||||
|
</a>
|
||||||
|
|
||||||
## Contribute money:
|
## Contribute money:
|
||||||
|
|
||||||
Donating at least $5 gets you cool Onionr stickers. Get in touch if you want them.
|
Donating at least $3 gets you cool Onionr stickers. Get in touch if you want them.
|
||||||
|
|
||||||
Bitcoin: [1onion55FXzm6h8KQw3zFw2igpHcV7LPq](bitcoin:1onion55FXzm6h8KQw3zFw2igpHcV7LPq) (Contact us for a unique address or for other coins)
|
![sticker](docs/sticker.png)
|
||||||
|
|
||||||
Monero: 4B5BA24d1P3R5aWEpkGY5TP7buJJcn2aSGBVRQCHhpiahxeB4aWsu15XwmuTjC6VF62NApZeJGTS248RMVECP8aW73Uj2ax
|
|
||||||
|
|
||||||
USD (Card/Paypal): [Ko-Fi](https://www.ko-fi.com/beardogkf)
|
* Bitcoin: [bc1qpayme9rlpkch0qp3r79lvm5racr7t6llauwfmg](bitcoin:bc1qpayme9rlpkch0qp3r79lvm5racr7t6llauwfmg) (Contact us for a unique address or for other coins)
|
||||||
|
|
||||||
Note: probably not tax deductible
|
* Monero: 4B5BA24d1P3R5aWEpkGY5TP7buJJcn2aSGBVRQCHhpiahxeB4aWsu15XwmuTjC6VF62NApZeJGTS248RMVECP8aW73Uj2ax
|
||||||
|
|
||||||
# Contact
|
* USD (Card/Paypal (no account required)): [Ko-Fi](https://www.ko-fi.com/beardogkf)
|
||||||
|
|
||||||
Email: beardog [ at ] mailbox.org
|
* Sign up for [privacy.com (refferal link)](https://privacy.com/join/FNNDF) to protect your personal information when contributing or shopping elsewhere, we both get $5 USD.
|
||||||
|
|
||||||
Onionr Mail: TRH763JURNY47QPBTTQ4LLPYCYQK6Q5YA33R6GANKZK5C5DKCIGQ
|
Note: not tax deductible
|
||||||
|
|
||||||
# Security
|
# Security
|
||||||
|
|
||||||
Onionr is pre-alpha. This means it is unstable, probably insecure, and experimental.
|
Onionr is alpha software. This means it is unstable, probably insecure, and experimental.
|
||||||
|
|
||||||
No matter how good Onionr and other software gets, there will always be ways for clever or well-funded adversaries to break your security.
|
No matter how good Onionr and other software gets, there will always be ways for clever or well-funded adversaries to break your security.
|
||||||
|
|
||||||
|
46
ROADMAP.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# Onionr Roadmap
|
||||||
|
|
||||||
|
|
||||||
|
## Taraxacum Release (9.0)
|
||||||
|
|
||||||
|
|
||||||
|
* [ X ] Implement new block format with verifiable delay function
|
||||||
|
|
||||||
|
* [ X ] Implement overhauled gossip system with dandelion++
|
||||||
|
|
||||||
|
The new system is separated from the underlying networks used and makes it much easier to implement new transport methods. Dandelion++ is also better than the old block mixing we did.
|
||||||
|
|
||||||
|
|
||||||
|
## Misc
|
||||||
|
|
||||||
|
* [ ] Spruce up documentation
|
||||||
|
* [ ] Restore LAN transport
|
||||||
|
* [ ] Restore webUI as a plugin
|
||||||
|
* [ ] Restore static site/file sharing plugin
|
||||||
|
* [ ] Restore/reimplement mail plugin
|
||||||
|
* [ ] Restore/reimplement friends plugin
|
||||||
|
* [ ] Refresh test suite
|
||||||
|
* [ ] Revamped key/encrypted messaging (encrypted blocks)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Web of trust release (~10.0)
|
||||||
|
|
||||||
|
To facilitate the below market plugin/application, Onionr will need a web of trust system.
|
||||||
|
|
||||||
|
* [ ] Web of trust plugin or module
|
||||||
|
|
||||||
|
|
||||||
|
## Market Plugin Release (~10.1)
|
||||||
|
|
||||||
|
The Onionr team believes the Monero community is currently lacking a good p2p market, and as such we hope to build a solution using Onionr as a transport. This may be a separate project and as opposed to a plugin.
|
||||||
|
|
||||||
|
|
||||||
|
* A new marketplace plugin will be developed with the following *tenative* features:
|
||||||
|
|
||||||
|
* [ ] Account management
|
||||||
|
* [ ] Monero management
|
||||||
|
* [ ] Store front discovery and search
|
||||||
|
* [ ] Product listing search
|
||||||
|
* [ ] User reviews
|
||||||
|
|
8
base-requirements.in
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
PyNaCl==1.5.0
|
||||||
|
psutil==5.9.1
|
||||||
|
filenuke==0.0.0
|
||||||
|
ujson==5.4.0
|
||||||
|
cffi==1.15.1
|
||||||
|
onionrblocks==7.0.0
|
||||||
|
ordered-set==4.1.0
|
||||||
|
json-rpc==1.13.0
|
@ -1,4 +1,6 @@
|
|||||||
# Onionr Documentation
|
<img src="onionr-logo.png" width="200px">
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
The Onionr [whitepaper](whitepaper.md) is the best place to start both for users and developers.
|
The Onionr [whitepaper](whitepaper.md) is the best place to start both for users and developers.
|
||||||
|
|
||||||
@ -16,4 +18,4 @@ The Onionr [whitepaper](whitepaper.md) is the best place to start both for users
|
|||||||
* [Technical overview](dev/overview.md)
|
* [Technical overview](dev/overview.md)
|
||||||
* [Project layout](dev/layout.md)
|
* [Project layout](dev/layout.md)
|
||||||
* [Plugin development guide](dev/plugins.md)
|
* [Plugin development guide](dev/plugins.md)
|
||||||
* [Testing](dev/testing.md)
|
* [Auto generated API docs (HTML)](html/onionr/index.html)
|
BIN
docs/basic-onionr-user-guide.pdf
Normal file
9
docs/dev/daemon-events.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# DaemonEvents
|
||||||
|
|
||||||
|
For things that need to be processed by the daemon
|
||||||
|
|
||||||
|
Observer pattern
|
||||||
|
|
||||||
|
Register listeners dynamically per event
|
||||||
|
|
||||||
|
Spawn new greenlets
|
4
docs/dev/error-codes.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Exit codes
|
||||||
|
|
||||||
|
10: run with no command
|
||||||
|
3: command does not exist
|
19
docs/dev/generating-requirements.txt.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Generating requirements.txt
|
||||||
|
|
||||||
|
To generate a requirements.txt file, install pip-tools from pip
|
||||||
|
|
||||||
|
Onionr requirements files should have hashes to prevent backdooring by the pypi server.
|
||||||
|
|
||||||
|
Put your package versions in requirements.in like normal. Child dependencies are usually not necessary:
|
||||||
|
|
||||||
|
```
|
||||||
|
requests==0.1.1
|
||||||
|
flask==0.1.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Then generate the requirements.txt:
|
||||||
|
|
||||||
|
`$ pip-compile requirements.in --generate-hashes -o requirements.txt`
|
||||||
|
|
||||||
|
|
||||||
|
Your requirements.txt will have hash-pinned requirements of all dependencies and child dependencies.
|
@ -1,118 +0,0 @@
|
|||||||
# Onionr HTTP API
|
|
||||||
|
|
||||||
All HTTP interfaces in the Onionr reference client use the [Flask](http://flask.pocoo.org/) web framework with the [gevent](http://www.gevent.org/) WSGI server.
|
|
||||||
|
|
||||||
## Client & Public difference
|
|
||||||
|
|
||||||
The client API server is a locked down interface intended for authenticated local communication.
|
|
||||||
|
|
||||||
The public API server is available only remotely from Tor & I2P. It is the interface in which peers use to communicate with one another.
|
|
||||||
|
|
||||||
# Client API
|
|
||||||
|
|
||||||
Please note: endpoints that simply provide static web app files are not documented here.
|
|
||||||
|
|
||||||
* /serviceactive/pubkey
|
|
||||||
- Methods: GET
|
|
||||||
- Returns true or false based on if a given public key has an active direct connection service.
|
|
||||||
* /queueResponseAdd/key (DEPRECATED)
|
|
||||||
- Methods: POST
|
|
||||||
- Accepts form key 'data' to set queue response information from a plugin
|
|
||||||
- Returns success if no error occurs
|
|
||||||
* /queueResponse/key (DEPRECATED)
|
|
||||||
- Methods: GET
|
|
||||||
- Returns the queue response for a key. Returns failure with a 404 code if a code is not set.
|
|
||||||
* /ping
|
|
||||||
- Methods: GET
|
|
||||||
- Returns "pong!"
|
|
||||||
* /getblocksbytype/type
|
|
||||||
- Methods: GET
|
|
||||||
- Returns a list of stored blocks by a given type
|
|
||||||
* /getblockbody/hash
|
|
||||||
- Methods: GET
|
|
||||||
- Returns the main data section of a block
|
|
||||||
* /getblockdata/hash
|
|
||||||
- Methods: GET
|
|
||||||
- Returns the entire data contents of a block, including metadata.
|
|
||||||
* /getblockheader/hash
|
|
||||||
- Methods: GET
|
|
||||||
- Returns the header (metadata section) of a block.
|
|
||||||
* /hitcount
|
|
||||||
- Methods: GET
|
|
||||||
- Return the amount of requests the public api server has received this session
|
|
||||||
* /lastconnect
|
|
||||||
- Methods: GET
|
|
||||||
- Returns the epoch timestamp of when the last incoming connection to the public API server was logged
|
|
||||||
* /site/hash
|
|
||||||
- Methods: GET
|
|
||||||
- Returns HTML content out of a block
|
|
||||||
* /waitforshare/hash
|
|
||||||
- Methods: POST
|
|
||||||
- Prevents the public API server from listing or sharing a block until it has been uploaded to at least 1 peer.
|
|
||||||
* /shutdown
|
|
||||||
- Methods: GET
|
|
||||||
- Shutdown Onionr. You should probably use /shutdownclean instead.
|
|
||||||
* /shutdownclean
|
|
||||||
- Methods: GET
|
|
||||||
- Tells the communicator daemon to shutdown Onionr. Slower but cleaner.
|
|
||||||
* /getstats
|
|
||||||
- Methods: GET
|
|
||||||
- Returns some JSON serialized statistics
|
|
||||||
* /getuptime
|
|
||||||
- Methods: GET
|
|
||||||
- Returns uptime in seconds
|
|
||||||
* /getActivePubkey
|
|
||||||
- Methods: GET
|
|
||||||
- Returns the current active public key in base32 format
|
|
||||||
* /getHumanReadable/pubkey
|
|
||||||
- Methods: GET
|
|
||||||
- Echos the specified public key in mnemonic format
|
|
||||||
* /insertblock
|
|
||||||
- Methods: POST
|
|
||||||
- Accepts JSON data for creating a new block. 'message' contains the block data, 'to' specifies the peer's public key to encrypt the data to, 'sign' is a boolean for signing the message.
|
|
||||||
|
|
||||||
# Public API
|
|
||||||
|
|
||||||
v0
|
|
||||||
|
|
||||||
* /
|
|
||||||
- Methods: GET
|
|
||||||
- Returns a basic HTML informational banner describing Onionr.
|
|
||||||
* /getblocklist
|
|
||||||
- Methods: GET
|
|
||||||
- URI Parameters:
|
|
||||||
- date: unix epoch timestamp for offset
|
|
||||||
- Returns a list of block hashes stored on the node since an offset (all blocks if no timestamp is specified)
|
|
||||||
* /getdata/block-hash
|
|
||||||
- Methods: GET
|
|
||||||
- Returns data for a block based on a provided hash
|
|
||||||
* /www/file-path
|
|
||||||
- Methods: GET
|
|
||||||
- Returns file data. Intended for manually sharing file data directly from an Onionr node.
|
|
||||||
* /ping
|
|
||||||
- Methods: GET
|
|
||||||
- Returns 'pong!'
|
|
||||||
* /pex
|
|
||||||
- Methods: GET
|
|
||||||
- Returns a list of peer addresses reached within recent time
|
|
||||||
* /announce
|
|
||||||
- Methods: POST
|
|
||||||
- Accepts form data for 'node' (valid node address) and 'random' which is a nonce when hashed (blake2b_256) in the format `hash(peerAddress+serverAddress+nonce)`, begins with at least 5 zeros.
|
|
||||||
- Returns 200 with 'Success' if no error occurs. If the post is invalid, 'failure' with code 406 is returned.
|
|
||||||
* /upload
|
|
||||||
- Methods: POST
|
|
||||||
- Accepts form data for 'block' as a 'file' upload.
|
|
||||||
- Returns 200 with 'success' if no error occurs. If the block cannot be accepted, 'failure' with 400 is returned.
|
|
||||||
|
|
||||||
# Direct Connection API
|
|
||||||
|
|
||||||
These are constant endpoints available on direct connection servers. Plugin endpoints for direct connections are not documented here.
|
|
||||||
|
|
||||||
* /ping
|
|
||||||
- Methods: GET
|
|
||||||
- Returns 200 with 'pong!'
|
|
||||||
|
|
||||||
* /close
|
|
||||||
- Methods: GET
|
|
||||||
- Kills the direct connection server, destroying the onion address.
|
|
||||||
- Returns 200 with 'goodbye'
|
|
44
docs/dev/running-tests.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Running Onionr tests
|
||||||
|
|
||||||
|
Onionr has four types of tests:
|
||||||
|
|
||||||
|
* unittests
|
||||||
|
* integration tests
|
||||||
|
* selenium tests (web tests)
|
||||||
|
* runtime-tests
|
||||||
|
|
||||||
|
|
||||||
|
## unittests
|
||||||
|
|
||||||
|
Onionr uses Python's built in unittest module. These tests are located in tests/ (top level)
|
||||||
|
|
||||||
|
Run all tests with `$ make test`, which will also run integration tests.
|
||||||
|
|
||||||
|
Please note that one unittest tests if runtime-tests have passed recently. This is simply a forceful reminder to run those tests as well.
|
||||||
|
|
||||||
|
You can also run a single unittest in a loop by using the script scripts/run-unit-test-by-name.py
|
||||||
|
|
||||||
|
## integration tests
|
||||||
|
|
||||||
|
These tests are pretty basic and test on stdout of Onionr commands.
|
||||||
|
|
||||||
|
They are also run from `$ make test`
|
||||||
|
|
||||||
|
The runtime-tests do most of the actual integration testing.
|
||||||
|
|
||||||
|
## selenium tests
|
||||||
|
|
||||||
|
These are browser automation tests to test if the UI is working as how it should for a user.
|
||||||
|
|
||||||
|
There's only a couple and they're incomplete, so they can be ignored for now (test manually)
|
||||||
|
|
||||||
|
## runtime-tests
|
||||||
|
|
||||||
|
These are important. They look into the Onionr client Flask app when Onionr daemon is running and test a bunch of things.
|
||||||
|
|
||||||
|
If you do it a lot you should make your own Onionr network (disable official bootstrap)
|
||||||
|
|
||||||
|
You run this while the daemon is running (probably should make sure onboarding is done), with `$ onionr.sh runtime-test`
|
||||||
|
|
||||||
|
It's necessary to do this before running `$ make test` for unittesting
|
||||||
|
|
43
docs/dev/security-mechanisms.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Onionr Security Mechanisms
|
||||||
|
|
||||||
|
|
||||||
|
## bigbrother 👁️
|
||||||
|
|
||||||
|
Bigbrother is a cheeky module that uses Python3.8+ sys auditing events to log and/or block certain sensitive events.
|
||||||
|
|
||||||
|
It has a little overhead, so one can disable it in config in general.security_auditing
|
||||||
|
|
||||||
|
[ChaosWebs.net/blog/preventing-arbitrary-code-execution-in-python38-with-auditing.html](https://chaoswebs.net/blog/preventing-arbitrary-code-execution-in-python38-with-auditing.html)
|
||||||
|
|
||||||
|
### Threat model
|
||||||
|
|
||||||
|
It is intended to log bugs leaking private file system information, block+log network leaks, and block+log eval-like arbitrary code execution. It is not intended to block malicious browser scripts or malicious Python plugins. It cannot work with subprocesses that do not activate the module.
|
||||||
|
|
||||||
|
It's not intended to be bulletproof by any means, but it helps.
|
||||||
|
|
||||||
|
### What big brother does
|
||||||
|
|
||||||
|
* Disk access checks for disk access outside. Only logs, does not block
|
||||||
|
* Network leaks. (Non Tor/LAN) Blocks and logs
|
||||||
|
* Arbitrary code execution: logs and blocks non-whitelisted bytecode importing/compiling and subprocesses.
|
||||||
|
|
||||||
|
|
||||||
|
## Sybil attacks
|
||||||
|
|
||||||
|
As with any decentralized network, sybil nodes could collude to spy or cause mayhem. Due to the gossip nature of Onionr, sybil nodes would have a hard time fully stopping the network. In terms of spying, they could not conclusively prove the origin of messages due to the multiple transport nature of the network and layering behind Tor/etc.
|
||||||
|
|
||||||
|
## Tor configuration
|
||||||
|
|
||||||
|
When managed by Onionr, Tor has a control port password that gets stored in Onionr config.
|
||||||
|
|
||||||
|
Tor is also configured to reject requests to non-onion services, which helps to stop redirect based denial of service attacks.
|
||||||
|
|
||||||
|
## Web security
|
||||||
|
|
||||||
|
Onionr secures both it's main web APIs with anti-dns-rebinding logic, which validates the host header used in connections to it. This is to prevent exfiltration of data and side channel deanonymization.
|
||||||
|
|
||||||
|
Onionr secures the client API with a token that must be passed in most requests, with the exception of static API files. This is to prevent CSRF and side channel deanonymization.
|
||||||
|
|
||||||
|
Onionr binds most services to random loopback addresses to reduce all cross-site web attacks, including discovery of Onionr on a computer from a normal website. This is not supported on Mac because Mac does not support non 'typical' loopback addresses.
|
||||||
|
|
||||||
|
Onionr has a strict content-security-policy, rejecting all non-localhost requests and denying inline scripts and similar insecure sources.
|
9
docs/dev/selected-papers.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Interesting papers related to Onionr development
|
||||||
|
|
||||||
|
A paper being listed here is not end-all-be-all endorsement of every detail inside.
|
||||||
|
|
||||||
|
* [Epidemic Routing for Partially-Connected Ad Hoc Networks](https://web.archive.org/web/20200208074703/http://issg.cs.duke.edu/epidemic/epidemic.pdf)
|
||||||
|
* [Freenet: A distibuted decentralized information storage and retrieval system](https://freenetproject.org/assets/papers/ddisrs.pdf)
|
||||||
|
* [Protecting Free Expression Online with Freenet](https://freenetproject.org/assets/papers/ddisrs.pdf)
|
||||||
|
* [Bitmessage: A Peer‐to‐Peer Message Authentication and Delivery System](https://archive.org/details/BitmessageWhitepaper/)
|
||||||
|
* [MuON: Epidemic based Mutual Anonymity](https://web.archive.org/web/20060901153544/http://www.csl.mtu.edu/cs6461/www/Reading/MuON_ICNP2005.pdf)
|
72
docs/dev/setup.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<h1 align="center">Onionr Developer Guide</h1>
|
||||||
|
|
||||||
|
This page assumes that Onionr is already installed and normal user requirements are setup.
|
||||||
|
|
||||||
|
The Onionr development environment is simple. All one really needs is a supported Python version (currently 3.7-3.8 as of writing).
|
||||||
|
|
||||||
|
There are additional requirements specified in requirements-dev.txt
|
||||||
|
|
||||||
|
**Developers agree to the [CoC](../../CODE_OF_CONDUCT.md) and to contribute new code under GPLv3 or later**. Developers should stick to PEP8 in most cases, and write unittests or integration tests where possible.
|
||||||
|
|
||||||
|
## Developer Scripts
|
||||||
|
|
||||||
|
run-onionr-node.py can be used to start a node with specific parameters
|
||||||
|
|
||||||
|
Intended to be used from VSCode (but could work otherwise), there are scripts in scripts/ named enable/disable-dev-config.py.
|
||||||
|
These make modifications to the default config for the purpose of making testing Onionr nodes easier.
|
||||||
|
Be sure to disable it again before pushing work.
|
||||||
|
|
||||||
|
There are also scripts to generate new tests.
|
||||||
|
|
||||||
|
*When adjusting PoW, it will make your node not compatible with the existing network*
|
||||||
|
|
||||||
|
Generally, one should disable bootstrap list usage when testing non trivial changes. This is a config option: general.use_bootstrap_list. and can be configured through enable-dev-config.py and run-onionr-node.py
|
||||||
|
|
||||||
|
|
||||||
|
# Current state of Onionr [2021-01-14]
|
||||||
|
|
||||||
|
Onionr in it's current form is functional, albeit buggy.
|
||||||
|
|
||||||
|
|
||||||
|
## Current major components
|
||||||
|
|
||||||
|
Onionr runs via two main HTTP gevent servers serving Flask apps.
|
||||||
|
|
||||||
|
Dir: apiservers
|
||||||
|
|
||||||
|
* 1 Parent app hosts all public API endpoints for the Tor transport.
|
||||||
|
* 1 Parent app hosts all UI-related files and endpoints. Some commands and internal modules interact with this API as well
|
||||||
|
* The HTTP servers have strict anti-dns-rebinding and CSRF countermeasures, so there is a script to craft requests to the UI-related API in scripts/
|
||||||
|
* Block storage is currently handled via metadata in sqlite (mostly defunct now), and block data storage in a different database. This is in blocks/ in running Onionr daemon data directory
|
||||||
|
* cryptography is currently handled in onionrcrypto/ except for ephemeral messages which are handled by onionr
|
||||||
|
* Transport clients run from looping threads mostly created in communicator/__init__.py, this includes block lookups and uploading on the Tor transport
|
||||||
|
|
||||||
|
## Road map
|
||||||
|
|
||||||
|
There are several big ways Onionr will be improved in the next major version:
|
||||||
|
|
||||||
|
* Migration to the [new modular block system](https://git.voidnet.tech/kev/onionrblocks)
|
||||||
|
* Probability proof of work -> verifiable delay function
|
||||||
|
* Friend system built on top of signing proofs (Private networks?)
|
||||||
|
* Gossip transport improvements such as with neighbor improvements. See streamfill/ and [simple gossip](https://github.com/onion-sudo/simplegossip) for incomplete experiments
|
||||||
|
|
||||||
|
* Finish removing "communicator"
|
||||||
|
* I2P transports
|
||||||
|
* Gossip
|
||||||
|
* Torrents (patch for sha1?)
|
||||||
|
* Modular transports
|
||||||
|
* Currently transports are just threads coupled together.
|
||||||
|
* It would be better if there was a generic way to tell any loaded transport what blocks are wanted and feed back received blocks to the database
|
||||||
|
* Migrate to SafeDB for peers and blocks
|
||||||
|
* SafeDB wrapper that contacts http endpoint to store if it is running, otherwise directly open DB
|
||||||
|
* Separate UI logic from daemon. Refactor code to
|
||||||
|
* Improve cryptography
|
||||||
|
* Restore phrases or deterministic keys (generate key from password, be very careful)
|
||||||
|
* Change identities to be dual keys (ed25519+curve25519)
|
||||||
|
* Finish treasurechest
|
||||||
|
* Interact via [named pipes](https://en.wikipedia.org/wiki/Named_pipe)
|
||||||
|
* Ephemeral key management
|
||||||
|
* Encrypt/decrypt/sign/verify functions to keep key out of main memory
|
||||||
|
* PGP-like symmetric messages
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
# Onionr Block Spec v1.1.0
|
# Onionr Block Spec v2.0.0
|
||||||
|
|
||||||
# Block Description
|
# Block Description
|
||||||
|
|
||||||
@ -20,13 +20,13 @@ The metadata section has the following fields. If a block contains any other fie
|
|||||||
|
|
||||||
## meta
|
## meta
|
||||||
|
|
||||||
Max byte size: 1000
|
Max byte size (when in escaped json string format): 1000
|
||||||
|
|
||||||
Meta is a string field which can contain arbitrary sub fields. It is intended for applications and plugins to use it for arbitrary metadata information. In the reference client, if the data section is encrypted or signed, the meta section also is.
|
Meta is a string field which can contain arbitrary sub fields. It is intended for applications and plugins to use it for arbitrary metadata information. If the data section is encrypted or signed, the meta section also is.
|
||||||
|
|
||||||
Common meta fields, such as 'type' are used by the reference Onionr client to describe the type of a block.
|
Common meta fields, such as 'type' are used by the reference Onionr client to describe the type of a block.
|
||||||
|
|
||||||
## sig
|
## sig (optional)
|
||||||
|
|
||||||
Max byte size: 200
|
Max byte size: 200
|
||||||
|
|
||||||
@ -34,30 +34,30 @@ Sig is a field for storing public key signatures of the block, typically ed25519
|
|||||||
|
|
||||||
Note: the max field size is larger than a EdDSA signature (which is what is typically used) in order to allow other primitives for signing in alternative implementations or future versions.
|
Note: the max field size is larger than a EdDSA signature (which is what is typically used) in order to allow other primitives for signing in alternative implementations or future versions.
|
||||||
|
|
||||||
## signer
|
## signer (optional, necessary if sig is present)
|
||||||
|
|
||||||
Max byte size: 200
|
Max byte size: 200
|
||||||
|
|
||||||
Signer is a field for specifying the public key which signed the block. In the reference client this is a base64 encoded ed25519 public key.
|
Signer is a field for specifying the public key which signed the block. In the reference client this is a base64 encoded ed25519 public key.
|
||||||
|
|
||||||
## time
|
## time (mandatory)
|
||||||
|
|
||||||
Max byte size: 10
|
Max byte size: 10
|
||||||
|
|
||||||
Time is an integer field for specifying the time of which a block was created. The trustworthiness of this field is based on one's trust of the block creator, however blocks with a time field set in the future (past a reasonable clock skew) are thrown out by the reference client.
|
Time is an integer field for specifying the time of which a block was created. The trustworthiness of this field is based on one's trust of the block creator, however blocks with a time field set in the future at the point of block receipt (past a reasonable clock skew) are thrown out by the reference client.
|
||||||
|
|
||||||
## expire
|
## expire (optional)
|
||||||
|
|
||||||
Max byte size: 10
|
Max byte size: 10
|
||||||
|
|
||||||
Expire is an integer field for specifying the time of which the block creator has indicated that the block should be deleted. The purpose of this is for voluntarily freeing the burden of unwanted blocks on the Onionr network, rather than security/privacy (since blocks could be trivially kept past expiration). Regardless, the reference client deletes blocks after a preset time if the expire field is either not set or longer than the preset time.
|
Expire is an integer field for specifying the time of which the block creator has indicated that the block should be deleted. The purpose of this is for voluntarily freeing the burden of unwanted blocks on the Onionr network, rather than security/privacy (since blocks could be trivially kept past expiration). Regardless, the reference client deletes blocks after a preset time if the expire field is either not set or longer than the preset time.
|
||||||
|
|
||||||
## pow
|
## pow (effectively mandatory)
|
||||||
|
|
||||||
Max byte size: 1000
|
Max byte size: 1000
|
||||||
|
|
||||||
Pow is a field for placing the nonce found to make a block meet a target proof of work. In theory, a block could meet a target without a random token in this field.
|
Pow is a field for placing the nonce found to make a block meet a target proof of work. In theory, a block could meet a target without a random token in this field.
|
||||||
|
|
||||||
## encryptType
|
## encryptType (optional)
|
||||||
|
|
||||||
encryptType is a field to specify the mode of encryption for a block. The values supported by Onionr are 'asym' and 'sym'.
|
encryptType is a field to specify the mode of encryption for a block. The values supported by Onionr are 'asym' and 'sym'.
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Due to the natural trade-offs of implementing [forward secrecy](https://en.wikipedia.org/wiki/Forward_secrecy) in a distributed, decentralized system, Onionr has optional
|
Due to the natural trade-offs of implementing [forward secrecy](https://en.wikipedia.org/wiki/Forward_secrecy) in a distributed, decentralized system, Onionr has optional ephemeral keys.
|
||||||
|
28
docs/docker.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Running Onionr in Docker
|
||||||
|
|
||||||
|
A Dockerfile is included in the root directory of Onionr.
|
||||||
|
|
||||||
|
In Docker version 20.10 (and probably others), there is a strange bug where Onionr must be run with -it or stdout will be garbled and it may hang.
|
||||||
|
|
||||||
|
## Clone and build the image
|
||||||
|
|
||||||
|
`$ git clone https://git.voidnet.tech/kev/onionr/`
|
||||||
|
`$ cd onionr`
|
||||||
|
`$ sudo docker build -t onionr .`
|
||||||
|
|
||||||
|
|
||||||
|
## Run Onionr
|
||||||
|
|
||||||
|
`$ sudo docker run -it -p 8080:8080 onionr`
|
||||||
|
|
||||||
|
Onionr will be accessible over any network interface by default, so make sure to either change the entry point bind-address argument or set a firewall rule.
|
||||||
|
|
||||||
|
That said, Onionr does protect it's interface by default with a web token, which will be shown in stdout.
|
||||||
|
|
||||||
|
**However, anyone who can access the port may be able to see what Onionr sites you have saved and potentially deanonymize your node**
|
||||||
|
|
||||||
|
## View the UI
|
||||||
|
|
||||||
|
Visit the address and port for the machine Onionr is running on, for example: http://192.168.1.5:8080/#<long-token-taken-from-stdout>
|
||||||
|
|
||||||
|
If you want a secure connection to the interface, either use a proxy such as nginx or caddy, or use [SSH tunneling](./vps-cloud-guide.md).
|
24
docs/faq.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<h1 align="center">Onionr FAQ</h1>
|
||||||
|
|
||||||
|
(Most of the FAQ answers apply to planned features and do not reflect in the demo network)
|
||||||
|
|
||||||
|
* How does Onionr route messages?
|
||||||
|
|
||||||
|
Onionr creates a message with an anti-spam proof (usually). It is then forwarded between nodes using binomial tree broadcast.
|
||||||
|
|
||||||
|
The network is structured based on the particular transport being used, for Tor, .onion addresses are used to determine closeness between nodes.
|
||||||
|
|
||||||
|
Churn due to connectivity changes or issues, membership changes or malicious activity means nodes need to sometimes look far away for missed messages.
|
||||||
|
|
||||||
|
To help with scale, messages can be intelligently deleted or forwarded, for example a mail message can be marked by its recipient at a given point for deletion, or forum posts can be set to expire after a short period or after lack of activity.
|
||||||
|
|
||||||
|
|
||||||
|
* Why do you use Python instead of [language]?
|
||||||
|
|
||||||
|
I'm very comfortable in Python, and I believe it is a maintainable language if you use it correctly with modern features, also it has many quality libraries useful to the project, like pyncal and stem. Most places in the project are IO bound.
|
||||||
|
|
||||||
|
|
||||||
|
* What do you think of bad actors who might use Onionr?
|
||||||
|
|
||||||
|
Users should be able to exclude viewing, processing, and hosting content they do not want to. To this end, I want to enable user-configurable filtering based on lists provided by friends, fuzzy hashing, and voting.
|
||||||
|
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 34 KiB |
BIN
docs/sticker.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
docs/talk.png
Normal file
After Width: | Height: | Size: 436 KiB |
Before Width: | Height: | Size: 28 KiB |
7
docs/usage/deterministic.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Deterministic address
|
||||||
|
|
||||||
|
Deterministic addresses are simply Onionr user IDs that are generated from a passphrase rather than general entropy.
|
||||||
|
|
||||||
|
To generate an Onionr deterministic, create a random passphrase of at least 25 characters of length. **It is very important that your passphrase is highly random. 9+ words is recommended for your passphrase**
|
||||||
|
|
||||||
|
`$ onionr add-id true`
|
@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
After installing Onionr, there are several things to do:
|
After installing Onionr, there are several things to do:
|
||||||
|
|
||||||
1. Setup a [deterministic address](usage/deterministic.md) (optional)
|
1. Setup a [deterministic address](deterministic.md) (optional)
|
||||||
2. Add friends' ids
|
2. Start your node `/path/to/onionr.sh start`
|
||||||
3. Publish your id
|
3. Copy your ID and share it with friends
|
@ -1,13 +1,18 @@
|
|||||||
# Onionr Installation
|
# Onionr Installation
|
||||||
|
|
||||||
The following steps work broadly speaking for Windows, Mac, and Linux.
|
The following steps work broadly speaking for WSL, Mac, and Linux.
|
||||||
|
|
||||||
1. Verify python3.6+ is installed: if its not see https://www.python.org/downloads/
|
1. Verify python3.7+ is installed: if not, see https://www.python.org/downloads/
|
||||||
|
|
||||||
2. Verify Tor is installed (does not need to be running, binary can be put into system path or Onionr directory)
|
2. Verify Tor is installed (does not need to be running, binary can be put into system path or Onionr directory)
|
||||||
|
|
||||||
3. [Optional but recommended]: setup virtual environment using [virtualenv](https://virtualenv.pypa.io/en/latest/), activate the virtual environment
|
3. [Optional but recommended]: setup virtual environment using [virtualenv](https://virtualenv.pypa.io/en/latest/), activate the virtual environment
|
||||||
|
|
||||||
4. Clone Onionr: git clone https://gitlab.com/beardog/onionr
|
4. Clone Onionr: `$ git clone https://gitlab.com/beardog/onionr`
|
||||||
|
|
||||||
5. Install the Python module dependencies: pip3 install --require-hashes -r requirements.txt
|
5. Install the Python module dependencies: `$ pip3 install --require-hashes -r requirements.txt`
|
||||||
|
|
||||||
|
|
||||||
|
Note: if an alternative python install is needed, use virtualenv or run Onionr commands with:
|
||||||
|
|
||||||
|
`$ /path/to/python /path/to/onionr/onionr/__init__.py`
|
16
docs/usage/mail.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
To use OnionrMail, open the web interface:
|
||||||
|
|
||||||
|
`$ onionr.sh openweb`
|
||||||
|
|
||||||
|
Navigate to the mail interface from the navbar.
|
||||||
|
|
||||||
|
## Receiving mail
|
||||||
|
|
||||||
|
Copy your ID from the textbox below the navbar. Publish the ID so that someone (or general people) know your ID to send messages to it. Note that associating the ID with your real ID publicly removes anonymity.
|
||||||
|
|
||||||
|
## Sending mail
|
||||||
|
|
||||||
|
1. optionally add the recipient as a friend via the friends page.
|
||||||
|
2. click compose in the mail menu
|
||||||
|
3. either select the recipient from the friend list or paste their ID in manually into the recipient box
|
||||||
|
4. send away!
|
59
docs/usage/pages.md
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
Onionr sites come in two forms:
|
||||||
|
|
||||||
|
* Single-page sites, identified by the hash of a single page contained within a single Onionr block.
|
||||||
|
|
||||||
|
* Multi-page sites, identified by a user ID. Contains directory archives of a full site.
|
||||||
|
|
||||||
|
|
||||||
|
# Metadata Awareness
|
||||||
|
|
||||||
|
Before creating an Onionr site, one should be cautious of the metadata one could be leaking. For example, some HTML generators may insert author meta tags. Onionr does not filter out any web page data.
|
||||||
|
|
||||||
|
# No JavaScript, no third-party resources
|
||||||
|
|
||||||
|
Currently, in order to protect Onionr users, JavaScript is disabled within Onionr sites. JS will remain present in the HTML file, but be non functional. Additionally, third party resources outside of Onionr cannot be loaded.
|
||||||
|
|
||||||
|
|
||||||
|
# Creating multi page sites
|
||||||
|
|
||||||
|
Multi page sites are the most useful, as they can contain an arbitrary amount of static files.
|
||||||
|
|
||||||
|
To create a single page site, create a directory for your site and write standard HTML file(s) within them. CSS, images and other files can be placed in the directory as well. The home page should be name index.html and in the parent level directory.
|
||||||
|
|
||||||
|
Then, create a strong passphrase for the site. If the site will be updated, be sure to write it down or remember it. A strong passphrase can be generated by running:
|
||||||
|
|
||||||
|
`$ scripts/passphrase-generator.py`
|
||||||
|
|
||||||
|
Sample output: lovesick blubberer haemoglobin... and so on.
|
||||||
|
|
||||||
|
## Generating or updating the site:
|
||||||
|
|
||||||
|
`$ ./onionr.sh addsite`
|
||||||
|
|
||||||
|
All files in the current working directory will be added to the site.
|
||||||
|
|
||||||
|
The command will prompt for a passphrase.
|
||||||
|
|
||||||
|
After the site is generated, a user ID that identifies the site will be outputted.
|
||||||
|
|
||||||
|
# Creating single page sites
|
||||||
|
|
||||||
|
Single page sites are incredibly straight forward.
|
||||||
|
|
||||||
|
Single page sites cannot be modified or updated, but are somewhat more secure due to having lower complexity.
|
||||||
|
|
||||||
|
To create a single page site, write a standard HTML file. Inline or data-uri CSS can be included, as well as data-uri images. Data-URI generators can be found online.
|
||||||
|
|
||||||
|
After creating the HTML file, run this command:
|
||||||
|
|
||||||
|
`$ ./onionr.sh addhtml filename.html`
|
||||||
|
|
||||||
|
![single page screenshot](single-page.png)
|
||||||
|
|
||||||
|
# Viewing sites
|
||||||
|
|
||||||
|
To view a site, open the Onionr web interface and paste the site hash or ID into the site opener box that looks like this:
|
||||||
|
|
||||||
|
![site opener box screenshot](site-opener.png)
|
||||||
|
|
||||||
|
Then, press open.
|
6
docs/usage/safety.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Onionr and all privacy-oriented software are not silver bullets.
|
||||||
|
|
||||||
|
For example, if one gives away too much about themselves on an Onionr forum, it doesn't matter how good Onionr's privacy is.
|
||||||
|
|
||||||
|
|
||||||
|
TODO: expand this page
|
BIN
docs/usage/single-page.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
docs/usage/site-opener.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
18
docs/vps-cloud-guide.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Cloud/Server Hosting Onionr
|
||||||
|
|
||||||
|
Cloud hosting is not the recommended way to run Onionr, as it gives the cloud provider control over your data.
|
||||||
|
|
||||||
|
That said, it is quite useful and by running a 24/7 Onionr node you contribute to the network's health.
|
||||||
|
|
||||||
|
![https://cock.li/img/cockbox.png](https://cockbox.org/?r=12)
|
||||||
|
|
||||||
|
[Cockbox](https://cockbox.org/?r=12) is the recommended provider, as they do not demand personal information and accept Monero. This is an affiliate link, which gives us a commission at no expense or complication to you.
|
||||||
|
|
||||||
|
|
||||||
|
1. [Install Onionr like normal](./basic-onionr-user-guide.pdf) or [from Docker](./docker.md)
|
||||||
|
2. Run with specific host and port to bind to: `$ ./run-onionr-node.py --bind-address 0.0.0.0 --port 8080`
|
||||||
|
3. Get the web security token: `$ ./onionr.sh get-web` (the long string at the end of the URL)
|
||||||
|
4. [Configure Firefox for SSH tunneling](https://web.archive.org/web/20210123034529/https://gist.github.com/brentjanderson/6ed800376e53746d2d28ba7b6bdcdc12). `Set network.proxy.allow_hijacking_localhost` to true in about:config
|
||||||
|
|
||||||
|
|
||||||
|
Disable random host binding in config (general.security.random_bind_ip = false) if you have Onionr auto start. You may also want to disable deniable block inserts.
|
@ -1,13 +1,16 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="onionr-logo.png" alt="<h1>Onionr</h1>" width=200>
|
<h1 align="center">Onionr</h1>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">Anonymous, Decentralized, Distributed Network</p>
|
<p align="center">Anonymous, Decentralized, Distributed Network</p>
|
||||||
|
|
||||||
|
June 2020
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
We believe that the ability to communicate freely with others is crucial for maintaining societal and personal liberty. The internet has provided humanity with the ability to spread information globally, but there are many persons and organizations who try to stifle the flow of information, sometimes with success.
|
We believe that the ability to communicate freely with others is crucial for maintaining societal and personal liberty. The internet has provided humanity with the ability to spread information globally, but there are many persons and organizations who try to stifle the flow of information, sometimes with success.
|
||||||
|
|
||||||
Internet censorship comes in many forms, state censorship, corporate consolidation of media, threats of violence, network exploitation (e.g. denial of service attacks) and other threats.
|
Internet censorship comes in many forms, state censorship, threats of violence, network exploitation (e.g. denial of service attacks) and others.
|
||||||
|
|
||||||
We hold that in order to protect individual privacy, users must have the ability to communicate anonymously and with decentralization.
|
We hold that in order to protect individual privacy, users must have the ability to communicate anonymously and with decentralization.
|
||||||
|
|
||||||
@ -63,6 +66,8 @@ Metadata defines what kind of data is in a block, signature data, encryption set
|
|||||||
|
|
||||||
Optionally, a random token can be inserted into the metadata for use in Proof of Work.
|
Optionally, a random token can be inserted into the metadata for use in Proof of Work.
|
||||||
|
|
||||||
|
The proof of work function should be a Verifiable Delay Function (VDF). We have chosen MiMC for it's simplicity.
|
||||||
|
|
||||||
### Block Encryption
|
### Block Encryption
|
||||||
|
|
||||||
For encryption, Onionr uses ephemeral Curve25519 keys for key exchange and XSalsa20-Poly1305 as a symmetric cipher or optionally using only XSalsa20-Poly1305 with a pre-shared key.
|
For encryption, Onionr uses ephemeral Curve25519 keys for key exchange and XSalsa20-Poly1305 as a symmetric cipher or optionally using only XSalsa20-Poly1305 with a pre-shared key.
|
||||||
@ -83,9 +88,7 @@ Blocks are stored indefinitely until the allocated space is filled, at which poi
|
|||||||
|
|
||||||
## Block Timestamping
|
## Block Timestamping
|
||||||
|
|
||||||
Onionr can provide evidence of when a block was inserted by requesting other users to sign a hash of the current time with the block data hash: sha3_256(time + sha3_256(block data)).
|
Onionr blocks are by default not accepted if their timestamp is set too far in the past, or is in the future.
|
||||||
|
|
||||||
This can be done either by the creator of the block prior to generation, or by any node after insertion.
|
|
||||||
|
|
||||||
In addition, randomness beacons such as the one operated by [NIST](https://beacon.nist.gov/home), [Chile](https://beacon.clcert.cl/), or the hash of the latest blocks in a cryptocurrency network could be used to affirm that a block was at least not *created* before a given time.
|
In addition, randomness beacons such as the one operated by [NIST](https://beacon.nist.gov/home), [Chile](https://beacon.clcert.cl/), or the hash of the latest blocks in a cryptocurrency network could be used to affirm that a block was at least not *created* before a given time.
|
||||||
|
|
||||||
|
9
git-update.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "This will git pull origin master, then update dependencies and default plugins."
|
||||||
|
echo "Enter to continue, ctrl-c to stop."
|
||||||
|
read
|
||||||
|
|
||||||
|
git pull origin master
|
||||||
|
pip3 install -r --require-hashes requirements.txt
|
||||||
|
./onionr.sh reset-plugins
|
35
install/CentOS-install
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
yum install epel-release
|
||||||
|
yum clean all
|
||||||
|
yum update -y
|
||||||
|
|
||||||
|
yum group install "Development Tools"
|
||||||
|
yum install centos-release-scl
|
||||||
|
yum install wget zlib zlib-devel openssl-devel bzip2-devel libffi-devel python-gevent -y
|
||||||
|
yum install rh-python38 rh-python38-python-devel
|
||||||
|
scl enable rh-python38 bash
|
||||||
|
yum update -y
|
||||||
|
|
||||||
|
pip3 install --require-hashes -r requirements.txt
|
||||||
|
chown nobody. ../
|
||||||
|
su -l nobody -s /bin/bash
|
||||||
|
scl enable rh-python38 bash
|
||||||
|
./onionr.sh start
|
||||||
|
|
||||||
|
Like a black hole, NSA pulls in every signal that comes near, but no electron is ever allowed to escape│
|
||||||
|
│ -James Bamford │
|
||||||
|
└───────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
|
[+] Tor is starting...
|
||||||
|
[+] Jan 11 18:35:55.000 [notice] Bootstrapped 0%: Starting
|
||||||
|
[+] Jan 11 18:35:56.000 [notice] Bootstrapped 10%: Finishing handshake with directory server
|
||||||
|
[+] Jan 11 18:35:56.000 [notice] Bootstrapped 80%: Connecting to the Tor network
|
||||||
|
[+] Jan 11 18:35:56.000 [notice] Bootstrapped 90%: Establishing a Tor circuit
|
||||||
|
[+] Finished starting Tor.
|
||||||
|
[+] Onionr v8.0.1 (x86_64) (API v2)
|
||||||
|
[+] Private P2P Communication - GPLv3 - https://Onionr.net
|
||||||
|
[+] CPython 3.8.6 on Linux-3.10.0-1062.4.1.el7.x86_64-x86_64-with-glibc2.2.5 3.10.0-1062.4.1.el7.x86_64
|
||||||
|
[+] Onionr data dir: /root/.local/share/onionr/
|
||||||
|
[+] Onionr daemon is running under 5186
|
||||||
|
[+] Not binding to LAN due to no private network configured.
|
||||||
|
[+] First run detected. Run openhome to get setup.
|
||||||
|
|
||||||
|
./onionr.sh openhome
|
5
install/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Service/System Installation Notes
|
||||||
|
|
||||||
|
Currently, the most reliable and well tested way to use Onionr is straight from the master branch of the repository, or from the released bundles.
|
||||||
|
|
||||||
|
System services and system-wide installation is not supported well yet.
|
@ -80,7 +80,7 @@ systemctl start onionr
|
|||||||
|
|
||||||
# pretty header thing
|
# pretty header thing
|
||||||
|
|
||||||
"$EXECUTABLE" --header 'Onionr successfully installed.'
|
"$EXECUTABLE" details
|
||||||
|
|
||||||
# and we're good!
|
# and we're good!
|
||||||
|
|
||||||
|
@ -1,23 +1,16 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
export OUTPUT_DIR=${OUTPUT_DIR:=/usr/share/onionr}
|
if [[ $EUID -eq 0 ]]; then
|
||||||
|
export ONIONR_HOME=${ONIONR_HOME:-/var/lib/onionr}
|
||||||
if [ -n "$HOME" ]; then
|
export LOG_DIR=${LOG_DIR:-/var/log/onionr}
|
||||||
export XDG_DATA_HOME=${XDG_DATA_HOME:=$HOME/.local/share/onionr}
|
|
||||||
|
|
||||||
export ONIONR_HOME=${ONIONR_HOME:=$XDG_DATA_HOME}
|
|
||||||
export LOG_DIR=${LOG_DIR:=$XDG_DATA_HOME/logs}
|
|
||||||
else
|
else
|
||||||
export ONIONR_HOME=${ONIONR_HOME:=/etc/onionr}
|
export ONIONR_HOME=${ONIONR_HOME:-${XDG_DATA_HOME:-$HOME/.local/share}/onionr}
|
||||||
export LOG_DIR=${LOG_DIR:=/var/log/onionr}
|
export LOG_DIR=${LOG_DIR:-$ONIONR_HOME/logs}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$ONIONR_HOME" "$LOG_DIR"
|
mkdir -p "$ONIONR_HOME" "$LOG_DIR"
|
||||||
|
|
||||||
chmod -R 700 "$ONIONR_HOME" "$LOG_DIR"
|
chmod 0700 "$ONIONR_HOME" "$LOG_DIR"
|
||||||
chown -R $USER:$USER "$ONIONR_HOME" "$LOG_DIR"
|
|
||||||
|
|
||||||
cd "$OUTPUT_DIR/onionr"
|
exec ${ONIONR_BASEDIR:-/usr/share/onionr}/onionr.sh "$@"
|
||||||
exec python3.7 onionr.py "$@"
|
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Onionr Daemon
|
Description=Onionr Daemon
|
||||||
Documentation=https://onionr.net/docs/
|
Documentation=https://onionr.net/docs/
|
||||||
After=network.target tor.service
|
After=network-online.target
|
||||||
Requires=network.target tor.service systemd-networkd-wait-online.service
|
Requires=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Environment="DATA_DIR=/usr/share/onionr"
|
Environment="ONIONR_HOME=/var/lib/onionr"
|
||||||
Environment="LOG_DIR=/var/log/onionr/"
|
Environment="LOG_DIR=/var/log/onionr"
|
||||||
|
|
||||||
ExecStart=/usr/bin/onionr --start
|
ExecStart=/usr/bin/onionr start
|
||||||
ExecStop=/usr/bin/onionr --stop
|
ExecStop=/usr/bin/onionr stop
|
||||||
|
|
||||||
KillMode=mixed
|
KillMode=mixed
|
||||||
KillSignal=SIGQUIT
|
KillSignal=SIGQUIT
|
||||||
TimeoutStopSec=5s
|
TimeoutStopSec=30s
|
||||||
Type=simple
|
|
||||||
Restart=on-abnormal
|
Restart=on-abnormal
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=tor.service
|
WantedBy=multi-user.target
|
||||||
|
15
make-release.sh
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
rm -rf dist
|
||||||
|
mkdir dist
|
||||||
|
mkdir dist/onionr/
|
||||||
|
cp -t dist/onionr/ -r docs static-data install src onionr.sh start-daemon.sh setprofile.sh requirements.txt requirements-notifications.txt
|
||||||
|
cp *.md dist/onionr/
|
||||||
|
PIP_USER=false
|
||||||
|
export PIP_USER
|
||||||
|
cd dist
|
||||||
|
tar -czvf onionr-no-deps.tar.gz onionr
|
||||||
|
cd ..
|
||||||
|
pip3 install --require-hashes -r requirements.txt --target=dist/onionr/src/
|
||||||
|
pip3 install --require-hashes -r requirements-notifications.txt --target=dist/onionr/src/
|
||||||
|
cd dist
|
||||||
|
tar -czvf onionr.tar.gz onionr
|
@ -1,6 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
ORIG_ONIONR_RUN_DIR=`pwd`
|
ORIG_ONIONR_RUN_DIR=`pwd`
|
||||||
export ORIG_ONIONR_RUN_DIR
|
export ORIG_ONIONR_RUN_DIR
|
||||||
|
export PYTHONDONTWRITEBYTECODE=1
|
||||||
|
export PYTHONUNBUFFERED=1
|
||||||
|
export PYTHONOPTIMIZE="true"
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
cd onionr/
|
cd src
|
||||||
./__init__.py "$@"
|
./__init__.py "$@"
|
@ -1,62 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
This file initializes Onionr when ran to be a daemon or with commands
|
|
||||||
|
|
||||||
Run with 'help' for usage.
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
|
|
||||||
# Set the user's locale for encoding reasons
|
|
||||||
import locale
|
|
||||||
locale.setlocale(locale.LC_ALL, '')
|
|
||||||
|
|
||||||
# Import standard libraries
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# 3rd party lib imports
|
|
||||||
# Ensure that PySocks is installed
|
|
||||||
try:
|
|
||||||
from urllib3.contrib.socks import SOCKSProxyManager
|
|
||||||
except ModuleNotFoundError:
|
|
||||||
raise ModuleNotFoundError("You need the PySocks module (for use with socks5 proxy to use Tor)")
|
|
||||||
|
|
||||||
# Onionr imports
|
|
||||||
from etc import onionrvalues # For different Onionr related constants such as versions
|
|
||||||
import onionrsetup as setup
|
|
||||||
|
|
||||||
# Ensure we have at least the minimum python version
|
|
||||||
if sys.version_info[0] == 2 or sys.version_info[1] < onionrvalues.MIN_PY_VERSION:
|
|
||||||
sys.stderr.write('Error, Onionr requires Python 3.%s+\n' % (onionrvalues.MIN_PY_VERSION,))
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Create Onionr data directories, must be done before most imports
|
|
||||||
from utils import createdirs
|
|
||||||
createdirs.create_dirs()
|
|
||||||
|
|
||||||
from onionrcommands import parser
|
|
||||||
import onionrevents as events
|
|
||||||
|
|
||||||
setup.setup_config()
|
|
||||||
setup.setup_default_plugins()
|
|
||||||
|
|
||||||
def onionr_main():
|
|
||||||
parser.register()
|
|
||||||
return
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
onionr_main()
|
|
@ -1,9 +0,0 @@
|
|||||||
# API Servers
|
|
||||||
|
|
||||||
Contains the WSGI servers Onionr uses for remote peer communication and local daemon control
|
|
||||||
|
|
||||||
## Files
|
|
||||||
|
|
||||||
* \_\_init\_\_.py: Exposes the server classes
|
|
||||||
* private: Contains the client API (the server used to interact with the local Onionr daemon, and view the web UI)
|
|
||||||
* public: Contains the public API (the server used by remote peers to talk to our daemon)
|
|
@ -1,3 +0,0 @@
|
|||||||
from . import public, private
|
|
||||||
PublicAPI = public.PublicAPI
|
|
||||||
ClientAPI = private.PrivateAPI
|
|
@ -1,8 +0,0 @@
|
|||||||
# Private API Server
|
|
||||||
|
|
||||||
Private API server, used to access the web interface locally and control Onionr
|
|
||||||
|
|
||||||
## Files
|
|
||||||
|
|
||||||
* \_\_init\_\_.py: Sets up the server and a few misc functions
|
|
||||||
* register_private_blueprints.py: Adds in flask blueprints for various sub-APIs
|
|
@ -1,95 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
This file handles all incoming http requests to the client, using Flask
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import base64, os, time
|
|
||||||
import flask
|
|
||||||
from gevent.pywsgi import WSGIServer
|
|
||||||
from onionrutils import epoch
|
|
||||||
import httpapi, filepaths, logger
|
|
||||||
from . import register_private_blueprints
|
|
||||||
from etc import waitforsetvar
|
|
||||||
import serializeddata, config
|
|
||||||
from .. import public
|
|
||||||
class PrivateAPI:
|
|
||||||
'''
|
|
||||||
Client HTTP api
|
|
||||||
'''
|
|
||||||
|
|
||||||
callbacks = {'public' : {}, 'private' : {}}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
'''
|
|
||||||
Initialize the api server, preping variables for later use
|
|
||||||
|
|
||||||
This initialization defines all of the API entry points and handlers for the endpoints and errors
|
|
||||||
This also saves the used host (random localhost IP address) to the data folder in host.txt
|
|
||||||
'''
|
|
||||||
self.config = config
|
|
||||||
self.startTime = epoch.get_epoch()
|
|
||||||
app = flask.Flask(__name__)
|
|
||||||
bindPort = int(config.get('client.client.port', 59496))
|
|
||||||
self.bindPort = bindPort
|
|
||||||
|
|
||||||
self.clientToken = config.get('client.webpassword')
|
|
||||||
self.timeBypassToken = base64.b16encode(os.urandom(32)).decode()
|
|
||||||
|
|
||||||
self.host = httpapi.apiutils.setbindip.set_bind_IP(filepaths.private_API_host_file)
|
|
||||||
logger.info('Running api on %s:%s' % (self.host, self.bindPort))
|
|
||||||
self.httpServer = ''
|
|
||||||
|
|
||||||
self.queueResponse = {}
|
|
||||||
self.get_block_data = httpapi.apiutils.GetBlockData(self)
|
|
||||||
register_private_blueprints.register_private_blueprints(self, app)
|
|
||||||
httpapi.load_plugin_blueprints(app)
|
|
||||||
self.app = app
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
waitforsetvar.wait_for_set_var(self, "_too_many")
|
|
||||||
self.publicAPI = self._too_many.get(public.PublicAPI)
|
|
||||||
self.httpServer = WSGIServer((self.host, self.bindPort), self.app, log=None, handler_class=httpapi.fdsafehandler.FDSafeHandler)
|
|
||||||
self.httpServer.serve_forever()
|
|
||||||
|
|
||||||
def setPublicAPIInstance(self, inst):
|
|
||||||
self.publicAPI = inst
|
|
||||||
|
|
||||||
def validateToken(self, token):
|
|
||||||
'''
|
|
||||||
Validate that the client token matches the given token. Used to prevent CSRF and data exfiltration
|
|
||||||
'''
|
|
||||||
if not self.clientToken:
|
|
||||||
logger.error("client password needs to be set")
|
|
||||||
return False
|
|
||||||
try:
|
|
||||||
if not hmac.compare_digest(self.clientToken, token):
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
except TypeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def getUptime(self):
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
return epoch.get_epoch() - self.startTime
|
|
||||||
except (AttributeError, NameError):
|
|
||||||
# Don't error on race condition with startup
|
|
||||||
pass
|
|
||||||
|
|
||||||
def getBlockData(self, bHash, decrypt=False, raw=False, headerOnly=False):
|
|
||||||
return self.get_block_data.get_block_data(bHash, decrypt=decrypt, raw=raw, headerOnly=headerOnly)
|
|
@ -1,35 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
This file registers blueprints for the private api server
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import os
|
|
||||||
from httpapi import security, friendsapi, profilesapi, configapi, insertblock, miscclientapi, onionrsitesapi, apiutils
|
|
||||||
from httpapi import directconnections
|
|
||||||
def register_private_blueprints(private_api, app):
|
|
||||||
app.register_blueprint(security.client.ClientAPISecurity(private_api).client_api_security_bp)
|
|
||||||
app.register_blueprint(friendsapi.friends)
|
|
||||||
app.register_blueprint(profilesapi.profile_BP)
|
|
||||||
app.register_blueprint(configapi.config_BP)
|
|
||||||
app.register_blueprint(insertblock.ib)
|
|
||||||
app.register_blueprint(miscclientapi.getblocks.client_get_blocks)
|
|
||||||
app.register_blueprint(miscclientapi.endpoints.PrivateEndpoints(private_api).private_endpoints_bp)
|
|
||||||
app.register_blueprint(onionrsitesapi.site_api)
|
|
||||||
app.register_blueprint(apiutils.shutdown.shutdown_bp)
|
|
||||||
app.register_blueprint(miscclientapi.staticfiles.static_files_bp)
|
|
||||||
app.register_blueprint(directconnections.DirectConnectionManagement(private_api).direct_conn_management_bp)
|
|
||||||
return app
|
|
@ -1,64 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
This file handles all incoming http requests to the public api server, using Flask
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
import flask
|
|
||||||
from gevent.pywsgi import WSGIServer
|
|
||||||
from httpapi import apiutils, security, fdsafehandler, miscpublicapi
|
|
||||||
import logger, config, filepaths
|
|
||||||
from utils import gettransports
|
|
||||||
from etc import onionrvalues, waitforsetvar
|
|
||||||
|
|
||||||
def _get_tor_adder(pub_api):
|
|
||||||
transports = []
|
|
||||||
while len(transports) == 0:
|
|
||||||
transports = gettransports.get()
|
|
||||||
time.sleep(0.3)
|
|
||||||
pub_api.torAdder = transports[0]
|
|
||||||
|
|
||||||
class PublicAPI:
|
|
||||||
'''
|
|
||||||
The new client api server, isolated from the public api
|
|
||||||
'''
|
|
||||||
def __init__(self):
|
|
||||||
app = flask.Flask('PublicAPI')
|
|
||||||
app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024
|
|
||||||
self.i2pEnabled = config.get('i2p.host', False)
|
|
||||||
self.hideBlocks = [] # Blocks to be denied sharing
|
|
||||||
self.host = apiutils.setbindip.set_bind_IP(filepaths.public_API_host_file)
|
|
||||||
|
|
||||||
threading.Thread(target=_get_tor_adder, args=[self], daemon=True).start()
|
|
||||||
|
|
||||||
self.torAdder = ""
|
|
||||||
self.bindPort = config.get('client.public.port')
|
|
||||||
self.lastRequest = 0
|
|
||||||
self.hitCount = 0 # total rec requests to public api since server started
|
|
||||||
self.config = config
|
|
||||||
self.API_VERSION = onionrvalues.API_VERSION
|
|
||||||
logger.info('Running public api on %s:%s' % (self.host, self.bindPort))
|
|
||||||
|
|
||||||
app.register_blueprint(security.public.PublicAPISecurity(self).public_api_security_bp)
|
|
||||||
app.register_blueprint(miscpublicapi.endpoints.PublicEndpoints(self).public_endpoints_bp)
|
|
||||||
self.app = app
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
waitforsetvar.wait_for_set_var(self, "_too_many")
|
|
||||||
self.httpServer = WSGIServer((self.host, self.bindPort), self.app, log=None, handler_class=fdsafehandler.FDSafeHandler)
|
|
||||||
self.httpServer.serve_forever()
|
|
@ -1,54 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Import block data and save it
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import onionrexceptions, logger
|
|
||||||
from onionrutils import validatemetadata, blockmetadata
|
|
||||||
from coredb import blockmetadb
|
|
||||||
import onionrblacklist, onionrstorage
|
|
||||||
import onionrcrypto as crypto
|
|
||||||
def importBlockFromData(content):
|
|
||||||
blacklist = onionrblacklist.OnionrBlackList()
|
|
||||||
retData = False
|
|
||||||
|
|
||||||
try:
|
|
||||||
content = content.encode()
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
dataHash = crypto.hashers.sha3_hash(content)
|
|
||||||
|
|
||||||
if blacklist.inBlacklist(dataHash):
|
|
||||||
raise onionrexceptions.BlacklistedBlock('%s is a blacklisted block' % (dataHash,))
|
|
||||||
|
|
||||||
metas = blockmetadata.get_block_metadata_from_data(content) # returns tuple(metadata, meta), meta is also in metadata
|
|
||||||
metadata = metas[0]
|
|
||||||
if validatemetadata.validate_metadata(metadata, metas[2]): # check if metadata is valid
|
|
||||||
if crypto.cryptoutils.verify_POW(content): # check if POW is enough/correct
|
|
||||||
logger.info('Block passed proof, saving.', terminal=True)
|
|
||||||
try:
|
|
||||||
blockHash = onionrstorage.set_data(content)
|
|
||||||
except onionrexceptions.DiskAllocationReached:
|
|
||||||
logger.warn('Failed to save block due to full disk allocation')
|
|
||||||
else:
|
|
||||||
blockmetadb.add_to_block_DB(blockHash, dataSaved=True)
|
|
||||||
blockmetadata.process_block_metadata(blockHash) # caches block metadata values to block database
|
|
||||||
retData = True
|
|
||||||
else:
|
|
||||||
raise onionrexceptions.InvalidProof
|
|
||||||
return retData
|
|
@ -1,15 +0,0 @@
|
|||||||
# Onionr Communicator
|
|
||||||
|
|
||||||
Onionr communicator is the Onionr client. It "connects" to remote Onionr peers and does things such as:
|
|
||||||
|
|
||||||
* Finding new peers
|
|
||||||
* Uploading blocks
|
|
||||||
* Downloading blocks
|
|
||||||
* Daemon maintenance/housekeeping
|
|
||||||
|
|
||||||
## Files
|
|
||||||
|
|
||||||
* \_\_init\_\_.py: Contains the main communicator code. Inits and launches the communicator and sets up the timers
|
|
||||||
* peeraction.py: contains a function to send commands to remote peers
|
|
||||||
* bootstrappers.py: adds peers from the bootstrap list to the communicator to try to connect to them
|
|
||||||
* onlinepeers: management of the online peer pool for the communicator
|
|
@ -1,261 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
This file contains both the OnionrCommunicate class for communcating with peers
|
|
||||||
and code to operate as a daemon, getting commands from the command queue database (see core.Core.daemonQueue)
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import sys, os, time
|
|
||||||
import config, logger
|
|
||||||
import onionrexceptions, onionrpeers, onionrevents as events, onionrplugins as plugins, onionrblockapi as block
|
|
||||||
from . import onlinepeers, uploadqueue
|
|
||||||
from communicatorutils import servicecreator, onionrcommunicatortimers
|
|
||||||
from communicatorutils import downloadblocks, lookupblocks, lookupadders
|
|
||||||
from communicatorutils import servicecreator, connectnewpeers
|
|
||||||
from communicatorutils import uploadblocks
|
|
||||||
from communicatorutils import daemonqueuehandler, announcenode, deniableinserts
|
|
||||||
from communicatorutils import cooldownpeer, housekeeping, netcheck
|
|
||||||
from onionrutils import localcommand, epoch
|
|
||||||
from etc import humanreadabletime
|
|
||||||
import onionrservices, filepaths, storagecounter
|
|
||||||
from coredb import daemonqueue, dbfiles
|
|
||||||
from utils import gettransports
|
|
||||||
from netcontroller import NetController
|
|
||||||
OnionrCommunicatorTimers = onionrcommunicatortimers.OnionrCommunicatorTimers
|
|
||||||
|
|
||||||
config.reload()
|
|
||||||
class OnionrCommunicatorDaemon:
|
|
||||||
def __init__(self, shared_state, developmentMode=config.get('general.dev_mode', False)):
|
|
||||||
# configure logger and stuff
|
|
||||||
self.config = config
|
|
||||||
self.storage_counter = storagecounter.StorageCounter()
|
|
||||||
self.isOnline = True # Assume we're connected to the internet
|
|
||||||
self.shared_state = shared_state # TooManyObjects module
|
|
||||||
|
|
||||||
# list of timer instances
|
|
||||||
self.timers = []
|
|
||||||
|
|
||||||
# initialize core with Tor socks port being 3rd argument
|
|
||||||
self.proxyPort = shared_state.get(NetController).socksPort
|
|
||||||
|
|
||||||
# Upload information, list of blocks to upload
|
|
||||||
self.blocksToUpload = []
|
|
||||||
self.upload_session_manager = self.shared_state.get(uploadblocks.sessionmanager.BlockUploadSessionManager)
|
|
||||||
self.shared_state.share_object()
|
|
||||||
|
|
||||||
# loop time.sleep delay in seconds
|
|
||||||
self.delay = 1
|
|
||||||
|
|
||||||
# lists of connected peers and peers we know we can't reach currently
|
|
||||||
self.onlinePeers = []
|
|
||||||
self.offlinePeers = []
|
|
||||||
self.cooldownPeer = {}
|
|
||||||
self.connectTimes = {}
|
|
||||||
self.peerProfiles = [] # list of peer's profiles (onionrpeers.PeerProfile instances)
|
|
||||||
self.newPeers = [] # Peers merged to us. Don't add to db until we know they're reachable
|
|
||||||
self.announceProgress = {}
|
|
||||||
self.announceCache = {}
|
|
||||||
|
|
||||||
self.generating_blocks = []
|
|
||||||
|
|
||||||
# amount of threads running by name, used to prevent too many
|
|
||||||
self.threadCounts = {}
|
|
||||||
|
|
||||||
# set true when shutdown command received
|
|
||||||
self.shutdown = False
|
|
||||||
|
|
||||||
# list of new blocks to download, added to when new block lists are fetched from peers
|
|
||||||
self.blockQueue = {}
|
|
||||||
|
|
||||||
# list of blocks currently downloading, avoid s
|
|
||||||
self.currentDownloading = []
|
|
||||||
|
|
||||||
# timestamp when the last online node was seen
|
|
||||||
self.lastNodeSeen = None
|
|
||||||
|
|
||||||
# Dict of time stamps for peer's block list lookup times, to avoid downloading full lists all the time
|
|
||||||
self.dbTimestamps = {}
|
|
||||||
|
|
||||||
# Clear the daemon queue for any dead messages
|
|
||||||
if os.path.exists(dbfiles.daemon_queue_db):
|
|
||||||
daemonqueue.clear_daemon_queue()
|
|
||||||
|
|
||||||
# Loads in and starts the enabled plugins
|
|
||||||
plugins.reload()
|
|
||||||
|
|
||||||
# time app started running for info/statistics purposes
|
|
||||||
self.startTime = epoch.get_epoch()
|
|
||||||
|
|
||||||
uploadqueue.UploadQueue(self) # extends our upload list and saves our list when Onionr exits
|
|
||||||
|
|
||||||
if developmentMode:
|
|
||||||
OnionrCommunicatorTimers(self, self.heartbeat, 30)
|
|
||||||
|
|
||||||
# Set timers, function reference, seconds
|
|
||||||
# requires_peer True means the timer function won't fire if we have no connected peers
|
|
||||||
peerPoolTimer = OnionrCommunicatorTimers(self, onlinepeers.get_online_peers, 60, max_threads=1, my_args=[self])
|
|
||||||
OnionrCommunicatorTimers(self, self.runCheck, 2, max_threads=1)
|
|
||||||
|
|
||||||
# Timers to periodically lookup new blocks and download them
|
|
||||||
lookup_blocks_timer = OnionrCommunicatorTimers(self, lookupblocks.lookup_blocks_from_communicator, config.get('timers.lookupBlocks', 25), my_args=[self], requires_peer=True, max_threads=1)
|
|
||||||
# The block download timer is accessed by the block lookup function to trigger faster download starts
|
|
||||||
self.download_blocks_timer = OnionrCommunicatorTimers(self, self.getBlocks, config.get('timers.getBlocks', 10), requires_peer=True, max_threads=5)
|
|
||||||
|
|
||||||
# Timer to reset the longest offline peer so contact can be attempted again
|
|
||||||
OnionrCommunicatorTimers(self, onlinepeers.clear_offline_peer, 58, my_args=[self])
|
|
||||||
|
|
||||||
# Timer to cleanup old blocks
|
|
||||||
blockCleanupTimer = OnionrCommunicatorTimers(self, housekeeping.clean_old_blocks, 20, my_args=[self])
|
|
||||||
|
|
||||||
# Timer to discover new peers
|
|
||||||
OnionrCommunicatorTimers(self, lookupadders.lookup_new_peer_transports_with_communicator, 60, requires_peer=True, my_args=[self], max_threads=2)
|
|
||||||
|
|
||||||
# Timer for adjusting which peers we actively communicate to at any given time, to avoid over-using peers
|
|
||||||
OnionrCommunicatorTimers(self, cooldownpeer.cooldown_peer, 30, my_args=[self], requires_peer=True)
|
|
||||||
|
|
||||||
# Timer to read the upload queue and upload the entries to peers
|
|
||||||
OnionrCommunicatorTimers(self, uploadblocks.upload_blocks_from_communicator, 5, my_args=[self], requires_peer=True, max_threads=1)
|
|
||||||
|
|
||||||
# Timer to process the daemon command queue
|
|
||||||
OnionrCommunicatorTimers(self, daemonqueuehandler.handle_daemon_commands, 6, my_args=[self], max_threads=3)
|
|
||||||
|
|
||||||
# Setup direct connections
|
|
||||||
if config.get('general.socket_servers', False):
|
|
||||||
self.services = onionrservices.OnionrServices()
|
|
||||||
self.active_services = []
|
|
||||||
self.service_greenlets = []
|
|
||||||
OnionrCommunicatorTimers(self, servicecreator.service_creator, 5, max_threads=50, my_args=[self])
|
|
||||||
else:
|
|
||||||
self.services = None
|
|
||||||
|
|
||||||
# {peer_pubkey: ephemeral_address}, the address to reach them
|
|
||||||
self.direct_connection_clients = {}
|
|
||||||
|
|
||||||
# This timer creates deniable blocks, in an attempt to further obfuscate block insertion metadata
|
|
||||||
if config.get('general.insert_deniable_blocks', True):
|
|
||||||
deniableBlockTimer = OnionrCommunicatorTimers(self, deniableinserts.insert_deniable_block, 180, my_args=[self], requires_peer=True, max_threads=1)
|
|
||||||
deniableBlockTimer.count = (deniableBlockTimer.frequency - 175)
|
|
||||||
|
|
||||||
# Timer to check for connectivity, through Tor to various high-profile onion services
|
|
||||||
netCheckTimer = OnionrCommunicatorTimers(self, netcheck.net_check, 500, my_args=[self], max_threads=1)
|
|
||||||
|
|
||||||
# Announce the public API server transport address to other nodes if security level allows
|
|
||||||
if config.get('general.security_level', 1) == 0 and config.get('general.announce_node', True):
|
|
||||||
# Default to high security level incase config breaks
|
|
||||||
announceTimer = OnionrCommunicatorTimers(self, announcenode.announce_node, 3600, my_args=[self], requires_peer=True, max_threads=1)
|
|
||||||
announceTimer.count = (announceTimer.frequency - 120)
|
|
||||||
else:
|
|
||||||
logger.debug('Will not announce node.')
|
|
||||||
|
|
||||||
# Timer to delete malfunctioning or long-dead peers
|
|
||||||
cleanupTimer = OnionrCommunicatorTimers(self, self.peerCleanup, 300, requires_peer=True)
|
|
||||||
|
|
||||||
# Timer to cleanup dead ephemeral forward secrecy keys
|
|
||||||
forwardSecrecyTimer = OnionrCommunicatorTimers(self, housekeeping.clean_keys, 15, my_args=[self], max_threads=1)
|
|
||||||
|
|
||||||
# Adjust initial timer triggers
|
|
||||||
peerPoolTimer.count = (peerPoolTimer.frequency - 1)
|
|
||||||
cleanupTimer.count = (cleanupTimer.frequency - 60)
|
|
||||||
blockCleanupTimer.count = (blockCleanupTimer.frequency - 2)
|
|
||||||
lookup_blocks_timer = (lookup_blocks_timer.frequency - 2)
|
|
||||||
|
|
||||||
shared_state.add(self)
|
|
||||||
|
|
||||||
# Main daemon loop, mainly for calling timers, don't do any complex operations here to avoid locking
|
|
||||||
try:
|
|
||||||
while not self.shutdown:
|
|
||||||
for i in self.timers:
|
|
||||||
if self.shutdown:
|
|
||||||
break
|
|
||||||
i.processTimer()
|
|
||||||
time.sleep(self.delay)
|
|
||||||
# Debug to print out used FDs (regular and net)
|
|
||||||
#proc = psutil.Process()
|
|
||||||
#print(proc.open_files(), len(psutil.net_connections()))
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
self.shutdown = True
|
|
||||||
pass
|
|
||||||
|
|
||||||
logger.info('Goodbye. (Onionr is cleaning up, and will exit)', terminal=True)
|
|
||||||
try:
|
|
||||||
self.service_greenlets
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
for server in self.service_greenlets:
|
|
||||||
server.stop()
|
|
||||||
localcommand.local_command('shutdown') # shutdown the api
|
|
||||||
try:
|
|
||||||
time.sleep(0.5)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def getBlocks(self):
|
|
||||||
'''download new blocks in queue'''
|
|
||||||
downloadblocks.download_blocks_from_communicator(self)
|
|
||||||
|
|
||||||
def decrementThreadCount(self, threadName):
|
|
||||||
'''Decrement amount of a thread name if more than zero, called when a function meant to be run in a thread ends'''
|
|
||||||
try:
|
|
||||||
if self.threadCounts[threadName] > 0:
|
|
||||||
self.threadCounts[threadName] -= 1
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def connectNewPeer(self, peer='', useBootstrap=False):
|
|
||||||
'''Adds a new random online peer to self.onlinePeers'''
|
|
||||||
connectnewpeers.connect_new_peer_to_communicator(self, peer, useBootstrap)
|
|
||||||
|
|
||||||
def peerCleanup(self):
|
|
||||||
'''This just calls onionrpeers.cleanupPeers, which removes dead or bad peers (offline too long, too slow)'''
|
|
||||||
onionrpeers.peer_cleanup()
|
|
||||||
self.decrementThreadCount('peerCleanup')
|
|
||||||
|
|
||||||
def getPeerProfileInstance(self, peer):
|
|
||||||
'''Gets a peer profile instance from the list of profiles, by address name'''
|
|
||||||
for i in self.peerProfiles:
|
|
||||||
# if the peer's profile is already loaded, return that
|
|
||||||
if i.address == peer:
|
|
||||||
retData = i
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# if the peer's profile is not loaded, return a new one. connectNewPeer also adds it to the list on connect
|
|
||||||
retData = onionrpeers.PeerProfiles(peer)
|
|
||||||
self.peerProfiles.append(retData)
|
|
||||||
return retData
|
|
||||||
|
|
||||||
def getUptime(self):
|
|
||||||
return epoch.get_epoch() - self.startTime
|
|
||||||
|
|
||||||
def heartbeat(self):
|
|
||||||
'''Show a heartbeat debug message'''
|
|
||||||
logger.debug('Heartbeat. Node running for %s.' % humanreadabletime.human_readable_time(self.getUptime()))
|
|
||||||
self.decrementThreadCount('heartbeat')
|
|
||||||
|
|
||||||
def runCheck(self):
|
|
||||||
if run_file_exists(self):
|
|
||||||
logger.debug('Status check; looks good.')
|
|
||||||
|
|
||||||
self.decrementThreadCount('runCheck')
|
|
||||||
|
|
||||||
def startCommunicator(shared_state):
|
|
||||||
OnionrCommunicatorDaemon(shared_state)
|
|
||||||
|
|
||||||
def run_file_exists(daemon):
|
|
||||||
if os.path.isfile(filepaths.run_check_file):
|
|
||||||
os.remove(filepaths.run_check_file)
|
|
||||||
return True
|
|
||||||
return False
|
|
@ -1,30 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
add bootstrap peers to the communicator peer list
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
from utils import readstatic, gettransports
|
|
||||||
from coredb import keydb
|
|
||||||
bootstrap_peers = readstatic.read_static('bootstrap-nodes.txt').split(',')
|
|
||||||
def add_bootstrap_list_to_peer_list(comm_inst, peerList):
|
|
||||||
'''
|
|
||||||
Add the bootstrap list to the peer list (no duplicates)
|
|
||||||
'''
|
|
||||||
for i in bootstrap_peers:
|
|
||||||
if i not in peerList and i not in comm_inst.offlinePeers and not i in gettransports.get() and len(str(i).strip()) > 0:
|
|
||||||
peerList.append(i)
|
|
||||||
keydb.addkeys.add_address(i)
|
|
@ -1,12 +0,0 @@
|
|||||||
# Online Peers
|
|
||||||
|
|
||||||
Manages a pool of peers to perform actions with. Since Onionr does not maintain socket connections, it holds a list of peers.
|
|
||||||
|
|
||||||
|
|
||||||
## Files
|
|
||||||
|
|
||||||
* \_\_init\_\_.py: exposes some functions to interact with the pool
|
|
||||||
* clearofflinepeer.py: Pop the oldest peer in the offline list
|
|
||||||
* onlinepeers.py: communicator timer to add new peers to the pool randomly
|
|
||||||
* pickonlinepeers.py: returns a random peer from the online pool
|
|
||||||
* removeonlinepeer.py: removes a specified peer from the online pool
|
|
@ -1,6 +0,0 @@
|
|||||||
from . import clearofflinepeer, onlinepeers, pickonlinepeers, removeonlinepeer
|
|
||||||
|
|
||||||
clear_offline_peer = clearofflinepeer.clear_offline_peer
|
|
||||||
get_online_peers = onlinepeers.get_online_peers
|
|
||||||
pick_online_peer = pickonlinepeers.pick_online_peer
|
|
||||||
remove_online_peer = removeonlinepeer.remove_online_peer
|
|
@ -1,29 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
clear offline peer in a communicator instance
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import logger
|
|
||||||
def clear_offline_peer(comm_inst):
|
|
||||||
'''Removes the longest offline peer to retry later'''
|
|
||||||
try:
|
|
||||||
removed = comm_inst.offlinePeers.pop(0)
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
logger.debug('Removed ' + removed + ' from offline list, will try them again.')
|
|
||||||
comm_inst.decrementThreadCount('clear_offline_peer')
|
|
@ -1,45 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
get online peers in a communicator instance
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import time
|
|
||||||
from etc import humanreadabletime
|
|
||||||
import logger
|
|
||||||
def get_online_peers(comm_inst):
|
|
||||||
'''
|
|
||||||
Manages the comm_inst.onlinePeers attribute list, connects to more peers if we have none connected
|
|
||||||
'''
|
|
||||||
config = comm_inst.config
|
|
||||||
logger.debug('Refreshing peer pool...')
|
|
||||||
maxPeers = int(config.get('peers.max_connect', 10))
|
|
||||||
needed = maxPeers - len(comm_inst.onlinePeers)
|
|
||||||
|
|
||||||
for i in range(needed):
|
|
||||||
if len(comm_inst.onlinePeers) == 0:
|
|
||||||
comm_inst.connectNewPeer(useBootstrap=True)
|
|
||||||
else:
|
|
||||||
comm_inst.connectNewPeer()
|
|
||||||
|
|
||||||
if comm_inst.shutdown:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if len(comm_inst.onlinePeers) == 0:
|
|
||||||
logger.debug('Couldn\'t connect to any peers.' + (' Last node seen %s ago.' % humanreadabletime.human_readable_time(time.time() - comm_inst.lastNodeSeen) if not comm_inst.lastNodeSeen is None else ''), terminal=True)
|
|
||||||
else:
|
|
||||||
comm_inst.lastNodeSeen = time.time()
|
|
||||||
comm_inst.decrementThreadCount('get_online_peers')
|
|
@ -1,35 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
pick online peers in a communicator instance
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import secrets
|
|
||||||
def pick_online_peer(comm_inst):
|
|
||||||
'''randomly picks peer from pool without bias (using secrets module)'''
|
|
||||||
ret_data = ''
|
|
||||||
while True:
|
|
||||||
peer_length = len(comm_inst.onlinePeers)
|
|
||||||
if peer_length <= 0:
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
# get a random online peer, securely. May get stuck in loop if network is lost or if all peers in pool magically disconnect at once
|
|
||||||
ret_data = comm_inst.onlinePeers[secrets.randbelow(peer_length)]
|
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
return ret_data
|
|
@ -1,33 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
remove an online peer from the pool in a communicator instance
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
def remove_online_peer(comm_inst, peer):
|
|
||||||
'''Remove an online peer'''
|
|
||||||
try:
|
|
||||||
del comm_inst.connectTimes[peer]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
del comm_inst.dbTimestamps[peer]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
comm_inst.onlinePeers.remove(peer)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
@ -1,55 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
This file implements logic for performing requests to Onionr peers
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import streamedrequests
|
|
||||||
import logger
|
|
||||||
from onionrutils import epoch, basicrequests
|
|
||||||
from coredb import keydb
|
|
||||||
from . import onlinepeers
|
|
||||||
|
|
||||||
def peer_action(comm_inst, peer, action, returnHeaders=False, max_resp_size=5242880):
|
|
||||||
'''Perform a get request to a peer'''
|
|
||||||
penalty_score = -10
|
|
||||||
if len(peer) == 0:
|
|
||||||
return False
|
|
||||||
url = 'http://%s/%s' % (peer, action)
|
|
||||||
|
|
||||||
try:
|
|
||||||
ret_data = basicrequests.do_get_request(url, port=comm_inst.proxyPort,
|
|
||||||
max_size=max_resp_size)
|
|
||||||
except streamedrequests.exceptions.ResponseLimitReached:
|
|
||||||
logger.warn('Request failed due to max response size being overflowed', terminal=True)
|
|
||||||
ret_data = False
|
|
||||||
penalty_score = -100
|
|
||||||
# if request failed, (error), mark peer offline
|
|
||||||
if ret_data == False: # For some reason "if not" breaks this. Prob has to do with empty string.
|
|
||||||
try:
|
|
||||||
comm_inst.getPeerProfileInstance(peer).addScore(penalty_score)
|
|
||||||
onlinepeers.remove_online_peer(comm_inst, peer)
|
|
||||||
keydb.transportinfo.set_address_info(peer, 'lastConnectAttempt', epoch.get_epoch())
|
|
||||||
if action != 'ping' and not comm_inst.shutdown:
|
|
||||||
logger.warn(f'Lost connection to {peer}', terminal=True)
|
|
||||||
onlinepeers.get_online_peers(comm_inst) # Will only add a new peer to pool if needed
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
peer_profile = comm_inst.getPeerProfileInstance(peer)
|
|
||||||
peer_profile.update_connect_time()
|
|
||||||
peer_profile.addScore(1)
|
|
||||||
return ret_data # If returnHeaders, returns tuple of data, headers. if not, just data string
|
|
@ -1,60 +0,0 @@
|
|||||||
"""
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Class to remember blocks that need to be uploaded and not shared on startup/shutdown
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import atexit
|
|
||||||
import json
|
|
||||||
|
|
||||||
import deadsimplekv
|
|
||||||
|
|
||||||
import filepaths
|
|
||||||
from onionrutils import localcommand
|
|
||||||
|
|
||||||
UPLOAD_MEMORY_FILE = filepaths.upload_list
|
|
||||||
|
|
||||||
def _add_to_hidden_blocks(cache):
|
|
||||||
for bl in cache:
|
|
||||||
localcommand.local_command('waitforshare/' + bl, post=True)
|
|
||||||
|
|
||||||
class UploadQueue:
|
|
||||||
"""
|
|
||||||
Saves and loads block upload info from json file
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, communicator: 'OnionrCommunicatorDaemon'):
|
|
||||||
"""Start the UploadQueue object, loading left over uploads into queue
|
|
||||||
and registering save shutdown function
|
|
||||||
"""
|
|
||||||
self.communicator = communicator
|
|
||||||
cache = deadsimplekv.DeadSimpleKV(UPLOAD_MEMORY_FILE)
|
|
||||||
self.store_obj = cache
|
|
||||||
cache: list = cache.get('uploads')
|
|
||||||
if cache == None:
|
|
||||||
cache = []
|
|
||||||
|
|
||||||
_add_to_hidden_blocks(cache)
|
|
||||||
self.communicator.blocksToUpload.extend(cache)
|
|
||||||
|
|
||||||
atexit.register(self.save)
|
|
||||||
|
|
||||||
def save(self):
|
|
||||||
"""Saves to disk on shutdown or if called manually"""
|
|
||||||
bl: list = self.communicator.blocksToUpload
|
|
||||||
self.store_obj.put('uploads', bl)
|
|
||||||
self.store_obj.flush()
|
|
@ -1,33 +0,0 @@
|
|||||||
# communicatorutils
|
|
||||||
|
|
||||||
The files in this submodule handle various subtasks and utilities for the onionr communicator.
|
|
||||||
|
|
||||||
## Files:
|
|
||||||
|
|
||||||
announcenode.py: Uses a communicator instance to announce our transport address to connected nodes
|
|
||||||
|
|
||||||
connectnewpeers.py: takes a communicator instance and has it connect to as many peers as needed, and/or to a new specified peer.
|
|
||||||
|
|
||||||
cooldownpeer.py: randomly selects a connected peer in a communicator and disconnects them for the purpose of security and network balancing.
|
|
||||||
|
|
||||||
daemonqueuehandler.py: checks for new commands in the daemon queue and processes them accordingly.
|
|
||||||
|
|
||||||
deniableinserts.py: insert fake blocks with the communicator for plausible deniability
|
|
||||||
|
|
||||||
downloadblocks.py: iterates a communicator instance's block download queue and attempts to download the blocks from online peers
|
|
||||||
|
|
||||||
housekeeping.py: cleans old blocks and forward secrecy keys
|
|
||||||
|
|
||||||
lookupadders.py: ask connected peers to share their list of peer transport addresses
|
|
||||||
|
|
||||||
lookupblocks.py: lookup new blocks from connected peers from the communicator
|
|
||||||
|
|
||||||
netcheck.py: check if the node is online based on communicator status and onion server ping results
|
|
||||||
|
|
||||||
onionrcommunicataortimers.py: create a timer for a function to be launched on an interval. Control how many possible instances of a timer may be running a function at once and control if the timer should be ran in a thread or not.
|
|
||||||
|
|
||||||
proxypicker.py: returns a string name for the appropriate proxy to be used with a particular peer transport address.
|
|
||||||
|
|
||||||
servicecreator.py: iterate connection blocks and create new direct connection servers for them.
|
|
||||||
|
|
||||||
uploadblocks.py: iterate a communicator's upload queue and upload the blocks to connected peers
|
|
@ -1,86 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Use a communicator instance to announce our transport address to connected nodes
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import base64
|
|
||||||
import onionrproofs, logger
|
|
||||||
from etc import onionrvalues
|
|
||||||
from onionrutils import basicrequests, bytesconverter
|
|
||||||
from utils import gettransports
|
|
||||||
from netcontroller import NetController
|
|
||||||
from communicator import onlinepeers
|
|
||||||
from coredb import keydb
|
|
||||||
def announce_node(daemon):
|
|
||||||
'''Announce our node to our peers'''
|
|
||||||
ret_data = False
|
|
||||||
announce_fail = False
|
|
||||||
|
|
||||||
# Do not let announceCache get too large
|
|
||||||
if len(daemon.announceCache) >= 10000:
|
|
||||||
daemon.announceCache.popitem()
|
|
||||||
|
|
||||||
if daemon.config.get('general.security_level', 0) == 0:
|
|
||||||
# Announce to random online peers
|
|
||||||
for i in daemon.onlinePeers:
|
|
||||||
if not i in daemon.announceCache and not i in daemon.announceProgress:
|
|
||||||
peer = i
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
peer = onlinepeers.pick_online_peer(daemon)
|
|
||||||
|
|
||||||
for x in range(1):
|
|
||||||
try:
|
|
||||||
ourID = gettransports.get()[0]
|
|
||||||
except IndexError:
|
|
||||||
break
|
|
||||||
|
|
||||||
url = 'http://' + peer + '/announce'
|
|
||||||
data = {'node': ourID}
|
|
||||||
|
|
||||||
combinedNodes = ourID + peer
|
|
||||||
if ourID != 1:
|
|
||||||
existingRand = bytesconverter.bytes_to_str(keydb.transportinfo.get_address_info(peer, 'powValue'))
|
|
||||||
# Reset existingRand if it no longer meets the minimum POW
|
|
||||||
if type(existingRand) is type(None) or not existingRand.endswith('0' * onionrvalues.ANNOUNCE_POW):
|
|
||||||
existingRand = ''
|
|
||||||
|
|
||||||
if peer in daemon.announceCache:
|
|
||||||
data['random'] = daemon.announceCache[peer]
|
|
||||||
elif len(existingRand) > 0:
|
|
||||||
data['random'] = existingRand
|
|
||||||
else:
|
|
||||||
daemon.announceProgress[peer] = True
|
|
||||||
proof = onionrproofs.DataPOW(combinedNodes, minDifficulty=onionrvalues.ANNOUNCE_POW)
|
|
||||||
del daemon.announceProgress[peer]
|
|
||||||
try:
|
|
||||||
data['random'] = base64.b64encode(proof.waitForResult()[1])
|
|
||||||
except TypeError:
|
|
||||||
# Happens when we failed to produce a proof
|
|
||||||
logger.error("Failed to produce a pow for announcing to " + peer)
|
|
||||||
announce_fail = True
|
|
||||||
else:
|
|
||||||
daemon.announceCache[peer] = data['random']
|
|
||||||
if not announce_fail:
|
|
||||||
logger.info('Announcing node to ' + url)
|
|
||||||
if basicrequests.do_post_request(url, data, port=daemon.shared_state.get(NetController).socksPort) == 'Success':
|
|
||||||
logger.info('Successfully introduced node to ' + peer, terminal=True)
|
|
||||||
ret_data = True
|
|
||||||
keydb.transportinfo.set_address_info(peer, 'introduced', 1)
|
|
||||||
keydb.transportinfo.set_address_info(peer, 'powValue', data['random'])
|
|
||||||
daemon.decrementThreadCount('announce_node')
|
|
||||||
return ret_data
|
|
@ -1,91 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Connect a new peer to our communicator instance. Does so randomly if no peer is specified
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import time, sys, secrets
|
|
||||||
import onionrexceptions, logger, onionrpeers
|
|
||||||
from utils import networkmerger, gettransports
|
|
||||||
from onionrutils import stringvalidators, epoch
|
|
||||||
from communicator import peeraction, bootstrappeers
|
|
||||||
from coredb import keydb
|
|
||||||
def connect_new_peer_to_communicator(comm_inst, peer='', useBootstrap=False):
|
|
||||||
config = comm_inst.config
|
|
||||||
retData = False
|
|
||||||
tried = comm_inst.offlinePeers
|
|
||||||
transports = gettransports.get()
|
|
||||||
if peer != '':
|
|
||||||
if stringvalidators.validate_transport(peer):
|
|
||||||
peerList = [peer]
|
|
||||||
else:
|
|
||||||
raise onionrexceptions.InvalidAddress('Will not attempt connection test to invalid address')
|
|
||||||
else:
|
|
||||||
peerList = keydb.listkeys.list_adders()
|
|
||||||
|
|
||||||
mainPeerList = keydb.listkeys.list_adders()
|
|
||||||
peerList = onionrpeers.get_score_sorted_peer_list()
|
|
||||||
|
|
||||||
# If we don't have enough peers connected or random chance, select new peers to try
|
|
||||||
if len(peerList) < 8 or secrets.randbelow(4) == 3:
|
|
||||||
tryingNew = []
|
|
||||||
for x in comm_inst.newPeers:
|
|
||||||
if x not in peerList:
|
|
||||||
peerList.append(x)
|
|
||||||
tryingNew.append(x)
|
|
||||||
for i in tryingNew:
|
|
||||||
comm_inst.newPeers.remove(i)
|
|
||||||
|
|
||||||
if len(peerList) == 0 or useBootstrap:
|
|
||||||
# Avoid duplicating bootstrap addresses in peerList
|
|
||||||
bootstrappeers.add_bootstrap_list_to_peer_list(comm_inst, peerList)
|
|
||||||
|
|
||||||
for address in peerList:
|
|
||||||
if not config.get('tor.v3onions') and len(address) == 62:
|
|
||||||
continue
|
|
||||||
# Don't connect to our own address
|
|
||||||
if address in transports:
|
|
||||||
continue
|
|
||||||
# Don't connect to invalid address or if its already been tried/connected, or if its cooled down
|
|
||||||
if len(address) == 0 or address in tried or address in comm_inst.onlinePeers or address in comm_inst.cooldownPeer:
|
|
||||||
continue
|
|
||||||
if comm_inst.shutdown:
|
|
||||||
return
|
|
||||||
# Ping a peer,
|
|
||||||
ret = peeraction.peer_action(comm_inst, address, 'ping')
|
|
||||||
if ret == 'pong!':
|
|
||||||
time.sleep(0.1)
|
|
||||||
if address not in mainPeerList:
|
|
||||||
# Add a peer to our list if it isn't already since it successfully connected
|
|
||||||
networkmerger.mergeAdders(address)
|
|
||||||
if address not in comm_inst.onlinePeers:
|
|
||||||
logger.info('Connected to ' + address, terminal=True)
|
|
||||||
comm_inst.onlinePeers.append(address)
|
|
||||||
comm_inst.connectTimes[address] = epoch.get_epoch()
|
|
||||||
retData = address
|
|
||||||
|
|
||||||
# add peer to profile list if they're not in it
|
|
||||||
for profile in comm_inst.peerProfiles:
|
|
||||||
if profile.address == address:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
comm_inst.peerProfiles.append(onionrpeers.PeerProfiles(address))
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# Mark a peer as tried if they failed to respond to ping
|
|
||||||
tried.append(address)
|
|
||||||
logger.debug('Failed to connect to %s: %s ' % (address, ret))
|
|
||||||
return retData
|
|
@ -1,54 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Select a random online peer in a communicator instance and have them "cool down"
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
from onionrutils import epoch
|
|
||||||
from communicator import onlinepeers
|
|
||||||
def cooldown_peer(comm_inst):
|
|
||||||
'''Randomly add an online peer to cooldown, so we can connect a new one'''
|
|
||||||
config = comm_inst.config
|
|
||||||
onlinePeerAmount = len(comm_inst.onlinePeers)
|
|
||||||
minTime = 300
|
|
||||||
cooldownTime = 600
|
|
||||||
toCool = ''
|
|
||||||
tempConnectTimes = dict(comm_inst.connectTimes)
|
|
||||||
|
|
||||||
# Remove peers from cooldown that have been there long enough
|
|
||||||
tempCooldown = dict(comm_inst.cooldownPeer)
|
|
||||||
for peer in tempCooldown:
|
|
||||||
if (epoch.get_epoch() - tempCooldown[peer]) >= cooldownTime:
|
|
||||||
del comm_inst.cooldownPeer[peer]
|
|
||||||
|
|
||||||
# Cool down a peer, if we have max connections alive for long enough
|
|
||||||
if onlinePeerAmount >= config.get('peers.max_connect', 10, save = True):
|
|
||||||
finding = True
|
|
||||||
|
|
||||||
while finding:
|
|
||||||
try:
|
|
||||||
toCool = min(tempConnectTimes, key=tempConnectTimes.get)
|
|
||||||
if (epoch.get_epoch() - tempConnectTimes[toCool]) < minTime:
|
|
||||||
del tempConnectTimes[toCool]
|
|
||||||
else:
|
|
||||||
finding = False
|
|
||||||
except ValueError:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
onlinepeers.remove_online_peer(comm_inst, toCool)
|
|
||||||
comm_inst.cooldownPeer[toCool] = epoch.get_epoch()
|
|
||||||
|
|
||||||
comm_inst.decrementThreadCount('cooldown_peer')
|
|
@ -1,71 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - P2P Anonymous Storage Network
|
|
||||||
|
|
||||||
Handle daemon queue commands in the communicator
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import logger
|
|
||||||
import onionrevents as events
|
|
||||||
from onionrutils import localcommand
|
|
||||||
from coredb import daemonqueue
|
|
||||||
import filepaths
|
|
||||||
from . import restarttor
|
|
||||||
def handle_daemon_commands(comm_inst):
|
|
||||||
cmd = daemonqueue.daemon_queue()
|
|
||||||
response = ''
|
|
||||||
if cmd is not False:
|
|
||||||
events.event('daemon_command', data = {'cmd' : cmd})
|
|
||||||
if cmd[0] == 'shutdown':
|
|
||||||
comm_inst.shutdown = True
|
|
||||||
elif cmd[0] == 'remove_from_insert_list':
|
|
||||||
try:
|
|
||||||
comm_inst.generating_blocks.remove(cmd[1])
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
elif cmd[0] == 'announceNode':
|
|
||||||
if len(comm_inst.onlinePeers) > 0:
|
|
||||||
comm_inst.announce(cmd[1])
|
|
||||||
else:
|
|
||||||
logger.debug("No nodes connected. Will not introduce node.")
|
|
||||||
elif cmd[0] == 'runCheck': # deprecated
|
|
||||||
logger.debug('Status check; looks good.')
|
|
||||||
open(filepaths.run_check_file + '.runcheck', 'w+').close()
|
|
||||||
elif cmd[0] == 'connectedPeers':
|
|
||||||
response = '\n'.join(list(comm_inst.onlinePeers)).strip()
|
|
||||||
if response == '':
|
|
||||||
response = 'none'
|
|
||||||
elif cmd[0] == 'localCommand':
|
|
||||||
response = localcommand.local_command(cmd[1])
|
|
||||||
elif cmd[0] == 'clearOffline':
|
|
||||||
comm_inst.offlinePeers = []
|
|
||||||
elif cmd[0] == 'restartTor':
|
|
||||||
restarttor.restart(comm_inst)
|
|
||||||
comm_inst.offlinePeers = []
|
|
||||||
elif cmd[0] == 'pex':
|
|
||||||
for i in comm_inst.timers:
|
|
||||||
if i.timerFunction.__name__ == 'lookupAdders':
|
|
||||||
i.count = (i.frequency - 1)
|
|
||||||
elif cmd[0] == 'uploadBlock':
|
|
||||||
comm_inst.blocksToUpload.append(cmd[1])
|
|
||||||
else:
|
|
||||||
logger.debug('Received daemon queue command unable to be handled: %s' % (cmd[0],))
|
|
||||||
|
|
||||||
if cmd[0] not in ('', None):
|
|
||||||
if response != '':
|
|
||||||
localcommand.local_command('queueResponseAdd/' + cmd[4], post=True, postData={'data': response})
|
|
||||||
response = ''
|
|
||||||
|
|
||||||
comm_inst.decrementThreadCount('handle_daemon_commands')
|
|
@ -1,32 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Use the communicator to insert fake mail messages
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import secrets
|
|
||||||
from etc import onionrvalues
|
|
||||||
import onionrblocks
|
|
||||||
def insert_deniable_block(comm_inst):
|
|
||||||
'''Insert a fake block in order to make it more difficult to track real blocks'''
|
|
||||||
fakePeer = ''
|
|
||||||
chance = 10
|
|
||||||
if secrets.randbelow(chance) == (chance - 1):
|
|
||||||
# This assumes on the libsodium primitives to have key-privacy
|
|
||||||
fakePeer = onionrvalues.DENIABLE_PEER_ADDRESS
|
|
||||||
data = secrets.token_hex(secrets.randbelow(1024) + 1)
|
|
||||||
onionrblocks.insert(data, header='pm', encryptType='asym', asymPeer=fakePeer, disableForward=True, meta={'subject': 'foo'})
|
|
||||||
comm_inst.decrementThreadCount('insert_deniable_block')
|
|
@ -1,132 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Download blocks using the communicator instance
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import communicator, onionrexceptions
|
|
||||||
import logger, onionrpeers
|
|
||||||
from onionrutils import blockmetadata, stringvalidators, validatemetadata
|
|
||||||
from coredb import blockmetadb
|
|
||||||
from . import shoulddownload
|
|
||||||
from communicator import peeraction, onlinepeers
|
|
||||||
import onionrcrypto, onionrstorage, onionrblacklist, storagecounter
|
|
||||||
def download_blocks_from_communicator(comm_inst):
|
|
||||||
'''Use Onionr communicator instance to download blocks in the communicator's queue'''
|
|
||||||
assert isinstance(comm_inst, communicator.OnionrCommunicatorDaemon)
|
|
||||||
blacklist = onionrblacklist.OnionrBlackList()
|
|
||||||
storage_counter = storagecounter.StorageCounter()
|
|
||||||
LOG_SKIP_COUNT = 50 # for how many iterations we skip logging the counter
|
|
||||||
count: int = 0
|
|
||||||
metadata_validation_result: bool = False
|
|
||||||
# Iterate the block queue in the communicator
|
|
||||||
for blockHash in list(comm_inst.blockQueue):
|
|
||||||
count += 1
|
|
||||||
if len(comm_inst.onlinePeers) == 0:
|
|
||||||
break
|
|
||||||
triedQueuePeers = [] # List of peers we've tried for a block
|
|
||||||
try:
|
|
||||||
blockPeers = list(comm_inst.blockQueue[blockHash])
|
|
||||||
except KeyError:
|
|
||||||
blockPeers = []
|
|
||||||
removeFromQueue = True
|
|
||||||
|
|
||||||
if not shoulddownload.should_download(comm_inst, blockHash):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if comm_inst.shutdown or not comm_inst.isOnline or storage_counter.is_full():
|
|
||||||
# Exit loop if shutting down or offline, or disk allocation reached
|
|
||||||
break
|
|
||||||
# Do not download blocks being downloaded
|
|
||||||
if blockHash in comm_inst.currentDownloading:
|
|
||||||
#logger.debug('Already downloading block %s...' % blockHash)
|
|
||||||
continue
|
|
||||||
|
|
||||||
comm_inst.currentDownloading.append(blockHash) # So we can avoid concurrent downloading in other threads of same block
|
|
||||||
if len(blockPeers) == 0:
|
|
||||||
peerUsed = onlinepeers.pick_online_peer(comm_inst)
|
|
||||||
else:
|
|
||||||
blockPeers = onionrcrypto.cryptoutils.random_shuffle(blockPeers)
|
|
||||||
peerUsed = blockPeers.pop(0)
|
|
||||||
|
|
||||||
if not comm_inst.shutdown and peerUsed.strip() != '':
|
|
||||||
logger.info("Attempting to download %s from %s..." % (blockHash[:12], peerUsed))
|
|
||||||
content = peeraction.peer_action(comm_inst, peerUsed, 'getdata/' + blockHash, max_resp_size=3000000) # block content from random peer (includes metadata)
|
|
||||||
|
|
||||||
if content != False and len(content) > 0:
|
|
||||||
try:
|
|
||||||
content = content.encode()
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
realHash = onionrcrypto.hashers.sha3_hash(content)
|
|
||||||
try:
|
|
||||||
realHash = realHash.decode() # bytes on some versions for some reason
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
if realHash == blockHash:
|
|
||||||
#content = content.decode() # decode here because sha3Hash needs bytes above
|
|
||||||
metas = blockmetadata.get_block_metadata_from_data(content) # returns tuple(metadata, meta), meta is also in metadata
|
|
||||||
metadata = metas[0]
|
|
||||||
try:
|
|
||||||
metadata_validation_result = validatemetadata.validate_metadata(metadata, metas[2])
|
|
||||||
except onionrexceptions.DataExists:
|
|
||||||
metadata_validation_result = False
|
|
||||||
if metadata_validation_result: # check if metadata is valid, and verify nonce
|
|
||||||
if onionrcrypto.cryptoutils.verify_POW(content): # check if POW is enough/correct
|
|
||||||
logger.info('Attempting to save block %s...' % blockHash[:12])
|
|
||||||
try:
|
|
||||||
onionrstorage.set_data(content)
|
|
||||||
except onionrexceptions.DataExists:
|
|
||||||
logger.warn('Data is already set for %s ' % (blockHash,))
|
|
||||||
except onionrexceptions.DiskAllocationReached:
|
|
||||||
logger.error('Reached disk allocation allowance, cannot save block %s.' % (blockHash,))
|
|
||||||
removeFromQueue = False
|
|
||||||
else:
|
|
||||||
blockmetadb.add_to_block_DB(blockHash, dataSaved=True) # add block to meta db
|
|
||||||
blockmetadata.process_block_metadata(blockHash) # caches block metadata values to block database
|
|
||||||
else:
|
|
||||||
logger.warn('POW failed for block %s.' % (blockHash,))
|
|
||||||
else:
|
|
||||||
if blacklist.inBlacklist(realHash):
|
|
||||||
logger.warn('Block %s is blacklisted.' % (realHash,))
|
|
||||||
else:
|
|
||||||
logger.warn('Metadata for block %s is invalid.' % (blockHash,))
|
|
||||||
blacklist.addToDB(blockHash)
|
|
||||||
else:
|
|
||||||
# if block didn't meet expected hash
|
|
||||||
tempHash = onionrcrypto.hashers.sha3_hash(content) # lazy hack, TODO use var
|
|
||||||
try:
|
|
||||||
tempHash = tempHash.decode()
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
# Punish peer for sharing invalid block (not always malicious, but is bad regardless)
|
|
||||||
onionrpeers.PeerProfiles(peerUsed).addScore(-50)
|
|
||||||
if tempHash != 'ed55e34cb828232d6c14da0479709bfa10a0923dca2b380496e6b2ed4f7a0253':
|
|
||||||
# Dumb hack for 404 response from peer. Don't log it if 404 since its likely not malicious or a critical error.
|
|
||||||
logger.warn('Block hash validation failed for ' + blockHash + ' got ' + tempHash)
|
|
||||||
else:
|
|
||||||
removeFromQueue = False # Don't remove from queue if 404
|
|
||||||
if removeFromQueue:
|
|
||||||
try:
|
|
||||||
del comm_inst.blockQueue[blockHash] # remove from block queue both if success or false
|
|
||||||
if count == LOG_SKIP_COUNT:
|
|
||||||
logger.info('%s blocks remaining in queue' % [len(comm_inst.blockQueue)], terminal=True)
|
|
||||||
count = 0
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
comm_inst.currentDownloading.remove(blockHash)
|
|
||||||
comm_inst.decrementThreadCount('getBlocks')
|
|
@ -1,36 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Check if a block should be downloaded (if we already have it or its blacklisted or not)
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
from coredb import blockmetadb
|
|
||||||
import onionrblacklist
|
|
||||||
def should_download(comm_inst, block_hash):
|
|
||||||
blacklist = onionrblacklist.OnionrBlackList()
|
|
||||||
ret_data = True
|
|
||||||
if block_hash in blockmetadb.get_block_list(): # Dont download block we have
|
|
||||||
ret_data = False
|
|
||||||
else:
|
|
||||||
if blacklist.inBlacklist(block_hash): # Dont download blacklisted block
|
|
||||||
ret_data = False
|
|
||||||
if ret_data is False:
|
|
||||||
# Remove block from communicator queue if it shouldnt be downloaded
|
|
||||||
try:
|
|
||||||
del comm_inst.blockQueue[block_hash]
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
return ret_data
|
|
@ -1,75 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Cleanup old Onionr blocks and forward secrecy keys using the communicator. Ran from a timer usually
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import sqlite3
|
|
||||||
import logger
|
|
||||||
from onionrusers import onionrusers
|
|
||||||
from onionrutils import epoch
|
|
||||||
from coredb import blockmetadb, dbfiles
|
|
||||||
import onionrstorage
|
|
||||||
from onionrstorage import removeblock
|
|
||||||
import onionrblacklist
|
|
||||||
|
|
||||||
def __remove_from_upload(comm_inst, block_hash: str):
|
|
||||||
try:
|
|
||||||
comm_inst.blocksToUpload.remove(block_hash)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def clean_old_blocks(comm_inst):
|
|
||||||
'''Delete old blocks if our disk allocation is full/near full, and also expired blocks'''
|
|
||||||
blacklist = onionrblacklist.OnionrBlackList()
|
|
||||||
# Delete expired blocks
|
|
||||||
for bHash in blockmetadb.expiredblocks.get_expired_blocks():
|
|
||||||
blacklist.addToDB(bHash)
|
|
||||||
removeblock.remove_block(bHash)
|
|
||||||
onionrstorage.deleteBlock(bHash)
|
|
||||||
__remove_from_upload(comm_inst, bHash)
|
|
||||||
logger.info('Deleted block: %s' % (bHash,))
|
|
||||||
|
|
||||||
while comm_inst.storage_counter.is_full():
|
|
||||||
oldest = blockmetadb.get_block_list()[0]
|
|
||||||
blacklist.addToDB(oldest)
|
|
||||||
removeblock.remove_block(oldest)
|
|
||||||
onionrstorage.deleteBlock(oldest)
|
|
||||||
__remove_from_upload.remove(comm_inst, oldest)
|
|
||||||
logger.info('Deleted block: %s' % (oldest,))
|
|
||||||
|
|
||||||
comm_inst.decrementThreadCount('clean_old_blocks')
|
|
||||||
|
|
||||||
def clean_keys(comm_inst):
|
|
||||||
'''Delete expired forward secrecy keys'''
|
|
||||||
conn = sqlite3.connect(dbfiles.user_id_info_db, timeout=10)
|
|
||||||
c = conn.cursor()
|
|
||||||
time = epoch.get_epoch()
|
|
||||||
deleteKeys = []
|
|
||||||
|
|
||||||
for entry in c.execute("SELECT * FROM forwardKeys WHERE expire <= ?", (time,)):
|
|
||||||
logger.debug('Forward key: %s' % entry[1])
|
|
||||||
deleteKeys.append(entry[1])
|
|
||||||
|
|
||||||
for key in deleteKeys:
|
|
||||||
logger.debug('Deleting forward key %s' % key)
|
|
||||||
c.execute("DELETE from forwardKeys where forwardKey = ?", (key,))
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
onionrusers.deleteExpiredKeys()
|
|
||||||
|
|
||||||
comm_inst.decrementThreadCount('clean_keys')
|
|
@ -1,55 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Lookup new peer transport addresses using the communicator
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import logger
|
|
||||||
from onionrutils import stringvalidators
|
|
||||||
from communicator import peeraction, onlinepeers
|
|
||||||
from utils import gettransports
|
|
||||||
def lookup_new_peer_transports_with_communicator(comm_inst):
|
|
||||||
logger.info('Looking up new addresses...')
|
|
||||||
tryAmount = 1
|
|
||||||
newPeers = []
|
|
||||||
transports = gettransports.get()
|
|
||||||
|
|
||||||
for i in range(tryAmount):
|
|
||||||
# Download new peer address list from random online peers
|
|
||||||
if len(newPeers) > 10000:
|
|
||||||
# Don't get new peers if we have too many queued up
|
|
||||||
break
|
|
||||||
peer = onlinepeers.pick_online_peer(comm_inst)
|
|
||||||
newAdders = peeraction.peer_action(comm_inst, peer, action='pex')
|
|
||||||
try:
|
|
||||||
newPeers = newAdders.split(',')
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
# Validate new peers are good format and not already in queue
|
|
||||||
invalid = []
|
|
||||||
for x in newPeers:
|
|
||||||
x = x.strip()
|
|
||||||
if not stringvalidators.validate_transport(x) or x in comm_inst.newPeers or x in transports:
|
|
||||||
# avoid adding if its our address
|
|
||||||
invalid.append(x)
|
|
||||||
for x in invalid:
|
|
||||||
try:
|
|
||||||
newPeers.remove(x)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
comm_inst.newPeers.extend(newPeers)
|
|
||||||
comm_inst.decrementThreadCount('lookup_new_peer_transports_with_communicator')
|
|
@ -1,94 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Lookup new blocks with the communicator using a random connected peer
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import logger, onionrproofs
|
|
||||||
from onionrutils import stringvalidators, epoch
|
|
||||||
from communicator import peeraction, onlinepeers
|
|
||||||
from coredb import blockmetadb
|
|
||||||
from utils import reconstructhash
|
|
||||||
import onionrblacklist
|
|
||||||
blacklist = onionrblacklist.OnionrBlackList()
|
|
||||||
def lookup_blocks_from_communicator(comm_inst):
|
|
||||||
logger.info('Looking up new blocks')
|
|
||||||
tryAmount = 2
|
|
||||||
newBlocks = ''
|
|
||||||
existingBlocks = blockmetadb.get_block_list() # List of existing saved blocks
|
|
||||||
triedPeers = [] # list of peers we've tried this time around
|
|
||||||
maxBacklog = 1560 # Max amount of *new* block hashes to have already in queue, to avoid memory exhaustion
|
|
||||||
lastLookupTime = 0 # Last time we looked up a particular peer's list
|
|
||||||
new_block_count = 0
|
|
||||||
for i in range(tryAmount):
|
|
||||||
listLookupCommand = 'getblocklist' # This is defined here to reset it each time
|
|
||||||
if len(comm_inst.blockQueue) >= maxBacklog:
|
|
||||||
break
|
|
||||||
if not comm_inst.isOnline:
|
|
||||||
break
|
|
||||||
# check if disk allocation is used
|
|
||||||
if comm_inst.storage_counter.is_full():
|
|
||||||
logger.debug('Not looking up new blocks due to maximum amount of allowed disk space used')
|
|
||||||
break
|
|
||||||
peer = onlinepeers.pick_online_peer(comm_inst) # select random online peer
|
|
||||||
# if we've already tried all the online peers this time around, stop
|
|
||||||
if peer in triedPeers:
|
|
||||||
if len(comm_inst.onlinePeers) == len(triedPeers):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
triedPeers.append(peer)
|
|
||||||
|
|
||||||
# Get the last time we looked up a peer's stamp to only fetch blocks since then.
|
|
||||||
# Saved in memory only for privacy reasons
|
|
||||||
try:
|
|
||||||
lastLookupTime = comm_inst.dbTimestamps[peer]
|
|
||||||
except KeyError:
|
|
||||||
lastLookupTime = 0
|
|
||||||
else:
|
|
||||||
listLookupCommand += '?date=%s' % (lastLookupTime,)
|
|
||||||
try:
|
|
||||||
newBlocks = peeraction.peer_action(comm_inst, peer, listLookupCommand) # get list of new block hashes
|
|
||||||
except Exception as error:
|
|
||||||
logger.warn('Could not get new blocks from %s.' % peer, error = error)
|
|
||||||
newBlocks = False
|
|
||||||
else:
|
|
||||||
comm_inst.dbTimestamps[peer] = epoch.get_rounded_epoch(roundS=60)
|
|
||||||
if newBlocks != False:
|
|
||||||
# if request was a success
|
|
||||||
for i in newBlocks.split('\n'):
|
|
||||||
if stringvalidators.validate_hash(i):
|
|
||||||
i = reconstructhash.reconstruct_hash(i)
|
|
||||||
# if newline seperated string is valid hash
|
|
||||||
if not i in existingBlocks:
|
|
||||||
# if block does not exist on disk and is not already in block queue
|
|
||||||
if i not in comm_inst.blockQueue:
|
|
||||||
if onionrproofs.hashMeetsDifficulty(i) and not blacklist.inBlacklist(i):
|
|
||||||
if len(comm_inst.blockQueue) <= 1000000:
|
|
||||||
comm_inst.blockQueue[i] = [peer] # add blocks to download queue
|
|
||||||
new_block_count += 1
|
|
||||||
else:
|
|
||||||
if peer not in comm_inst.blockQueue[i]:
|
|
||||||
if len(comm_inst.blockQueue[i]) < 10:
|
|
||||||
comm_inst.blockQueue[i].append(peer)
|
|
||||||
if new_block_count > 0:
|
|
||||||
block_string = ""
|
|
||||||
if new_block_count > 1:
|
|
||||||
block_string = "s"
|
|
||||||
logger.info('Discovered %s new block%s' % (new_block_count, block_string), terminal=True)
|
|
||||||
comm_inst.download_blocks_timer.count = int(comm_inst.download_blocks_timer.frequency * 0.99)
|
|
||||||
comm_inst.decrementThreadCount('lookup_blocks_from_communicator')
|
|
||||||
return
|
|
@ -1,43 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Determine if our node is able to use Tor based on the status of a communicator instance
|
|
||||||
and the result of pinging onion http servers
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import logger
|
|
||||||
from utils import netutils
|
|
||||||
from onionrutils import localcommand, epoch
|
|
||||||
from . import restarttor
|
|
||||||
def net_check(comm_inst):
|
|
||||||
'''Check if we are connected to the internet or not when we can't connect to any peers'''
|
|
||||||
rec = False # for detecting if we have received incoming connections recently
|
|
||||||
if len(comm_inst.onlinePeers) == 0:
|
|
||||||
try:
|
|
||||||
if (epoch.get_epoch() - int(localcommand.local_command('/lastconnect'))) <= 60:
|
|
||||||
comm_inst.isOnline = True
|
|
||||||
rec = True
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
if not rec and not netutils.checkNetwork(torPort=comm_inst.proxyPort):
|
|
||||||
if not comm_inst.shutdown:
|
|
||||||
logger.warn('Network check failed, are you connected to the Internet, and is Tor working?', terminal=True)
|
|
||||||
restarttor.restart(comm_inst)
|
|
||||||
comm_inst.offlinePeers = []
|
|
||||||
comm_inst.isOnline = False
|
|
||||||
else:
|
|
||||||
comm_inst.isOnline = True
|
|
||||||
comm_inst.decrementThreadCount('net_check')
|
|
@ -1,79 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
This file contains timer control for the communicator
|
|
||||||
'''
|
|
||||||
from __future__ import annotations # thank you python, very cool
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import onionrexceptions, logger
|
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
from typing import Callable, NewType, Iterable
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from communicator import OnionrCommunicatorDaemon
|
|
||||||
|
|
||||||
CallFreqSeconds = NewType('CallFreqSeconds', int)
|
|
||||||
|
|
||||||
class OnionrCommunicatorTimers:
|
|
||||||
def __init__(self, daemon_inst: OnionrCommunicatorDaemon,
|
|
||||||
timer_function: Callable, frequency: CallFreqSeconds,
|
|
||||||
make_thread:bool=True, thread_amount:int=1, max_threads:int=5,
|
|
||||||
requires_peer:bool=False, my_args:Iterable=[]):
|
|
||||||
self.timer_function = timer_function
|
|
||||||
self.frequency = frequency
|
|
||||||
self.thread_amount = thread_amount
|
|
||||||
self.make_thread = make_thread
|
|
||||||
self.requires_peer = requires_peer
|
|
||||||
self.daemon_inst = daemon_inst
|
|
||||||
self.max_threads = max_threads
|
|
||||||
self.args = my_args
|
|
||||||
|
|
||||||
self.daemon_inst.timers.append(self)
|
|
||||||
self.count = 0
|
|
||||||
|
|
||||||
def processTimer(self):
|
|
||||||
|
|
||||||
# mark how many instances of a thread we have (decremented at thread end)
|
|
||||||
try:
|
|
||||||
self.daemon_inst.threadCounts[self.timer_function.__name__]
|
|
||||||
except KeyError:
|
|
||||||
self.daemon_inst.threadCounts[self.timer_function.__name__] = 0
|
|
||||||
|
|
||||||
# execute thread if it is time, and we are not missing *required* online peer
|
|
||||||
if self.count == self.frequency and not self.daemon_inst.shutdown:
|
|
||||||
try:
|
|
||||||
if self.requires_peer and len(self.daemon_inst.onlinePeers) == 0:
|
|
||||||
raise onionrexceptions.OnlinePeerNeeded
|
|
||||||
except onionrexceptions.OnlinePeerNeeded:
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
if self.make_thread:
|
|
||||||
for i in range(self.thread_amount):
|
|
||||||
if self.daemon_inst.threadCounts[self.timer_function.__name__] >= self.max_threads:
|
|
||||||
logger.debug('%s is currently using the maximum number of threads, not starting another.' % self.timer_function.__name__, terminal=True)
|
|
||||||
else:
|
|
||||||
self.daemon_inst.threadCounts[self.timer_function.__name__] += 1
|
|
||||||
newThread = threading.Thread(target=self.timer_function, args=self.args, daemon=True,
|
|
||||||
name=self.timer_function.__name__ + ' - ' + str(uuid.uuid4()))
|
|
||||||
newThread.start()
|
|
||||||
else:
|
|
||||||
self.timer_function()
|
|
||||||
self.count = -1 # negative 1 because its incremented at bottom
|
|
||||||
self.count += 1
|
|
@ -1,26 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Just picks a proxy to use based on a peer's address
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
|
|
||||||
def pick_proxy(peer_address):
|
|
||||||
if peer_address.endswith('.onion'):
|
|
||||||
return 'tor'
|
|
||||||
elif peer_address.endswith('.i2p'):
|
|
||||||
return 'i2p'
|
|
||||||
raise ValueError("Peer address was not string ending with acceptable value")
|
|
@ -1,5 +0,0 @@
|
|||||||
import netcontroller
|
|
||||||
def restart(comm_inst):
|
|
||||||
net = comm_inst.shared_state.get(netcontroller.NetController)
|
|
||||||
net.killTor()
|
|
||||||
net.startTor()
|
|
@ -1,44 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Creates an onionr direct connection service by scanning all connection blocks
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import communicator, onionrblockapi
|
|
||||||
import logger
|
|
||||||
from onionrutils import stringvalidators, bytesconverter
|
|
||||||
from coredb import blockmetadb
|
|
||||||
from onionrservices import server_exists
|
|
||||||
def service_creator(daemon):
|
|
||||||
assert isinstance(daemon, communicator.OnionrCommunicatorDaemon)
|
|
||||||
|
|
||||||
# Find socket connection blocks
|
|
||||||
# TODO cache blocks and only look at recently received ones
|
|
||||||
con_blocks = blockmetadb.get_blocks_by_type('con')
|
|
||||||
for b in con_blocks:
|
|
||||||
if not b in daemon.active_services:
|
|
||||||
bl = onionrblockapi.Block(b, decrypt=True)
|
|
||||||
bs = bytesconverter.bytes_to_str(bl.bcontent) + '.onion'
|
|
||||||
if server_exists(bl.signer):
|
|
||||||
continue
|
|
||||||
if stringvalidators.validate_pub_key(bl.signer) and stringvalidators.validate_transport(bs):
|
|
||||||
signer = bytesconverter.bytes_to_str(bl.signer)
|
|
||||||
daemon.active_services.append(b)
|
|
||||||
daemon.active_services.append(signer)
|
|
||||||
if not daemon.services.create_server(signer, bs, daemon):
|
|
||||||
daemon.active_services.remove(b)
|
|
||||||
daemon.active_services.remove(signer)
|
|
||||||
daemon.decrementThreadCount('service_creator')
|
|
@ -1,92 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Upload blocks in the upload queue to peers from the communicator
|
|
||||||
'''
|
|
||||||
from __future__ import annotations
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
from typing import Union, TYPE_CHECKING
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import logger
|
|
||||||
from communicatorutils import proxypicker
|
|
||||||
import onionrexceptions
|
|
||||||
import onionrblockapi as block
|
|
||||||
from onionrutils import localcommand, stringvalidators, basicrequests
|
|
||||||
from communicator import onlinepeers
|
|
||||||
import onionrcrypto
|
|
||||||
from . import sessionmanager
|
|
||||||
|
|
||||||
def upload_blocks_from_communicator(comm_inst: OnionrCommunicatorDaemon):
|
|
||||||
"""Accepts a communicator instance and uploads blocks from its upload queue"""
|
|
||||||
"""when inserting a block, we try to upload
|
|
||||||
it to a few peers to add some deniability & increase functionality"""
|
|
||||||
TIMER_NAME = "upload_blocks_from_communicator"
|
|
||||||
|
|
||||||
session_manager: sessionmanager.BlockUploadSessionManager = comm_inst.shared_state.get(sessionmanager.BlockUploadSessionManager)
|
|
||||||
triedPeers = []
|
|
||||||
finishedUploads = []
|
|
||||||
comm_inst.blocksToUpload = onionrcrypto.cryptoutils.random_shuffle(comm_inst.blocksToUpload)
|
|
||||||
if len(comm_inst.blocksToUpload) != 0:
|
|
||||||
for bl in comm_inst.blocksToUpload:
|
|
||||||
if not stringvalidators.validate_hash(bl):
|
|
||||||
logger.warn('Requested to upload invalid block', terminal=True)
|
|
||||||
comm_inst.decrementThreadCount(TIMER_NAME)
|
|
||||||
return
|
|
||||||
session = session_manager.add_session(bl)
|
|
||||||
for i in range(min(len(comm_inst.onlinePeers), 6)):
|
|
||||||
peer = onlinepeers.pick_online_peer(comm_inst)
|
|
||||||
try:
|
|
||||||
session.peer_exists[peer]
|
|
||||||
continue
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
if session.peer_fails[peer] > 3: continue
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
if peer in triedPeers: continue
|
|
||||||
triedPeers.append(peer)
|
|
||||||
url = f'http://{peer}/upload'
|
|
||||||
try:
|
|
||||||
data = block.Block(bl).getRaw()
|
|
||||||
except onionrexceptions.NoDataAvailable:
|
|
||||||
finishedUploads.append(bl)
|
|
||||||
break
|
|
||||||
proxyType = proxypicker.pick_proxy(peer)
|
|
||||||
logger.info(f"Uploading block {bl[:8]} to {peer}", terminal=True)
|
|
||||||
resp = basicrequests.do_post_request(url, data=data, proxyType=proxyType, content_type='application/octet-stream')
|
|
||||||
if not resp == False:
|
|
||||||
if resp == 'success':
|
|
||||||
session.success()
|
|
||||||
session.peer_exists[peer] = True
|
|
||||||
elif resp == 'exists':
|
|
||||||
session.success()
|
|
||||||
session.peer_exists[peer] = True
|
|
||||||
else:
|
|
||||||
session.fail()
|
|
||||||
session.fail_peer(peer)
|
|
||||||
comm_inst.getPeerProfileInstance(peer).addScore(-5)
|
|
||||||
logger.warn(f'Failed to upload {bl[:8]}, reason: {resp[:15]}', terminal=True)
|
|
||||||
else:
|
|
||||||
session.fail()
|
|
||||||
session_manager.clean_session()
|
|
||||||
for x in finishedUploads:
|
|
||||||
try:
|
|
||||||
comm_inst.blocksToUpload.remove(x)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
comm_inst.decrementThreadCount(TIMER_NAME)
|
|
@ -1,54 +0,0 @@
|
|||||||
"""
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Virtual upload "sessions" for blocks
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
"""
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
from onionrutils import stringvalidators
|
|
||||||
from onionrutils import bytesconverter
|
|
||||||
from onionrutils import epoch
|
|
||||||
from utils import reconstructhash
|
|
||||||
|
|
||||||
class UploadSession:
|
|
||||||
"""Manages statistics for an Onionr block upload session
|
|
||||||
|
|
||||||
accepting a block hash (incl. unpadded) as an argument"""
|
|
||||||
def __init__(self, block_hash: Union[str, bytes]):
|
|
||||||
block_hash = bytesconverter.bytes_to_str(block_hash)
|
|
||||||
block_hash = reconstructhash.reconstruct_hash(block_hash)
|
|
||||||
if not stringvalidators.validate_hash(block_hash): raise ValueError
|
|
||||||
|
|
||||||
self.start_time = epoch.get_epoch()
|
|
||||||
self.block_hash = reconstructhash.deconstruct_hash(block_hash)
|
|
||||||
self.total_fail_count: int = 0
|
|
||||||
self.total_success_count: int = 0
|
|
||||||
self.peer_fails = {}
|
|
||||||
self.peer_exists = {}
|
|
||||||
|
|
||||||
def fail_peer(self, peer):
|
|
||||||
try:
|
|
||||||
self.peer_fails[peer] += 1
|
|
||||||
except KeyError:
|
|
||||||
self.peer_fails[peer] = 0
|
|
||||||
|
|
||||||
def fail(self):
|
|
||||||
self.total_fail_count += 1
|
|
||||||
|
|
||||||
def success(self):
|
|
||||||
self.total_success_count += 1
|
|
@ -1,85 +0,0 @@
|
|||||||
"""
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Manager for upload 'sessions'
|
|
||||||
"""
|
|
||||||
from __future__ import annotations
|
|
||||||
"""
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
from typing import Iterable, Union
|
|
||||||
|
|
||||||
from onionrutils import bytesconverter
|
|
||||||
from onionrutils import localcommand
|
|
||||||
from etc import onionrvalues
|
|
||||||
from etc import waitforsetvar
|
|
||||||
from utils import reconstructhash
|
|
||||||
|
|
||||||
from . import session
|
|
||||||
|
|
||||||
class BlockUploadSessionManager:
|
|
||||||
"""Holds block UploadSession instances. Optionally accepts iterable of sessions to added on init
|
|
||||||
|
|
||||||
Arguments: old_session: iterable of old UploadSession objects"""
|
|
||||||
def __init__(self, old_sessions:Iterable=None):
|
|
||||||
#self._too_many: TooMany = None
|
|
||||||
if old_sessions is None:
|
|
||||||
self.sessions = []
|
|
||||||
else:
|
|
||||||
self.sessions = old_session
|
|
||||||
|
|
||||||
def add_session(self, session_or_block: Union(str, bytes, session.UploadSession))->session.UploadSession:
|
|
||||||
"""Create (or add existing) block upload session from a str/bytes block hex hash, existing UploadSession"""
|
|
||||||
if isinstance(session_or_block, session.UploadSession):
|
|
||||||
if not session_or_block in self.sessions:
|
|
||||||
self.sessions.append(session_or_block)
|
|
||||||
return session_or_block
|
|
||||||
try:
|
|
||||||
return self.get_session(session_or_block)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
# convert bytes hash to str
|
|
||||||
if isinstance(session_or_block, bytes): session_or_block = bytesconverter.bytes_to_str(session_or_block)
|
|
||||||
# intentionally not elif
|
|
||||||
if isinstance(session_or_block, str):
|
|
||||||
new_session = session.UploadSession(session_or_block)
|
|
||||||
self.sessions.append(new_session)
|
|
||||||
return new_session
|
|
||||||
|
|
||||||
def get_session(self, block_hash: Union(str, bytes))->session.UploadSession:
|
|
||||||
block_hash = reconstructhash.deconstruct_hash(bytesconverter.bytes_to_str(block_hash))
|
|
||||||
for session in self.sessions:
|
|
||||||
if session.block_hash == block_hash: return session
|
|
||||||
raise KeyError
|
|
||||||
|
|
||||||
def clean_session(self, specific_session: Union[str, UploadSession]=None):
|
|
||||||
comm_inst: OnionrCommunicatorDaemon = self._too_many.get_by_string("OnionrCommunicatorDaemon")
|
|
||||||
sessions_to_delete = []
|
|
||||||
if comm_inst.getUptime() < 120: return
|
|
||||||
for session in self.sessions:
|
|
||||||
if (session.total_success_count / len(comm_inst.onlinePeers)) >= onionrvalues.MIN_BLOCK_UPLOAD_PEER_PERCENT:
|
|
||||||
sessions_to_delete.append(session)
|
|
||||||
for session in sessions_to_delete:
|
|
||||||
self.sessions.remove(session)
|
|
||||||
# TODO cleanup to one round of search
|
|
||||||
# Remove the blocks from the sessions, upload list, and waitforshare list
|
|
||||||
try:
|
|
||||||
comm_inst.blocksToUpload.remove(reconstructhash.reconstruct_hash(session.block_hash))
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
comm_inst.blocksToUpload.remove(session.block_hash)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
localcommand.local_command('waitforshare/{session.block_hash}')
|
|
@ -1 +0,0 @@
|
|||||||
from . import keydb, blockmetadb, daemonqueue
|
|
@ -1,80 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
This module works with information relating to blocks stored on the node
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import sqlite3
|
|
||||||
from . import expiredblocks, updateblockinfo, add
|
|
||||||
from .. import dbfiles
|
|
||||||
update_block_info = updateblockinfo.update_block_info
|
|
||||||
add_to_block_DB = add.add_to_block_DB
|
|
||||||
def get_block_list(dateRec = None, unsaved = False):
|
|
||||||
'''
|
|
||||||
Get list of our blocks
|
|
||||||
'''
|
|
||||||
if dateRec == None:
|
|
||||||
dateRec = 0
|
|
||||||
|
|
||||||
conn = sqlite3.connect(dbfiles.block_meta_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
execute = 'SELECT hash FROM hashes WHERE dateReceived >= ? ORDER BY dateReceived ASC;'
|
|
||||||
args = (dateRec,)
|
|
||||||
rows = list()
|
|
||||||
for row in c.execute(execute, args):
|
|
||||||
for i in row:
|
|
||||||
rows.append(i)
|
|
||||||
conn.close()
|
|
||||||
return rows
|
|
||||||
|
|
||||||
def get_block_date(blockHash):
|
|
||||||
'''
|
|
||||||
Returns the date a block was received
|
|
||||||
'''
|
|
||||||
|
|
||||||
conn = sqlite3.connect(dbfiles.block_meta_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
execute = 'SELECT dateReceived FROM hashes WHERE hash=?;'
|
|
||||||
args = (blockHash,)
|
|
||||||
for row in c.execute(execute, args):
|
|
||||||
for i in row:
|
|
||||||
return int(i)
|
|
||||||
conn.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_blocks_by_type(blockType, orderDate=True):
|
|
||||||
'''
|
|
||||||
Returns a list of blocks by the type
|
|
||||||
'''
|
|
||||||
|
|
||||||
conn = sqlite3.connect(dbfiles.block_meta_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
if orderDate:
|
|
||||||
execute = 'SELECT hash FROM hashes WHERE dataType=? ORDER BY dateReceived;'
|
|
||||||
else:
|
|
||||||
execute = 'SELECT hash FROM hashes WHERE dataType=?;'
|
|
||||||
|
|
||||||
args = (blockType,)
|
|
||||||
rows = list()
|
|
||||||
|
|
||||||
for row in c.execute(execute, args):
|
|
||||||
for i in row:
|
|
||||||
rows.append(i)
|
|
||||||
conn.close()
|
|
||||||
return rows
|
|
@ -1,42 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Add an entry to the block metadata database
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import os, sqlite3, secrets
|
|
||||||
from onionrutils import epoch, blockmetadata
|
|
||||||
from .. import dbfiles
|
|
||||||
def add_to_block_DB(newHash, selfInsert=False, dataSaved=False):
|
|
||||||
'''
|
|
||||||
Add a hash value to the block db
|
|
||||||
|
|
||||||
Should be in hex format!
|
|
||||||
'''
|
|
||||||
|
|
||||||
if blockmetadata.has_block(newHash):
|
|
||||||
return
|
|
||||||
conn = sqlite3.connect(dbfiles.block_meta_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
currentTime = epoch.get_epoch() + secrets.randbelow(301)
|
|
||||||
if selfInsert or dataSaved:
|
|
||||||
selfInsert = 1
|
|
||||||
else:
|
|
||||||
selfInsert = 0
|
|
||||||
data = (newHash, currentTime, '', selfInsert)
|
|
||||||
c.execute('INSERT INTO hashes (hash, dateReceived, dataType, dataSaved) VALUES(?, ?, ?, ?);', data)
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
@ -1,37 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Get a list of expired blocks still stored
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import sqlite3
|
|
||||||
from onionrutils import epoch
|
|
||||||
from .. import dbfiles
|
|
||||||
def get_expired_blocks():
|
|
||||||
'''Returns a list of expired blocks'''
|
|
||||||
conn = sqlite3.connect(dbfiles.block_meta_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
date = int(epoch.get_epoch())
|
|
||||||
|
|
||||||
compiled = (date,)
|
|
||||||
execute = 'SELECT hash FROM hashes WHERE expire <= ? ORDER BY dateReceived;'
|
|
||||||
|
|
||||||
rows = list()
|
|
||||||
for row in c.execute(execute, compiled):
|
|
||||||
for i in row:
|
|
||||||
rows.append(i)
|
|
||||||
conn.close()
|
|
||||||
return rows
|
|
@ -1,49 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Update block information in the metadata database by a field name
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import sqlite3
|
|
||||||
from .. import dbfiles
|
|
||||||
def update_block_info(hash, key, data):
|
|
||||||
'''
|
|
||||||
sets info associated with a block
|
|
||||||
|
|
||||||
hash - the hash of a block
|
|
||||||
dateReceived - the date the block was recieved, not necessarily when it was created
|
|
||||||
decrypted - if we can successfully decrypt the block (does not describe its current state)
|
|
||||||
dataType - data type of the block
|
|
||||||
dataFound - if the data has been found for the block
|
|
||||||
dataSaved - if the data has been saved for the block
|
|
||||||
sig - optional signature by the author (not optional if author is specified)
|
|
||||||
author - multi-round partial sha3-256 hash of authors public key
|
|
||||||
dateClaimed - timestamp claimed inside the block, only as trustworthy as the block author is
|
|
||||||
expire - expire date for a block
|
|
||||||
'''
|
|
||||||
if key not in ('dateReceived', 'decrypted', 'dataType', 'dataFound',
|
|
||||||
'dataSaved', 'sig', 'author', 'dateClaimed', 'expire'):
|
|
||||||
raise ValueError('Key must be in the allowed list')
|
|
||||||
|
|
||||||
conn = sqlite3.connect(dbfiles.block_meta_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
args = (data, hash)
|
|
||||||
# Unfortunately, not really possible
|
|
||||||
c.execute("UPDATE hashes SET " + key + " = ? where hash = ?;", args)
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
return True
|
|
@ -1,92 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Write and read the daemon queue, which is how messages are passed into the onionr daemon in a more
|
|
||||||
direct way than the http api
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
'''
|
|
||||||
import sqlite3, os
|
|
||||||
import onionrevents as events
|
|
||||||
from onionrutils import localcommand, epoch
|
|
||||||
from .. import dbfiles
|
|
||||||
import dbcreator
|
|
||||||
|
|
||||||
def daemon_queue()->str:
|
|
||||||
'''
|
|
||||||
Gives commands to the communication proccess/daemon by reading an sqlite3 database
|
|
||||||
|
|
||||||
This function intended to be used by the client. Queue to exchange data between "client" and server.
|
|
||||||
'''
|
|
||||||
|
|
||||||
retData = False
|
|
||||||
if not os.path.exists(dbfiles.daemon_queue_db):
|
|
||||||
dbcreator.createDaemonDB()
|
|
||||||
else:
|
|
||||||
conn = sqlite3.connect(dbfiles.daemon_queue_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
try:
|
|
||||||
for row in c.execute('SELECT command, data, date, min(ID), responseID FROM commands group by id'):
|
|
||||||
retData = row
|
|
||||||
break
|
|
||||||
except sqlite3.OperationalError:
|
|
||||||
dbcreator.createDaemonDB()
|
|
||||||
else:
|
|
||||||
if retData != False:
|
|
||||||
c.execute('DELETE FROM commands WHERE id=?;', (retData[3],))
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
return retData
|
|
||||||
|
|
||||||
def daemon_queue_add(command: str, data='', responseID: str =''):
|
|
||||||
'''
|
|
||||||
Add a command to the daemon queue, used by the communication daemon (communicator.py)
|
|
||||||
'''
|
|
||||||
|
|
||||||
retData = True
|
|
||||||
|
|
||||||
date = epoch.get_epoch()
|
|
||||||
conn = sqlite3.connect(dbfiles.daemon_queue_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
t = (command, data, date, responseID)
|
|
||||||
try:
|
|
||||||
c.execute('INSERT INTO commands (command, data, date, responseID) VALUES(?, ?, ?, ?)', t)
|
|
||||||
conn.commit()
|
|
||||||
except sqlite3.OperationalError:
|
|
||||||
retData = False
|
|
||||||
daemon_queue()
|
|
||||||
conn.close()
|
|
||||||
return retData
|
|
||||||
|
|
||||||
def daemon_queue_get_response(responseID=''):
|
|
||||||
'''
|
|
||||||
Get a response sent by communicator to the API, by requesting to the API
|
|
||||||
'''
|
|
||||||
if len(responseID) == 0: raise ValueError('ResponseID should not be empty')
|
|
||||||
resp = localcommand.local_command(dbfiles.daemon_queue_db, 'queueResponse/' + responseID)
|
|
||||||
return resp
|
|
||||||
|
|
||||||
def clear_daemon_queue():
|
|
||||||
'''
|
|
||||||
Clear the daemon queue (somewhat dangerous)
|
|
||||||
'''
|
|
||||||
conn = sqlite3.connect(dbfiles.daemon_queue_db, timeout=30)
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
c.execute('DELETE FROM commands;')
|
|
||||||
conn.commit()
|
|
||||||
|
|
||||||
conn.close()
|
|
@ -1,12 +0,0 @@
|
|||||||
from utils import identifyhome
|
|
||||||
import filepaths
|
|
||||||
home = identifyhome.identify_home()
|
|
||||||
if not home.endswith('/'): home += '/'
|
|
||||||
|
|
||||||
block_meta_db = '%sblock-metadata.db' % (home)
|
|
||||||
block_data_db = '%s/block-data.db' % (filepaths.block_data_location,)
|
|
||||||
daemon_queue_db = '%sdaemon-queue.db' % (home,)
|
|
||||||
address_info_db = '%saddress.db' % (home,)
|
|
||||||
user_id_info_db = '%susers.db' % (home,)
|
|
||||||
forward_keys_db = '%sforward-keys.db' % (home,)
|
|
||||||
blacklist_db = '%sblacklist.db' % (home,)
|
|
@ -1 +0,0 @@
|
|||||||
from . import addkeys, listkeys, removekeys, userinfo, transportinfo
|
|