include command to create a user

This commit is contained in:
Jakob Ketterl 2021-02-06 18:04:32 +01:00
parent dd2f0629d3
commit 99fe232a21
5 changed files with 138 additions and 31 deletions

6
openwebrx-admin.py Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env python3
from owrxadmin.__main__ import main
if __name__ == "__main__":
main()

View File

@ -1,4 +1,5 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from owrx.config import CoreConfig
import json import json
import logging import logging
@ -19,17 +20,32 @@ class Password(ABC):
return CleartextPassword(d) return CleartextPassword(d)
raise PasswordException("invalid passord encoding: {0}".format(d["type"])) raise PasswordException("invalid passord encoding: {0}".format(d["type"]))
def __init__(self, pwinfo: dict):
self.pwinfo = pwinfo
@abstractmethod @abstractmethod
def is_valid(self, inp: str): def is_valid(self, inp: str):
pass pass
@abstractmethod
def toJson(self):
pass
class CleartextPassword(Password): class CleartextPassword(Password):
def __init__(self, pwinfo):
if isinstance(pwinfo, str):
self._value = pwinfo
elif isinstance(pwinfo, dict):
self._value = pwinfo["value"]
else:
raise ValueError("invalid argument to ClearTextPassword()")
def is_valid(self, inp: str): def is_valid(self, inp: str):
return self.pwinfo["value"] == inp return self._value == inp
def toJson(self):
return {
"encoding": "string",
"value": self._value
}
class User(object): class User(object):
@ -38,6 +54,13 @@ class User(object):
self.enabled = enabled self.enabled = enabled
self.password = password self.password = password
def toJson(self):
return {
"user": self.name,
"enabled": self.enabled,
"password": self.password.toJson()
}
class UserList(object): class UserList(object):
sharedInstance = None sharedInstance = None
@ -51,30 +74,53 @@ class UserList(object):
def __init__(self): def __init__(self):
self.users = self._loadUsers() self.users = self._loadUsers()
def _getUsersFile(self):
config = CoreConfig()
return "{data_directory}/users.json".format(data_directory=config.get_data_directory())
def _loadUsers(self): def _loadUsers(self):
for file in ["/etc/openwebrx/users.json", "users.json"]: usersFile = self._getUsersFile()
try: try:
f = open(file, "r") with open(usersFile, "r") as f:
users_json = json.load(f) users_json = json.load(f)
f.close()
return {u.name: u for u in [self.buildUser(d) for d in users_json]} return {u.name: u for u in [self._jsonToUser(d) for d in users_json]}
except FileNotFoundError: except FileNotFoundError:
pass return {}
except json.JSONDecodeError: except json.JSONDecodeError:
logger.exception("error while parsing users file %s", file) logger.exception("error while parsing users file %s", usersFile)
return {} return {}
except Exception: except Exception:
logger.exception("error while processing users from %s", file) logger.exception("error while processing users from %s", usersFile)
return {} return {}
return {}
def buildUser(self, d): def _jsonToUser(self, d):
if "user" in d and "password" in d and "enabled" in d: if "user" in d and "password" in d and "enabled" in d:
return User(d["user"], d["enabled"], Password.from_dict(d["password"])) return User(d["user"], d["enabled"], Password.from_dict(d["password"]))
def _userToJson(self, u):
return u.toJson()
def _store(self):
usersFile = self._getUsersFile()
users = [u.toJson() for u in self.users.values()]
try:
with open(usersFile, "w") as f:
json.dump(users, f, indent=4)
except Exception:
logger.exception("error while writing users file %s", usersFile)
def addUser(self, user: User):
self[user.name] = user
def __getitem__(self, item): def __getitem__(self, item):
return self.users[item] return self.users[item]
def __contains__(self, item): def __contains__(self, item):
return item in self.users return item in self.users
def __setitem__(self, key, value):
if key in self.users:
raise KeyError("User {user} already exists".format(user=key))
self.users[key] = value
self._store()

View File

@ -1,2 +1,22 @@
from owrx.version import openwebrx_version
from owrxadmin.commands import NewUserCommand
import argparse
import sys
def main(): def main():
print("OpenWebRX admin") print("OpenWebRX admin version {version}".format(version=openwebrx_version))
parser = argparse.ArgumentParser()
parser.add_argument("command", help="One of the following commands: adduser, removeuser")
parser.add_argument("--noninteractive", action="store_true", help="Don't ask for any user input (useful for automation)")
parser.add_argument("-u", "--user")
args = parser.parse_args()
if args.command == "adduser":
NewUserCommand().run(args)
elif args.command == "removeuser":
print("removing user")
else:
print("Unknown command: {command}".format(command=args.command))
sys.exit(1)

46
owrxadmin/commands.py Normal file
View File

@ -0,0 +1,46 @@
from abc import ABC, abstractmethod
from getpass import getpass
from owrx.users import UserList, User, CleartextPassword
import sys
import random
import string
class Command(ABC):
@abstractmethod
def run(self, args):
pass
class NewUserCommand(Command):
def run(self, args):
if args.user:
username = args.user
else:
if args.noninteractive:
print("ERROR: User name not specified")
sys.exit(1)
else:
username = input("Please enter the user name: ")
if args.noninteractive:
print("Generating password for user {username}...".format(username=username))
password = self.getRandomPassword()
print('Password for {username} is "{password}".'.format(username=username, password=password))
# TODO implement this threat
print('This password is suitable for initial setup only, you will be asked to reset it on initial use.')
print('This password cannot be recovered from the system, please note it down now.')
else:
password = getpass("Please enter the password for {username}: ".format(username=username))
confirm = getpass("Please confirm password: ")
if password != confirm:
print("ERROR: Password mismatch.")
sys.exit(1)
print("Creating user {username}...".format(username=username))
userList = UserList()
user = User(name=username, enabled=True, password=CleartextPassword(password))
userList.addUser(user)
def getRandomPassword(self, length=10):
printable = list(string.ascii_letters) + list(string.digits)
return ''.join(random.choices(printable, k=length))

View File

@ -1,11 +0,0 @@
[
{
"user": "admin",
"password": {
"encoding": "string",
"value": "password",
"force_change": true
},
"enabled": true
}
]