Bez popisu

manage_modules_routes.py 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. # IRIS Source Code
  2. # Copyright (C) 2024 - DFIR-IRIS
  3. # contact@dfir-iris.org
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU Lesser General Public
  7. # License as published by the Free Software Foundation; either
  8. # version 3 of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. # Lesser General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Lesser General Public License
  16. # along with this program; if not, write to the Free Software Foundation,
  17. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. import json
  19. import logging as log
  20. import traceback
  21. from flask import Blueprint
  22. from flask import request
  23. from app import app
  24. from app.datamgmt.iris_engine.modules_db import delete_module_from_id
  25. from app.datamgmt.iris_engine.modules_db import parse_module_parameter
  26. from app.datamgmt.iris_engine.modules_db import get_module_config_from_id
  27. from app.datamgmt.iris_engine.modules_db import iris_module_disable_by_id
  28. from app.datamgmt.iris_engine.modules_db import iris_module_enable_by_id
  29. from app.datamgmt.iris_engine.modules_db import iris_module_name_from_id
  30. from app.datamgmt.iris_engine.modules_db import iris_module_save_parameter
  31. from app.datamgmt.iris_engine.modules_db import iris_modules_list
  32. from app.datamgmt.iris_engine.modules_db import module_list_hooks_view
  33. from app.iris_engine.module_handler.module_handler import check_module_health
  34. from app.iris_engine.module_handler.module_handler import instantiate_module_from_name
  35. from app.iris_engine.module_handler.module_handler import iris_update_hooks
  36. from app.iris_engine.module_handler.module_handler import register_module
  37. from app.iris_engine.utils.tracker import track_activity
  38. from app.models.authorization import Permissions
  39. from app.blueprints.access_controls import ac_api_requires
  40. from app.blueprints.responses import response_error
  41. from app.blueprints.responses import response_success
  42. from app.schema.marshables import IrisModuleSchema
  43. manage_modules_rest_blueprint = Blueprint('manage_module_rest', __name__)
  44. @manage_modules_rest_blueprint.route('/manage/modules/list', methods=['GET'])
  45. @ac_api_requires(Permissions.server_administrator)
  46. def manage_modules_list():
  47. output = iris_modules_list()
  48. return response_success('', data=output)
  49. @manage_modules_rest_blueprint.route('/manage/modules/add', methods=['POST'])
  50. @ac_api_requires(Permissions.server_administrator)
  51. def add_module():
  52. if request.json is None:
  53. return response_error('Invalid request')
  54. module_name = request.json.get('module_name')
  55. # Try to import the module
  56. try:
  57. # Try to instantiate the module
  58. log.info(f'Trying to add module {module_name}')
  59. class_, logs = instantiate_module_from_name(module_name)
  60. if not class_:
  61. return response_error(f"Cannot import module. {logs}")
  62. # Check the health of the module
  63. is_ready, logs = check_module_health(class_)
  64. if not is_ready:
  65. return response_error("Cannot import module. Health check didn't pass. Please check logs below", data=logs)
  66. # Registers into Iris DB for further calls
  67. module, message = register_module(module_name)
  68. if module is None:
  69. track_activity(f"addition of IRIS module {module_name} was attempted and failed", ctx_less=True)
  70. return response_error(f'Unable to register module: {message}')
  71. track_activity(f"IRIS module {module_name} was added", ctx_less=True)
  72. module_schema = IrisModuleSchema()
  73. return response_success(message, data=module_schema.dump(module))
  74. except Exception as e:
  75. traceback.print_exc()
  76. return response_error(e.__str__())
  77. @manage_modules_rest_blueprint.route('/manage/modules/set-parameter/<param_name>', methods=['POST'])
  78. @ac_api_requires(Permissions.server_administrator)
  79. def update_module_param(param_name):
  80. if request.json is None:
  81. return response_error('Invalid request')
  82. mod_config, mod_id, mod_name, mod_iname, parameter = parse_module_parameter(param_name)
  83. if mod_config is None:
  84. return response_error('Invalid parameter')
  85. parameter_value = request.json.get('parameter_value')
  86. if iris_module_save_parameter(mod_id, mod_config, parameter['param_name'], parameter_value):
  87. track_activity(f"parameter {parameter['param_name']} of mod ({mod_name}) #{mod_id} was updated",
  88. ctx_less=True)
  89. success, logs = iris_update_hooks(mod_iname, mod_id)
  90. if not success:
  91. return response_error("Unable to update hooks", data=logs)
  92. return response_success("Saved", logs)
  93. return response_error('Malformed request')
  94. @manage_modules_rest_blueprint.route('/manage/modules/enable/<int:mod_id>', methods=['POST'])
  95. @ac_api_requires(Permissions.server_administrator)
  96. def enable_module(mod_id):
  97. module_name = iris_module_name_from_id(mod_id)
  98. if module_name is None:
  99. return response_error('Invalid module ID')
  100. if not iris_module_enable_by_id(mod_id):
  101. return response_error('Unable to enable module')
  102. success, logs = iris_update_hooks(module_name, mod_id)
  103. if not success:
  104. return response_error("Unable to update hooks when enabling module", data=logs)
  105. track_activity(f"IRIS module ({module_name}) #{mod_id} enabled", ctx_less=True)
  106. return response_success('Module enabled', data=logs)
  107. @manage_modules_rest_blueprint.route('/manage/modules/disable/<int:module_id>', methods=['POST'])
  108. @ac_api_requires(Permissions.server_administrator)
  109. def disable_module(module_id):
  110. if iris_module_disable_by_id(module_id):
  111. track_activity(f"IRIS module #{module_id} disabled", ctx_less=True)
  112. return response_success('Module disabled')
  113. return response_error('Unable to disable module')
  114. @manage_modules_rest_blueprint.route('/manage/modules/remove/<int:module_id>', methods=['POST'])
  115. @ac_api_requires(Permissions.server_administrator)
  116. def view_delete_module(module_id):
  117. try:
  118. delete_module_from_id(module_id=module_id)
  119. track_activity(f"IRIS module #{module_id} deleted", ctx_less=True)
  120. return response_success("Deleted")
  121. except Exception as e:
  122. log.error(e.__str__())
  123. return response_error(f"Cannot delete module. Error {e.__str__()}")
  124. @manage_modules_rest_blueprint.route('/manage/modules/export-config/<int:module_id>', methods=['GET'])
  125. @ac_api_requires(Permissions.server_administrator)
  126. def export_mod_config(module_id):
  127. mod_config, mod_name, _ = get_module_config_from_id(module_id)
  128. if mod_name:
  129. data = {
  130. "module_name": mod_name,
  131. "module_configuration": mod_config
  132. }
  133. return response_success(data=data)
  134. return response_error(f"Module ID {module_id} not found")
  135. @manage_modules_rest_blueprint.route('/manage/modules/import-config/<int:module_id>', methods=['POST'])
  136. @ac_api_requires(Permissions.server_administrator)
  137. def import_mod_config(module_id):
  138. mod_config, _, _ = get_module_config_from_id(module_id)
  139. logs = []
  140. parameters_data = request.get_json().get('module_configuration')
  141. if type(parameters_data) is not list:
  142. try:
  143. parameters = json.loads(parameters_data)
  144. except Exception as _:
  145. return response_error('Invalid data', data="Not a JSON file")
  146. else:
  147. parameters = parameters_data
  148. for param in parameters:
  149. param_name = param.get('param_name')
  150. parameter_value = param.get('value')
  151. if not iris_module_save_parameter(module_id, mod_config, param_name, parameter_value):
  152. logs.append(f'Unable to save parameter {param_name}')
  153. track_activity(f"parameters of mod #{module_id} were updated from config file", ctx_less=True)
  154. if len(logs) == 0:
  155. msg = "Successfully imported data."
  156. else:
  157. msg = "Configuration is partially imported, we got errors with the followings:\n- " + "\n- ".join(logs)
  158. return response_success(msg)
  159. @manage_modules_rest_blueprint.route('/manage/modules/hooks/list', methods=['GET'])
  160. @ac_api_requires(Permissions.server_administrator)
  161. def view_modules_hook():
  162. output = module_list_hooks_view()
  163. data = [item._asdict() for item in output]
  164. return response_success('', data=data)
  165. # TODO is this endpoint still useful?
  166. @manage_modules_rest_blueprint.route('/sitemap', methods=['GET'])
  167. @ac_api_requires()
  168. def site_map():
  169. links = []
  170. for rule in app.url_map.iter_rules():
  171. methods = [m for m in rule.methods if m != 'OPTIONS' and m != 'HEAD']
  172. links.append((','.join(methods), str(rule), rule.endpoint))
  173. return response_success('', data=links)