work on torgossip
This commit is contained in:
parent
4b36e9d3da
commit
7fba65c459
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
This file handles all incoming http requests to the client, using Flask
|
This file handles all incoming http requests to the client, using Flask
|
||||||
"""
|
"""
|
||||||
|
import http
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
import hmac
|
import hmac
|
||||||
|
|
||||||
@ -77,6 +78,7 @@ class PrivateAPI:
|
|||||||
"""Start client gevent API web server with flask client app."""
|
"""Start client gevent API web server with flask client app."""
|
||||||
waitforsetvar.wait_for_set_var(self, "_too_many")
|
waitforsetvar.wait_for_set_var(self, "_too_many")
|
||||||
fd_handler = httpapi.fdsafehandler.FDSafeHandler
|
fd_handler = httpapi.fdsafehandler.FDSafeHandler
|
||||||
|
self._too_many.add(httpapi.wrappedfunctions.SubProcVDFGenerator(self._too_many))
|
||||||
self.publicAPI = self._too_many.get( # pylint: disable=E1101
|
self.publicAPI = self._too_many.get( # pylint: disable=E1101
|
||||||
public.PublicAPI)
|
public.PublicAPI)
|
||||||
self.httpServer = WSGIServer((self.host, self.bindPort),
|
self.httpServer = WSGIServer((self.host, self.bindPort),
|
||||||
|
@ -23,7 +23,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def store_block(block: 'Kasten', safe_db: 'SafeDB'):
|
def store_block(block: 'Kasten', safe_db: 'SafeDB', own_block=False):
|
||||||
# This does not handle validation of blocks
|
# This does not handle validation of blocks
|
||||||
# safe_db is initialized by the daemon when starting normally
|
# safe_db is initialized by the daemon when starting normally
|
||||||
# so any other commands need to initialize it seperately
|
# so any other commands need to initialize it seperately
|
||||||
|
@ -1,16 +1,23 @@
|
|||||||
from base64 import b85encode
|
from base64 import b85encode
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import threading
|
||||||
|
|
||||||
import ujson as json
|
import ujson as json
|
||||||
|
|
||||||
import kasten
|
import kasten
|
||||||
|
|
||||||
|
from onionrplugins import onionrevents
|
||||||
|
from blockio import store_block
|
||||||
from onionrblocks.generators.anonvdf import AnonVDFGenerator
|
from onionrblocks.generators.anonvdf import AnonVDFGenerator
|
||||||
|
|
||||||
_DIR = os.path.dirname(os.path.realpath(__file__)) + '/../'
|
_DIR = os.path.dirname(os.path.realpath(__file__)) + '/../'
|
||||||
|
|
||||||
|
|
||||||
def vdf_block(data, data_type, ttl, **metadata):
|
def vdf_block(data, data_type, ttl, **metadata):
|
||||||
|
try:
|
||||||
|
data = data.encode('utf-8')
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
data = b85encode(data)
|
data = b85encode(data)
|
||||||
generated = subprocess.Popen(
|
generated = subprocess.Popen(
|
||||||
[
|
[
|
||||||
@ -25,3 +32,14 @@ def vdf_block(data, data_type, ttl, **metadata):
|
|||||||
generated[:64], generated[64:],
|
generated[:64], generated[64:],
|
||||||
AnonVDFGenerator, auto_check_generator=True)
|
AnonVDFGenerator, auto_check_generator=True)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_and_store_vdf_block(shared_state, *args, **kwargs):
|
||||||
|
safe_db = shared_state.get_by_string('SafeDB')
|
||||||
|
k = vdf_block(*args, **kwargs)
|
||||||
|
store_block(
|
||||||
|
k,
|
||||||
|
safe_db,
|
||||||
|
own_block=True
|
||||||
|
)
|
||||||
|
onionrevents.event('blockcreated', data=shared_state, threaded=True)
|
||||||
|
|
||||||
|
@ -1,25 +1,28 @@
|
|||||||
"""
|
"""
|
||||||
Onionr - Private P2P Communication
|
Onionr - Private P2P Communication
|
||||||
|
|
||||||
This file registers plugin's flask blueprints for the client http server
|
Register plugin's flask blueprints for the client http 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 onionrplugins
|
import onionrplugins
|
||||||
import config
|
import config
|
||||||
|
|
||||||
|
from . import wrappedfunctions
|
||||||
|
"""
|
||||||
|
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 load_plugin_blueprints(flaskapp, blueprint: str = 'flask_blueprint'):
|
def load_plugin_blueprints(flaskapp, blueprint: str = 'flask_blueprint'):
|
||||||
"""Iterate enabled plugins and load any http endpoints they have"""
|
"""Iterate enabled plugins and load any http endpoints they have"""
|
||||||
config.reload()
|
config.reload()
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
view and interact with onionr sites
|
view and interact with onionr sites
|
||||||
"""
|
"""
|
||||||
|
import traceback
|
||||||
|
|
||||||
from flask import Blueprint, Response, request, abort, g
|
from flask import Blueprint, Response, request, abort, g
|
||||||
import ujson as json
|
import ujson as json
|
||||||
"""
|
"""
|
||||||
@ -33,9 +35,10 @@ def serialized(name: str) -> Response:
|
|||||||
resp = str(resp)
|
resp = str(resp)
|
||||||
return Response(resp, content_type='application/octet-stream')
|
return Response(resp, content_type='application/octet-stream')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return Response(repr(e), content_type='text/plain', status=500)
|
return Response(traceback.format_exc(e), content_type='text/plain', status=500)
|
||||||
|
|
||||||
initial = g.too_many.get_by_string(name.split('.')[0])
|
initial = g.too_many.get_by_string(name.split('.')[0])
|
||||||
|
print('initial', initial)
|
||||||
for c, i in enumerate(name.split('.')):
|
for c, i in enumerate(name.split('.')):
|
||||||
if i and c != 0:
|
if i and c != 0:
|
||||||
attr = getattr(initial, i)
|
attr = getattr(initial, i)
|
||||||
@ -44,11 +47,16 @@ def serialized(name: str) -> Response:
|
|||||||
try:
|
try:
|
||||||
js = request.get_json(force=True)
|
js = request.get_json(force=True)
|
||||||
print('json', js, type(js))
|
print('json', js, type(js))
|
||||||
|
if not isinstance(js, dict):
|
||||||
data = json.loads(js)
|
data = json.loads(js)
|
||||||
args = data['args']
|
args = data['args']
|
||||||
del data['args']
|
del data['args']
|
||||||
|
else:
|
||||||
|
data = js
|
||||||
|
args = js['args']
|
||||||
|
del js['args']
|
||||||
except (TypeError, ValueError) as e:
|
except (TypeError, ValueError) as e:
|
||||||
print(repr(e))
|
print(traceback.format_exc())
|
||||||
data = {}
|
data = {}
|
||||||
args = []
|
args = []
|
||||||
print('data', data)
|
print('data', data)
|
||||||
|
11
src/httpapi/wrappedfunctions/__init__.py
Normal file
11
src/httpapi/wrappedfunctions/__init__.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from blockio import subprocgenerate
|
||||||
|
|
||||||
|
|
||||||
|
class SubProcVDFGenerator:
|
||||||
|
def __init__(self, shared_state):
|
||||||
|
self.shared_state = shared_state
|
||||||
|
|
||||||
|
def gen_and_store_vdf_block(self, *args, **kwargs):
|
||||||
|
|
||||||
|
return subprocgenerate.gen_and_store_vdf_block(
|
||||||
|
self.shared_state, *args, **kwargs)
|
@ -19,6 +19,7 @@ from .lanservertest import test_lan_server
|
|||||||
from .sneakernettest import test_sneakernet_import
|
from .sneakernettest import test_sneakernet_import
|
||||||
from .dnsrebindingtest import test_dns_rebinding
|
from .dnsrebindingtest import test_dns_rebinding
|
||||||
from .serviceonlinetest import test_service_online
|
from .serviceonlinetest import test_service_online
|
||||||
|
from .wrappedfunctionstest import test_vdf_create_and_store
|
||||||
"""
|
"""
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -46,7 +47,8 @@ RUN_TESTS = [uicheck.check_ui,
|
|||||||
test_lan_server,
|
test_lan_server,
|
||||||
test_sneakernet_import,
|
test_sneakernet_import,
|
||||||
test_dns_rebinding,
|
test_dns_rebinding,
|
||||||
test_service_online
|
test_service_online,
|
||||||
|
test_vdf_create_and_store
|
||||||
]
|
]
|
||||||
|
|
||||||
SUCCESS_FILE = os.path.dirname(os.path.realpath(__file__)) + '/../../tests/runtime-result.txt'
|
SUCCESS_FILE = os.path.dirname(os.path.realpath(__file__)) + '/../../tests/runtime-result.txt'
|
||||||
|
29
src/runtests/wrappedfunctionstest.py
Normal file
29
src/runtests/wrappedfunctionstest.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from time import sleep
|
||||||
|
from secrets import token_hex
|
||||||
|
|
||||||
|
import blockio
|
||||||
|
import logger
|
||||||
|
from onionrutils.localcommand import local_command
|
||||||
|
from blockio import list_all_blocks
|
||||||
|
|
||||||
|
|
||||||
|
def test_vdf_create_and_store(testmanager):
|
||||||
|
# data, data_type, ttl, **metadata
|
||||||
|
db = testmanager._too_many.get_by_string('SafeDB')
|
||||||
|
bls = list_all_blocks(db)
|
||||||
|
b_data = "test" + token_hex(5)
|
||||||
|
res = local_command(
|
||||||
|
'/serialized/SubProcVDFGenerator.gen_and_store_vdf_block', post=True, post_data={"args": [b_data, "txt", 6000]}, is_json=True)
|
||||||
|
|
||||||
|
print(res)
|
||||||
|
|
||||||
|
while len(list_all_blocks(db)) == len(bls):
|
||||||
|
sleep(1)
|
||||||
|
for i in list_all_blocks(db):
|
||||||
|
i = bytes(i)
|
||||||
|
if blockio.load_block(i, db).get_packed().decode('utf-8') == b_data:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
logger.error("Block was not generated", terminal=True)
|
||||||
|
raise ValueError
|
||||||
|
|
@ -5,172 +5,41 @@ This default plugin handles "flow" messages
|
|||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import deadsimplekv as simplekv
|
|
||||||
from utils import identifyhome, reconstructhash
|
|
||||||
from coredb import blockmetadb
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import locale
|
|
||||||
from oldblocks.onionrblockapi import Block
|
|
||||||
import logger
|
|
||||||
import oldblocks
|
|
||||||
from onionrutils import escapeansi, epoch, bytesconverter
|
|
||||||
|
|
||||||
|
import locale
|
||||||
locale.setlocale(locale.LC_ALL, '')
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
|
|
||||||
|
from blockio.subprocgenerate import gen_and_store_vdf_block
|
||||||
|
|
||||||
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
|
||||||
# import after path insert
|
# import after path insert
|
||||||
import flowapi # noqa
|
import flowapi # noqa
|
||||||
"""
|
"""
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
flask_blueprint = flowapi.flask_blueprint
|
flask_blueprint = flowapi.flask_blueprint
|
||||||
security_whitelist = ['circles.circlesstatic', 'circles.circlesindex']
|
security_whitelist = ['circles.circlesstatic', 'circles.circlesindex']
|
||||||
|
|
||||||
plugin_name = 'circles'
|
plugin_name = 'circles'
|
||||||
PLUGIN_VERSION = '0.1.0'
|
PLUGIN_VERSION = '1.0.0'
|
||||||
|
|
||||||
EXPIRE_TIME = 43200
|
|
||||||
|
|
||||||
class OnionrFlow:
|
|
||||||
def __init__(self):
|
|
||||||
self.alreadyOutputed = []
|
|
||||||
self.flowRunning = False
|
|
||||||
self.channel = ""
|
|
||||||
return
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
logger.warn(
|
|
||||||
"Please note: everything said here is public, " +
|
|
||||||
"even if a random channel name is used.", terminal=True)
|
|
||||||
message = ""
|
|
||||||
self.flowRunning = True
|
|
||||||
try:
|
|
||||||
self.channel = logger.readline(
|
|
||||||
"Enter a channel name or none for default:").strip()
|
|
||||||
except (KeyboardInterrupt, EOFError):
|
|
||||||
self.flowRunning = False
|
|
||||||
newThread = threading.Thread(target=self.showOutput, daemon=True)
|
|
||||||
newThread.start()
|
|
||||||
while self.flowRunning:
|
|
||||||
if self.channel == "":
|
|
||||||
self.channel = "global"
|
|
||||||
try:
|
|
||||||
message = logger.readline(f'\nInsert message into {plugin_name}:').strip().replace(
|
|
||||||
'\n', '\\n').replace('\r', '\\r')
|
|
||||||
except EOFError:
|
|
||||||
pass
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
self.flowRunning = False
|
|
||||||
else:
|
|
||||||
if message == "q":
|
|
||||||
self.flowRunning = False
|
|
||||||
expireTime = epoch.get_epoch() + EXPIRE_TIME
|
|
||||||
if len(message) > 0:
|
|
||||||
logger.info('Inserting message as block...', terminal=True)
|
|
||||||
oldblocks.insert(message, header='brd',
|
|
||||||
expire=expireTime,
|
|
||||||
meta = {
|
|
||||||
'ch': self.channel})
|
|
||||||
|
|
||||||
logger.info(f"{plugin_name} is exiting, goodbye", terminal=True)
|
|
||||||
return
|
|
||||||
|
|
||||||
def showOutput(self):
|
|
||||||
while isinstance(self.channel, type(None)) and self.flowRunning:
|
|
||||||
time.sleep(1)
|
|
||||||
try:
|
|
||||||
while self.flowRunning:
|
|
||||||
for block in blockmetadb.get_blocks_by_type('brd'):
|
|
||||||
if block in self.alreadyOutputed:
|
|
||||||
continue
|
|
||||||
block = Block(block)
|
|
||||||
b_hash = bytesconverter.bytes_to_str(block.getHash())
|
|
||||||
if block.getMetadata('ch') != self.channel:
|
|
||||||
continue
|
|
||||||
if not self.flowRunning:
|
|
||||||
break
|
|
||||||
logger.info('\n------------------------',
|
|
||||||
prompt=False, terminal=True)
|
|
||||||
content = block.getContent()
|
|
||||||
# Escape new lines, remove trailing whitespace, and escape ansi sequences
|
|
||||||
content = escapeansi.escape_ANSI(content.replace(
|
|
||||||
b'\n', b'\\n').replace(b'\r', b'\\r').strip().decode('utf-8'))
|
|
||||||
logger.info(block.getDate().strftime(
|
|
||||||
"%m/%d %H:%M") + ' - ' +
|
|
||||||
logger.colors.reset + content,
|
|
||||||
prompt=False, terminal=True)
|
|
||||||
self.alreadyOutputed.append(b_hash)
|
|
||||||
time.sleep(5)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
self.flowRunning = False
|
|
||||||
|
|
||||||
|
|
||||||
def on_circles_cmd(api, data=None):
|
def on_circles_cmd(api, data=None):
|
||||||
OnionrFlow().start()
|
message = ""
|
||||||
|
while message != "-q":
|
||||||
|
message = input("Enter message")
|
||||||
|
gen_and_store_vdf_block()
|
||||||
|
|
||||||
|
|
||||||
def on_circlesend_cmd(api, data=None):
|
|
||||||
err_msg = "Second arg is board name, third is quoted message"
|
|
||||||
try:
|
|
||||||
sys.argv[2]
|
|
||||||
except IndexError:
|
|
||||||
logger.error(err_msg, terminal=True)
|
|
||||||
try:
|
|
||||||
sys.argv[3]
|
|
||||||
except IndexError:
|
|
||||||
logger.error(err_msg, terminal=True)
|
|
||||||
|
|
||||||
bl = oldblocks.insert(sys.argv[3], header='brd',
|
|
||||||
expire=(EXPIRE_TIME + epoch.get_epoch()),
|
|
||||||
meta={'ch': sys.argv[2]})
|
|
||||||
print(bl)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def on_softreset(api, data=None):
|
|
||||||
try:
|
|
||||||
os.remove(identifyhome.identify_home() + '/board-index.cache.json')
|
|
||||||
logger.info('Cleared Circles board cache')
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def on_processblocks(api, data=None):
|
|
||||||
metadata = data['block'].bmetadata # Get the block metadata
|
|
||||||
if data['type'] != 'brd':
|
|
||||||
return
|
|
||||||
|
|
||||||
b_hash = reconstructhash.deconstruct_hash(
|
|
||||||
data['block'].hash) # Get the 0-truncated block hash
|
|
||||||
board_cache = simplekv.DeadSimpleKV(identifyhome.identify_home(
|
|
||||||
) + '/board-index.cache.json', flush_on_exit=False) # get the board index cache
|
|
||||||
board_cache.refresh()
|
|
||||||
# Validate the channel name is sane for caching
|
|
||||||
try:
|
|
||||||
ch = metadata['ch']
|
|
||||||
except KeyError:
|
|
||||||
ch = 'global'
|
|
||||||
ch_len = len(ch)
|
|
||||||
if ch_len == 0:
|
|
||||||
ch = 'global'
|
|
||||||
elif ch_len > 12:
|
|
||||||
return
|
|
||||||
|
|
||||||
existing_posts = board_cache.get(ch)
|
|
||||||
if existing_posts is None:
|
|
||||||
existing_posts = []
|
|
||||||
existing_posts.append(data['block'].hash)
|
|
||||||
board_cache.put(ch, existing_posts)
|
|
||||||
board_cache.flush()
|
|
||||||
|
@ -21,7 +21,7 @@ def _shrink_peer_address(peer):
|
|||||||
return peer
|
return peer
|
||||||
|
|
||||||
def torgossip_runtest(test_manager):
|
def torgossip_runtest(test_manager):
|
||||||
|
return
|
||||||
|
|
||||||
s_file = identifyhome.identify_home() + "/torgossip.sock"
|
s_file = identifyhome.identify_home() + "/torgossip.sock"
|
||||||
bl_test = blockcreator.create_anonvdf_block(b"test", "txt", 10)
|
bl_test = blockcreator.create_anonvdf_block(b"test", "txt", 10)
|
||||||
|
Loading…
Reference in New Issue
Block a user