diff --git a/.gitignore b/.gitignore index 131c935..6704941 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build dist config +__pycache__ diff --git a/bin/peerlink b/bin/peerlink new file mode 100755 index 0000000..71ced18 --- /dev/null +++ b/bin/peerlink @@ -0,0 +1,11 @@ +#!/usr/bin/python3 +import os +import sys + +root = os.path.join(os.path.abspath(os.path.dirname(__file__)), '..') +if os.path.exists(os.path.join(root, 'peerlink')): + sys.path.insert(0, root) + + +from peerlink import server +server.run() diff --git a/peerlink/directory.py b/peerlink/directory.py index 6f13523..a3ca155 100644 --- a/peerlink/directory.py +++ b/peerlink/directory.py @@ -1,14 +1,14 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 # DHT placeholder -from __future__ import division + import json import ed25519 import requests -import settings +from . import settings import logging logger = logging.getLogger('net.directory') @@ -41,7 +41,7 @@ def get(vk): def put(sk, data): id = sk.get_verifying_key().to_ascii(encoding='base64').decode() - data = json.dumps(data) + data = json.dumps(data).encode() sig = sk.sign(data, encoding='base64').decode() url = '%s/%s' % (base, id) headers = { diff --git a/peerlink/link.py b/peerlink/link.py index 11adf36..4101ab7 100644 --- a/peerlink/link.py +++ b/peerlink/link.py @@ -1,20 +1,20 @@ -import httplib +import http.client import socket -import urllib2 +import urllib.request, urllib.error, urllib.parse import ssl import hashlib -from utils import valid +from .utils import valid -import settings +from . import settings import logging logger = logging.getLogger('link') -class InvalidCertificateException(httplib.HTTPException, urllib2.URLError): +class InvalidCertificateException(http.client.HTTPException, urllib.error.URLError): def __init__(self, fingerprint, cert, reason): - httplib.HTTPException.__init__(self) + http.client.HTTPException.__init__(self) self.fingerprint = fingerprint self.cert_fingerprint = hashlib.sha1(cert).hexdigest() self.reason = reason @@ -23,11 +23,11 @@ class InvalidCertificateException(httplib.HTTPException, urllib2.URLError): return ('%s (local) != %s (remote) (%s)\n' % (self.fingerprint, self.cert_fingerprint, self.reason)) -class CertValidatingHTTPSConnection(httplib.HTTPConnection): - default_port = httplib.HTTPS_PORT +class CertValidatingHTTPSConnection(http.client.HTTPConnection): + default_port = http.client.HTTPS_PORT def __init__(self, host, port=None, fingerprint=None, strict=None, **kwargs): - httplib.HTTPConnection.__init__(self, host, port, strict, **kwargs) + http.client.HTTPConnection.__init__(self, host, port, strict, **kwargs) self.fingerprint = fingerprint if self.fingerprint: self.cert_reqs = ssl.CERT_REQUIRED @@ -50,30 +50,32 @@ class CertValidatingHTTPSConnection(httplib.HTTPConnection): 'fingerprint mismatch') #logger.debug('CIPHER %s VERSION %s', self.sock.cipher(), self.sock.ssl_version) -class VerifiedHTTPSHandler(urllib2.HTTPSHandler): +class VerifiedHTTPSHandler(urllib.request.HTTPSHandler): def __init__(self, **kwargs): - urllib2.AbstractHTTPHandler.__init__(self) + urllib.request.AbstractHTTPHandler.__init__(self) self._connection_args = kwargs def https_open(self, req): def http_class_wrapper(host, **kwargs): full_kwargs = dict(self._connection_args) full_kwargs.update(kwargs) + if 'timeout' in full_kwargs: + del full_kwargs['timeout'] return CertValidatingHTTPSConnection(host, **full_kwargs) try: return self.do_open(http_class_wrapper, req) - except urllib2.URLError, e: + except urllib.error.URLError as e: if type(e.reason) == ssl.SSLError and e.reason.args[0] == 1: raise InvalidCertificateException(self.fingerprint, '', e.reason.args[1]) raise - https_request = urllib2.HTTPSHandler.do_request_ + https_request = urllib.request.HTTPSHandler.do_request_ def get_opener(fingerprint): handler = VerifiedHTTPSHandler(fingerprint=fingerprint) - opener = urllib2.build_opener(handler) + opener = urllib.request.build_opener(handler) return opener class Response(object): @@ -91,23 +93,23 @@ def read(url, body=None, headers={}, fingerprint=None, timeout=None): body = None opener = get_opener(fingerprint) headers = dict(headers) - request = urllib2.Request(url, data=body, headers=headers) + request = urllib.request.Request(url, data=body, headers=headers) response = Response() logger.debug('open %s [%s]', url, fingerprint) logger.debug('headers: %s', headers) try: r = opener.open(request, timeout=timeout) - except urllib2.HTTPError as e: + except urllib.error.HTTPError as e: response.code = e.code if e.code >= 500: - logger.debug('urllib2.HTTPError %s %s', e, e.code) + logger.debug('urllib.error.HTTPError %s %s', e, e.code) response.error = e else: response.headers = e.headers response.body = e.read() return response - except urllib2.URLError as e: - logger.debug('urllib2.URLError %s', e) + except urllib.error.URLError as e: + logger.debug('urllib.error.URLError %s', e) response.error = e response.code = 500 return response diff --git a/peerlink/localnodes.py b/peerlink/localnodes.py index 2ca4f5d..3078359 100644 --- a/peerlink/localnodes.py +++ b/peerlink/localnodes.py @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from threading import Thread import json import socket import struct -import thread +import _thread import time -from link import can_connect -from settings import server, USER_ID, sk, ENCODING -from utils import valid, get_public_ipv6, get_local_ipv4, get_interface +from .link import can_connect +from .settings import server, USER_ID, sk, ENCODING +from .utils import valid, get_public_ipv6, get_local_ipv4, get_interface import logging logger = logging.getLogger('localnodes') @@ -85,7 +85,7 @@ class LocalNodesBase(Thread): while self._active: data, addr = s.recvfrom(1024) if self._active: - while data[-1] == b'\0': + while data[-1] == 0: data = data[:-1] # Strip trailing \0's data = self.verify(data) if data: @@ -94,7 +94,7 @@ class LocalNodesBase(Thread): now = time.mktime(time.localtime()) if now - last > 60: last = now - thread.start_new_thread(self.send, ()) + _thread.start_new_thread(self.send, ()) except: logger.debug('receive failed. restart later', exc_info=1) time.sleep(10) @@ -110,13 +110,14 @@ class LocalNodesBase(Thread): #logger.debug('update node %s', data) if data['id'] != USER_ID: if data['id'] not in self._nodes: - thread.start_new_thread(self.new_node, (data, )) + _thread.start_new_thread(self.new_node, (data, )) elif can_connect(data): self._nodes[data['id']] = data def verify(self, data): + try: - packet = json.loads(data) + packet = json.loads(data.decode()) except: return None if len(packet) == 3: @@ -172,7 +173,7 @@ class LocalNodes6(LocalNodesBase): s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - group_bin = socket.inet_pton(socket.AF_INET6, self._BROADCAST) + '\0'*4 + group_bin = socket.inet_pton(socket.AF_INET6, self._BROADCAST) + b'\0'*4 s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group_bin) self._socket = s return s @@ -209,7 +210,7 @@ class LocalNodes(object): def cleanup(self): if self._active: - for id in self._nodes.keys(): + for id in list(self._nodes.keys()): if not can_connect(self._nodes[id]): del self._nodes[id] if not self._active: @@ -221,7 +222,7 @@ class LocalNodes(object): return self._nodes[user_id] def info(self): - return self._nodes.keys() + return list(self._nodes.keys()) def join(self): self._active = False diff --git a/peerlink/nodes.py b/peerlink/nodes.py index 7a1633f..3784390 100644 --- a/peerlink/nodes.py +++ b/peerlink/nodes.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from threading import Thread -from Queue import Queue +from queue import Queue from tornado.ioloop import PeriodicCallback -import directory -from localnodes import LocalNodes -from link import can_connect, node_url +from . import directory +from .localnodes import LocalNodes +from .link import can_connect, node_url import logging logger = logging.getLogger('lookup') @@ -33,7 +33,7 @@ class Nodes(Thread): def cleanup(self): if self._active: self._local.cleanup() - for id in self._nodes.keys(): + for id in list(self._nodes.keys()): if id in self._local._nodes: del self._nodes[id] if not can_connect(self._nodes[id]): @@ -70,7 +70,7 @@ class Nodes(Thread): l = self._local.info() return { 'local': l, - 'nodes': sorted(set(self._nodes.keys() + l)) + 'nodes': sorted(set(list(self._nodes.keys()) + l)) } def join(self): diff --git a/peerlink/nodeserver.py b/peerlink/nodeserver.py index 42d95a3..da8bf57 100644 --- a/peerlink/nodeserver.py +++ b/peerlink/nodeserver.py @@ -7,11 +7,11 @@ from tornado.httpserver import HTTPServer from tornado.ioloop import PeriodicCallback import tornado.web -from proxy import ProxyHandler -from utils import get_public_ipv6, valid -import directory -import settings -import state +from .proxy import ProxyHandler +from .utils import get_public_ipv6, valid +from . import directory +from . import settings +from . import state import logging logger = logging.getLogger('nodeserver') diff --git a/peerlink/proxy.py b/peerlink/proxy.py index c535a5c..e6586cd 100644 --- a/peerlink/proxy.py +++ b/peerlink/proxy.py @@ -5,8 +5,8 @@ import tornado.web import tornado.httpclient import tornado.gen -from utils import run_async -import link +from .utils import run_async +from . import link import logging logger = logging.getLogger('proxy') @@ -52,7 +52,7 @@ class ProxyHandler(tornado.web.RequestHandler): ignored = set(response.headers.keys()) - set([h.lower() for h in allowed_headers]) if ignored: - print 'IGNORED', ignored + print('IGNORED', ignored) if response.data: self.write(response.data) diff --git a/peerlink/server.py b/peerlink/server.py index 8bca8cf..eb115d7 100644 --- a/peerlink/server.py +++ b/peerlink/server.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division, print_function + import json import os @@ -12,11 +12,11 @@ from tornado.ioloop import IOLoop from tornado.web import Application import tornado -from proxy import ProxyHandler -import nodes -import nodeserver -import settings -import state +from .proxy import ProxyHandler +from . import nodes +from . import nodeserver +from . import settings +from . import state import logging logger = logging.getLogger('server') diff --git a/peerlink/settings.py b/peerlink/settings.py index 899cccb..7bc4e3b 100644 --- a/peerlink/settings.py +++ b/peerlink/settings.py @@ -4,7 +4,7 @@ import os import ed25519 -from pdict import pdict +from .pdict import pdict base_dir = os.path.normpath(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..')) @@ -32,21 +32,21 @@ server = pdict(os.path.join(config_path, 'settings.json'), defaults) services = pdict(os.path.join(config_path, 'services.json'), {}) if os.path.exists(key_path): - with open(key_path) as fd: + with open(key_path, 'rb') as fd: sk = ed25519.SigningKey(fd.read()) vk = sk.get_verifying_key() else: sk, vk = ed25519.create_keypair() with open(key_path, 'wb') as fd: - os.chmod(key_path, 0600) + os.chmod(key_path, 0o600) fd.write(sk.to_bytes()) - os.chmod(key_path, 0400) + os.chmod(key_path, 0o400) ENCODING='base64' USER_ID = vk.to_ascii(encoding=ENCODING).decode() if not os.path.exists(tls_cert_path): - from tls import create_certificate + from .tls import create_certificate server['cert'] = create_certificate(tls_key_path, tls_cert_path, USER_ID) VERSION="0.0" diff --git a/peerlink/tls.py b/peerlink/tls.py index 410df9f..75df231 100644 --- a/peerlink/tls.py +++ b/peerlink/tls.py @@ -13,9 +13,9 @@ def create_certificate(tls_key_path, tls_cert_path, USER_ID): key = OpenSSL.crypto.PKey() key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) with open(tls_key_path, 'wb') as fd: - os.chmod(tls_key_path, 0600) + os.chmod(tls_key_path, 0o600) fd.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)) - os.chmod(tls_key_path, 0400) + os.chmod(tls_key_path, 0o400) ca = OpenSSL.crypto.X509() ca.set_version(2) diff --git a/peerlink/utils.py b/peerlink/utils.py index a7ae819..e4d951a 100644 --- a/peerlink/utils.py +++ b/peerlink/utils.py @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from functools import wraps from threading import Thread import socket import subprocess import sys -from urlparse import urlparse +from urllib.parse import urlparse import ed25519 -import settings +from . import settings import logging logger = logging.getLogger('utils') @@ -91,11 +91,11 @@ def valid(key, value, sig): ''' validate that value was signed by key ''' - if isinstance(sig, unicode): + if isinstance(sig, str): sig = sig.encode('utf-8') - if isinstance(value, unicode): + if isinstance(value, str): value = value.encode('utf-8') - if isinstance(key, unicode): + if isinstance(key, str): key = key.encode('utf-8') vk = ed25519.VerifyingKey(key, encoding=settings.ENCODING) try: