diff --git a/Pipfile b/Pipfile index 524fb1c..925b81a 100644 --- a/Pipfile +++ b/Pipfile @@ -4,13 +4,11 @@ verify_ssl = true name = "pypi" [packages] +apixu = {git = "https://github.com/apixu/apixu-python.git",ref = "master"} requests = "*" +pyotp = "*" [dev-packages] [requires] python_version = "3.7" - -[packages.apixu] -git = "https://github.com/apixu/apixu-python.git" -ref = "master" diff --git a/Pipfile.lock b/Pipfile.lock index 2ffc179..51d4eb0 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "ca9c2522bf07f03d1588afe76e9f6fc73bc1efec20d4f155d82b709efaf14a56" + "sha256": "01bd2ed801b62b47100921e0ace284388d352ad9433e70331c082550bf830e03" }, "pipfile-spec": 6, "requires": { @@ -18,14 +18,14 @@ "default": { "apixu": { "git": "https://github.com/apixu/apixu-python.git", - "ref": "master" + "ref": "370216999346d5caf7f8dc6724b5766dcc6da25d" }, "certifi": { "hashes": [ - "sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", - "sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae" + "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", + "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" ], - "version": "==2019.3.9" + "version": "==2019.9.11" }, "chardet": { "hashes": [ @@ -41,6 +41,14 @@ ], "version": "==2.8" }, + "pyotp": { + "hashes": [ + "sha256:c88f37fd47541a580b744b42136f387cdad481b560ef410c0d85c957eb2a2bc0", + "sha256:fc537e8acd985c5cbf51e11b7d53c42276fee017a73aec7c07380695671ca1a1" + ], + "index": "pypi", + "version": "==2.3.0" + }, "requests": { "hashes": [ "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", @@ -51,10 +59,10 @@ }, "urllib3": { "hashes": [ - "sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", - "sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232" + "sha256:3de946ffbed6e6746608990594d08faac602528ac7015ac28d33cee6a45b7398", + "sha256:9a107b99a5393caf59c7aa3c1249c16e6879447533d0887f4336dde834c7be86" ], - "version": "==1.25.3" + "version": "==1.25.6" } }, "develop": {} diff --git a/README.md b/README.md index d934845..f27fa88 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,23 @@ ungleich --help ungleich weather ``` +## Usage: Config + +``` +ungleich config-add \ + --name + --realm + --seed +``` + ## Usage: DNS ``` -ungleich dns --set-reverse --user --token --realm --email --name mirror.example.com +ungleich dns \ + --set-reverse + --user + --email + --name mirror.example.com ``` ### Usage: RIPE @@ -47,8 +60,11 @@ ungleich ripe-add-route6 \ Creating a new account object: ``` -ungleich account --create-user --name --lastname --email - +ungleich account \ + --create-user + --name + --lastname + --email ``` ### Usage: SSH Key diff --git a/ungleich b/ungleich index 34d86cf..dc99669 100755 --- a/ungleich +++ b/ungleich @@ -7,6 +7,7 @@ from ungleich_ripe import ungleichRIPE from ungleich_account import Account_Create from ungleich_weather import ungleichWeather from ungleich_ssh_key import SSHKey +from ungleich_config import Ungleich_Config VERSION = "0.0.4" @@ -17,7 +18,8 @@ class ungleichCLI(object): # FIXME: make it generic dns = ungleichDNS(self.parser, self.parser_parents) ripe = ungleichRIPE(self.parser, self.parser_parents) - ripe = Account_Create(self.parser, self.parser_parents) + account = Account_Create(self.parser, self.parser_parents) + config = Ungleich_Config(self.parser, self.parser_parents) SSHKey(self.parser, self.parser_parents) ungleichWeather(self.parser, self.parser_parents) diff --git a/ungleich_config.py b/ungleich_config.py new file mode 100644 index 0000000..bc2ca0d --- /dev/null +++ b/ungleich_config.py @@ -0,0 +1,82 @@ +import argparse +import json +import urllib.request + + +class Ungleich_Config(object): + def __init__(self, parser, parents): + self.parser = parser + + self.parser['add'] = self.parser['sub'].add_parser( + 'config-add', + help="Add user to configuration file", + parents=[parents]) + + self.parser['list'] = self.parser['sub'].add_parser( + 'config-list', + help="list users in configuration file", + parents=[parents]) + + self.parser['delete'] = self.parser['sub'].add_parser( + 'config-delete', + help="remove a user in configuration file", + parents=[parents]) + + self.parser['add'].add_argument('--name', help='otp name', required=True) + self.parser['add'].add_argument('--realm', help='otp realm', required=True) + self.parser['add'].add_argument('--seed', help='otp seed', required=True) + + self.parser['delete'].add_argument('--id', help='user ID to remove', required=True) + self.parser['list'].set_defaults(func=self._list_users) + self.parser['add'].set_defaults(func=self._add_user) + self.parser['delete'].set_defaults(func=self._delete_user) + + def _add_user(self, args): + try: + f = open('users.json', 'r') + json_info = json.loads(f.read()) + if len(json_info) > 0: + with open('users.json', 'w') as fp: + last_id = int(list(json_info.keys())[-1]) + 1 + json_info[last_id] = {"name": args.name, "realm": args.realm, "seed": args.seed} + json.dump(json_info, fp) + print('User added.') + else: + with open('users.json', 'w') as fp: + d = {"name": args.name, "realm": args.realm, "seed": args.seed} + json.dump({"1": d}, fp) + print('User added.') + + except FileNotFoundError: + with open('users.json', 'w') as fp: + d = {"name": args.name, "realm": args.realm, "seed": args.seed} + json.dump({"1": d}, fp) + print('User added.') + + def _list_users(self, args): + try: + f = open('users.json', 'r') + json_info = json.loads(f.read()) + for key, value in json_info.items(): + print('{}: {}'.format(key, value['name'])) + except FileNotFoundError: + print('No users loaded.') + + def _delete_user(self, args): + try: + f = open('users.json', 'r') + json_info = json.loads(f.read()) + try: + del json_info[args.id] + f = open('users.json', 'w') + x = 1 + for i in list(json_info.keys()): + json_info[str(x)] = json_info.pop(i) + x+=1 + f.write(json.dumps(json_info)) + f.close() + except KeyError: + print("No user with such id.") + + except FileNotFoundError: + print('No users loaded.') diff --git a/ungleich_dns.py b/ungleich_dns.py index 85eb6bd..571b635 100644 --- a/ungleich_dns.py +++ b/ungleich_dns.py @@ -1,7 +1,7 @@ - import urllib.request import argparse import json +from pyotp import TOTP class ungleichDNS(object): def __init__(self, parser, parents): @@ -13,15 +13,16 @@ class ungleichDNS(object): parents=[parents]) self.parser['dns'].add_argument('--set-reverse', help='REQUIRED: IPv6 Address of your VM', required=True) - self.parser['dns'].add_argument('--user', help='Your ungleich username', required=True) - self.parser['dns'].add_argument('--token', help='Your ungleich 6 digit OTP generated token', type=int, required=True) + self.parser['dns'].add_argument('--user', help='Your stored user ID', required=True) self.parser['dns'].add_argument('--name', help='Hostname', required=True) self.parser['dns'].add_argument('--email', help='registered email', required=True) - self.parser['dns'].add_argument('--realm', help='Otp realm', required=True) self.parser['dns'].set_defaults(func=self._handle_dns) def _handle_dns(self, args): """Reverse dns endpoint.""" + f = open('users.json', 'r') + data = json.loads(f.read())[args.user] + url = 'https://dns.service.ungleich.ch' req = urllib.request.Request( url=url, @@ -30,13 +31,17 @@ class ungleichDNS(object): "Content-Type": "application/json" }, data=json.dumps({ - 'username': args.user, - 'token': args.token, + 'username': data['name'], + 'token': TOTP(data['seed']).now(), 'ipaddress': args.set_reverse, 'name': args.name, 'email': args.email, - 'realm': args.realm + 'realm': data['realm'] }).encode('utf-8') ) - response = urllib.request.urlopen(req).read() - print(json.loads(response)) + try: + response = urllib.request.urlopen(req).read() + print(response) + except urllib.error.HTTPError as e: + error_message = e.read() + print(json.loads(error_message)) diff --git a/ungleich_ripe.py b/ungleich_ripe.py index 2d3fce4..77aaf09 100644 --- a/ungleich_ripe.py +++ b/ungleich_ripe.py @@ -3,9 +3,10 @@ import ipaddress import json import urllib.request import pprint +import requests # RIPE_URL = "https://rest.db.ripe.net/{source}/{objecttype}/{key}" -RIPE_URL = "https://rest.db.ripe.net/ripe" +# RIPE_URL = "https://rest.db.ripe.net/ripe" RIPE_URL = "https://rest-test.db.ripe.net/test" class ungleichRIPE(object): @@ -33,47 +34,50 @@ class ungleichRIPE(object): print("Sorry, {} does not look like an IPv6 network: {}".format(args.network, e)) raise - url = "{}/route6/?password={}".format(RIPE_URL, args.password) + url = "{}/route6?password={}".format(RIPE_URL, args.password) ripe_object = {} ripe_object['route6'] = args.network ripe_object['origin'] = "AS209898" ripe_object['descr'] = args.description ripe_object['mnt-by'] = "mnt-ungleich" + ripe_object['source'] = "TEST" ripe_attributes = [{ "name": key, "value": value } for key, value in ripe_object.items() ] # Format according to API layout ripe_element = {} - ripe_element['objects'] = [] - ripe_element['objects'].append( - { "object": - [ - { - "attributes": { - "attribute": ripe_attributes - } - } - ] - } - ) + ripe_element['objects'] = { + "object": [ + { + "attributes": { + "attribute": ripe_attributes + } + } + ] + } data = json.dumps(ripe_element).encode('utf-8') # debug - pprint.pprint(ripe_element) + # pprint.pprint(ripe_element) - method = 'POST' + # method = 'POST' + # req = urllib.request.Request(url=url, + # data=data, + # method='POST', + # headers={ + # "Content-Type": "application/json", + # "Accept": "application/json" + # }) + # print("Adding a v6 route object at {} for {} with {} req={}".format(url, args.network, data, str(req))) - req = urllib.request.Request(url=url, - data=data, - method='POST', - headers={ - "Content-Type": "application/json", - "Accept": "application/json" - }) + # with urllib.request.urlopen(req) as f: + # print(f.read().decode('utf-8')) - print("Adding a v6 route object at {} for {} with {} req={}".format(url, args.network, data, str(req))) - - with urllib.request.urlopen(req) as f: - print(f.read().decode('utf-8')) + r = requests.post(url, data=data, headers={ + "Content-Type": "application/json", + "Accept": "application/json" + }) + pprint.pprint(json.loads(r.content.decode("utf-8"))) + # print(r.content.decode("utf-8")) \ No newline at end of file