Removed more defunct code
This commit is contained in:
parent
e1b4b12024
commit
cb977a2719
@ -46,14 +46,6 @@ locale.setlocale(locale.LC_ALL, '') # noqa
|
|||||||
ran_as_script = False
|
ran_as_script = False
|
||||||
if __name__ == "__main__": ran_as_script = True
|
if __name__ == "__main__": ran_as_script = True
|
||||||
|
|
||||||
# Import standard libraries
|
|
||||||
|
|
||||||
try:
|
|
||||||
from onionrutils import dependencycheck # noqa
|
|
||||||
except ModuleNotFoundError as e:
|
|
||||||
print('Missing requirement: ' + str(e) + ' installed')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Import 3rd party libraries
|
# Import 3rd party libraries
|
||||||
|
|
||||||
from filenuke import nuke # noqa
|
from filenuke import nuke # noqa
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
"""Onionr - Private P2P Communication.
|
|
||||||
|
|
||||||
Desktop notification wrapper
|
|
||||||
"""
|
|
||||||
from subprocess import Popen
|
|
||||||
|
|
||||||
try:
|
|
||||||
import simplenotifications as simplenotify
|
|
||||||
except ImportError:
|
|
||||||
notifications_enabled = False
|
|
||||||
else:
|
|
||||||
notifications_enabled = True
|
|
||||||
|
|
||||||
from utils.readstatic import get_static_dir
|
|
||||||
import config
|
|
||||||
from onionrplugins.onionrevents import event as plugin_api_event
|
|
||||||
"""
|
|
||||||
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/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not config.get('general.show_notifications', True):
|
|
||||||
notifications_enabled = False
|
|
||||||
|
|
||||||
notification_sound_file = get_static_dir() + "sounds/notification1.mp3"
|
|
||||||
|
|
||||||
|
|
||||||
def notify(title: str = "Onionr", message: str = ""):
|
|
||||||
"""Cross platform method to show a notification."""
|
|
||||||
if not notifications_enabled:
|
|
||||||
return
|
|
||||||
plugin_api_event("notification", data={"title": title, "message": message})
|
|
||||||
simplenotify.notify(title, message)
|
|
||||||
|
|
||||||
|
|
||||||
def notification_with_sound(sound='', **kwargs):
|
|
||||||
if not notifications_enabled:
|
|
||||||
return
|
|
||||||
if not sound:
|
|
||||||
sound = notification_sound_file
|
|
||||||
try:
|
|
||||||
Popen(["mpv", sound])
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
notify(**kwargs)
|
|
@ -1,21 +0,0 @@
|
|||||||
from audioop import mul
|
|
||||||
import multiprocessing
|
|
||||||
|
|
||||||
|
|
||||||
def run_func_in_new_process(func, *args, **kwargs):
|
|
||||||
queue = multiprocessing.Queue()
|
|
||||||
|
|
||||||
def _wrap_func():
|
|
||||||
if args and kwargs:
|
|
||||||
queue.put(func(*args, **kwargs))
|
|
||||||
elif args:
|
|
||||||
queue.put(func(*args))
|
|
||||||
elif kwargs:
|
|
||||||
queue.put(func(**kwargs))
|
|
||||||
else:
|
|
||||||
queue.put(func())
|
|
||||||
|
|
||||||
proc = multiprocessing.Process(target=_wrap_func, daemon=True)
|
|
||||||
proc.start()
|
|
||||||
return queue.get()
|
|
||||||
|
|
@ -10,7 +10,6 @@ import ujson as json
|
|||||||
import config
|
import config
|
||||||
import logger
|
import logger
|
||||||
import onionrvalues
|
import onionrvalues
|
||||||
from onionrutils import getopenport
|
|
||||||
from logger.settings import *
|
from logger.settings import *
|
||||||
from utils import readstatic
|
from utils import readstatic
|
||||||
"""
|
"""
|
||||||
@ -77,14 +76,3 @@ def setup_config():
|
|||||||
set_level(map[verbosity])
|
set_level(map[verbosity])
|
||||||
else:
|
else:
|
||||||
logger.warn('Verbosity level %s is not valid, using default verbosity.' % verbosity)
|
logger.warn('Verbosity level %s is not valid, using default verbosity.' % verbosity)
|
||||||
|
|
||||||
if type(config.get('client.webpassword')) is type(None):
|
|
||||||
config.set('client.webpassword', base64.b16encode(os.urandom(32)).decode('utf-8'), savefile=True)
|
|
||||||
if type(config.get('client.client.port')) is type(None):
|
|
||||||
randomPort = getopenport.get_open_port()
|
|
||||||
config.set('client.client.port', randomPort, savefile=True)
|
|
||||||
if type(config.get('client.public.port')) is type(None):
|
|
||||||
randomPort = getopenport.get_open_port()
|
|
||||||
config.set('client.public.port', randomPort, savefile=True)
|
|
||||||
if type(config.get('client.api_version')) is type(None):
|
|
||||||
config.set('client.api_version', onionrvalues.API_VERSION, savefile=True)
|
|
@ -1 +0,0 @@
|
|||||||
from urllib3.contrib.socks import SOCKSProxyManager # noqa
|
|
@ -1,37 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Return the client api server address and port, which is usually random
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
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 filepaths
|
|
||||||
import config
|
|
||||||
def get_client_API_server():
|
|
||||||
config.reload()
|
|
||||||
retData = ''
|
|
||||||
getconf = lambda: config.get('client.client.port')
|
|
||||||
port = getconf()
|
|
||||||
if port is None:
|
|
||||||
config.reload()
|
|
||||||
port = getconf()
|
|
||||||
try:
|
|
||||||
with open(filepaths.private_API_host_file, 'r') as host:
|
|
||||||
hostname = host.read()
|
|
||||||
except FileNotFoundError:
|
|
||||||
raise FileNotFoundError
|
|
||||||
else:
|
|
||||||
retData += '%s:%s' % (hostname, port)
|
|
||||||
return retData
|
|
@ -1,29 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
get an open port
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
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 socket
|
|
||||||
def get_open_port():
|
|
||||||
# taken from (but modified) https://stackoverflow.com/a/2838309 by https://stackoverflow.com/users/133374/albert ccy-by-sa-3 https://creativecommons.org/licenses/by-sa/3.0/
|
|
||||||
# changes from source: import moved to top of file, bind specifically to localhost
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
s.bind(("127.0.0.1",0))
|
|
||||||
s.listen(1)
|
|
||||||
port = s.getsockname()[1]
|
|
||||||
s.close()
|
|
||||||
return port
|
|
@ -1,49 +1,30 @@
|
|||||||
'''
|
"""
|
||||||
Onionr - Private P2P Communication
|
Onionr - Private P2P Communication
|
||||||
|
|
||||||
validate various string data types
|
validate various string data types
|
||||||
'''
|
"""
|
||||||
'''
|
import base64
|
||||||
This program is free software: you can redistribute it and/or modify
|
import string
|
||||||
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, string
|
|
||||||
import unpaddedbase32, nacl.signing, nacl.encoding
|
import unpaddedbase32, nacl.signing, nacl.encoding
|
||||||
from onionrutils import bytesconverter
|
from onionrutils import bytesconverter
|
||||||
def validate_hash(data, length=64):
|
"""
|
||||||
'''
|
This program is free software: you can redistribute it and/or modify
|
||||||
Validate if a string is a valid hash hex digest (does not compare, just checks length and charset)
|
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.
|
||||||
|
|
||||||
Length is only invalid if its *more* than the specified
|
This program is distributed in the hope that it will be useful,
|
||||||
'''
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
retVal = True
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
if data == False or data == True:
|
GNU General Public License for more details.
|
||||||
return False
|
|
||||||
data = data.strip()
|
You should have received a copy of the GNU General Public License
|
||||||
if len(data) > length:
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
retVal = False
|
"""
|
||||||
else:
|
|
||||||
try:
|
|
||||||
int(data, 16)
|
|
||||||
except ValueError:
|
|
||||||
retVal = False
|
|
||||||
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
def validate_pub_key(key):
|
def validate_pub_key(key):
|
||||||
'''
|
"""Validate if a string is a valid base32 encoded Ed25519 key"""
|
||||||
Validate if a string is a valid base32 encoded Ed25519 key
|
|
||||||
'''
|
|
||||||
if type(key) is type(None):
|
if type(key) is type(None):
|
||||||
return False
|
return False
|
||||||
# Accept keys that have no = padding
|
# Accept keys that have no = padding
|
||||||
@ -54,18 +35,8 @@ def validate_pub_key(key):
|
|||||||
nacl.signing.SigningKey(seed=key, encoder=nacl.encoding.Base32Encoder)
|
nacl.signing.SigningKey(seed=key, encoder=nacl.encoding.Base32Encoder)
|
||||||
except nacl.exceptions.ValueError:
|
except nacl.exceptions.ValueError:
|
||||||
pass
|
pass
|
||||||
except base64.binascii.Error as err:
|
except base64.binascii.Error as _:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
retVal = True
|
retVal = True
|
||||||
return retVal
|
return retVal
|
||||||
|
|
||||||
|
|
||||||
def is_integer_string(data):
|
|
||||||
'''Check if a string is a valid base10 integer (also returns true if already an int)'''
|
|
||||||
try:
|
|
||||||
int(data)
|
|
||||||
except (ValueError, TypeError) as e:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import notifier
|
|
||||||
|
|
||||||
|
|
||||||
def update_event(bl):
|
|
||||||
"""Show update notification if available, return bool of if update happened"""
|
|
||||||
if not bl.isSigner(onionrvalues.UPDATE_SIGN_KEY): raise onionrexceptions.InvalidUpdate
|
|
||||||
onionr.notifier.notify(message="A new Onionr update is available. Stay updated to remain secure.")
|
|
@ -1,127 +0,0 @@
|
|||||||
"""Onionr - Private P2P Communication.
|
|
||||||
|
|
||||||
validate new block's metadata
|
|
||||||
"""
|
|
||||||
from json import JSONDecodeError
|
|
||||||
import ujson as json
|
|
||||||
|
|
||||||
import logger, onionrexceptions
|
|
||||||
import onionrvalues
|
|
||||||
from . import stringvalidators, epoch, bytesconverter
|
|
||||||
import config, filepaths, onionrcrypto
|
|
||||||
"""
|
|
||||||
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 validate_metadata(metadata, block_data) -> bool:
|
|
||||||
"""Validate metadata meets onionr spec (does not validate proof value computation), take in either dictionary or json string"""
|
|
||||||
|
|
||||||
ret_data = False
|
|
||||||
max_clock_difference = onionrvalues.MAX_BLOCK_CLOCK_SKEW
|
|
||||||
|
|
||||||
# convert to dict if it is json string
|
|
||||||
if type(metadata) is str:
|
|
||||||
try:
|
|
||||||
metadata = json.loads(metadata)
|
|
||||||
except JSONDecodeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Validate metadata dict for invalid keys to sizes that are too large
|
|
||||||
maxAge = onionrvalues.DEFAULT_EXPIRE
|
|
||||||
if type(metadata) is dict:
|
|
||||||
for i in metadata:
|
|
||||||
try:
|
|
||||||
onionrvalues.BLOCK_METADATA_LENGTHS[i]
|
|
||||||
except KeyError:
|
|
||||||
logger.warn('Block has invalid metadata key ' + i)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
testData = metadata[i]
|
|
||||||
try:
|
|
||||||
testData = len(testData)
|
|
||||||
except (TypeError, AttributeError) as e:
|
|
||||||
testData = len(str(testData))
|
|
||||||
if onionrvalues.BLOCK_METADATA_LENGTHS[i] < testData:
|
|
||||||
logger.warn('Block metadata key ' + i + ' exceeded maximum size')
|
|
||||||
break
|
|
||||||
if i == 'time':
|
|
||||||
if not stringvalidators.is_integer_string(metadata[i]):
|
|
||||||
logger.warn('Block metadata time stamp is not integer string or int')
|
|
||||||
break
|
|
||||||
isFuture = (metadata[i] - epoch.get_epoch())
|
|
||||||
if isFuture > max_clock_difference:
|
|
||||||
logger.warn('Block timestamp is skewed to the future over the max %s: %s', (max_clock_difference, isFuture))
|
|
||||||
break
|
|
||||||
if (epoch.get_epoch() - metadata[i]) > maxAge:
|
|
||||||
logger.warn('Block is outdated: %s' % (metadata[i],))
|
|
||||||
break
|
|
||||||
elif i == 'expire':
|
|
||||||
try:
|
|
||||||
if not int(metadata[i]) > epoch.get_epoch(): raise ValueError
|
|
||||||
except ValueError:
|
|
||||||
logger.warn('Block is expired: %s less than %s' % (metadata[i], epoch.get_epoch()))
|
|
||||||
break
|
|
||||||
elif i == 'encryptType':
|
|
||||||
try:
|
|
||||||
if not metadata[i] in ('asym', 'sym', ''): raise ValueError
|
|
||||||
except ValueError:
|
|
||||||
logger.warn('Invalid encryption mode')
|
|
||||||
break
|
|
||||||
elif i == 'sig':
|
|
||||||
try:
|
|
||||||
metadata['encryptType']
|
|
||||||
except KeyError:
|
|
||||||
signer = metadata['signer']
|
|
||||||
sig = metadata['sig']
|
|
||||||
encodedMeta = bytesconverter.str_to_bytes(metadata['meta'])
|
|
||||||
encodedBlock = bytesconverter.str_to_bytes(block_data)
|
|
||||||
if not onionrcrypto.signing.ed_verify(encodedMeta + encodedBlock[1:], signer, sig):
|
|
||||||
logger.warn(f'Block was signed by {signer}, but signature failed')
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# if metadata loop gets no errors, it does not break, therefore metadata is valid
|
|
||||||
# make sure we do not have another block with the same data content (prevent data duplication and replay attacks)
|
|
||||||
|
|
||||||
# Make sure time is set (validity was checked above if it is)
|
|
||||||
if not config.get('general.store_plaintext_blocks', True):
|
|
||||||
try:
|
|
||||||
if not metadata['encryptType']:
|
|
||||||
raise onionrexceptions.PlaintextNotSupported
|
|
||||||
except KeyError:
|
|
||||||
raise onionrexceptions.PlaintextNotSupported
|
|
||||||
try:
|
|
||||||
metadata['time']
|
|
||||||
except KeyError:
|
|
||||||
logger.warn("Time header not set")
|
|
||||||
return False
|
|
||||||
|
|
||||||
nonce = bytesconverter.bytes_to_str(onionrcrypto.hashers.sha3_hash(block_data))
|
|
||||||
try:
|
|
||||||
with open(filepaths.data_nonce_file, 'r') as nonceFile:
|
|
||||||
if nonce in nonceFile.read():
|
|
||||||
# we've seen that nonce before, so we can't pass metadata
|
|
||||||
raise onionrexceptions.DataExists
|
|
||||||
except FileNotFoundError:
|
|
||||||
ret_data = True
|
|
||||||
except onionrexceptions.DataExists:
|
|
||||||
# do not set ret_data to True, because data has been seen before
|
|
||||||
logger.warn(f'{nonce} seen before')
|
|
||||||
raise onionrexceptions.DataExists
|
|
||||||
else:
|
|
||||||
ret_data = True
|
|
||||||
else:
|
|
||||||
logger.warn('In call to utils.validateMetadata, metadata must be JSON string or a dictionary object')
|
|
||||||
|
|
||||||
return ret_data
|
|
@ -1,30 +0,0 @@
|
|||||||
"""Onionr - Private P2P Communication.
|
|
||||||
|
|
||||||
greenlet safe sleep, ignoring ctrl-c
|
|
||||||
"""
|
|
||||||
from gevent import sleep
|
|
||||||
from onionrutils.epoch import get_epoch
|
|
||||||
"""
|
|
||||||
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 better_sleep(wait: int):
|
|
||||||
"""Sleep catching ctrl c for wait seconds."""
|
|
||||||
start = get_epoch()
|
|
||||||
try:
|
|
||||||
sleep(wait)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
better_sleep(wait - (get_epoch() - start))
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
|||||||
"""Onionr - Private P2P Communication.
|
|
||||||
|
|
||||||
read from a file from an offset (efficiently)
|
|
||||||
"""
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
OffsetReadResult = namedtuple('OffsetReadResult', ['data', 'new_offset'])
|
|
||||||
|
|
||||||
|
|
||||||
def read_from_offset(file_path, offset=0):
|
|
||||||
with open(file_path, 'rb') as f:
|
|
||||||
if offset:
|
|
||||||
f.seek(offset)
|
|
||||||
data = f.read()
|
|
||||||
offset = f.tell()
|
|
||||||
|
|
||||||
return OffsetReadResult(data, offset)
|
|
@ -1,51 +0,0 @@
|
|||||||
'''
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
z-fill (zero fill) a string to a specific length
|
|
||||||
intended for reconstructing block hashes
|
|
||||||
'''
|
|
||||||
from typing import Union
|
|
||||||
'''
|
|
||||||
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 reconstruct_hash(hex_hash: Union[str, bytes],
|
|
||||||
length: int = 64) -> Union[str, bytes]:
|
|
||||||
"""Pad hash hex string with zeros, return result"""
|
|
||||||
return hex_hash.zfill(length)
|
|
||||||
|
|
||||||
|
|
||||||
def deconstruct_hash(hex_hash: Union[str, bytes]) -> Union[str, bytes]:
|
|
||||||
"""Remove leading zeros from hex hash, return result"""
|
|
||||||
new_hash = ''
|
|
||||||
ret_bytes = False
|
|
||||||
try:
|
|
||||||
hex_hash = hex_hash.decode()
|
|
||||||
ret_bytes = True
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
c = 0
|
|
||||||
for x in hex_hash:
|
|
||||||
if x == '0':
|
|
||||||
c += 1
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
new_hash = hex_hash[c:]
|
|
||||||
|
|
||||||
if ret_bytes:
|
|
||||||
|
|
||||||
new_hash = new_hash.encode()
|
|
||||||
return new_hash
|
|
@ -1 +0,0 @@
|
|||||||
https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion/robots.txt,http://2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion/robots.txt,http://rurcblzhmdk22kttfkel2zduhyu3r6to7knyc7wiorzrx5gw4c3lftad.onion/
|
|
Binary file not shown.
@ -1,19 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>
|
|
||||||
Onionr
|
|
||||||
</title>
|
|
||||||
<link rel="shortcut icon" type="image/ico" href="/shared/images/favicon.ico">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<p>Onionr</p>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -1,205 +0,0 @@
|
|||||||
/**
|
|
||||||
* Identicon.js 2.3.3
|
|
||||||
* http://github.com/stewartlord/identicon.js
|
|
||||||
*
|
|
||||||
* PNGLib required for PNG output
|
|
||||||
* http://www.xarg.org/download/pnglib.js
|
|
||||||
*
|
|
||||||
* Copyright 2018, Stewart Lord
|
|
||||||
* Released under the BSD license
|
|
||||||
* http://www.opensource.org/licenses/bsd-license.php
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var PNGlib;
|
|
||||||
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
||||||
PNGlib = require('./pnglib');
|
|
||||||
} else {
|
|
||||||
PNGlib = window.PNGlib;
|
|
||||||
}
|
|
||||||
|
|
||||||
var Identicon = function(hash, options){
|
|
||||||
if (typeof(hash) !== 'string' || hash.length < 15) {
|
|
||||||
throw 'A hash of at least 15 characters is required.';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.defaults = {
|
|
||||||
background: [240, 240, 240, 255],
|
|
||||||
margin: 0.08,
|
|
||||||
size: 64,
|
|
||||||
saturation: 0.7,
|
|
||||||
brightness: 0.5,
|
|
||||||
format: 'png'
|
|
||||||
};
|
|
||||||
|
|
||||||
this.options = typeof(options) === 'object' ? options : this.defaults;
|
|
||||||
|
|
||||||
// backward compatibility with old constructor (hash, size, margin)
|
|
||||||
if (typeof(arguments[1]) === 'number') { this.options.size = arguments[1]; }
|
|
||||||
if (arguments[2]) { this.options.margin = arguments[2]; }
|
|
||||||
|
|
||||||
this.hash = hash
|
|
||||||
this.background = this.options.background || this.defaults.background;
|
|
||||||
this.size = this.options.size || this.defaults.size;
|
|
||||||
this.format = this.options.format || this.defaults.format;
|
|
||||||
this.margin = this.options.margin !== undefined ? this.options.margin : this.defaults.margin;
|
|
||||||
|
|
||||||
// foreground defaults to last 7 chars as hue at 70% saturation, 50% brightness
|
|
||||||
var hue = parseInt(this.hash.substr(-7), 16) / 0xfffffff;
|
|
||||||
var saturation = this.options.saturation || this.defaults.saturation;
|
|
||||||
var brightness = this.options.brightness || this.defaults.brightness;
|
|
||||||
this.foreground = this.options.foreground || this.hsl2rgb(hue, saturation, brightness);
|
|
||||||
};
|
|
||||||
|
|
||||||
Identicon.prototype = {
|
|
||||||
background: null,
|
|
||||||
foreground: null,
|
|
||||||
hash: null,
|
|
||||||
margin: null,
|
|
||||||
size: null,
|
|
||||||
format: null,
|
|
||||||
|
|
||||||
image: function(){
|
|
||||||
return this.isSvg()
|
|
||||||
? new Svg(this.size, this.foreground, this.background)
|
|
||||||
: new PNGlib(this.size, this.size, 256);
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function(){
|
|
||||||
var image = this.image(),
|
|
||||||
size = this.size,
|
|
||||||
baseMargin = Math.floor(size * this.margin),
|
|
||||||
cell = Math.floor((size - (baseMargin * 2)) / 5),
|
|
||||||
margin = Math.floor((size - cell * 5) / 2),
|
|
||||||
bg = image.color.apply(image, this.background),
|
|
||||||
fg = image.color.apply(image, this.foreground);
|
|
||||||
|
|
||||||
// the first 15 characters of the hash control the pixels (even/odd)
|
|
||||||
// they are drawn down the middle first, then mirrored outwards
|
|
||||||
var i, color;
|
|
||||||
for (i = 0; i < 15; i++) {
|
|
||||||
color = parseInt(this.hash.charAt(i), 16) % 2 ? bg : fg;
|
|
||||||
if (i < 5) {
|
|
||||||
this.rectangle(2 * cell + margin, i * cell + margin, cell, cell, color, image);
|
|
||||||
} else if (i < 10) {
|
|
||||||
this.rectangle(1 * cell + margin, (i - 5) * cell + margin, cell, cell, color, image);
|
|
||||||
this.rectangle(3 * cell + margin, (i - 5) * cell + margin, cell, cell, color, image);
|
|
||||||
} else if (i < 15) {
|
|
||||||
this.rectangle(0 * cell + margin, (i - 10) * cell + margin, cell, cell, color, image);
|
|
||||||
this.rectangle(4 * cell + margin, (i - 10) * cell + margin, cell, cell, color, image);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
},
|
|
||||||
|
|
||||||
rectangle: function(x, y, w, h, color, image){
|
|
||||||
if (this.isSvg()) {
|
|
||||||
image.rectangles.push({x: x, y: y, w: w, h: h, color: color});
|
|
||||||
} else {
|
|
||||||
var i, j;
|
|
||||||
for (i = x; i < x + w; i++) {
|
|
||||||
for (j = y; j < y + h; j++) {
|
|
||||||
image.buffer[image.index(i, j)] = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// adapted from: https://gist.github.com/aemkei/1325937
|
|
||||||
hsl2rgb: function(h, s, b){
|
|
||||||
h *= 6;
|
|
||||||
s = [
|
|
||||||
b += s *= b < .5 ? b : 1 - b,
|
|
||||||
b - h % 1 * s * 2,
|
|
||||||
b -= s *= 2,
|
|
||||||
b,
|
|
||||||
b + h % 1 * s,
|
|
||||||
b + s
|
|
||||||
];
|
|
||||||
|
|
||||||
return[
|
|
||||||
s[ ~~h % 6 ] * 255, // red
|
|
||||||
s[ (h|16) % 6 ] * 255, // green
|
|
||||||
s[ (h|8) % 6 ] * 255 // blue
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
toString: function(raw){
|
|
||||||
// backward compatibility with old toString, default to base64
|
|
||||||
if (raw) {
|
|
||||||
return this.render().getDump();
|
|
||||||
} else {
|
|
||||||
return this.render().getBase64();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
isSvg: function(){
|
|
||||||
return this.format.match(/svg/i)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var Svg = function(size, foreground, background){
|
|
||||||
this.size = size;
|
|
||||||
this.foreground = this.color.apply(this, foreground);
|
|
||||||
this.background = this.color.apply(this, background);
|
|
||||||
this.rectangles = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
Svg.prototype = {
|
|
||||||
size: null,
|
|
||||||
foreground: null,
|
|
||||||
background: null,
|
|
||||||
rectangles: null,
|
|
||||||
|
|
||||||
color: function(r, g, b, a){
|
|
||||||
var values = [r, g, b].map(Math.round);
|
|
||||||
values.push((a >= 0) && (a <= 255) ? a/255 : 1);
|
|
||||||
return 'rgba(' + values.join(',') + ')';
|
|
||||||
},
|
|
||||||
|
|
||||||
getDump: function(){
|
|
||||||
var i,
|
|
||||||
xml,
|
|
||||||
rect,
|
|
||||||
fg = this.foreground,
|
|
||||||
bg = this.background,
|
|
||||||
stroke = this.size * 0.005;
|
|
||||||
|
|
||||||
xml = "<svg xmlns='http://www.w3.org/2000/svg'"
|
|
||||||
+ " width='" + this.size + "' height='" + this.size + "'"
|
|
||||||
+ " style='background-color:" + bg + ";'>"
|
|
||||||
+ "<g style='fill:" + fg + "; stroke:" + fg + "; stroke-width:" + stroke + ";'>";
|
|
||||||
|
|
||||||
for (i = 0; i < this.rectangles.length; i++) {
|
|
||||||
rect = this.rectangles[i];
|
|
||||||
if (rect.color == bg) continue;
|
|
||||||
xml += "<rect "
|
|
||||||
+ " x='" + rect.x + "'"
|
|
||||||
+ " y='" + rect.y + "'"
|
|
||||||
+ " width='" + rect.w + "'"
|
|
||||||
+ " height='" + rect.h + "'"
|
|
||||||
+ "/>";
|
|
||||||
}
|
|
||||||
xml += "</g></svg>"
|
|
||||||
|
|
||||||
return xml;
|
|
||||||
},
|
|
||||||
|
|
||||||
getBase64: function(){
|
|
||||||
if ('function' === typeof btoa) {
|
|
||||||
return btoa(this.getDump());
|
|
||||||
} else if (Buffer) {
|
|
||||||
return new Buffer(this.getDump(), 'binary').toString('base64');
|
|
||||||
} else {
|
|
||||||
throw 'Cannot generate base64 output';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
||||||
module.exports = Identicon;
|
|
||||||
} else {
|
|
||||||
window.Identicon = Identicon;
|
|
||||||
}
|
|
||||||
})();
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.5 KiB |
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
Onionr - Private P2P Communication
|
|
||||||
|
|
||||||
Provides userIcon which generates SVG identicons from a Onionr user pubkey
|
|
||||||
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
function toHexString(byteArray) {
|
|
||||||
// cc-by-sa-4 https://stackoverflow.com/a/44608819 by https://stackoverflow.com/users/1883624/grantpatterson
|
|
||||||
var s = '0x'
|
|
||||||
byteArray.forEach(function(byte) {
|
|
||||||
s += ('0' + (byte & 0xFF).toString(16)).slice(-2)
|
|
||||||
})
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sha256(str) {
|
|
||||||
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder("utf-8").encode(str))
|
|
||||||
return Array.prototype.map.call(new Uint8Array(buf), x=>(('00'+x.toString(16)).slice(-2))).join('')
|
|
||||||
}
|
|
||||||
|
|
||||||
async function userIcon(pubkey, imgSize=64){
|
|
||||||
pubkey = await sha256(base32.decode.asBytes(pubkey))
|
|
||||||
let options = {
|
|
||||||
//foreground: [0,0,0,1], // rgba black
|
|
||||||
background: [0, 0, 0, 0], // rgba white
|
|
||||||
//margin: 0.1,
|
|
||||||
size: imgSize,
|
|
||||||
format: 'svg' // use SVG instead of PNG
|
|
||||||
};
|
|
||||||
|
|
||||||
// create a base64 encoded SVG
|
|
||||||
let data = new Identicon(pubkey, options).toString();
|
|
||||||
return data
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user