Compare commits

...

4 Commits

Author SHA1 Message Date
Kevin F 61051d5711 Removed old scripts 2023-01-16 23:33:57 -06:00
Kevin F 59ad2731ba Disconnect peers who stem a bad block 2023-01-16 23:31:30 -06:00
Kevin F 560a20e90a Only expose wot to rpc if rpc is active 2023-01-16 23:30:50 -06:00
Kevin F ce3a548c70 Added create block RPC wrapper 2023-01-16 23:29:50 -06:00
11 changed files with 75 additions and 194 deletions

View File

@ -1,7 +1 @@
This directory contains useful scripts and utilities that don't make sense to include as official Onionr features. This directory contains useful scripts and utilities that don't make sense to include as official Onionr features.
passphrase-generator.py: very simple utility to generate and print a strong passphrase to stdout. 256 bits of entropy by default.
enable-dev-config.py/disable-dev-config.py: enable/disable dev default config setup
block-spammer.py: attack tool for spamming blocks
announce-attack.py: flood a node with false nodes
run-unit-test-by-name: runs a unit test (no browser, runtime or intgegration test) by name

View File

@ -1,51 +0,0 @@
#!/usr/bin/env python3
"""Craft and send requests to the local client API"""
import sys
import os
if not os.path.exists('onionr.sh'):
os.chdir('../')
sys.path.append("src/")
import atexit
import readline
histfile = os.path.join(os.path.expanduser("~"), ".onionr_history")
try:
readline.read_history_file(histfile)
# default history len is -1 (infinite), which may grow unruly
readline.set_history_length(1000)
except FileNotFoundError:
pass
atexit.register(readline.write_history_file, histfile)
from onionrutils.localcommand import local_command
from onionrutils.localcommand import get_hostname
try:
print('API file found, probably running on ' + get_hostname())
except TypeError:
print('Onionr not running')
sys.exit(1)
print('1. get request (default)')
print('2. post request')
choice = input(">").lower().strip()
post = False
post_data = {}
json = False
endpoint = input("URL Endpoint: ")
data = input("Data url param: ")
if choice in ("2", "post", "post request"):
post = True
print("Enter post data")
post_data = input()
if post_data:
print("Is this JSON?")
json = input("y/n").lower().strip()
if json == "y":
json = True
ret = local_command(endpoint, data=data, post=post, post_data=post_data, is_json=json)
print("Response: \n", ret)

View File

@ -1,41 +0,0 @@
#!/usr/bin/env python3
import sys
import os
import stem
from stem import process
from stem.control import Controller
if not os.path.exists('onionr.sh'):
os.chdir('../')
sys.path.append("src/")
try:
sys.argv[1]
except IndexError:
sys.exit(1)
tor_process = process.launch_tor_with_config(
completion_percent=0,
config = {
'ControlPort': '2778',
'DisableNetwork': '1',
'Log': [
'NOTICE stdout',
'ERR file /tmp/tor_error_log',
],
},
)
with Controller.from_port('127.0.0.1', 2778) as controller:
controller.authenticate()
for i in range(1024, 1024 + int(sys.argv[1])):
hs = controller.create_ephemeral_hidden_service(
{80: i},
key_type='NEW',
key_content='ED25519-V3',
await_publication=False,
detached=True)
print(hs.service_id + ".onion")
controller.remove_ephemeral_hidden_service(hs.service_id)
tor_process.kill()

View File

@ -1,16 +0,0 @@
import sys
import os
import stem
if not os.path.exists('onionr.sh'):
os.chdir('../')
sys.path.append("src/")
from coredb.blockmetadb import get_block_list
from onionrblocks.onionrblockapi import Block
for bl in get_block_list():
bl_obj = Block(bl, decrypt=False)
b_type = bl_obj.getType()
if not b_type:
b_type = "encrypted"
print(bl + " - " + str(bl_obj.date) + " - " + b_type)

View File

@ -1,40 +0,0 @@
import sys
import os
import stem
if not os.path.exists('onionr.sh'):
os.chdir('../')
sys.path.append("src/")
from onionrutils import stringvalidators
from onionrutils import basicrequests
from stem.control import Controller
onionr_ip = input("onionr ip address: ")
onionr_port = int(input("Enter onionr public api port: "))
controller = Controller.from_port('127.0.0.1', int(input("Enter tor controller port: ")))
controller.authenticate()
node = input("Enter node to attack. Note that you legally must use your own, and even that might lead to technical or legal issues: ")
assert stringvalidators.validate_transport(node)
socks = input("Socks:")
adders = set([])
for i in range(int(input("Sybil addresses: "))):
response = controller.create_ephemeral_hidden_service({80: f'{onionr_ip}:{onionr_port}'}, await_publication=True)
#print(i, response.service_id)
adders.add(response.service_id)
for x in adders:
x += '.onion'
print(f"Introducing {x} to {node}")
basicrequests.do_post_request(
f'http://{node}/announce',
data = {'node': x},
port=socks)

View File

@ -1,12 +0,0 @@
#!/usr/bin/env python3
import sys
import os
if not os.path.exists('onionr.sh'):
os.chdir('../')
sys.path.append("src/")
import onionrblocks
expire = 600
print(onionrblocks.insert(data=os.urandom(32), expire=expire))

View File

@ -1,3 +1,4 @@
import traceback
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import List from typing import List
import secrets import secrets
@ -61,10 +62,18 @@ async def accept_stem_blocks(
if not raw_block: if not raw_block:
break break
try:
bl = Block(block_id, raw_block, auto_verify=True)
except Exception as e:
logging.warn(
f"Error in received stem block {block_id} {str(e)}")
logging.debug(traceback.format_exc())
break
logging.debug("Got a stem block, put into queue") logging.debug("Got a stem block, put into queue")
block_queue_to_use.put(
Block(block_id, raw_block, auto_verify=True) block_queue_to_use.put(bl)
)
# Regardless of stem phase, we add to queue # Regardless of stem phase, we add to queue
# Client will decide if they are to be stemmed # Client will decide if they are to be stemmed

View File

@ -2,20 +2,16 @@
""" """
import threading import threading
import os
import time
import traceback
import collections import collections
from typing import Union from typing import Union
import ujson import ujson
import jsonrpc import jsonrpc
from logger import log as logging
rpc_results = collections.deque(maxlen=10000) rpc_results = collections.deque(maxlen=10000)
def get_results(id) -> Union[str, None]: def get_results(id) -> Union[str, None]:
final = None final = None
for result in rpc_results: for result in rpc_results:
@ -29,13 +25,15 @@ def get_results(id) -> Union[str, None]:
def _exec_rpc(rpc_json_str): def _exec_rpc(rpc_json_str):
json_resp = jsonrpc.JSONRPCResponseManager.handle(rpc_json_str, jsonrpc.dispatcher) json_resp = jsonrpc.JSONRPCResponseManager.handle(
rpc_json_str, jsonrpc.dispatcher)
data = json_resp.data data = json_resp.data
rpc_results.append(data) rpc_results.append(data)
def threaded_rpc(rpc_json_str): def threaded_rpc(rpc_json_str):
threading.Thread( threading.Thread(
target=_exec_rpc, target=_exec_rpc,
args=(rpc_json_str,), args=(rpc_json_str,),
daemon=True, daemon=True,
name="JSON RPC").start() name="JSON RPC").start()

View File

@ -57,6 +57,7 @@ import longrpc
plugin_apis['rpc.add_module_to_api'] = add_module_to_api plugin_apis['rpc.add_module_to_api'] = add_module_to_api
def _detect_cors_and_add_headers(): def _detect_cors_and_add_headers():
cherrypy.response.headers['Access-Control-Allow-Headers'] = 'Content-Type' cherrypy.response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
cherrypy.response.headers['Access-Control-Allow-Origin'] = '*' cherrypy.response.headers['Access-Control-Allow-Origin'] = '*'
@ -65,12 +66,13 @@ def _detect_cors_and_add_headers():
return True return True
return False return False
class OnionrRPC(object): class OnionrRPC(object):
@cherrypy.expose @cherrypy.expose
def threaded_rpc(self): def threaded_rpc(self):
if _detect_cors_and_add_headers(): if _detect_cors_and_add_headers():
return '' return ''
rpc_request_json: str = cherrypy.request.body.read().decode('utf-8') rpc_request_json: str = cherrypy.request.body.read().decode('utf-8')
longrpc.threaded_rpc(rpc_request_json) longrpc.threaded_rpc(rpc_request_json)
return 'ok' return 'ok'
@ -79,19 +81,19 @@ class OnionrRPC(object):
def get_rpc_result(self, id=0): def get_rpc_result(self, id=0):
if _detect_cors_and_add_headers(): if _detect_cors_and_add_headers():
return '' return ''
results = longrpc.get_results(id) results = longrpc.get_results(id)
if not results: if not results:
return '"no result"' return '"no result"'
return results return results
@cherrypy.expose @cherrypy.expose
def rpc(self): def rpc(self):
# Basic RPC, intended for small amounts of work # Basic RPC, intended for small amounts of work
# Use /queue_rpc for large workloads like creating blocks # Use /queue_rpc for large workloads like creating blocks
# and getting results with /get_rpc_result?id=<id> # and getting results with /get_rpc_result?id=<id>
# Dispatcher is dictionary {<method_name>: callable} # Dispatcher is dictionary {<method_name>: callable}
if _detect_cors_and_add_headers(): if _detect_cors_and_add_headers():
return '' return ''
@ -146,7 +148,7 @@ def on_settcpsocket_cmd(api, data=None):
config.set('rpc.bind_port', port, savefile=True) config.set('rpc.bind_port', port, savefile=True)
logging.info( logging.info(
'Set RPC to use TCP socket http://' + 'Set RPC to use TCP socket http://' +
f'{config.get("rpc.bind_host")}:{config.get("rpc.bind_port")}') f'{config.get("rpc.bind_host")}:{config.get("rpc.bind_port")}')

View File

@ -1,26 +1,39 @@
from secrets import randbits from secrets import randbits
import base64 import base64
from base64 import b85decode from typing import Union
from onionrblocks import Block from onionrblocks import Block
import onionrblocks import onionrblocks
from jsonrpc import dispatcher from jsonrpc import dispatcher
from gossip.blockqueues import gossip_block_queues from gossip.blockqueues import gossip_block_queues
from blockdb import get_blocks_after_timestamp import blockdb
from utils import multiproc from utils import multiproc
@dispatcher.add_method
def get_block(block_id: str) -> dict:
bl = blockdb.get_block(block_id)
@dispatcher.add_method @dispatcher.add_method
def get_blocks(timestamp): def get_blocks(timestamp):
return [block.raw for block in get_blocks_after_timestamp(timestamp)] blocks = []
for block in blockdb.get_blocks_after_timestamp(timestamp):
blocks.append({
'id': block.id,
'raw': base64.b64encode(block.raw).decode('utf-8')
})
return blocks
@dispatcher.add_method @dispatcher.add_method
def create_block( def create_block(
block_data: 'base64', block_type: str, ttl: int, metadata: dict): block_data: 'base64', block_type: str, ttl: int, metadata: dict):
# Wrapper for onionrblocks.create_block (take base64 to be compatible with RPC) # Wrapper for onionrblocks.create_block
bl = multiproc.subprocess_compute( # (take base64 to be compatible with RPC)
bl: Block = multiproc.subprocess_compute(
onionrblocks.create_anonvdf_block, onionrblocks.create_anonvdf_block,
3600, 3600,
base64.b64decode(block_data), base64.b64decode(block_data),
@ -28,14 +41,35 @@ def create_block(
ttl, ttl,
**metadata **metadata
) )
try:
block_id = bl.id.decode('utf-8')
except AttributeError:
block_id = bl.id
bl_json = {
'id': block_id,
'raw': base64.b64encode(bl.raw).decode('utf-8')
}
return bl_json
return base64.b85encode(bl.raw).decode('utf-8')
queue_to_use = randbits(1)
@dispatcher.add_method @dispatcher.add_method
def insert_block(block): def create_and_insert_block(
block = Block( block_data: 'base64',
block['id'], b85decode(block['raw']), auto_verify=False) block_type: str, ttl: int, metadata: dict) -> str:
bl = create_block(block_data, block_type, ttl, metadata)['id']
insert_block(bl)
return bl['id']
# As per dandelion++ spec the edge should be the same.
# We keep it the same for each daemon life time.
queue_to_use = randbits(1)
@dispatcher.add_method
def insert_block(block: Union[dict, Block]):
if isinstance(block, dict):
block = Block(
block['id'], base64.b64decode(block['raw']), auto_verify=False)
gossip_block_queues[queue_to_use].put_nowait(block) gossip_block_queues[queue_to_use].put_nowait(block)
return "ok" return "ok"

View File

@ -66,7 +66,11 @@ def on_init(api, data=None):
load_identities_from_blocks()) load_identities_from_blocks())
) )
plugin_apis['rpc.add_module_to_api'](wot) # Expose WOT to RPC if the RPC plugin is loaded
try:
plugin_apis['rpc.add_module_to_api'](wot)
except KeyError:
pass
# load active identity, from there load our trust graph # load active identity, from there load our trust graph
active_identity = config.get('wot.active_identity_name', '') active_identity = config.get('wot.active_identity_name', '')