From 716aa44d2eccde4b2762b6991e3d04ec7ab0549e Mon Sep 17 00:00:00 2001 From: l-n-s Date: Sun, 25 Jun 2017 07:08:46 -0400 Subject: [PATCH 1/2] Added --no-encryption option. Disables local private key encryption. --- pyseeder.py | 4 ++++ pyseeder/actions.py | 18 ++++++++++++++---- pyseeder/crypto.py | 12 ++++++++---- pyseeder/su3file.py | 2 +- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/pyseeder.py b/pyseeder.py index bc9a3e1..f5b526b 100755 --- a/pyseeder.py +++ b/pyseeder.py @@ -25,6 +25,8 @@ def main(): help="RSA private key (default: data/priv_key.pem)") kg_parser.add_argument("--cert", default=None, help="Certificate (example: data/user_at_mail.i2p.crt)") + kg_parser.add_argument("--no-encryption", action="store_true", + help="Disable private key encryption") kg_parser.set_defaults(func=pyseeder.actions.keygen) @@ -44,6 +46,8 @@ echo $YOUR_PASSWORD | %(prog)s --netdb /path/to/netDb \\ help="Output file (default: output/i2pseeds.su3)") rs_parser.add_argument("--netdb", required=True, help="Path to netDb folder (example: ~/.i2pd/netDb)") + rs_parser.add_argument("--no-encryption", action="store_true", + help="Disable private key encryption") rs_parser.set_defaults(func=pyseeder.actions.reseed) diff --git a/pyseeder/actions.py b/pyseeder/actions.py index b87f935..c3ab90a 100644 --- a/pyseeder/actions.py +++ b/pyseeder/actions.py @@ -11,9 +11,14 @@ def keygen(args): for f in [args.cert, args.private_key]: check_writable(f) from pyseeder.crypto import keygen - from getpass import getpass - priv_key_password = getpass("Set private key password: ").encode("utf-8") - keygen(args.cert, args.private_key, priv_key_password, args.signer_id) + + if args.no_encryption: + priv_key_password = None + else: + from getpass import getpass + priv_key_password = getpass("Set private key password: ").encode("utf-8") + + keygen(args.cert, args.private_key, args.signer_id, priv_key_password) def reseed(args): """Sub-command to generate reseed file""" @@ -21,7 +26,12 @@ def reseed(args): for f in [args.netdb, args.private_key]: check_readable(f) from pyseeder.su3file import SU3File - priv_key_password = input().encode("utf-8") + + if args.no_encryption: + priv_key_password = None + else: + priv_key_password = input().encode("utf-8") + su3file = SU3File(args.signer_id) su3file.reseed(args.netdb) su3file.write(args.outfile, args.private_key, priv_key_password) diff --git a/pyseeder/crypto.py b/pyseeder/crypto.py index 3a9e8eb..c544ac2 100644 --- a/pyseeder/crypto.py +++ b/pyseeder/crypto.py @@ -13,19 +13,23 @@ from cryptography.x509.oid import NameOID from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding -def keygen(pub_key, priv_key, priv_key_password, user_id): +def keygen(pub_key, priv_key, user_id, priv_key_password=None): """Generate new private key and certificate RSA_SHA512_4096""" # Generate our key key = rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend()) + if priv_key_password: + ea = serialization.BestAvailableEncryption(priv_key_password) + else: + ea = serialization.NoEncryption() + # Write our key to disk for safe keeping with open(priv_key, "wb") as f: f.write(key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, - encryption_algorithm=serialization.BestAvailableEncryption( - priv_key_password), + encryption_algorithm=ea, )) # Various details about who we are. For a self-signed certificate the @@ -57,7 +61,7 @@ def keygen(pub_key, priv_key, priv_key_password, user_id): f.write(cert.public_bytes(serialization.Encoding.PEM)) -def append_signature(target_file, priv_key, priv_key_password): +def append_signature(target_file, priv_key, priv_key_password=None): """Append signature to the end of file""" with open(target_file, "rb") as f: contents = f.read() diff --git a/pyseeder/su3file.py b/pyseeder/su3file.py index af57847..95694f6 100644 --- a/pyseeder/su3file.py +++ b/pyseeder/su3file.py @@ -25,7 +25,7 @@ class SU3File: self.VERSION = str(int(time.time())).encode("utf-8") #self.keytype = "RSA_SHA512_4096" - def write(self, filename, priv_key, priv_key_password): + def write(self, filename, priv_key, priv_key_password=None): """Write file to disc""" nullbyte = bytes([0]) with open(filename, "wb") as f: From e333cc5b56e91a1e3e41860477a1a32b3cf1b574 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Mon, 26 Jun 2017 05:10:25 -0400 Subject: [PATCH 2/2] add github transport (#3) --- pyseeder.py | 14 +++++++++- pyseeder/transport.py | 6 ++++- pyseeder/transports/github.py | 49 +++++++++++++++++++++++++++++++++++ requirements.txt | 1 + transports.ini.example | 14 +++++++++- 5 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 pyseeder/transports/github.py diff --git a/pyseeder.py b/pyseeder.py index f5b526b..8ffa99e 100755 --- a/pyseeder.py +++ b/pyseeder.py @@ -2,13 +2,20 @@ import os import sys import argparse +import logging import pyseeder.transport import pyseeder.actions from pyseeder.utils import PyseederException + +log = logging.getLogger(__name__) def main(): parser = argparse.ArgumentParser() + parser.add_argument('--loglevel', default=logging.INFO, help="Log level", + choices=[logging.CRITICAL, logging.ERROR, logging.WARNING, + logging.INFO, logging.DEBUG]) + subparsers = parser.add_subparsers(title="actions", help="Command to execute") @@ -101,12 +108,17 @@ echo $YOUR_PASSWORD | %(prog)s --netdb /path/to/netDb \\ help=".su3 file (default: output/i2pseeds.su3)") serve_parser.set_defaults(func=pyseeder.actions.serve) + args = parser.parse_args() + + logging.basicConfig(level=args.loglevel, + format='%(levelname)-8s %(message)s') + if hasattr(args, "func"): try: args.func(args) except PyseederException as pe: - print("Pyseeder error: {}".format(pe)) + log.critical("Pyseeder error: {}".format(pe)) sys.exit(1) else: parser.print_help() diff --git a/pyseeder/transport.py b/pyseeder/transport.py index 3735734..6e94320 100644 --- a/pyseeder/transport.py +++ b/pyseeder/transport.py @@ -3,9 +3,11 @@ import urllib.request from urllib.error import URLError import os import importlib +import logging -from pyseeder.utils import PyseederException +from pyseeder.utils import PyseederException, TransportException +log = logging.getLogger(__name__) RESEED_URLS = [ "https://reseed.i2p-projekt.de/", @@ -55,4 +57,6 @@ def upload(filename, config): except ImportError: raise PyseederException( "{} transport can't be loaded".format(t)) + except TransportException as e: + log.error("Transport error: {}".format(e)) diff --git a/pyseeder/transports/github.py b/pyseeder/transports/github.py new file mode 100644 index 0000000..5393a2e --- /dev/null +++ b/pyseeder/transports/github.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# (re)uploads reseed file to github repository releases as an asset +import requests + +from urllib.parse import urljoin +from mimetypes import guess_type +import sys +import os + +from pyseeder.utils import TransportException + +TRANSPORT_NAME = "github" + +def run(filename, config): + API_URL = "https://api.github.com/" + asset_name = os.path.split(filename)[-1] + content_type = guess_type(asset_name)[0] or "application/zip" + creds = (config["username"], config["token"]) + release_info_url = urljoin(API_URL, "/repos/{}/releases/tags/{}".format( + config["repo"], config["release_tag"])) + + # get release info + try: + resp = requests.get(release_info_url, auth=creds) + except: + raise TransportException("Failed to connect to GitHub API") + + if resp.status_code is not 200: + raise TransportException("Check your GitHub API auth settings") + + # delete old asset + for x in resp.json()["assets"]: + if x["name"] == asset_name: + r = requests.delete(x["url"], auth=creds) + if r.status_code is not 204: + raise TransportException("Failed to delete asset from GitHub") + + # upload new asset + upload_url = resp.json()["upload_url"].split("{")[0] # wat + headers = {'Content-Type': content_type} + params = {'name': asset_name} + + data = open(filename, 'rb').read() + r = requests.post(upload_url, headers=headers, params=params, auth=creds, + data=data) + + if r.status_code is not 201: + raise TransportException("Failed to upload asset to GitHub API") + diff --git a/requirements.txt b/requirements.txt index b98e00d..9be67a1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ cryptography>=1.4 +requests diff --git a/transports.ini.example b/transports.ini.example index 285eaef..8a88045 100644 --- a/transports.ini.example +++ b/transports.ini.example @@ -1,6 +1,6 @@ [transports] ; enabled transports separated by space -enabled=git +enabled=github [git] ; Folder with git repository to use @@ -8,3 +8,15 @@ folder=/home/user/reseed-data-repo [dropbox] ; todo + +[github] +; GitHub username +username=username +; GitHub API token +; Generate token for this script here --> https://github.com/settings/tokens +; Check scope: public_repo (shall be enough) +token=token +; Repository +repo=username/repo-name +; Repository tag to which asset is being uploaded +release_tag=v1.0