def new_empty_command(workspace: Workspace): command = Command() command.workspace = workspace command.start_date = datetime.now() command.import_source = 'report' command.tool = "In progress" command.command = "In progress" db.session.commit() return command
def create_command(self, itime, params, tool_name): self.itime = itime self.params = params self.tool_name = tool_name data = self._command_info() command = Command(**data) self.session.add(command) self.session.flush() return command.id
def run_agent(self, workspace_name, agent_id): """ --- tags: ["Agent"] description: Runs an agent responses: 400: description: Bad request 201: description: Ok content: application/json: schema: AgentSchema """ if flask.request.content_type != 'application/json': abort(400, "Only application/json is a valid content-type") data = self._parse_data(AgentRunSchema(unknown=EXCLUDE), request) agent = self._get_object(agent_id, workspace_name) workspace = self._get_workspace(workspace_name) executor_data = data['executorData'] try: executor = Executor.query.filter(Executor.name == executor_data['executor'], Executor.agent_id == agent_id).one() # VALIDATE errors = {} for param_name, param_data in executor_data["args"].items(): if executor.parameters_metadata.get(param_name): val_error = type_validate(executor.parameters_metadata[param_name]['type'], param_data) if val_error: errors[param_name] = val_error else: errors['message'] = f'"{param_name}" not recognized as an executor argument' if errors: response = jsonify(errors) response.status_code = 400 abort(response) params = ', '.join([f'{key}={value}' for (key, value) in executor_data["args"].items()]) command = Command( import_source="agent", tool=agent.name, command=executor.name, user='', hostname='', params=params, start_date=datetime.utcnow(), workspace=workspace ) agent_execution = AgentExecution( running=None, successful=None, message='', executor=executor, workspace_id=workspace.id, parameters_data=executor_data["args"], command=command ) executor.last_run = datetime.utcnow() db.session.add(agent_execution) db.session.commit() changes_queue.put({ 'execution_id': agent_execution.id, 'agent_id': agent.id, 'workspace': agent_execution.workspace.name, 'action': 'RUN', "executor": executor_data.get('executor'), "args": executor_data.get('args') }) except NoResultFound as e: logger.exception(e) abort(400, "Can not find an agent execution with that id") else: return flask.jsonify({ 'command_id': command.id, })
def file_upload(workspace=None): """ Upload a report file to Server and process that report with Faraday client plugins. """ logger.info("Importing new plugin report in server...") # Authorization code copy-pasted from server/api/base.py ws = Workspace.query.filter_by(name=workspace).first() if not ws or not ws.active: # Don't raise a 403 to prevent workspace name enumeration abort(404, f"Workspace disabled: {workspace}") if 'file' not in request.files: abort(400) try: validate_csrf(request.form.get('csrf_token')) except ValidationError: abort(403) report_file = request.files['file'] if report_file: chars = string.ascii_uppercase + string.digits random_prefix = ''.join(random.choice(chars) for x in range(12)) # nosec raw_report_filename = f'{random_prefix}_{secure_filename(report_file.filename)}' try: file_path = CONST_FARADAY_HOME_PATH / 'uploaded_reports' \ / raw_report_filename with file_path.open('wb') as output: output.write(report_file.read()) except AttributeError: logger.warning( "Upload reports in WEB-UI not configurated, run Faraday client and try again..." ) abort( make_response( jsonify( message= "Upload reports not configurated: Run faraday client and start Faraday server again" ), 500)) else: logger.info(f"Get plugin for file: {file_path}") plugin = report_analyzer.get_plugin(file_path) if not plugin: logger.info("Could not get plugin for file") abort( make_response(jsonify(message="Invalid report file"), 400)) else: logger.info( f"Plugin for file: {file_path} Plugin: {plugin.id}") workspace_instance = Workspace.query.filter_by( name=workspace).one() command = Command() command.workspace = workspace_instance command.start_date = datetime.now() command.import_source = 'report' # The data will be updated in the bulk_create function command.tool = "In progress" command.command = "In progress" db.session.add(command) db.session.commit() REPORTS_QUEUE.put((workspace_instance.name, command.id, file_path, plugin.id, flask.g.user.id)) return make_response( jsonify(message="ok", command_id=command.id), 200) else: abort(make_response(jsonify(message="Missing report file"), 400))
def post(self, workspace_name): """ --- tags: ["Bulk"] description: Creates all faraday objects in bulk for a workspace requestBody: required: true content: application/json: schema: BulkCreateSchema responses: 201:tags: description: Created content: application/json: schema: BulkCreateSchema 401: $ref: "#/components/responses/UnauthorizedError" 403: description: Disabled workspace 404: description: Workspace not found """ data = self._parse_data(self._get_schema_instance({}), flask.request) if flask.g.user is None: agent = require_agent_token() workspace = self._get_workspace(workspace_name) if not workspace or workspace not in agent.workspaces: flask.abort(404, f"No such workspace: {workspace_name}") if "execution_id" not in data: flask.abort(400, "'execution_id' argument expected") execution_id = data["execution_id"] agent_execution: AgentExecution = AgentExecution.query.filter( AgentExecution.id == execution_id).one_or_none() if agent_execution is None: logger.exception( NoResultFound( f"No row was found for agent executor id {execution_id}" )) flask.abort(400, "Can not find an agent execution with that id") if workspace_name != agent_execution.workspace.name: logger.exception( ValueError( f"The {agent.name} agent has permission to workspace {workspace_name} and ask to write " f"to workspace {agent_execution.workspace.name}")) flask.abort(400, "Trying to write to the incorrect workspace") params_data = agent_execution.parameters_data params = ', '.join( [f'{key}={value}' for (key, value) in params_data.items()]) start_date = (data["command"].get("start_date") or agent_execution.command.start_date) \ if "command" in data else agent_execution.command.start_date end_date = data["command"].get("end_date", None) if "command" in data else None data["command"] = { 'id': agent_execution.command.id, 'tool': agent.name, # Agent name 'command': agent_execution.executor.name, 'user': '', 'hostname': '', 'params': params, 'import_source': 'agent', 'start_date': start_date } if end_date is not None: data["command"]["end_date"] = end_date command = Command.query.filter( Command.id == agent_execution.command.id).one_or_none() if command is None: logger.exception( ValueError( f"There is no command with {agent_execution.command.id}" )) flask.abort(400, "Trying to update a not existent command") _update_command(command, data['command']) db.session.flush() else: workspace = self._get_workspace(workspace_name) creator_user = flask.g.user data = add_creator(data, creator_user) if 'command' in data: command = Command(**(data['command'])) command.workspace = workspace db.session.add(command) db.session.commit() else: # Here the data won't appear in the activity field command = None bulk_create(workspace, command, data, True, False) return flask.jsonify({ "message": "Created", "command_id": None if command is None else command.id }), 201
def post(self, workspace_name): """ --- tags: ["Bulk"] description: Creates all faraday objects in bulk for a workspace requestBody: required: true content: application/json: schema: BulkCreateSchema responses: 201:tags: description: Created content: application/json: schema: BulkCreateSchema 401: $ref: "#/components/responses/UnauthorizedError" 403: description: Disabled workspace 404: description: Workspace not found """ from faraday.server.threads.reports_processor import REPORTS_QUEUE # pylint: disable=import-outside-toplevel if flask_login.current_user.is_anonymous: agent = require_agent_token() data = self._parse_data(self._get_schema_instance({}), flask.request) json_data = flask.request.json if flask_login.current_user.is_anonymous: workspace = self._get_workspace(workspace_name) if not workspace or workspace not in agent.workspaces: flask.abort(404, f"No such workspace: {workspace_name}") if "execution_id" not in data: flask.abort(400, "argument expected: execution_id") execution_id = data["execution_id"] agent_execution: AgentExecution = AgentExecution.query.filter( AgentExecution.id == execution_id).one_or_none() if agent_execution is None: logger.exception( NoResultFound( f"No row was found for agent executor id {execution_id}" )) flask.abort(400, "Can not find an agent execution with that id") if workspace_name != agent_execution.workspace.name: logger.exception( ValueError( f"The {agent.name} agent has permission to workspace {workspace_name} and ask to write " f"to workspace {agent_execution.workspace.name}")) flask.abort(400, "Trying to write to the incorrect workspace") params_data = agent_execution.parameters_data params = ', '.join( [f'{key}={value}' for (key, value) in params_data.items()]) start_date = (data["command"].get("start_date") or agent_execution.command.start_date) \ if "command" in data else agent_execution.command.start_date end_date = data["command"].get("end_date", None) if "command" in data else None data["command"] = { 'id': agent_execution.command.id, 'tool': agent.name, # Agent name 'command': agent_execution.executor.name, 'user': '', 'hostname': '', 'params': params, 'import_source': 'agent', 'start_date': start_date } if end_date is not None: data["command"]["end_date"] = end_date command = Command.query.filter( Command.id == agent_execution.command.id).one_or_none() if command is None: logger.exception( ValueError( f"There is no command with {agent_execution.command.id}" )) flask.abort(400, "Trying to update a not existent command") _update_command(command, data['command']) db.session.flush() if data['hosts']: json_data['command'] = data["command"] json_data['command']["start_date"] = data["command"][ "start_date"].isoformat() if 'end_date' in data["command"]: json_data['command']["end_date"] = data["command"][ "end_date"].isoformat() else: workspace = self._get_workspace(workspace_name) command = Command(**(data['command'])) command.workspace = workspace db.session.add(command) db.session.commit() if data['hosts']: # Create random file chars = string.ascii_uppercase + string.digits random_prefix = ''.join(random.choice(chars) for x in range(30)) # nosec json_file = f"{random_prefix}.json" file_path = CONST_FARADAY_HOME_PATH / 'uploaded_reports' \ / json_file with file_path.open('w') as output: json.dump(json_data, output) logger.info("Create tmp json file for bulk_create: %s", file_path) user_id = flask_login.current_user.id if not flask_login.current_user.is_anonymous else None REPORTS_QUEUE.put( (workspace.name, command.id, file_path, None, user_id)) return flask.jsonify({ "message": "Created", "command_id": None if command is None else command.id }), 201