async def read_global( request: Request, global_var: UUID, to_decrypt: str = "false", global_col: AsyncIOMotorCollection = Depends(get_mongo_c)): """ Returns the Global Variable for the specified id. """ walkoff_db = get_mongo_d(request) curr_user_id = await get_jwt_identity(request) global_variable = await mongo_helpers.get_item(global_col, GlobalVariable, global_var) to_read = await auth_check(global_variable, curr_user_id, "read", walkoff_db) if to_read: if to_decrypt == "false": return global_variable.value else: key = config.get_from_file(config.ENCRYPTION_KEY_PATH) #, 'rb') # for testing try: key = key.encode('utf-8') key = base64.b64encode(key) except: key = key return fernet_decrypt(key, global_variable.value) else: raise UnauthorizedException("read data for", "Global Variable", global_variable.name)
async def update_personal_user( *, username: str, walkoff_db: AsyncIOMotorDatabase = Depends(get_mongo_d), request: Request, new_user: EditPersonalUser): user_col = walkoff_db.users curr_id = await get_jwt_identity(request) user_obj = await mongo_helpers.get_item(user_col, UserModel, username, projection=ignore_password) if not user_obj: raise DoesNotExistException("update personal data", "User", username) if str(curr_id) == str(user_obj.id): d = dict(new_user) d.update({ "id_": await get_jwt_identity(request), "roles": [], "hashed": False }) return await update_user(walkoff_db=walkoff_db, user_id=curr_id, new_user=EditUser(**d), request=request) else: raise UnauthorizedException("edit personal data for", "User", user_obj.username)
async def update_global(request: Request, updated_global: GlobalVariable, global_var: UUID, global_col: AsyncIOMotorCollection = Depends(get_mongo_c)): """ Updates a specific Global Variable (fetched by id) and returns it. """ walkoff_db = get_mongo_d(request) curr_user_id = await get_jwt_identity(request) old_global = await mongo_helpers.get_item(global_col, GlobalVariable, global_var) if not old_global: raise DoesNotExistException("update", "Global Variable", global_var) global_id = old_global.id_ new_permissions = updated_global.permissions access_level = new_permissions.access_level to_update = await auth_check(old_global, curr_user_id, "update", walkoff_db) if to_update: if access_level == AccessLevel.CREATOR_ONLY: updated_global.permissions = await creator_only_permissions(curr_user_id) elif access_level == AccessLevel.EVERYONE: updated_global.permissions = await default_permissions(curr_user_id, walkoff_db, "global_variables") elif access_level == AccessLevel.ROLE_BASED: await append_super_and_internal(updated_global.permissions) updated_global.permissions.creator = curr_user_id # try: key = config.get_from_file(config.ENCRYPTION_KEY_PATH, mode='rb') updated_global.value = fernet_encrypt(key, updated_global.value) return await mongo_helpers.update_item(global_col, GlobalVariable, global_id, updated_global) # except Exception as e: # logger.info(e) # raise UniquenessException("global_variable", "update", updated_global.name) else: raise UnauthorizedException("update data for", "Global Variable", old_global.name)
async def update_workflow( *, walkoff_db: AsyncIOMotorDatabase = Depends(get_mongo_d), workflow_name_id: Union[UUID, str], request: Request, updated_workflow: WorkflowModel): """ Updates a specific Workflow object (fetched by id or name) and returns it. """ workflow_col = walkoff_db.workflows curr_user_id = await get_jwt_identity(request) old_workflow = await mongo_helpers.get_item(workflow_col, WorkflowModel, workflow_name_id) to_update = await auth_check(old_workflow, curr_user_id, "update", walkoff_db=walkoff_db) if to_update: await set_permissions(updated_workflow, curr_user_id, walkoff_db) try: return await mongo_helpers.update_item(workflow_col, WorkflowModel, old_workflow.id_, updated_workflow) except: raise UniquenessException("workflow", "update", updated_workflow.name) else: raise UnauthorizedException("update data for", "Workflow", old_workflow.name)
async def read_workflow( *, walkoff_db: AsyncIOMotorDatabase = Depends(get_mongo_d), mode: str = None, workflow_name_id: Union[UUID, str], request: Request): """ Returns the Workflow for the specified id or name. """ workflow_col = walkoff_db.workflows curr_user_id = await get_jwt_identity(request) workflow = await mongo_helpers.get_item(workflow_col, WorkflowModel, workflow_name_id) to_read = await auth_check(workflow, curr_user_id, "read", walkoff_db=walkoff_db) if to_read: if mode == "export": workflow_str = workflow.json().encode('utf-8') workflow_file = BytesIO() workflow_file.write(workflow_str) workflow_file.seek(0) return StreamingResponse(workflow_file, media_type="application/json") else: return workflow else: raise UnauthorizedException("read data for", "Workflow", workflow.name)
async def read_role(*, role_col: AsyncIOMotorCollection = Depends(get_mongo_c), role_id: Union[int, str]): """ Returns the Role for the specified role name or ID """ role = await mongo_helpers.get_item(role_col, RoleModel, role_id) role_string = f"{role.name} ({role.id_})" if role.id_ in hidden_roles: raise UnauthorizedException("read", "Role", role_string) else: return role
async def create_user(*, user_col: AsyncIOMotorCollection = Depends(get_mongo_c), new_user: UserModel): """ Creates a new User and returns it. """ if DefaultRoleUUID.INTERNAL_USER.value in new_user.roles or \ DefaultRoleUUID.SUPER_ADMIN.value in new_user.roles: raise UnauthorizedException("create a user with the roles", "User", "internal_user or super_user") else: return await mongo_helpers.create_item(user_col, UserModel, new_user, projection=ignore_password)
async def read_user(*, user_col: AsyncIOMotorCollection = Depends(get_mongo_c), user_id: Union[UUID, str]): """ Returns the User for the specified username. """ if user_id == "internal_user" or user_id == DefaultUserUUID.INTERNAL_USER.value: raise UnauthorizedException("get data for", "User", "internal_user") else: return await mongo_helpers.get_item( user_col, UserModel, user_id, query={"id_": { "$nin": hidden_users }}, projection=ignore_password)
async def read_personal_user( *, username: str, user_col: AsyncIOMotorCollection = Depends(get_mongo_c), request: Request): curr_id = await get_jwt_identity(request) user_obj = await mongo_helpers.get_item(user_col, UserModel, username, projection=ignore_password) if not user_obj: raise DoesNotExistException("read personal data", "User", username) if str(curr_id) == str(user_obj.id_): return user_obj else: raise UnauthorizedException("view personal data for", "User", user_obj.username)
async def delete_global(request: Request, global_var: UUID, global_col: AsyncIOMotorCollection = Depends(get_mongo_c)): """ Deletes a specific Global Variable (fetched by id). """ walkoff_db = get_mongo_d(request) curr_user_id = await get_jwt_identity(request) global_variable = await mongo_helpers.get_item(global_col, GlobalVariable, global_var) if not global_variable: raise DoesNotExistException("delete", "Global Variable", global_var) global_id = global_variable.id_ to_delete = await auth_check(global_variable, curr_user_id, "delete", walkoff_db) if to_delete: return await mongo_helpers.delete_item(global_col, GlobalVariable, global_id) else: raise UnauthorizedException("delete data for", "Global Variable", global_variable.name)
async def delete_role(*, role_col: AsyncIOMotorCollection = Depends(get_mongo_c), role_id: Union[int, str]): """ Deletes a role. """ role = await mongo_helpers.get_item(role_col, RoleModel, role_id, raise_exc=False) if not role: raise DoesNotExistException("delete", "Role", role_id) role_string = f"{role.name} ({role.id_})" if role.id_ in DefaultRoleUUIDS: raise UnauthorizedException("delete", "role", role_string) else: return await mongo_helpers.delete_item(role_col, RoleModel, role_id)
async def delete_user(*, user_col: AsyncIOMotorCollection = Depends(get_mongo_c), user_id: Union[UUID, str], request: Request): user = await mongo_helpers.get_item(user_col, UserModel, user_id, projection=ignore_password, raise_exc=False) if not user: raise DoesNotExistException("delete", "User", user_id) user_string = f"{user.username} ({user.id_})" if user.id_ in (DefaultUserUUID.INTERNAL_USER.value, DefaultUserUUID.SUPER_ADMIN.value) \ or user.id_ == await get_jwt_identity(request) \ or DefaultRoleUUID.INTERNAL_USER.value in user.roles \ or DefaultRoleUUID.SUPER_ADMIN.value in user.roles: raise UnauthorizedException("delete", "User", user_string) else: return await mongo_helpers.delete_item(user_col, UserModel, user_id)
async def get_workflow_status( *, walkoff_db: AsyncIOMotorDatabase = Depends(get_mongo_d), execution: UUID, request: Request): """ Returns status information of a workflow currently executing WALKOFF. """ workflow_col = walkoff_db.workflows wfq_col = walkoff_db.workflowqueue curr_user_id = await get_jwt_identity(request) wf_status: WorkflowStatus = await mongo_helpers.get_item( wfq_col, WorkflowStatus, execution, id_key="execution_id") wf = await mongo_helpers.get_item(workflow_col, WorkflowModel, wf_status.workflow_id) if await auth_check(wf, curr_user_id, "read", walkoff_db=walkoff_db): wf_status.to_response() return wf_status else: raise UnauthorizedException("read", "Workflow Status", wf_status.workflow_id)
async def upload_workflow_helper(curr_user_id: UUID, old_workflow, new_workflow: WorkflowModel, walkoff_db): to_update = await auth_check(old_workflow, curr_user_id, "update", walkoff_db=walkoff_db) if not to_update: raise UnauthorizedException("import", "Workflow", old_workflow['name']) to_regenerate = dict(new_workflow) try: regenerate_workflow_ids(to_regenerate) except (KeyError, ValueError, TypeError) as e: raise InvalidInputException("import", "workflow", new_workflow.id_, errors={"exception": str(e)}) new_workflow = WorkflowModel(**to_regenerate) new_workflow.name += "." + str(new_workflow.id_) return new_workflow
async def update_role(*, role_col: AsyncIOMotorCollection = Depends(get_mongo_c), role_id: Union[int, str], new_role: RoleModel): """ Updates a role and returns it. """ role: RoleModel = await mongo_helpers.get_item(role_col, RoleModel, role_id, raise_exc=False) if not role: raise DoesNotExistException("update", "Role", role_id) role_string = f"{role.name} ({role.id_})" if role.id_ in DefaultRoleUUIDS: raise UnauthorizedException("update", "role", role_string) if new_role.name: existing_user = await mongo_helpers.get_item(role_col, RoleModel, new_role.name, raise_exc=False) if existing_user: raise UniquenessException( "change role for", "Role", f"{role_string} -> " f"{new_role.name} ({role.id_})") else: role.name = new_role.name if new_role.description: role.description = new_role.description if new_role.resources: role.resources = new_role.resources return await mongo_helpers.update_item(role_col, RoleModel, role_id, role)
async def copy_workflow_helper(curr_user_id: UUID, old_workflow, new_name: str, walkoff_db: AsyncIOMotorDatabase): to_update = await auth_check(old_workflow, curr_user_id, "update", walkoff_db=walkoff_db) if not to_update: raise UnauthorizedException("copy", "Workflow", old_workflow["name"]) copied_workflow = deepcopy(old_workflow) workflow_dict = dict(copied_workflow) regenerate_workflow_ids(workflow_dict) copied_workflow = WorkflowModel(**workflow_dict) if new_name: copied_workflow.name = new_name else: copied_workflow.name += " (Copy)" # TODO: UI element for new permissions for copied workflows # copied_workflow.permissions = new_workflow.permissions return copied_workflow
async def delete_workflow( *, walkoff_db: AsyncIOMotorDatabase = Depends(get_mongo_d), request: Request, workflow_name_id: Union[UUID, str]): """ Deletes a specific Workflow object (fetched by id or name). """ workflow_col = walkoff_db.workflows curr_user_id = await get_jwt_identity(request) workflow = await mongo_helpers.get_item(workflow_col, WorkflowModel, workflow_name_id) to_delete = await auth_check(workflow, curr_user_id, "delete", walkoff_db=walkoff_db) if to_delete: return await mongo_helpers.delete_item(workflow_col, WorkflowModel, workflow.id_) else: raise UnauthorizedException("delete data for", "Workflow", workflow.name)
async def update_user(*, walkoff_db: AsyncIOMotorDatabase = Depends(get_mongo_d), user_id: Union[UUID, str], new_user: EditUser, request: Request): """ Updates the User for the specified username and returns it. """ user_col = walkoff_db.users role_col = walkoff_db.roles if user_id == DefaultUserUUID.INTERNAL_USER or user_id == "internal_user": raise UnauthorizedException("update", "User", "internal_user") user: UserModel = await mongo_helpers.get_item(user_col, UserModel, user_id, raise_exc=False) if not user: raise DoesNotExistException("update", "User", user_id) current_user: UserModel = await mongo_helpers.get_item( user_col, UserModel, await get_jwt_identity(request)) user_string = f"{user.username} ({user.id_})" if await user.verify_password(new_user.old_password): if user.id_ == DefaultUserUUID.SUPER_ADMIN.value \ or DefaultRoleUUID.SUPER_ADMIN.value in user.roles: if DRoles.SUPER_ADMIN.value not in current_user.roles: raise UnauthorizedException("edit values for", "User", "super_admin") else: if new_user.roles: role_ids = [ role.id_ for role in await mongo_helpers.get_all_items( role_col, RoleModel) ] if set(new_user.roles) <= set(role_ids): user.roles = new_user.roles else: invalid_roles = set(role_ids) - set(new_user.roles) raise InvalidInputException( "edit roles for", "User", user_string, errors= f"The following roles do not exist: {invalid_roles}") user.active = new_user.active if new_user.new_username: existing_user = await mongo_helpers.get_item(user_col, UserModel, new_user.new_username, raise_exc=False) if existing_user: raise UniquenessException( "change username for", "User", f"{user_string} -> " f"{new_user.new_username} ({user_id})") else: user.username = new_user.new_username if new_user.new_password: await user.hash_and_set_password(new_user.new_password) return await mongo_helpers.update_item(user_col, UserModel, user_id, user) else: raise UnauthorizedException("update the data", "User", f"{new_user.username}")