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.
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 List
import secrets
@ -61,10 +62,18 @@ async def accept_stem_blocks(
if not raw_block:
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")
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
# Client will decide if they are to be stemmed

View File

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

View File

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

View File

@ -1,26 +1,39 @@
from secrets import randbits
import base64
from base64 import b85decode
from typing import Union
from onionrblocks import Block
import onionrblocks
from jsonrpc import dispatcher
from gossip.blockqueues import gossip_block_queues
from blockdb import get_blocks_after_timestamp
import blockdb
from utils import multiproc
@dispatcher.add_method
def get_block(block_id: str) -> dict:
bl = blockdb.get_block(block_id)
@dispatcher.add_method
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
def create_block(
block_data: 'base64', block_type: str, ttl: int, metadata: dict):
# Wrapper for onionrblocks.create_block (take base64 to be compatible with RPC)
bl = multiproc.subprocess_compute(
# Wrapper for onionrblocks.create_block
# (take base64 to be compatible with RPC)
bl: Block = multiproc.subprocess_compute(
onionrblocks.create_anonvdf_block,
3600,
base64.b64decode(block_data),
@ -28,14 +41,35 @@ def create_block(
ttl,
**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
def insert_block(block):
block = Block(
block['id'], b85decode(block['raw']), auto_verify=False)
def create_and_insert_block(
block_data: 'base64',
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)
return "ok"

View File

@ -66,7 +66,11 @@ def on_init(api, data=None):
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
active_identity = config.get('wot.active_identity_name', '')