|
| 1 | +from django.db import migrations |
| 2 | +from django.db.models.fields.related_descriptors import ( |
| 3 | + ForwardManyToOneDescriptor, |
| 4 | + ForwardOneToOneDescriptor, |
| 5 | + ManyToManyDescriptor, |
| 6 | +) |
| 7 | + |
| 8 | +plugin = { |
| 9 | + "python_module": { |
| 10 | + "health_check_schedule": None, |
| 11 | + "update_schedule": None, |
| 12 | + "module": "criminalip.criminalip_scan.CriminalIpScan", |
| 13 | + "base_path": "api_app.analyzers_manager.observable_analyzers", |
| 14 | + }, |
| 15 | + "name": "CriminalIpScan", |
| 16 | + "description": "[Criminal IP](https://www.criminalip.io/) is an OSINT search engine specialized in attack surface assessment and threat hunting. It offers extensive cyber threat intelligence, including device reputation, geolocation, IP reputation for C2 or scanners, domain safety, malicious link detection, and APT attack vectors via search and API.", |
| 17 | + "disabled": False, |
| 18 | + "soft_time_limit": 10, |
| 19 | + "routing_key": "default", |
| 20 | + "health_check_status": True, |
| 21 | + "type": "observable", |
| 22 | + "docker_based": False, |
| 23 | + "maximum_tlp": "AMBER", |
| 24 | + "observable_supported": ["ip", "domain", "generic"], |
| 25 | + "supported_filetypes": [], |
| 26 | + "run_hash": False, |
| 27 | + "run_hash_type": "", |
| 28 | + "not_supported_filetypes": [], |
| 29 | + "model": "analyzers_manager.AnalyzerConfig", |
| 30 | +} |
| 31 | + |
| 32 | +params = [ |
| 33 | + { |
| 34 | + "python_module": { |
| 35 | + "module": "criminalip.criminalip_scan.CriminalIpScan", |
| 36 | + "base_path": "api_app.analyzers_manager.observable_analyzers", |
| 37 | + }, |
| 38 | + "name": "api_key", |
| 39 | + "type": "str", |
| 40 | + "description": "api key for criminal ip", |
| 41 | + "is_secret": True, |
| 42 | + "required": False, |
| 43 | + }, |
| 44 | + { |
| 45 | + "python_module": { |
| 46 | + "module": "criminalip.criminalip_scan.CriminalIpScan", |
| 47 | + "base_path": "api_app.analyzers_manager.observable_analyzers", |
| 48 | + }, |
| 49 | + "name": "malicious_info", |
| 50 | + "type": "bool", |
| 51 | + "description": "for IP, default endpoint", |
| 52 | + "is_secret": False, |
| 53 | + "required": False, |
| 54 | + }, |
| 55 | + { |
| 56 | + "python_module": { |
| 57 | + "module": "criminalip.criminalip_scan.CriminalIpScan", |
| 58 | + "base_path": "api_app.analyzers_manager.observable_analyzers", |
| 59 | + }, |
| 60 | + "name": "privacy_threat", |
| 61 | + "type": "bool", |
| 62 | + "description": "for IP, privacy-threat endpoint", |
| 63 | + "is_secret": False, |
| 64 | + "required": False, |
| 65 | + }, |
| 66 | + { |
| 67 | + "python_module": { |
| 68 | + "module": "criminalip.criminalip_scan.CriminalIpScan", |
| 69 | + "base_path": "api_app.analyzers_manager.observable_analyzers", |
| 70 | + }, |
| 71 | + "name": "is_safe_dns_server", |
| 72 | + "type": "bool", |
| 73 | + "description": "for IP, is-safe-dns-server endpoint", |
| 74 | + "is_secret": False, |
| 75 | + "required": False, |
| 76 | + }, |
| 77 | + { |
| 78 | + "python_module": { |
| 79 | + "module": "criminalip.criminalip_scan.CriminalIpScan", |
| 80 | + "base_path": "api_app.analyzers_manager.observable_analyzers", |
| 81 | + }, |
| 82 | + "name": "suspicious_info", |
| 83 | + "type": "bool", |
| 84 | + "description": "for IP, suspicious_info endpoint", |
| 85 | + "is_secret": False, |
| 86 | + "required": False, |
| 87 | + }, |
| 88 | + { |
| 89 | + "python_module": { |
| 90 | + "module": "criminalip.criminalip_scan.CriminalIpScan", |
| 91 | + "base_path": "api_app.analyzers_manager.observable_analyzers", |
| 92 | + }, |
| 93 | + "name": "banner_search", |
| 94 | + "type": "bool", |
| 95 | + "description": "for generics", |
| 96 | + "is_secret": False, |
| 97 | + "required": False, |
| 98 | + }, |
| 99 | + { |
| 100 | + "python_module": { |
| 101 | + "module": "criminalip.criminalip_scan.CriminalIpScan", |
| 102 | + "base_path": "api_app.analyzers_manager.observable_analyzers", |
| 103 | + }, |
| 104 | + "name": "banner_stats", |
| 105 | + "type": "bool", |
| 106 | + "description": "for generics", |
| 107 | + "is_secret": False, |
| 108 | + "required": False, |
| 109 | + }, |
| 110 | +] |
| 111 | + |
| 112 | +values = [] |
| 113 | + |
| 114 | + |
| 115 | +def _get_real_obj(Model, field, value): |
| 116 | + def _get_obj(Model, other_model, value): |
| 117 | + if isinstance(value, dict): |
| 118 | + real_vals = {} |
| 119 | + for key, real_val in value.items(): |
| 120 | + real_vals[key] = _get_real_obj(other_model, key, real_val) |
| 121 | + value = other_model.objects.get_or_create(**real_vals)[0] |
| 122 | + # it is just the primary key serialized |
| 123 | + else: |
| 124 | + if isinstance(value, int): |
| 125 | + if Model.__name__ == "PluginConfig": |
| 126 | + value = other_model.objects.get(name=plugin["name"]) |
| 127 | + else: |
| 128 | + value = other_model.objects.get(pk=value) |
| 129 | + else: |
| 130 | + value = other_model.objects.get(name=value) |
| 131 | + return value |
| 132 | + |
| 133 | + if ( |
| 134 | + type(getattr(Model, field)) |
| 135 | + in [ForwardManyToOneDescriptor, ForwardOneToOneDescriptor] |
| 136 | + and value |
| 137 | + ): |
| 138 | + other_model = getattr(Model, field).get_queryset().model |
| 139 | + value = _get_obj(Model, other_model, value) |
| 140 | + elif type(getattr(Model, field)) in [ManyToManyDescriptor] and value: |
| 141 | + other_model = getattr(Model, field).rel.model |
| 142 | + value = [_get_obj(Model, other_model, val) for val in value] |
| 143 | + return value |
| 144 | + |
| 145 | + |
| 146 | +def _create_object(Model, data): |
| 147 | + mtm, no_mtm = {}, {} |
| 148 | + for field, value in data.items(): |
| 149 | + value = _get_real_obj(Model, field, value) |
| 150 | + if type(getattr(Model, field)) is ManyToManyDescriptor: |
| 151 | + mtm[field] = value |
| 152 | + else: |
| 153 | + no_mtm[field] = value |
| 154 | + try: |
| 155 | + o = Model.objects.get(**no_mtm) |
| 156 | + except Model.DoesNotExist: |
| 157 | + o = Model(**no_mtm) |
| 158 | + o.full_clean() |
| 159 | + o.save() |
| 160 | + for field, value in mtm.items(): |
| 161 | + attribute = getattr(o, field) |
| 162 | + if value is not None: |
| 163 | + attribute.set(value) |
| 164 | + return False |
| 165 | + return True |
| 166 | + |
| 167 | + |
| 168 | +def migrate(apps, schema_editor): |
| 169 | + Parameter = apps.get_model("api_app", "Parameter") |
| 170 | + PluginConfig = apps.get_model("api_app", "PluginConfig") |
| 171 | + python_path = plugin.pop("model") |
| 172 | + Model = apps.get_model(*python_path.split(".")) |
| 173 | + if not Model.objects.filter(name=plugin["name"]).exists(): |
| 174 | + exists = _create_object(Model, plugin) |
| 175 | + if not exists: |
| 176 | + for param in params: |
| 177 | + _create_object(Parameter, param) |
| 178 | + for value in values: |
| 179 | + _create_object(PluginConfig, value) |
| 180 | + |
| 181 | + PythonModule = apps.get_model("api_app", "PythonModule") |
| 182 | + # we will update the python module path |
| 183 | + pm = PythonModule.objects.get( |
| 184 | + module="criminalip.CriminalIp", |
| 185 | + base_path="api_app.analyzers_manager.observable_analyzers", |
| 186 | + ) |
| 187 | + pm.module = "criminalip.criminalip.CriminalIp" |
| 188 | + pm.save() |
| 189 | + Model.objects.filter(name="CriminalIp").update(python_module=pm) |
| 190 | + |
| 191 | + |
| 192 | +def reverse_migrate(apps, schema_editor): |
| 193 | + python_path = plugin.pop("model") |
| 194 | + Model = apps.get_model(*python_path.split(".")) |
| 195 | + Model.objects.get(name=plugin["name"]).delete() |
| 196 | + PythonModule = apps.get_model("api_app", "PythonModule") |
| 197 | + pm = PythonModule.objects.get( |
| 198 | + module="criminalip.criminalip.CriminalIp", |
| 199 | + base_path="api_app.analyzers_manager.observable_analyzers", |
| 200 | + ) |
| 201 | + pm.module = "criminalip.CriminalIp" |
| 202 | + pm.save() |
| 203 | + Model.objects.filter(name="CriminalIp").update(python_module=pm) |
| 204 | + |
| 205 | + |
| 206 | +class Migration(migrations.Migration): |
| 207 | + atomic = False |
| 208 | + dependencies = [ |
| 209 | + ("api_app", "0062_alter_parameter_python_module"), |
| 210 | + ("analyzers_manager", "0111_analyzer_config_criminalip"), |
| 211 | + ] |
| 212 | + |
| 213 | + operations = [migrations.RunPython(migrate, reverse_migrate)] |
0 commit comments