diff --git a/apps/assets/api/platform.py b/apps/assets/api/platform.py index 16ef2ef15..12daa7b0a 100644 --- a/apps/assets/api/platform.py +++ b/apps/assets/api/platform.py @@ -6,7 +6,7 @@ from common.drf.serializers import GroupedChoiceSerailizer from assets.models import Platform from assets.serializers import PlatformSerializer, PlatformOpsMethodSerializer from assets.const import AllTypes, Category -from assets.playbooks.platform import filter_platform_methods +from assets.playbooks import filter_platform_methods __all__ = ['AssetPlatformViewSet'] diff --git a/apps/assets/migrations/0112_auto_20220909_1907.py b/apps/assets/migrations/0112_auto_20220909_1907.py new file mode 100644 index 000000000..6aaba7513 --- /dev/null +++ b/apps/assets/migrations/0112_auto_20220909_1907.py @@ -0,0 +1,38 @@ +# Generated by Django 3.2.14 on 2022-09-09 11:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0111_auto_20220908_1958'), + ] + + operations = [ + migrations.AddField( + model_name='web', + name='autofill', + field=models.CharField(default='basic', max_length=16), + ), + migrations.AddField( + model_name='web', + name='password_selector', + field=models.CharField(blank=True, default='', max_length=128), + ), + migrations.AddField( + model_name='web', + name='submit_selector', + field=models.CharField(blank=True, default='', max_length=128), + ), + migrations.AddField( + model_name='web', + name='username_selector', + field=models.CharField(blank=True, default='', max_length=128), + ), + migrations.AlterField( + model_name='platform', + name='domain_enabled', + field=models.BooleanField(default=True, verbose_name='Domain enabled'), + ), + ] diff --git a/apps/assets/models/asset/web.py b/apps/assets/models/asset/web.py index 34e23828a..5b66cc71b 100644 --- a/apps/assets/models/asset/web.py +++ b/apps/assets/models/asset/web.py @@ -6,7 +6,7 @@ from .common import Asset class Web(Asset): url = models.CharField(max_length=1024, verbose_name=_("url")) - - username_selector = models.CharField() - password_selector = models.CharField() - confirm_selector = models.CharField() + autofill = models.CharField(max_length=16, default='basic') + username_selector = models.CharField(max_length=128, blank=True, default='') + password_selector = models.CharField(max_length=128, blank=True, default='') + submit_selector = models.CharField(max_length=128, blank=True, default='') diff --git a/apps/assets/playbooks/__init__.py b/apps/assets/playbooks/__init__.py new file mode 100644 index 000000000..0acc08789 --- /dev/null +++ b/apps/assets/playbooks/__init__.py @@ -0,0 +1,65 @@ +import os +import yaml +from functools import partial + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + + +def check_platform_method(manifest, manifest_path): + required_keys = ['category', 'method', 'name', 'id', 'type'] + less_key = set(required_keys) - set(manifest.keys()) + if less_key: + raise ValueError("Manifest missing keys: {}, {}".format(less_key, manifest_path)) + if not isinstance(manifest['type'], list): + raise ValueError("Manifest type must be a list: {}".format(manifest_path)) + return True + + +def check_platform_methods(methods): + ids = [m['id'] for m in methods] + for i, _id in enumerate(ids): + if _id in ids[i+1:]: + raise ValueError("Duplicate id: {}".format(_id)) + + +def get_platform_methods(): + methods = [] + for root, dirs, files in os.walk(BASE_DIR, topdown=False): + for name in files: + path = os.path.join(root, name) + if not path.endswith('manifest.yml'): + continue + + with open(path, 'r') as f: + manifest = yaml.safe_load(f) + check_platform_method(manifest, path) + manifest['dir'] = os.path.dirname(path) + methods.append(manifest) + + check_platform_methods(methods) + return methods + + +def filter_key(manifest, attr, value): + manifest_value = manifest.get(attr, '') + if isinstance(manifest_value, str): + manifest_value = [manifest_value] + return value in manifest_value or 'all' in manifest_value + + +def filter_platform_methods(category, tp, method): + methods = platform_ops_methods + if category: + methods = filter(partial(filter_key, attr='category', value=category), methods) + if tp: + methods = filter(partial(filter_key, attr='type', value=tp), methods) + if method: + methods = filter(lambda x: x['method'] == method, methods) + return methods + + +platform_ops_methods = get_platform_methods() + + +if __name__ == '__main__': + print(get_platform_methods()) diff --git a/apps/assets/serializers/asset/web.py b/apps/assets/serializers/asset/web.py index fc726c68e..c553a8062 100644 --- a/apps/assets/serializers/asset/web.py +++ b/apps/assets/serializers/asset/web.py @@ -8,4 +8,7 @@ __all__ = ['WebSerializer'] class WebSerializer(AssetSerializer): class Meta(AssetSerializer.Meta): model = Web - fields = AssetSerializer.Meta.fields + ['url'] + fields = AssetSerializer.Meta.fields + [ + 'url', 'autofill', 'username_selector', + 'password_selector', 'submit_selector' + ] diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index d1b1455d6..6a233cf07 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -10,7 +10,7 @@ router = BulkRouter() router.register(r'assets', api.AssetViewSet, 'asset') router.register(r'hosts', api.HostViewSet, 'host') router.register(r'databases', api.DatabaseViewSet, 'database') -router.register(r'webs', api.WebViewSet, 'web') +router.register(r'web', api.WebViewSet, 'web') router.register(r'clouds', api.CloudViewSet, 'cloud') router.register(r'networks', api.NetworkViewSet, 'network') router.register(r'accounts', api.AccountViewSet, 'account')