def delete(self, email: str, verify: bool = True) -> bool: """ Deletes the user with the given email address. :param email: email address of user :param verify: whether to wait to confirm that the user has been deleted :return: `True` if the user has been deleted, else `False` if they haven't because they didn't exist """ user = self.get(email) if user is None: return False account = {"uid": user["uid"], "ke": user["ke"], "mail": email} # Odd interface, defined here: # https://gitlab.com/Shinobi-Systems/Shinobi/-/blob/dev/libs/webServerSuperPaths.js#L385 response = requests.post(f"{self._base_url}/deleteAdmin", json=dict(account=account)) raise_if_errors(response) if verify: if not wait_and_verify(lambda: self.get(email) is None): raise RuntimeError( f"User with email \"{email}\" was not deleted") return True
def modify(self, email: str, *, password: str) -> bool: """ Modify a user. :param email: the email address of the user to modify :param password: new password :return: whether the user was modified """ try: user = self.get(email, password) # The user can't be none as otherwise their credentials shouldn't have worked at getting the user's details assert user is not None return False except ShinobiWrongPasswordError: pass user = self.get(email) if user is None: raise ShinobiUserDoesNotExistError(email) data = { "mail": email, "pass": password, "password_again": password, } account = {"mail": email, "uid": user["uid"], "ke": user["ke"]} response = requests.post(f"{self._base_url}/editAdmin", json=dict(data=data, account=account)) raise_if_errors(response) return True
def create(self, email: str, password: str, verify: bool = True) -> Dict: """ Creates a user with the given details. :param email: email address of the user :param password: password for the user :param verify: whether to wait to confirm that the user has been created :return: details about created user """ # Not trusting Shinobi's API to give back anything useful if the user already exists if self.get(email): raise ShinobiUserAlreadyExistsError(email) # The required post does not align with the API documentation (https://shinobi.video/docs/api) # Exploiting the undocumented API successfully used by UI. # See source: https://gitlab.com/Shinobi-Systems/Shinobi/-/blob/dev/libs/webServerSuperPaths.js data = { "mail": email, "pass": password, "password_again": password, "details": json.dumps({ "factorAuth": "0", "size": "", "days": "", "event_days": "", "log_days": "", "max_camera": "", "permissions": "all", "edit_size": "1", "edit_days": "1", "edit_event_days": "1", "edit_log_days": "1", "use_admin": "1", "use_aws_s3": "1", "use_whcs": "1", "use_sftp": "1", "use_webdav": "1", "use_discordbot": "1", "use_ldap": "1", "aws_use_global": "0", "b2_use_global": "0", "webdav_use_global": "0" }) } response = requests.post(f"{self._base_url}/registerAdmin", json=dict(data=data)) raise_if_errors(response) create_user = response.json() if verify: if not wait_and_verify(lambda: self.get(email) is not None): raise RuntimeError("Unable to verify created user") return ShinobiUserOrm._create_improved_user_entry(create_user["user"])
def get_all(self) -> Tuple: """ Gets details about all users. :return: tuple where each element contains details about a specific user """ response = requests.get(f"{self._base_url}/list") raise_if_errors(response) return tuple( ShinobiUserOrm._create_improved_user_entry(user) for user in response.json()["users"])
def _configure(self, monitor_id: str, configuration: Dict): """ Configures the monitor with the given ID with the given configuration. Will create the monitor if it does not exist. :param monitor_id: ID of the monitor :param configuration: configuration of the monitor """ # Note: Shinobi used to represent "details" as a JSON dumped string but now needs to be JSON configuration["details"] = ShinobiMonitorOrm._parse_details( configuration["details"]) response = requests.post( f"{self.base_url}/configureMonitor/{self.group_key}/{monitor_id}", json=dict(data=configuration)) raise_if_errors(response)
def delete(self, monitor_id: str, verify: bool = True) -> bool: """ Deletes the monitor with the given ID. NoOp if the monitor does not exist. :param monitor_id: ID of the monitor :param verify: wait and verify that the monitor has been deleted if `True` :return: `True` if the monitor was deleted """ # Note: if we don"t do this check, Shinobi errors (and the connection hangs) if asked to remove a non-existent # monitor if not self.get(monitor_id): return False response = requests.post( f"{self.base_url}/configureMonitor/{self.group_key}/{monitor_id}/delete" ) raise_if_errors(response) if verify and not wait_and_verify( lambda: self.get(monitor_id) is None): raise RuntimeError(f"Could not delete monitor: {monitor_id}") return True
def _get_as_user(self, email: str, password: str) -> Dict: """ Gets details about the user with the given email address, using the user's own credentials. :param email: user's email address :param password: user's password :return: details about user :raises ShinobiWrongPasswordError: raised if an incorrect email/password pair is supplied """ response = requests.post( f"http://{self.shinobi_client.host}:{self.shinobi_client.port}/?json=true", data={ "mail": email, "pass": password }) raise_if_errors(response, raise_if_json_not_ok=False) if not response.json()["ok"]: # We can only assume this means that the password was incorrect/the user doesn't exist... raise ShinobiWrongPasswordError(email, password) user = response.json()["$user"] user["pass"] = password return ShinobiUserOrm._create_improved_user_entry(user)