diff --git a/owrx/users.py b/owrx/users.py index 935480f..4ee0a50 100644 --- a/owrx/users.py +++ b/owrx/users.py @@ -102,6 +102,9 @@ class User(object): "password": self.password.toJson() } + def setPassword(self, password: Password): + self.password = password + class UserList(object): sharedInstance = None @@ -142,7 +145,7 @@ class UserList(object): def _userToJson(self, u): return u.toJson() - def _store(self): + def store(self): usersFile = self._getUsersFile() users = [u.toJson() for u in self.users.values()] try: @@ -169,7 +172,7 @@ class UserList(object): if key not in self.users: raise KeyError("User {user} doesn't exist".format(user=key)) del self.users[key] - self._store() + self.store() def __getitem__(self, item): return self.users[item] @@ -181,4 +184,4 @@ class UserList(object): if key in self.users: raise KeyError("User {user} already exists".format(user=key)) self.users[key] = value - self._store() + self.store() diff --git a/owrxadmin/__main__.py b/owrxadmin/__main__.py index 4435523..ea38ca0 100644 --- a/owrxadmin/__main__.py +++ b/owrxadmin/__main__.py @@ -1,5 +1,5 @@ from owrx.version import openwebrx_version -from owrxadmin.commands import NewUser, DeleteUser +from owrxadmin.commands import NewUser, DeleteUser, ResetPassword import argparse import sys import traceback @@ -9,7 +9,7 @@ def main(): 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("command", help="One of the following commands: adduser, removeuser, resetpassword") parser.add_argument( "--noninteractive", action="store_true", help="Don't ask for any user input (useful for automation)" ) @@ -21,6 +21,8 @@ def main(): command = NewUser() elif args.command == "removeuser": command = DeleteUser() + elif args.command == "resetpassword": + command = ResetPassword() else: if not args.silent: print("Unknown command: {command}".format(command=args.command)) diff --git a/owrxadmin/commands.py b/owrxadmin/commands.py index 078809d..3793463 100644 --- a/owrxadmin/commands.py +++ b/owrxadmin/commands.py @@ -23,6 +23,26 @@ class UserCommand(Command, metaclass=ABCMeta): else: return input("Please enter the user name: ") + def getPassword(self, args, username): + 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 copy it now.') + else: + password = getpass("Please enter the new password for {username}: ".format(username=username)) + confirm = getpass("Please confirm the new password: ") + if password != confirm: + print("ERROR: Password mismatch.") + sys.exit(1) + return password + + def getRandomPassword(self, length=10): + printable = list(string.ascii_letters) + list(string.digits) + return ''.join(random.choices(printable, k=length)) + class NewUser(UserCommand): def run(self, args): @@ -32,28 +52,12 @@ class NewUser(UserCommand): if username in userList: raise KeyError("User {username} already exists".format(username=username)) - 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 copy it 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) + password = self.getPassword(args, username) print("Creating user {username}...".format(username=username)) user = User(name=username, enabled=True, password=DefaultPasswordClass(password)) userList.addUser(user) - def getRandomPassword(self, length=10): - printable = list(string.ascii_letters) + list(string.digits) - return ''.join(random.choices(printable, k=length)) - class DeleteUser(UserCommand): def run(self, args): @@ -61,3 +65,14 @@ class DeleteUser(UserCommand): print("Deleting user {username}...".format(username=username)) userList = UserList() userList.deleteUser(username) + + +class ResetPassword(UserCommand): + def run(self, args): + username = self.getUser(args) + password = self.getPassword(args, username) + userList = UserList() + userList[username].setPassword(DefaultPasswordClass(password)) + # this is a change to an object in the list, not the list itself + # in this case, store() is explicit + userList.store()