2021-02-06 17:15:02 +00:00
|
|
|
from abc import ABC, ABCMeta, abstractmethod
|
2021-02-06 17:04:32 +00:00
|
|
|
from getpass import getpass
|
2021-02-06 17:22:13 +00:00
|
|
|
from owrx.users import UserList, User, DefaultPasswordClass
|
2021-02-06 17:04:32 +00:00
|
|
|
import sys
|
|
|
|
import random
|
|
|
|
import string
|
2021-02-18 00:32:27 +00:00
|
|
|
import os
|
2021-02-06 17:04:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Command(ABC):
|
|
|
|
@abstractmethod
|
|
|
|
def run(self, args):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2021-02-06 17:15:02 +00:00
|
|
|
class UserCommand(Command, metaclass=ABCMeta):
|
2021-02-06 18:12:44 +00:00
|
|
|
def getPassword(self, args, username):
|
2021-02-06 17:04:32 +00:00
|
|
|
if args.noninteractive:
|
2021-02-18 00:32:27 +00:00
|
|
|
if "OWRX_PASSWORD" in os.environ:
|
|
|
|
password = os.environ["OWRX_PASSWORD"]
|
|
|
|
generated = False
|
|
|
|
else:
|
|
|
|
print("Generating password for user {username}...".format(username=username))
|
|
|
|
password = self.getRandomPassword()
|
|
|
|
generated = True
|
|
|
|
print('Password for {username} is "{password}".'.format(username=username, password=password))
|
|
|
|
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.')
|
2021-02-06 17:04:32 +00:00
|
|
|
else:
|
2021-02-06 18:12:44 +00:00
|
|
|
password = getpass("Please enter the new password for {username}: ".format(username=username))
|
|
|
|
confirm = getpass("Please confirm the new password: ")
|
2021-02-06 17:04:32 +00:00
|
|
|
if password != confirm:
|
|
|
|
print("ERROR: Password mismatch.")
|
|
|
|
sys.exit(1)
|
2021-02-08 17:30:54 +00:00
|
|
|
generated = False
|
|
|
|
return password, generated
|
2021-02-06 17:04:32 +00:00
|
|
|
|
|
|
|
def getRandomPassword(self, length=10):
|
|
|
|
printable = list(string.ascii_letters) + list(string.digits)
|
|
|
|
return ''.join(random.choices(printable, k=length))
|
2021-02-06 17:15:02 +00:00
|
|
|
|
|
|
|
|
2021-02-06 18:12:44 +00:00
|
|
|
class NewUser(UserCommand):
|
|
|
|
def run(self, args):
|
2021-02-12 17:34:28 +00:00
|
|
|
username = args.user
|
2021-02-06 18:12:44 +00:00
|
|
|
userList = UserList()
|
|
|
|
# early test to bypass the password stuff if the user already exists
|
|
|
|
if username in userList:
|
|
|
|
raise KeyError("User {username} already exists".format(username=username))
|
|
|
|
|
2021-02-08 17:30:54 +00:00
|
|
|
password, generated = self.getPassword(args, username)
|
2021-02-06 18:12:44 +00:00
|
|
|
|
|
|
|
print("Creating user {username}...".format(username=username))
|
2021-02-08 17:30:54 +00:00
|
|
|
user = User(name=username, enabled=True, password=DefaultPasswordClass(password), must_change_password=generated)
|
2021-02-06 18:12:44 +00:00
|
|
|
userList.addUser(user)
|
|
|
|
|
|
|
|
|
2021-02-06 17:15:02 +00:00
|
|
|
class DeleteUser(UserCommand):
|
|
|
|
def run(self, args):
|
2021-02-12 17:34:28 +00:00
|
|
|
username = args.user
|
2021-02-06 17:15:02 +00:00
|
|
|
print("Deleting user {username}...".format(username=username))
|
|
|
|
userList = UserList()
|
|
|
|
userList.deleteUser(username)
|
2021-02-06 18:12:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ResetPassword(UserCommand):
|
|
|
|
def run(self, args):
|
2021-02-12 17:34:28 +00:00
|
|
|
username = args.user
|
2021-02-08 17:30:54 +00:00
|
|
|
password, generated = self.getPassword(args, username)
|
2021-02-06 18:12:44 +00:00
|
|
|
userList = UserList()
|
2021-02-08 17:30:54 +00:00
|
|
|
userList[username].setPassword(DefaultPasswordClass(password), must_change_password=generated)
|
2021-02-06 18:12:44 +00:00
|
|
|
# this is a change to an object in the list, not the list itself
|
|
|
|
# in this case, store() is explicit
|
|
|
|
userList.store()
|
2021-02-08 16:04:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
class DisableUser(UserCommand):
|
|
|
|
def run(self, args):
|
2021-02-12 17:34:28 +00:00
|
|
|
username = args.user
|
2021-02-08 16:04:55 +00:00
|
|
|
userList = UserList()
|
|
|
|
userList[username].disable()
|
|
|
|
userList.store()
|
|
|
|
|
|
|
|
|
|
|
|
class EnableUser(UserCommand):
|
|
|
|
def run(self, args):
|
2021-02-12 17:34:28 +00:00
|
|
|
username = args.user
|
2021-02-08 16:04:55 +00:00
|
|
|
userList = UserList()
|
|
|
|
userList[username].enable()
|
|
|
|
userList.store()
|
|
|
|
|
|
|
|
|
|
|
|
class ListUsers(Command):
|
|
|
|
def run(self, args):
|
|
|
|
userList = UserList()
|
|
|
|
print("List of enabled users:")
|
|
|
|
for u in userList.values():
|
|
|
|
if args.all or u.enabled:
|
|
|
|
print(" {name}".format(name=u.name))
|
2021-02-18 14:42:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
class HasUser(Command):
|
|
|
|
"""
|
|
|
|
internal command used by the debian config scripts to test if the admin user has already been created
|
|
|
|
"""
|
|
|
|
def run(self, args):
|
|
|
|
userList = UserList()
|
|
|
|
if args.user in userList:
|
|
|
|
if not args.silent:
|
|
|
|
print('User "{name}" exists.'.format(name=args.user))
|
|
|
|
else:
|
|
|
|
if not args.silent:
|
|
|
|
print('User "{name}" does not exist.'.format(name=args.user))
|
|
|
|
# in bash, a return code > 0 is interpreted as "false"
|
|
|
|
sys.exit(1)
|