Compare commits
No commits in common. "61051d5711c4c3d02b150b49c05f09a5cf4ff910" and "8712a1c40123cb8e01642ce6749d3fc96ce6ba5b" have entirely different histories.
61051d5711
...
8712a1c401
@ -1 +1,7 @@
|
|||||||
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
|
51
scripts/client-api-request-crafter.py
Normal file
51
scripts/client-api-request-crafter.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#!/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)
|
41
scripts/generate-onions.py
Executable file
41
scripts/generate-onions.py
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
#!/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()
|
16
scripts/show-blocks.py
Normal file
16
scripts/show-blocks.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
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)
|
40
scripts/sybil-attack.py
Normal file
40
scripts/sybil-attack.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
12
scripts/testblock.py
Executable file
12
scripts/testblock.py
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/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))
|
||||||
|
|
@ -1,4 +1,3 @@
|
|||||||
import traceback
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from typing import List
|
from typing import List
|
||||||
import secrets
|
import secrets
|
||||||
@ -62,18 +61,10 @@ 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_queue_to_use.put(bl)
|
Block(block_id, raw_block, auto_verify=True)
|
||||||
|
)
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -2,16 +2,20 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
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:
|
||||||
@ -25,15 +29,13 @@ def get_results(id) -> Union[str, None]:
|
|||||||
|
|
||||||
|
|
||||||
def _exec_rpc(rpc_json_str):
|
def _exec_rpc(rpc_json_str):
|
||||||
json_resp = jsonrpc.JSONRPCResponseManager.handle(
|
json_resp = jsonrpc.JSONRPCResponseManager.handle(rpc_json_str, jsonrpc.dispatcher)
|
||||||
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()
|
||||||
|
@ -57,7 +57,6 @@ 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'] = '*'
|
||||||
@ -66,13 +65,12 @@ 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'
|
||||||
@ -81,19 +79,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 ''
|
||||||
|
|
||||||
@ -148,7 +146,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")}')
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,39 +1,26 @@
|
|||||||
from secrets import randbits
|
from secrets import randbits
|
||||||
import base64
|
import base64
|
||||||
from typing import Union
|
from base64 import b85decode
|
||||||
|
|
||||||
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
|
||||||
import blockdb
|
from blockdb import get_blocks_after_timestamp
|
||||||
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):
|
||||||
blocks = []
|
return [block.raw for block in get_blocks_after_timestamp(timestamp)]
|
||||||
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
|
# Wrapper for onionrblocks.create_block (take base64 to be compatible with RPC)
|
||||||
# (take base64 to be compatible with RPC)
|
bl = multiproc.subprocess_compute(
|
||||||
bl: Block = multiproc.subprocess_compute(
|
|
||||||
onionrblocks.create_anonvdf_block,
|
onionrblocks.create_anonvdf_block,
|
||||||
3600,
|
3600,
|
||||||
base64.b64decode(block_data),
|
base64.b64decode(block_data),
|
||||||
@ -41,35 +28,14 @@ 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')
|
||||||
|
|
||||||
@dispatcher.add_method
|
|
||||||
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)
|
queue_to_use = randbits(1)
|
||||||
|
|
||||||
|
|
||||||
@dispatcher.add_method
|
@dispatcher.add_method
|
||||||
def insert_block(block: Union[dict, Block]):
|
def insert_block(block):
|
||||||
if isinstance(block, dict):
|
block = Block(
|
||||||
block = Block(
|
block['id'], b85decode(block['raw']), auto_verify=False)
|
||||||
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"
|
||||||
|
|
||||||
|
@ -66,11 +66,7 @@ def on_init(api, data=None):
|
|||||||
load_identities_from_blocks())
|
load_identities_from_blocks())
|
||||||
)
|
)
|
||||||
|
|
||||||
# Expose WOT to RPC if the RPC plugin is loaded
|
plugin_apis['rpc.add_module_to_api'](wot)
|
||||||
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', '')
|
||||||
|
Loading…
Reference in New Issue
Block a user