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 owrx.config import CoreConfig
import json
import logging
@ -19,17 +20,32 @@ class Password(ABC):
return CleartextPassword(d)
raise PasswordException("invalid passord encoding: {0}".format(d["type"]))
def __init__(self, pwinfo: dict):
self.pwinfo = pwinfo
@abstractmethod
def is_valid(self, inp: str):
pass
@abstractmethod
def toJson(self):
pass
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):
return self.pwinfo["value"] == inp
return self._value == inp
def toJson(self):
return {
"encoding": "string",
"value": self._value
}
class User(object):
@ -38,6 +54,13 @@ class User(object):
self.enabled = enabled
self.password = password
def toJson(self):
return {
"user": self.name,
"enabled": self.enabled,
"password": self.password.toJson()
}
class UserList(object):
sharedInstance = None
@ -51,30 +74,53 @@ class UserList(object):
def __init__(self):
self.users = self._loadUsers()
def _getUsersFile(self):
config = CoreConfig()
return "{data_directory}/users.json".format(data_directory=config.get_data_directory())
def _loadUsers(self):
for file in ["/etc/openwebrx/users.json", "users.json"]:
try:
f = open(file, "r")
usersFile = self._getUsersFile()
try:
with open(usersFile, "r") as f:
users_json = json.load(f)
f.close()
return {u.name: u for u in [self.buildUser(d) for d in users_json]}
except FileNotFoundError:
pass
except json.JSONDecodeError:
logger.exception("error while parsing users file %s", file)
return {}
except Exception:
logger.exception("error while processing users from %s", file)
return {}
return {}
return {u.name: u for u in [self._jsonToUser(d) for d in users_json]}
except FileNotFoundError:
return {}
except json.JSONDecodeError:
logger.exception("error while parsing users file %s", usersFile)
return {}
except Exception:
logger.exception("error while processing users from %s", usersFile)
return {}
def buildUser(self, d):
def _jsonToUser(self, d):
if "user" in d and "password" in d and "enabled" in d:
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):
return self.users[item]
def __contains__(self, item):
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():
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
}
]