OnionValidator: a dumb plugin for validating onion peers

This commit is contained in:
Dmitri Bogomolov 2019-04-10 18:36:26 +03:00
parent d20486df0c
commit 5e11a04e9a
Signed by untrusted user: g1itch
GPG Key ID: 720A756F18DEED13
3 changed files with 80 additions and 0 deletions

View File

@ -16,6 +16,7 @@ EXTRAS_REQUIRE = {
'prctl': ['python_prctl'], # Named threads
'qrcode': ['qrcode'],
'sound;platform_system=="Windows"': ['winsound'],
'tor': ['stem'],
'docs': [
'sphinx', # fab build_docs
'graphviz', # fab build_docs
@ -129,6 +130,9 @@ if __name__ == "__main__":
ext_modules=[bitmsghash],
zip_safe=False,
entry_points={
'bitmessage.nodes.validator': [
'onion = pybitmessage.plugins.validator_onion [tor]'
],
'bitmessage.gui.menu': [
'address.qrcode = pybitmessage.plugins.menu_qrcode [qrcode]'
],

View File

@ -0,0 +1,31 @@
import unittest
from pybitmessage.state import Peer
try:
from validator_onion import OnionValidator
validator_onion = True
except ImportError:
validator_onion = False
@unittest.skipIf(not validator_onion, 'OnionValidator is not available')
class TestOnionValidator(unittest.TestCase):
"""Test case for OnionValidator"""
@classmethod
def setUpClass(cls):
cls.check = OnionValidator()
def test_valid(self):
"""Ensure validator returns True for valid nodes"""
# not onion node
self.assertTrue(self.check(Peer('5.45.99.75', 8444)))
# default onion node
self.assertTrue(self.check(Peer('quzwelsuziwqgpt2.onion', 8444)))
def test_invalid(self):
"""Ensure validator returns False for invalid hostnames"""
# is not base32
self.assertFalse(self.check(Peer('test.onion', 8444)))
# no descriptor
self.assertFalse(self.check(Peer('aaaaaaaaaaaaaaaa.onion', 8444)))

View File

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
import base64
import stem
from stem.control import Controller
class OnionValidator(object):
"""Validation plugin for onion nodes"""
def __init__(self):
try: # TODO: deal with authentication
self.controller = Controller.from_port()
self.controller.authenticate()
except (stem.SocketError, stem.connection.AuthenticationFailure):
raise ValueError # do not load this if controller is not available
def _validate_onion(self, addr):
"""Check the .onion address validity"""
try:
base64.b32decode(addr, True)
except TypeError:
return False
if not self.controller:
return True
try:
self.controller.get_hidden_service_descriptor(addr)
except stem.DescriptorUnavailable:
return False
return True
def __call__(self, node):
"""Filter check for .onion addresses validation"""
addr = node.host
try:
addr, dom = addr.split('.')
except ValueError:
return True
return self._validate_onion(addr) if dom == 'onion' else True
connect_plugin = OnionValidator()