| 286 | return services |
| 287 | |
| 288 | def register(self, plugin, filename): |
| 289 | if plugin.disabled: |
| 290 | return |
| 291 | |
| 292 | if plugin.name is None: |
| 293 | fail('Error: Plugin with class name "' + plugin.__class__.__name__ + '" in ' + filename + ' does not have a name.') |
| 294 | |
| 295 | for _, loaded_plugin in self.plugins.items(): |
| 296 | if plugin.name == loaded_plugin.name: |
| 297 | fail('Error: Duplicate plugin name "' + plugin.name + '" detected in ' + filename + '.', file=sys.stderr) |
| 298 | |
| 299 | if plugin.slug is None: |
| 300 | plugin.slug = slugify(plugin.name) |
| 301 | elif not self.__slug_regex.match(plugin.slug): |
| 302 | fail('Error: provided slug "' + plugin.slug + '" in ' + filename + ' is not valid (must only contain lowercase letters, numbers, and hyphens).', file=sys.stderr) |
| 303 | |
| 304 | if plugin.slug in config['protected_classes']: |
| 305 | fail('Error: plugin slug "' + plugin.slug + '" in ' + filename + ' is a protected string. Please change.') |
| 306 | |
| 307 | if plugin.slug not in self.plugins: |
| 308 | |
| 309 | for _, loaded_plugin in self.plugins.items(): |
| 310 | if plugin is loaded_plugin: |
| 311 | fail('Error: plugin "' + plugin.name + '" in ' + filename + ' already loaded as "' + loaded_plugin.name + '" (' + str(loaded_plugin) + ')', file=sys.stderr) |
| 312 | |
| 313 | configure_function_found = False |
| 314 | run_coroutine_found = False |
| 315 | manual_function_found = False |
| 316 | |
| 317 | for member_name, member_value in inspect.getmembers(plugin, predicate=inspect.ismethod): |
| 318 | if member_name == 'configure': |
| 319 | configure_function_found = True |
| 320 | elif member_name == 'run' and inspect.iscoroutinefunction(member_value): |
| 321 | if len(inspect.getfullargspec(member_value).args) != 2: |
| 322 | fail('Error: the "run" coroutine in the plugin "' + plugin.name + '" in ' + filename + ' should have two arguments.', file=sys.stderr) |
| 323 | run_coroutine_found = True |
| 324 | elif member_name == 'manual': |
| 325 | if len(inspect.getfullargspec(member_value).args) != 3: |
| 326 | fail('Error: the "manual" function in the plugin "' + plugin.name + '" in ' + filename + ' should have three arguments.', file=sys.stderr) |
| 327 | manual_function_found = True |
| 328 | |
| 329 | if not run_coroutine_found and not manual_function_found: |
| 330 | fail('Error: the plugin "' + plugin.name + '" in ' + filename + ' needs either a "manual" function, a "run" coroutine, or both.', file=sys.stderr) |
| 331 | |
| 332 | if issubclass(plugin.__class__, PortScan): |
| 333 | if plugin.type is None: |
| 334 | fail('Error: the PortScan plugin "' + plugin.name + '" in ' + filename + ' requires a type (either tcp or udp).') |
| 335 | else: |
| 336 | plugin.type = plugin.type.lower() |
| 337 | if plugin.type not in ['tcp', 'udp']: |
| 338 | fail('Error: the PortScan plugin "' + plugin.name + '" in ' + filename + ' has an invalid type (should be tcp or udp).') |
| 339 | self.plugin_types["port"].append(plugin) |
| 340 | elif issubclass(plugin.__class__, ServiceScan): |
| 341 | self.plugin_types["service"].append(plugin) |
| 342 | elif issubclass(plugin.__class__, Report): |
| 343 | self.plugin_types["report"].append(plugin) |
| 344 | else: |
| 345 | fail('Plugin "' + plugin.name + '" in ' + filename + ' is neither a PortScan, ServiceScan, nor a Report.', file=sys.stderr) |