From c991a73632de6c8ebea44977072b0e2f2fe51d15 Mon Sep 17 00:00:00 2001 From: ibuler Date: Sun, 23 Apr 2023 16:15:27 +0800 Subject: [PATCH 001/153] v1 --- apps/common/db/fields.py | 104 ++++++++++++++++++++++++++++++++- apps/perms/models/perm_node.py | 9 ++- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index a4a128671..97461774f 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # -import json from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models @@ -32,6 +31,7 @@ __all__ = [ "PortRangeField", "BitChoices", "TreeChoices", + "JSONManyToManyField", ] @@ -274,3 +274,105 @@ class PortRangeField(models.CharField): kwargs['max_length'] = 16 super().__init__(**kwargs) self.validators.append(PortRangeValidator()) + + +from django.db.models import Q +from django.apps import apps + +from django.db import models +from django.core.exceptions import ValidationError +import json + + +class JSONManyToManyDescriptor: + def __init__(self, field): + self.field = field + self._is_setting = False + + def __get__(self, instance, owner=None): + if instance is None: + return self + + if not hasattr(instance, "_related_manager_cache"): + instance._related_manager_cache = {} + + current_value = getattr(instance, self.field.attname, {}) + + if self.field.name not in instance._related_manager_cache or instance._related_manager_cache[ + self.field.name]._is_value_stale(current_value): + manager = RelatedManager(instance, self.field) + instance._related_manager_cache[self.field.name] = manager + + return instance._related_manager_cache[self.field.name] + + def __set__(self, instance, value): + if instance is None: + return + + if not hasattr(instance, "_is_setting"): + instance._is_setting = {} + + if self.field.name not in instance._is_setting or not instance._is_setting[self.field.name]: + instance._is_setting[self.field.name] = True + manager = self.__get__(instance, instance.__class__) + manager.set(value) + serialized_value = manager.serialize() + instance.__dict__[self.field.attname] = serialized_value + instance._is_setting[self.field.name] = False + + +class JSONManyToManyField(models.JSONField): + def __init__(self, related_model, *args, **kwargs): + self.related_model = related_model + super().__init__(*args, **kwargs) + + def contribute_to_class(self, cls, name, **kwargs): + super().contribute_to_class(cls, name, **kwargs) + setattr(cls, self.name, JSONManyToManyDescriptor(self)) + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + kwargs['related_model'] = self.related_model + return name, path, args, kwargs + + def validate(self, value, model_instance): + super().validate(value, model_instance) + if not isinstance(value, list) or not all(isinstance(item, int) for item in value): + raise ValidationError("Invalid JSON data for JSONManyToManyField.") + + +class RelatedManager: + def __init__(self, instance, field): + self.instance = instance + self.field = field + + def _is_value_stale(self, current_value): + return self.serialize() != current_value + + def set(self, value): + self.field.value = value + + def serialize(self): + return self.field.value + + def _get_queryset(self): + model = apps.get_model(self.field.to) + value = self.field.value + + if value["type"] == "all": + return model.objects.all() + elif value["type"] == "ids": + return model.objects.filter(id__in=value["ids"]) + elif value["type"] == "attrs": + filters = Q() + for attr in value["attrs"]: + if attr["match"] == "exact": + filters &= Q(**{attr["attr"]: attr["value"]}) + return model.objects.filter(filters) + + def all(self): + return self._get_queryset() + + def filter(self, *args, **kwargs): + queryset = self._get_queryset() + return queryset.filter(*args, **kwargs) diff --git a/apps/perms/models/perm_node.py b/apps/perms/models/perm_node.py index e51851db9..ccd1898aa 100644 --- a/apps/perms/models/perm_node.py +++ b/apps/perms/models/perm_node.py @@ -2,12 +2,19 @@ from django.db import models from django.db.models import F, TextChoices from django.utils.translation import ugettext_lazy as _ -from assets.models import Asset, Node, FamilyMixin from accounts.models import Account +from assets.models import Asset, Node, FamilyMixin +from common.db.fields import JSONManyToManyField from common.utils import lazyproperty from orgs.mixins.models import JMSOrgBaseModel +class TestPermission2(models.Model): + name = models.CharField(max_length=128, verbose_name=_('Name')) + users = JSONManyToManyField("users.User") + assets = JSONManyToManyField("assets.Asset") + + class NodeFrom(TextChoices): granted = 'granted', 'Direct node granted' child = 'child', 'Have children node' From 378eee040202daf4a126d4955bef3ed56a85b369 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 24 Apr 2023 16:27:13 +0800 Subject: [PATCH 002/153] pref: stash 2 --- apps/common/db/fields.py | 137 ++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 59 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 97461774f..210e61719 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -278,79 +278,27 @@ class PortRangeField(models.CharField): from django.db.models import Q from django.apps import apps - from django.db import models from django.core.exceptions import ValidationError import json -class JSONManyToManyDescriptor: - def __init__(self, field): - self.field = field - self._is_setting = False - - def __get__(self, instance, owner=None): - if instance is None: - return self - - if not hasattr(instance, "_related_manager_cache"): - instance._related_manager_cache = {} - - current_value = getattr(instance, self.field.attname, {}) - - if self.field.name not in instance._related_manager_cache or instance._related_manager_cache[ - self.field.name]._is_value_stale(current_value): - manager = RelatedManager(instance, self.field) - instance._related_manager_cache[self.field.name] = manager - - return instance._related_manager_cache[self.field.name] - - def __set__(self, instance, value): - if instance is None: - return - - if not hasattr(instance, "_is_setting"): - instance._is_setting = {} - - if self.field.name not in instance._is_setting or not instance._is_setting[self.field.name]: - instance._is_setting[self.field.name] = True - manager = self.__get__(instance, instance.__class__) - manager.set(value) - serialized_value = manager.serialize() - instance.__dict__[self.field.attname] = serialized_value - instance._is_setting[self.field.name] = False - - -class JSONManyToManyField(models.JSONField): - def __init__(self, related_model, *args, **kwargs): - self.related_model = related_model - super().__init__(*args, **kwargs) - - def contribute_to_class(self, cls, name, **kwargs): - super().contribute_to_class(cls, name, **kwargs) - setattr(cls, self.name, JSONManyToManyDescriptor(self)) - - def deconstruct(self): - name, path, args, kwargs = super().deconstruct() - kwargs['related_model'] = self.related_model - return name, path, args, kwargs - - def validate(self, value, model_instance): - super().validate(value, model_instance) - if not isinstance(value, list) or not all(isinstance(item, int) for item in value): - raise ValidationError("Invalid JSON data for JSONManyToManyField.") - - class RelatedManager: def __init__(self, instance, field): self.instance = instance self.field = field def _is_value_stale(self, current_value): - return self.serialize() != current_value + return self.field.value != current_value def set(self, value): + print("set value: {} [{}] ({})".format(self, self.field, value)) + self._set_value(value) + + def _set_value(self, value): self.field.value = value + if self.instance: + self.instance.__dict__[self.field.name] = value def serialize(self): return self.field.value @@ -376,3 +324,74 @@ class RelatedManager: def filter(self, *args, **kwargs): queryset = self._get_queryset() return queryset.filter(*args, **kwargs) + + +class JSONManyToManyDescriptor: + def __init__(self, field): + print("DES Call __init__: ", field) + self.field = field + self._is_setting = False + + def __get__(self, instance, owner=None): + print("Call __get__: ", instance, id(instance)) + if instance is None: + return self + + if not hasattr(instance, "_related_manager_cache"): + instance._related_manager_cache = {} + if self.field.name not in instance._related_manager_cache: + manager = RelatedManager(instance, self.field) + instance._related_manager_cache[self.field.name] = manager + return instance._related_manager_cache[self.field.name] + + def __set__(self, instance, value): + if instance is None: + return + + if not hasattr(instance, "_related_manager_cache"): + instance._related_manager_cache = {} + + if self.field.name not in instance._related_manager_cache: + manager = self.__get__(instance, instance.__class__) + else: + manager = instance._related_manager_cache[self.field.name] + + print("manager: ", manager) + print("Call __set__: ", id(instance), value) + if isinstance(value, RelatedManager): + value = value.field.value + manager.set(value) + + +class JSONManyToManyField(models.JSONField): + def __init__(self, to, *args, **kwargs): + self.to = to + super().__init__(*args, **kwargs) + + def contribute_to_class(self, cls, name, **kwargs): + super().contribute_to_class(cls, name, **kwargs) + setattr(cls, self.name, JSONManyToManyDescriptor(self)) + + def deconstruct(self): + name, path, args, kwargs = super().deconstruct() + kwargs['to'] = self.to + return name, path, args, kwargs + + def get_db_prep_value(self, value, connection, prepared=False): + if value is None: + return None + v = value.field.value + print("get_db_prep_value: ", value, v) + return json.dumps(v) + + def get_prep_value(self, value): + if value is None: + return value + v = value.field.value + print("get_prep_value: ", value, v) + return json.dumps(v) + + def validate(self, value, model_instance): + super().validate(value, model_instance) + if not isinstance(value, dict): + raise ValidationError("Invalid JSON data for JSONManyToManyField.") From 3cdb81cf4aab41aef5cc4a7e9616d7cbb015918b Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 24 Apr 2023 19:00:31 +0800 Subject: [PATCH 003/153] =?UTF-8?q?perf:=20=E6=90=9E=E5=AE=9A=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=20orm=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 210e61719..31818a438 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -287,25 +287,21 @@ class RelatedManager: def __init__(self, instance, field): self.instance = instance self.field = field + self.value = None def _is_value_stale(self, current_value): - return self.field.value != current_value + return self.value != current_value def set(self, value): - print("set value: {} [{}] ({})".format(self, self.field, value)) - self._set_value(value) - - def _set_value(self, value): - self.field.value = value - if self.instance: - self.instance.__dict__[self.field.name] = value + self.value = value + self.instance.__dict__[self.field.name] = value def serialize(self): - return self.field.value + return self.value def _get_queryset(self): model = apps.get_model(self.field.to) - value = self.field.value + value = self.value if value["type"] == "all": return model.objects.all() @@ -328,12 +324,10 @@ class RelatedManager: class JSONManyToManyDescriptor: def __init__(self, field): - print("DES Call __init__: ", field) self.field = field self._is_setting = False def __get__(self, instance, owner=None): - print("Call __get__: ", instance, id(instance)) if instance is None: return self @@ -342,7 +336,13 @@ class JSONManyToManyDescriptor: if self.field.name not in instance._related_manager_cache: manager = RelatedManager(instance, self.field) instance._related_manager_cache[self.field.name] = manager - return instance._related_manager_cache[self.field.name] + manager = instance._related_manager_cache[self.field.name] + # if self.field.name == 'users': + # print(">>> Call __get__: ", manager) + # print("Field: ", self.field) + # print("Instance: ", instance.__dict__) + # print("Current value: ", manager.value) + return manager def __set__(self, instance, value): if instance is None: @@ -356,10 +356,12 @@ class JSONManyToManyDescriptor: else: manager = instance._related_manager_cache[self.field.name] - print("manager: ", manager) - print("Call __set__: ", id(instance), value) + # if self.field.name == 'users': + # print(">>> Call __set__: ", manager, value) + # print("Field: ", self.field.name) + # print("Instance: ", instance.__dict__) if isinstance(value, RelatedManager): - value = value.field.value + value = value.value manager.set(value) @@ -380,8 +382,9 @@ class JSONManyToManyField(models.JSONField): def get_db_prep_value(self, value, connection, prepared=False): if value is None: return None - v = value.field.value - print("get_db_prep_value: ", value, v) + v = value.value + print("$$$ Get_db_prep_value: ", self.to, value, v) + print("Value field: ", value.__dict__) return json.dumps(v) def get_prep_value(self, value): From c824ae4478ea9e45459396938231b47f775e5ecf Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 24 Apr 2023 19:03:44 +0800 Subject: [PATCH 004/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20manager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 31818a438..4de393932 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -356,10 +356,6 @@ class JSONManyToManyDescriptor: else: manager = instance._related_manager_cache[self.field.name] - # if self.field.name == 'users': - # print(">>> Call __set__: ", manager, value) - # print("Field: ", self.field.name) - # print("Instance: ", instance.__dict__) if isinstance(value, RelatedManager): value = value.value manager.set(value) @@ -379,19 +375,16 @@ class JSONManyToManyField(models.JSONField): kwargs['to'] = self.to return name, path, args, kwargs - def get_db_prep_value(self, value, connection, prepared=False): - if value is None: + def get_db_prep_value(self, manager, connection, prepared=False): + if manager is None: return None - v = value.value - print("$$$ Get_db_prep_value: ", self.to, value, v) - print("Value field: ", value.__dict__) + v = manager.value return json.dumps(v) - def get_prep_value(self, value): - if value is None: - return value - v = value.field.value - print("get_prep_value: ", value, v) + def get_prep_value(self, manager): + if manager is None: + return manager + v = manager.value return json.dumps(v) def validate(self, value, model_instance): From 19d29d663798d82330574f08d707d94299ed6396 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 24 Apr 2023 19:04:47 +0800 Subject: [PATCH 005/153] perf: remove debug msg --- apps/common/db/fields.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 4de393932..978fcd865 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -337,11 +337,6 @@ class JSONManyToManyDescriptor: manager = RelatedManager(instance, self.field) instance._related_manager_cache[self.field.name] = manager manager = instance._related_manager_cache[self.field.name] - # if self.field.name == 'users': - # print(">>> Call __get__: ", manager) - # print("Field: ", self.field) - # print("Instance: ", instance.__dict__) - # print("Current value: ", manager.value) return manager def __set__(self, instance, value): From 20b7b794d84a3c1e49ced6ffb5e697a07900b280 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 25 Apr 2023 14:00:19 +0800 Subject: [PATCH 006/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20m2m=20fiel?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 978fcd865..9a43061e5 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -289,16 +289,10 @@ class RelatedManager: self.field = field self.value = None - def _is_value_stale(self, current_value): - return self.value != current_value - def set(self, value): self.value = value self.instance.__dict__[self.field.name] = value - def serialize(self): - return self.value - def _get_queryset(self): model = apps.get_model(self.field.to) value = self.value From 632627db11bfbbc1c7fff56c3549af6786e4dabd Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 25 Apr 2023 16:25:00 +0800 Subject: [PATCH 007/153] =?UTF-8?q?perf:=20=E5=8E=BB=E6=8E=89=20debug=20mo?= =?UTF-8?q?del?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 61 ++++++++++++++++++++++++++++------ apps/perms/models/perm_node.py | 7 ---- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 9a43061e5..7ff001e92 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -1,8 +1,13 @@ # -*- coding: utf-8 -*- # +import json + +from django.apps import apps +from django.core.exceptions import ValidationError from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models +from django.db.models import Q from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ from rest_framework.utils.encoders import JSONEncoder @@ -276,13 +281,6 @@ class PortRangeField(models.CharField): self.validators.append(PortRangeValidator()) -from django.db.models import Q -from django.apps import apps -from django.db import models -from django.core.exceptions import ValidationError -import json - - class RelatedManager: def __init__(self, instance, field): self.instance = instance @@ -296,17 +294,31 @@ class RelatedManager: def _get_queryset(self): model = apps.get_model(self.field.to) value = self.value + if not value or not isinstance(value, dict): + return model.objects.none() if value["type"] == "all": return model.objects.all() - elif value["type"] == "ids": + elif value["type"] == "ids" and isinstance(value.get("ids"), list): return model.objects.filter(id__in=value["ids"]) - elif value["type"] == "attrs": + elif value["type"] == "attrs" and isinstance(value.get("attrs"), list): filters = Q() for attr in value["attrs"]: - if attr["match"] == "exact": - filters &= Q(**{attr["attr"]: attr["value"]}) + if not isinstance(attr, dict): + continue + name = attr.get('name') + val = attr.get('value') + match = attr.get('match', 'exact') + if name is None or val is None: + continue + + lookup = name + if match in ("exact", "contains", "startswith", "endswith", "regex"): + lookup = "{}__{}".format(name, match) + filters &= Q(**{lookup: val}) return model.objects.filter(filters) + else: + return model.objects.none() def all(self): return self._get_queryset() @@ -364,16 +376,43 @@ class JSONManyToManyField(models.JSONField): kwargs['to'] = self.to return name, path, args, kwargs + @staticmethod + def _check_value(val): + if not val: + return val + e = ValueError( + 'Invalid JSON data for JSONManyToManyField, should be like ' + '{"type": "all"} or {"type": "ids", "ids": []} ' + 'or {"type": "attrs", "attrs": [{"name": "ip", "match": "exact", "value": "value"}' + ) + if not isinstance(val, dict): + raise e + if val["type"] not in ["all", "ids", "attrs"]: + raise e + if val["type"] == "ids": + if not isinstance(val["ids"], list): + raise e + elif val["type"] == "attrs": + if not isinstance(val["attrs"], list): + raise e + for attr in val["attrs"]: + if not isinstance(attr, dict): + raise e + if 'name' not in attr or 'value' not in attr: + raise e + def get_db_prep_value(self, manager, connection, prepared=False): if manager is None: return None v = manager.value + self._check_value(v) return json.dumps(v) def get_prep_value(self, manager): if manager is None: return manager v = manager.value + self._check_value(v) return json.dumps(v) def validate(self, value, model_instance): diff --git a/apps/perms/models/perm_node.py b/apps/perms/models/perm_node.py index ccd1898aa..f5dc52be3 100644 --- a/apps/perms/models/perm_node.py +++ b/apps/perms/models/perm_node.py @@ -4,17 +4,10 @@ from django.utils.translation import ugettext_lazy as _ from accounts.models import Account from assets.models import Asset, Node, FamilyMixin -from common.db.fields import JSONManyToManyField from common.utils import lazyproperty from orgs.mixins.models import JMSOrgBaseModel -class TestPermission2(models.Model): - name = models.CharField(max_length=128, verbose_name=_('Name')) - users = JSONManyToManyField("users.User") - assets = JSONManyToManyField("assets.Asset") - - class NodeFrom(TextChoices): granted = 'granted', 'Direct node granted' child = 'child', 'Have children node' From 338ab5c6340947a11b460c366923037d12aca7ca Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 26 Apr 2023 19:11:53 +0800 Subject: [PATCH 008/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20acl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0011_auto_20230425_1704.py | 44 ++++++++++ .../migrations/0012_auto_20230426_1111.py | 42 ++++++++++ .../migrations/0013_auto_20230426_1759.py | 66 +++++++++++++++ apps/acls/models/base.py | 7 +- apps/common/db/fields.py | 81 +++++++++++++++---- 5 files changed, 221 insertions(+), 19 deletions(-) create mode 100644 apps/acls/migrations/0011_auto_20230425_1704.py create mode 100644 apps/acls/migrations/0012_auto_20230426_1111.py create mode 100644 apps/acls/migrations/0013_auto_20230426_1759.py diff --git a/apps/acls/migrations/0011_auto_20230425_1704.py b/apps/acls/migrations/0011_auto_20230425_1704.py new file mode 100644 index 000000000..2a8682129 --- /dev/null +++ b/apps/acls/migrations/0011_auto_20230425_1704.py @@ -0,0 +1,44 @@ +# Generated by Django 3.2.17 on 2023-04-25 09:04 + +from django.db import migrations + +import common.db.fields + + +class Migration(migrations.Migration): + dependencies = [ + ('acls', '0010_alter_commandfilteracl_command_groups'), + ] + + operations = [ + migrations.AddField( + model_name='commandfilteracl', + name='new_accounts', + field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Account', verbose_name='Accounts'), + ), + migrations.AddField( + model_name='commandfilteracl', + name='new_assets', + field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Asset', verbose_name='Assets'), + ), + migrations.AddField( + model_name='commandfilteracl', + name='new_users', + field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'), + ), + migrations.AddField( + model_name='loginassetacl', + name='new_accounts', + field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Account', verbose_name='Accounts'), + ), + migrations.AddField( + model_name='loginassetacl', + name='new_assets', + field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Asset', verbose_name='Assets'), + ), + migrations.AddField( + model_name='loginassetacl', + name='new_users', + field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'), + ), + ] diff --git a/apps/acls/migrations/0012_auto_20230426_1111.py b/apps/acls/migrations/0012_auto_20230426_1111.py new file mode 100644 index 000000000..23984ac30 --- /dev/null +++ b/apps/acls/migrations/0012_auto_20230426_1111.py @@ -0,0 +1,42 @@ +# Generated by Django 3.2.17 on 2023-04-26 03:11 + +from django.db import migrations + + +def migrate_base_acl_users_assets_accounts(apps, *args): + cmd_acl_model = apps.get_model('acls', 'CommandFilterACL') + login_asset_acl_model = apps.get_model('acls', 'LoginAssetACL') + + for model in [cmd_acl_model, login_asset_acl_model]: + for obj in model.objects.all(): + user_names = (obj.users or {}).get('username_group', []) + obj.new_users = { + "type": "attrs", + "attrs": [{"name": "username", "value": user_names, "match": "in"}] + } + + asset_names = (obj.assets or {}).get('name_group', []) + asset_attrs = [] + if asset_names: + asset_attrs.append({"name": "name", "value": asset_names, "match": "in"}) + asset_address = (obj.assets or {}).get('address_group', []) + if asset_address: + asset_attrs.append({"name": "address", "value": asset_address, "match": "ip_in", "rel": "or"}) + obj.new_assets = {"type": "attrs", "attrs": asset_attrs} + + account_usernames = (obj.accounts or {}).get('username_group', []) + obj.new_accounts = { + "type": "attrs", + "attrs": [{"name": "username", "value": account_usernames, "match": "in"}] + } + obj.save() + + +class Migration(migrations.Migration): + dependencies = [ + ('acls', '0011_auto_20230425_1704'), + ] + + operations = [ + migrations.RunPython(migrate_base_acl_users_assets_accounts) + ] diff --git a/apps/acls/migrations/0013_auto_20230426_1759.py b/apps/acls/migrations/0013_auto_20230426_1759.py new file mode 100644 index 000000000..56dd58446 --- /dev/null +++ b/apps/acls/migrations/0013_auto_20230426_1759.py @@ -0,0 +1,66 @@ +# Generated by Django 3.2.17 on 2023-04-26 09:59 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ('acls', '0012_auto_20230426_1111'), + ] + + operations = [ + migrations.RemoveField( + model_name='commandfilteracl', + name='accounts', + ), + migrations.RemoveField( + model_name='commandfilteracl', + name='assets', + ), + migrations.RemoveField( + model_name='commandfilteracl', + name='users', + ), + migrations.RemoveField( + model_name='loginassetacl', + name='accounts', + ), + migrations.RemoveField( + model_name='loginassetacl', + name='assets', + ), + migrations.RemoveField( + model_name='loginassetacl', + name='users', + ), + migrations.RenameField( + model_name='commandfilteracl', + old_name='new_accounts', + new_name='accounts', + ), + migrations.RenameField( + model_name='commandfilteracl', + old_name='new_assets', + new_name='assets', + ), + migrations.RenameField( + model_name='commandfilteracl', + old_name='new_users', + new_name='users', + ), + migrations.RenameField( + model_name='loginassetacl', + old_name='new_accounts', + new_name='accounts', + ), + migrations.RenameField( + model_name='loginassetacl', + old_name='new_assets', + new_name='assets', + ), + migrations.RenameField( + model_name='loginassetacl', + old_name='new_users', + new_name='users', + ), + ] diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 2624e34cd..def536724 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -3,6 +3,7 @@ from django.db import models from django.db.models import Q from django.utils.translation import gettext_lazy as _ +from common.db.fields import JSONManyToManyField from common.db.models import JMSBaseModel from common.utils import contains_ip from orgs.mixins.models import OrgModelMixin, OrgManager @@ -95,11 +96,11 @@ class BaseACL(JMSBaseModel): class UserAssetAccountBaseACL(BaseACL, OrgModelMixin): # username_group - users = models.JSONField(verbose_name=_('User')) + users = JSONManyToManyField('users.User', default=dict, verbose_name=_('Users')) # name_group, address_group - assets = models.JSONField(verbose_name=_('Asset')) + assets = JSONManyToManyField('assets.Asset', default=dict, verbose_name=_('Assets')) # username_group - accounts = models.JSONField(verbose_name=_('Account')) + accounts = JSONManyToManyField('assets.Account', default=dict, verbose_name=_('Accounts')) objects = OrgACLManager.from_queryset(UserAssetAccountACLQuerySet)() diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 7ff001e92..c80c2b84d 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # +import ipaddress import json from django.apps import apps @@ -291,6 +292,34 @@ class RelatedManager: self.value = value self.instance.__dict__[self.field.name] = value + @staticmethod + def get_ip_in_q(name, val): + q = Q() + if isinstance(val, str): + val = [val] + for ip in val: + if not ip: + continue + try: + if ip == '*': + return Q() + elif '/' in ip: + network = ipaddress.ip_network(ip) + ips = network.hosts() + q |= Q(**{"{}__in".format(name): ips}) + elif '-' in ip: + start_ip, end_ip = ip.split('-') + start_ip = ipaddress.ip_address(start_ip) + end_ip = ipaddress.ip_address(end_ip) + q |= Q(**{"{}__range".format(name): (start_ip, end_ip)}) + elif len(ip.split('.')) == 4: + q |= Q(**{"{}__exact".format(name): ip}) + else: + q |= Q(**{"{}__startswith".format(name): ip}) + except ValueError: + continue + return q + def _get_queryset(self): model = apps.get_model(self.field.to) value = self.value @@ -303,20 +332,43 @@ class RelatedManager: return model.objects.filter(id__in=value["ids"]) elif value["type"] == "attrs" and isinstance(value.get("attrs"), list): filters = Q() + excludes = Q() for attr in value["attrs"]: if not isinstance(attr, dict): continue + name = attr.get('name') val = attr.get('value') match = attr.get('match', 'exact') + rel = attr.get('rel', 'and') if name is None or val is None: continue - lookup = name - if match in ("exact", "contains", "startswith", "endswith", "regex"): + if val == '*': + filters = Q() + break + + if match == 'ip_in': + q = self.get_ip_in_q(name, val) + elif match in ("exact", "contains", "startswith", "endswith", "regex"): lookup = "{}__{}".format(name, match) - filters &= Q(**{lookup: val}) - return model.objects.filter(filters) + q = Q(**{lookup: val}) + elif match == "in" and isinstance(val, list): + if '*' not in val: + lookup = "{}__in".format(name) + q = Q(**{lookup: val}) + else: + q = Q() + else: + q = Q(**{name: val}) + + if rel == 'or': + filters |= q + elif rel == 'not': + excludes |= q + else: + filters &= q + return model.objects.filter(filters).exclude(excludes) else: return model.objects.none() @@ -401,19 +453,16 @@ class JSONManyToManyField(models.JSONField): if 'name' not in attr or 'value' not in attr: raise e - def get_db_prep_value(self, manager, connection, prepared=False): - if manager is None: - return None - v = manager.value - self._check_value(v) - return json.dumps(v) + def get_db_prep_value(self, value, connection, prepared=False): + return self.get_prep_value(value) - def get_prep_value(self, manager): - if manager is None: - return manager - v = manager.value - self._check_value(v) - return json.dumps(v) + def get_prep_value(self, value): + if value is None: + return None + if isinstance(value, RelatedManager): + value = value.value + self._check_value(value) + return json.dumps(value) def validate(self, value, model_instance): super().validate(value, model_instance) From 90090a7fc77f8243689d23ed40b59b6a748827e9 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 27 Apr 2023 14:13:40 +0800 Subject: [PATCH 009/153] =?UTF-8?q?perf:=20=E6=B7=BB=E5=8A=A0=20JSONManyTo?= =?UTF-8?q?ManyFieldSerializer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/serializers/base.py | 26 ++++---------------------- apps/common/db/fields.py | 24 ++++++++++++------------ apps/common/serializers/fields.py | 17 ++++++++++++++++- 3 files changed, 32 insertions(+), 35 deletions(-) diff --git a/apps/acls/serializers/base.py b/apps/acls/serializers/base.py index dbdac67e7..ca319284f 100644 --- a/apps/acls/serializers/base.py +++ b/apps/acls/serializers/base.py @@ -2,7 +2,7 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from acls.models.base import ActionChoices -from common.serializers.fields import LabeledChoiceField, ObjectRelatedField +from common.serializers.fields import JSONManyToManyField, ObjectRelatedField, LabeledChoiceField from orgs.models import Organization from users.models import User @@ -52,25 +52,9 @@ class ACLAccountsSerializer(serializers.Serializer): class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer): - users = ACLUsersSerializer(label=_('User')) - assets = ACLAssestsSerializer(label=_('Asset')) - accounts = ACLAccountsSerializer(label=_('Account')) - users_username_group = serializers.ListField( - source='users.username_group', read_only=True, child=serializers.CharField(), - label=_('User (username)') - ) - assets_name_group = serializers.ListField( - source='assets.name_group', read_only=True, child=serializers.CharField(), - label=_('Asset (name)') - ) - assets_address_group = serializers.ListField( - source='assets.address_group', read_only=True, child=serializers.CharField(), - label=_('Asset (address)') - ) - accounts_username_group = serializers.ListField( - source='accounts.username_group', read_only=True, child=serializers.CharField(), - label=_('Account (username)') - ) + users = JSONManyToManyField(label=_('User')) + assets = JSONManyToManyField(label=_('Asset')) + accounts = JSONManyToManyField(label=_('Account')) reviewers = ObjectRelatedField( queryset=User.objects, many=True, required=False, label=_('Reviewers') ) @@ -84,8 +68,6 @@ class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer): class Meta: fields_mini = ["id", "name"] fields_small = fields_mini + [ - 'users_username_group', 'assets_address_group', 'assets_name_group', - 'accounts_username_group', "users", "accounts", "assets", "is_active", "date_created", "date_updated", "priority", "action", "comment", "created_by", "org_id", diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index c80c2b84d..50f7bb60a 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -429,29 +429,29 @@ class JSONManyToManyField(models.JSONField): return name, path, args, kwargs @staticmethod - def _check_value(val): + def check_value(val): if not val: return val - e = ValueError( - 'Invalid JSON data for JSONManyToManyField, should be like ' - '{"type": "all"} or {"type": "ids", "ids": []} ' - 'or {"type": "attrs", "attrs": [{"name": "ip", "match": "exact", "value": "value"}' - ) + e = ValueError(_( + "Invalid JSON data for JSONManyToManyField, should be like " + "{'type': 'all'} or {'type': 'ids', 'ids': []} " + "or {'type': 'attrs', 'attrs': [{'name': 'ip', 'match': 'exact', 'value': 'value'}" + )) if not isinstance(val, dict): raise e if val["type"] not in ["all", "ids", "attrs"]: - raise e + raise ValueError(_('Invalid type, should be "all", "ids" or "attrs"')) if val["type"] == "ids": if not isinstance(val["ids"], list): - raise e + raise ValueError(_("Invalid ids for ids, should be a list")) elif val["type"] == "attrs": if not isinstance(val["attrs"], list): - raise e + raise ValueError(_("Invalid attrs, should be a list of dict")) for attr in val["attrs"]: if not isinstance(attr, dict): - raise e + raise ValueError(_("Invalid attrs, should be a list of dict")) if 'name' not in attr or 'value' not in attr: - raise e + raise ValueError(_("Invalid attrs, should be has name and value")) def get_db_prep_value(self, value, connection, prepared=False): return self.get_prep_value(value) @@ -461,7 +461,7 @@ class JSONManyToManyField(models.JSONField): return None if isinstance(value, RelatedManager): value = value.value - self._check_value(value) + self.check_value(value) return json.dumps(value) def validate(self, value, model_instance): diff --git a/apps/common/serializers/fields.py b/apps/common/serializers/fields.py index 0b1e7040c..9595e09e1 100644 --- a/apps/common/serializers/fields.py +++ b/apps/common/serializers/fields.py @@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from rest_framework.fields import ChoiceField, empty -from common.db.fields import TreeChoices +from common.db.fields import TreeChoices, JSONManyToManyField as ModelJSONManyToManyField from common.local import add_encrypted_field_set from common.utils import decrypt_password @@ -20,6 +20,7 @@ __all__ = [ "TreeChoicesField", "LabeledMultipleChoiceField", "PhoneField", + "JSONManyToManyField" ] @@ -216,3 +217,17 @@ class PhoneField(serializers.CharField): phone = phonenumbers.parse(value, 'CN') value = {'code': '+%s' % phone.country_code, 'phone': phone.national_number} return value + + +class JSONManyToManyField(serializers.JSONField): + def to_representation(self, value): + return value.value + + def to_internal_value(self, data): + if not data: + data = {} + try: + ModelJSONManyToManyField.check_value(data) + except ValueError as e: + raise serializers.ValidationError(e) + return super().to_internal_value(data) From 5a6e13721d43259021286f0165c8ff38ceefb4a8 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 27 Apr 2023 18:05:16 +0800 Subject: [PATCH 010/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20json=20m2m?= =?UTF-8?q?=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/serializers/fields.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/common/serializers/fields.py b/apps/common/serializers/fields.py index 9595e09e1..e41a90944 100644 --- a/apps/common/serializers/fields.py +++ b/apps/common/serializers/fields.py @@ -220,8 +220,17 @@ class PhoneField(serializers.CharField): class JSONManyToManyField(serializers.JSONField): - def to_representation(self, value): - return value.value + def to_representation(self, manager): + if manager is None: + return manager + value = manager.value + if not isinstance(value, dict): + return {"type": "ids", "ids": []} + if value.get("type") == "ids": + valid_ids = manager.all().values_list("id", flat=True) + valid_ids = [str(i) for i in valid_ids] + return {"type": "ids", "ids": valid_ids} + return value def to_internal_value(self, data): if not data: From a112d3c99d0cb313b0972e05f3b4af2f2b312017 Mon Sep 17 00:00:00 2001 From: ibuler Date: Sat, 6 May 2023 19:52:03 +0800 Subject: [PATCH 011/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20accounts?= =?UTF-8?q?=20=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/models/base.py | 25 +----------------------- apps/acls/serializers/base.py | 4 ++-- apps/audits/handler.py | 19 +++++++++--------- apps/common/db/fields.py | 4 +++- apps/perms/serializers/permission.py | 29 +++++++--------------------- 5 files changed, 23 insertions(+), 58 deletions(-) diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index def536724..c85af7c0b 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -95,35 +95,12 @@ class BaseACL(JMSBaseModel): class UserAssetAccountBaseACL(BaseACL, OrgModelMixin): - # username_group users = JSONManyToManyField('users.User', default=dict, verbose_name=_('Users')) - # name_group, address_group assets = JSONManyToManyField('assets.Asset', default=dict, verbose_name=_('Assets')) - # username_group - accounts = JSONManyToManyField('assets.Account', default=dict, verbose_name=_('Accounts')) + accounts = models.JSONField(default=list, verbose_name=_("Account")) objects = OrgACLManager.from_queryset(UserAssetAccountACLQuerySet)() class Meta(BaseACL.Meta): unique_together = ('name', 'org_id') abstract = True - - @classmethod - def filter_queryset(cls, user=None, asset=None, account=None, account_username=None, **kwargs): - queryset = cls.objects.all() - org_id = None - if user: - queryset = queryset.filter_user(user.username) - if account: - org_id = account.org_id - queryset = queryset.filter_account(account.username) - if account_username: - queryset = queryset.filter_account(username=account_username) - if asset: - org_id = asset.org_id - queryset = queryset.filter_asset(asset.name, asset.address) - if org_id: - kwargs['org_id'] = org_id - if kwargs: - queryset = queryset.filter(**kwargs) - return queryset diff --git a/apps/acls/serializers/base.py b/apps/acls/serializers/base.py index ca319284f..069a92a90 100644 --- a/apps/acls/serializers/base.py +++ b/apps/acls/serializers/base.py @@ -20,7 +20,7 @@ class ACLUsersSerializer(serializers.Serializer): ) -class ACLAssestsSerializer(serializers.Serializer): +class ACLAssetsSerializer(serializers.Serializer): address_group_help_text = _( "With * indicating a match all. " "Such as: " @@ -54,7 +54,7 @@ class ACLAccountsSerializer(serializers.Serializer): class BaseUserAssetAccountACLSerializerMixin(serializers.Serializer): users = JSONManyToManyField(label=_('User')) assets = JSONManyToManyField(label=_('Asset')) - accounts = JSONManyToManyField(label=_('Account')) + accounts = serializers.ListField(label=_('Account')) reviewers = ObjectRelatedField( queryset=User.objects, many=True, required=False, label=_('Reviewers') ) diff --git a/apps/audits/handler.py b/apps/audits/handler.py index 27b116488..6491c69da 100644 --- a/apps/audits/handler.py +++ b/apps/audits/handler.py @@ -1,21 +1,20 @@ +import json from datetime import datetime -from django.db import transaction from django.core.cache import cache +from django.db import transaction from django.utils.translation import ugettext_lazy as _ -from common.utils import get_request_ip, get_logger -from common.utils.timezone import as_current_tz -from common.utils.encode import Singleton from common.local import encrypted_field_set -from settings.serializers import SettingsSerializer +from common.utils import get_request_ip, get_logger +from common.utils.encode import Singleton +from common.utils.timezone import as_current_tz from jumpserver.utils import current_request -from orgs.utils import get_current_org_id from orgs.models import Organization - +from orgs.utils import get_current_org_id +from settings.serializers import SettingsSerializer from .backends import get_operate_log_storage - logger = get_logger(__name__) @@ -106,7 +105,9 @@ class OperatorLogHandler(metaclass=Singleton): return '' if isinstance(value[0], str): return ','.join(value) - return ','.join([i['value'] for i in value if i.get('value')]) + if isinstance(value[0], dict) and value[0].get('value') and isinstance(value[0]['value'], str): + return ','.join([str(i['value']) for i in value]) + return json.dumps(value) def __data_processing(self, dict_item, loop=True): encrypt_value = '******' diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 50f7bb60a..027567e4e 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -353,6 +353,8 @@ class RelatedManager: elif match in ("exact", "contains", "startswith", "endswith", "regex"): lookup = "{}__{}".format(name, match) q = Q(**{lookup: val}) + elif match == "not": + q = ~Q(**{name: val}) elif match == "in" and isinstance(val, list): if '*' not in val: lookup = "{}__in".format(name) @@ -435,7 +437,7 @@ class JSONManyToManyField(models.JSONField): e = ValueError(_( "Invalid JSON data for JSONManyToManyField, should be like " "{'type': 'all'} or {'type': 'ids', 'ids': []} " - "or {'type': 'attrs', 'attrs': [{'name': 'ip', 'match': 'exact', 'value': 'value'}" + "or {'type': 'attrs', 'attrs': [{'name': 'ip', 'match': 'exact', 'value': 'value', 'rel': 'and|or|not'}}" )) if not isinstance(val, dict): raise e diff --git a/apps/perms/serializers/permission.py b/apps/perms/serializers/permission.py index 0e5f3b80a..43876d864 100644 --- a/apps/perms/serializers/permission.py +++ b/apps/perms/serializers/permission.py @@ -44,25 +44,12 @@ class AssetPermissionSerializer(BulkOrgResourceModelSerializer): model = AssetPermission fields_mini = ["id", "name"] fields_generic = [ - "accounts", - "actions", - "created_by", - "date_created", - "date_start", - "date_expired", - "is_active", - "is_expired", - "is_valid", - "comment", - "from_ticket", + "accounts", "actions", "created_by", "date_created", + "date_start", "date_expired", "is_active", "is_expired", + "is_valid", "comment", "from_ticket", ] fields_small = fields_mini + fields_generic - fields_m2m = [ - "users", - "user_groups", - "assets", - "nodes", - ] + fields_m2m = ["users", "user_groups", "assets", "nodes"] fields = fields_mini + fields_m2m + fields_generic read_only_fields = ["created_by", "date_created", "from_ticket"] extra_kwargs = { @@ -91,7 +78,8 @@ class AssetPermissionSerializer(BulkOrgResourceModelSerializer): def create_accounts(self, assets): need_create_accounts = [] account_attribute = [ - 'name', 'username', 'secret_type', 'secret', 'privileged', 'is_active', 'org_id' + 'name', 'username', 'secret_type', 'secret', + 'privileged', 'is_active', 'org_id' ] for asset in assets: asset_exist_accounts = Account.objects.none() @@ -139,10 +127,7 @@ class AssetPermissionSerializer(BulkOrgResourceModelSerializer): def setup_eager_loading(cls, queryset): """Perform necessary eager loading of data.""" queryset = queryset.prefetch_related( - "users", - "user_groups", - "assets", - "nodes", + "users", "user_groups", "assets", "nodes", ) return queryset From 1ec4cbdf38c7c3283c102b8d66cef1dae1b3f6b9 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 8 May 2023 14:09:44 +0800 Subject: [PATCH 012/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20m2m=20json?= =?UTF-8?q?=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/api/login_asset_check.py | 3 +- apps/acls/models/base.py | 49 ++--------------------------- apps/acls/models/login_asset_acl.py | 2 -- apps/common/db/models.py | 2 -- 4 files changed, 5 insertions(+), 51 deletions(-) diff --git a/apps/acls/api/login_asset_check.py b/apps/acls/api/login_asset_check.py index a593f0c27..f272dd1d4 100644 --- a/apps/acls/api/login_asset_check.py +++ b/apps/acls/api/login_asset_check.py @@ -37,7 +37,8 @@ class LoginAssetCheckAPI(CreateAPIView): 'account_username': self.serializer.validated_data.get('account_username'), 'action': LoginAssetACL.ActionChoices.review } - acl = LoginAssetACL.filter_queryset(**kwargs).valid().first() + acl = LoginAssetACL.objects.filter(**kwargs).valid().first() + if acl: need_review = True response_data = self._get_response_data_of_need_review(acl) diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index c85af7c0b..80f0affe6 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -1,19 +1,13 @@ from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models -from django.db.models import Q from django.utils.translation import gettext_lazy as _ from common.db.fields import JSONManyToManyField from common.db.models import JMSBaseModel -from common.utils import contains_ip -from orgs.mixins.models import OrgModelMixin, OrgManager +from orgs.mixins.models import OrgModelMixin __all__ = [ - 'ACLManager', - 'BaseACL', - 'BaseACLQuerySet', - 'UserAssetAccountBaseACL', - 'UserAssetAccountACLQuerySet' + 'BaseACL', 'UserAssetAccountBaseACL', ] @@ -37,41 +31,6 @@ class BaseACLQuerySet(models.QuerySet): return self.inactive() -class UserAssetAccountACLQuerySet(BaseACLQuerySet): - def filter_user(self, username): - q = Q(users__username_group__contains=username) | \ - Q(users__username_group__contains='*') - return self.filter(q) - - def filter_asset(self, name=None, address=None): - queryset = self.filter() - if name: - q = Q(assets__name_group__contains=name) | \ - Q(assets__name_group__contains='*') - queryset = queryset.filter(q) - if address: - ids = [ - q.id for q in queryset - if contains_ip(address, q.assets.get('address_group', [])) - ] - queryset = queryset.filter(id__in=ids) - return queryset - - def filter_account(self, username): - q = Q(accounts__username_group__contains=username) | \ - Q(accounts__username_group__contains='*') - return self.filter(q) - - -class ACLManager(models.Manager): - def valid(self): - return self.get_queryset().valid() - - -class OrgACLManager(OrgManager, ACLManager): - pass - - class BaseACL(JMSBaseModel): name = models.CharField(max_length=128, verbose_name=_('Name')) priority = models.IntegerField( @@ -84,7 +43,7 @@ class BaseACL(JMSBaseModel): is_active = models.BooleanField(default=True, verbose_name=_("Active")) ActionChoices = ActionChoices - objects = ACLManager.from_queryset(BaseACLQuerySet)() + objects = BaseACLQuerySet.as_manager() class Meta: ordering = ('priority', 'date_updated', 'name') @@ -99,8 +58,6 @@ class UserAssetAccountBaseACL(BaseACL, OrgModelMixin): assets = JSONManyToManyField('assets.Asset', default=dict, verbose_name=_('Assets')) accounts = models.JSONField(default=list, verbose_name=_("Account")) - objects = OrgACLManager.from_queryset(UserAssetAccountACLQuerySet)() - class Meta(BaseACL.Meta): unique_together = ('name', 'org_id') abstract = True diff --git a/apps/acls/models/login_asset_acl.py b/apps/acls/models/login_asset_acl.py index 609491e8d..fc5da088b 100644 --- a/apps/acls/models/login_asset_acl.py +++ b/apps/acls/models/login_asset_acl.py @@ -1,11 +1,9 @@ from django.utils.translation import ugettext_lazy as _ - from .base import UserAssetAccountBaseACL class LoginAssetACL(UserAssetAccountBaseACL): - class Meta(UserAssetAccountBaseACL.Meta): verbose_name = _('Login asset acl') abstract = False diff --git a/apps/common/db/models.py b/apps/common/db/models.py index 4d292827a..d01a37266 100644 --- a/apps/common/db/models.py +++ b/apps/common/db/models.py @@ -10,7 +10,6 @@ """ import uuid -from functools import reduce from django.db import models from django.db import transaction @@ -55,7 +54,6 @@ def output_as_string(field_name): class MultiTableChildQueryset(QuerySet): - def bulk_create(self, objs, batch_size=None): assert batch_size is None or batch_size > 0 if not objs: From 7c850a8a1eebd11f70e968b3678d665cd1f39e6f Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 12 May 2023 19:16:55 +0800 Subject: [PATCH 013/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20json=20fie?= =?UTF-8?q?ld=20query?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/api/login_asset_check.py | 21 ++++-- .../migrations/0012_auto_20230426_1111.py | 2 +- apps/common/db/fields.py | 68 ++++++++++++++++--- 3 files changed, 74 insertions(+), 17 deletions(-) diff --git a/apps/acls/api/login_asset_check.py b/apps/acls/api/login_asset_check.py index f272dd1d4..3c157a1cc 100644 --- a/apps/acls/api/login_asset_check.py +++ b/apps/acls/api/login_asset_check.py @@ -1,6 +1,7 @@ from rest_framework.generics import CreateAPIView from rest_framework.response import Response +from common.db.fields import JSONManyToManyField from common.utils import reverse, lazyproperty from orgs.utils import tmp_to_org from .. import serializers @@ -30,14 +31,20 @@ class LoginAssetCheckAPI(CreateAPIView): return serializer def check_review(self): + user = self.serializer.user + asset = self.serializer.asset + + # 用户满足的 acls + queryset = LoginAssetACL.objects.all() + q = JSONManyToManyField.get_filter_q(LoginAssetACL, 'users', user) + queryset = queryset.filter(q) + q = JSONManyToManyField.get_filter_q(LoginAssetACL, 'assets', asset) + queryset = queryset.filter(q) + account_username = self.serializer.validated_data.get('account_username') + queryset = queryset.filter(accounts__contains=account_username) + with tmp_to_org(self.serializer.asset.org): - kwargs = { - 'user': self.serializer.user, - 'asset': self.serializer.asset, - 'account_username': self.serializer.validated_data.get('account_username'), - 'action': LoginAssetACL.ActionChoices.review - } - acl = LoginAssetACL.objects.filter(**kwargs).valid().first() + acl = queryset.order_by('priority').valid().first() if acl: need_review = True diff --git a/apps/acls/migrations/0012_auto_20230426_1111.py b/apps/acls/migrations/0012_auto_20230426_1111.py index 23984ac30..277905fcd 100644 --- a/apps/acls/migrations/0012_auto_20230426_1111.py +++ b/apps/acls/migrations/0012_auto_20230426_1111.py @@ -21,7 +21,7 @@ def migrate_base_acl_users_assets_accounts(apps, *args): asset_attrs.append({"name": "name", "value": asset_names, "match": "in"}) asset_address = (obj.assets or {}).get('address_group', []) if asset_address: - asset_attrs.append({"name": "address", "value": asset_address, "match": "ip_in", "rel": "or"}) + asset_attrs.append({"name": "address", "value": asset_address, "match": "ip_in"}) obj.new_assets = {"type": "attrs", "attrs": asset_attrs} account_usernames = (obj.accounts or {}).get('username_group', []) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 027567e4e..70c14c4f2 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -3,6 +3,7 @@ import ipaddress import json +import re from django.apps import apps from django.core.exceptions import ValidationError @@ -344,10 +345,6 @@ class RelatedManager: if name is None or val is None: continue - if val == '*': - filters = Q() - break - if match == 'ip_in': q = self.get_ip_in_q(name, val) elif match in ("exact", "contains", "startswith", "endswith", "regex"): @@ -362,7 +359,10 @@ class RelatedManager: else: q = Q() else: - q = Q(**{name: val}) + if val == '*': + q = Q() + else: + q = Q(**{name: val}) if rel == 'or': filters |= q @@ -415,6 +415,59 @@ class JSONManyToManyDescriptor: value = value.value manager.set(value) + def test_is(self): + print("Self.field is", self.field) + print("Self.field to", self.field.to) + print("Self.field model", self.field.model) + print("Self.field column", self.field.column) + print("Self.field to", self.field.__dict__) + + @staticmethod + def attr_to_regex(attr): + """将属性规则转换为正则表达式""" + name, value, match = attr['name'], attr['value'], attr['match'] + if match == 'contains': + return r'.*{}.*'.format(escape_regex(value)) + elif match == 'startswith': + return r'^{}.*'.format(escape_regex(value)) + elif match == 'endswith': + return r'.*{}$'.format(escape_regex(value)) + elif match == 'regex': + return value + elif match == 'not': + return r'^(?!^{}$)'.format(escape_regex(value)) + elif match == 'in': + values = '|'.join(map(escape_regex, value)) + return r'^(?:{})$'.format(values) + else: + return r'^{}$'.format(escape_regex(value)) + + def is_match(self, attr_dict, attr_rules): + for rule in attr_rules: + value = attr_dict.get(rule['name'], '') + regex = self.attr_to_regex(rule) + if not re.match(regex, value): + return False + return True + + def get_filter_q(self, instance): + model_cls = self.field.model + field_name = self.field.column + q = Q(users__type='all') | Q(users__type='ids', users__ids__contains=[str(instance.id)]) + queryset_id_attrs = model_cls.objects \ + .filter(**{'{}__type'.format(field_name): 'attrs'}) \ + .values_list('id', '{}__attrs'.format(field_name)) + instance_attr = {k: v for k, v in instance.__dict__.items() if not k.startswith('_')} + ids = [str(_id) for _id, attr_rules in queryset_id_attrs if self.is_match(instance_attr, attr_rules)] + if ids: + q |= Q(id__in=ids) + return q + + +def escape_regex(s): + """转义字符串中的正则表达式特殊字符""" + return re.sub('[.*+?^${}()|[\\]]', r'\\\g<0>', s) + class JSONManyToManyField(models.JSONField): def __init__(self, to, *args, **kwargs): @@ -455,18 +508,15 @@ class JSONManyToManyField(models.JSONField): if 'name' not in attr or 'value' not in attr: raise ValueError(_("Invalid attrs, should be has name and value")) - def get_db_prep_value(self, value, connection, prepared=False): - return self.get_prep_value(value) - def get_prep_value(self, value): if value is None: return None if isinstance(value, RelatedManager): value = value.value - self.check_value(value) return json.dumps(value) def validate(self, value, model_instance): super().validate(value, model_instance) if not isinstance(value, dict): raise ValidationError("Invalid JSON data for JSONManyToManyField.") + self.check_value(value) From 4e5ab5a605000c52346d5c987315f0fbc13083e5 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 18 May 2023 13:14:32 +0800 Subject: [PATCH 014/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E7=9A=84=20q?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/api/login_acl.py | 3 +- apps/acls/api/login_asset_check.py | 5 +- apps/common/db/fields.py | 219 ++++++++++++++++++----------- apps/common/utils/ip/utils.py | 18 +++ apps/users/models/user.py | 28 +++- 5 files changed, 181 insertions(+), 92 deletions(-) diff --git a/apps/acls/api/login_acl.py b/apps/acls/api/login_acl.py index 806ffb343..07aa7f46e 100644 --- a/apps/acls/api/login_acl.py +++ b/apps/acls/api/login_acl.py @@ -1,7 +1,7 @@ from common.api import JMSBulkModelViewSet -from ..models import LoginACL from .. import serializers from ..filters import LoginAclFilter +from ..models import LoginACL __all__ = ['LoginACLViewSet'] @@ -11,4 +11,3 @@ class LoginACLViewSet(JMSBulkModelViewSet): filterset_class = LoginAclFilter search_fields = ('name',) serializer_class = serializers.LoginACLSerializer - diff --git a/apps/acls/api/login_asset_check.py b/apps/acls/api/login_asset_check.py index 3c157a1cc..bb61a9043 100644 --- a/apps/acls/api/login_asset_check.py +++ b/apps/acls/api/login_asset_check.py @@ -1,7 +1,6 @@ from rest_framework.generics import CreateAPIView from rest_framework.response import Response -from common.db.fields import JSONManyToManyField from common.utils import reverse, lazyproperty from orgs.utils import tmp_to_org from .. import serializers @@ -36,9 +35,9 @@ class LoginAssetCheckAPI(CreateAPIView): # 用户满足的 acls queryset = LoginAssetACL.objects.all() - q = JSONManyToManyField.get_filter_q(LoginAssetACL, 'users', user) + q = LoginAssetACL.users.get_filter_q(LoginAssetACL, 'users', user) queryset = queryset.filter(q) - q = JSONManyToManyField.get_filter_q(LoginAssetACL, 'assets', asset) + q = LoginAssetACL.assets.get_filter_q(LoginAssetACL, 'assets', asset) queryset = queryset.filter(q) account_username = self.serializer.validated_data.get('account_username') queryset = queryset.filter(accounts__contains=account_username) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 70c14c4f2..d2087f5d4 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -3,19 +3,20 @@ import ipaddress import json +import logging import re from django.apps import apps from django.core.exceptions import ValidationError from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models -from django.db.models import Q +from django.db.models import Q, Manager from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ from rest_framework.utils.encoders import JSONEncoder from common.local import add_encrypted_field_set -from common.utils import signer, crypto +from common.utils import signer, crypto, contains_ip from .validators import PortRangeValidator __all__ = [ @@ -321,58 +322,82 @@ class RelatedManager: continue return q + def _get_filter_attrs_q(self, value, to_model): + filters = Q() + # 特殊情况有这几种, + # 1. 像 资产中的 type 和 category,集成自 Platform。所以不能直接查询 + # 2. 像 资产中的 nodes,不是简单的 m2m,是树 的关系 + # 3. 像 用户中的 orgs 也不是简单的 m2m,也是计算出来的 + # get_filter_{}_attr_q 处理复杂的 + custom_attr_filter = getattr(to_model, "get_json_filter_attr_q", None) + for attr in value["attrs"]: + if not isinstance(attr, dict): + continue + + name = attr.get('name') + val = attr.get('value') + match = attr.get('match', 'exact') + if name is None or val is None: + continue + + print("Has custom filter: {}".format(custom_attr_filter)) + if custom_attr_filter: + custom_filter_q = custom_attr_filter(name, val, match) + print("Custom filter: {}".format(custom_filter_q)) + if custom_filter_q: + filters &= custom_filter_q + continue + + if match == 'ip_in': + q = self.get_ip_in_q(name, val) + elif match in ("exact", "contains", "startswith", "endswith", "regex", "gte", "lte", "gt", "lt"): + lookup = "{}__{}".format(name, match) + q = Q(**{lookup: val}) + elif match == "not": + q = ~Q(**{name: val}) + elif match == "m2m": + if not isinstance(val, list): + val = [val] + q = Q(**{"{}__in".format(name): val}) + elif match == "in" and isinstance(val, list): + if '*' not in val: + lookup = "{}__in".format(name) + q = Q(**{lookup: val}) + else: + q = Q() + else: + if val == '*': + q = Q() + else: + q = Q(**{name: val}) + + filters &= q + return filters + def _get_queryset(self): - model = apps.get_model(self.field.to) + to_model = apps.get_model(self.field.to) value = self.value + if hasattr(to_model, "get_queryset"): + queryset = to_model.get_queryset() + else: + queryset = to_model.objects.all() + if not value or not isinstance(value, dict): - return model.objects.none() + return queryset.none() if value["type"] == "all": - return model.objects.all() + return queryset elif value["type"] == "ids" and isinstance(value.get("ids"), list): - return model.objects.filter(id__in=value["ids"]) + return queryset.filter(id__in=value["ids"]) elif value["type"] == "attrs" and isinstance(value.get("attrs"), list): - filters = Q() - excludes = Q() - for attr in value["attrs"]: - if not isinstance(attr, dict): - continue - - name = attr.get('name') - val = attr.get('value') - match = attr.get('match', 'exact') - rel = attr.get('rel', 'and') - if name is None or val is None: - continue - - if match == 'ip_in': - q = self.get_ip_in_q(name, val) - elif match in ("exact", "contains", "startswith", "endswith", "regex"): - lookup = "{}__{}".format(name, match) - q = Q(**{lookup: val}) - elif match == "not": - q = ~Q(**{name: val}) - elif match == "in" and isinstance(val, list): - if '*' not in val: - lookup = "{}__in".format(name) - q = Q(**{lookup: val}) - else: - q = Q() - else: - if val == '*': - q = Q() - else: - q = Q(**{name: val}) - - if rel == 'or': - filters |= q - elif rel == 'not': - excludes |= q - else: - filters &= q - return model.objects.filter(filters).exclude(excludes) + q = self._get_filter_attrs_q(value, to_model) + return queryset.filter(q) else: - return model.objects.none() + return queryset.none() + + def get_attr_q(self): + q = self._get_filter_attrs_q(self.value) + return q def all(self): return self._get_queryset() @@ -415,40 +440,68 @@ class JSONManyToManyDescriptor: value = value.value manager.set(value) - def test_is(self): - print("Self.field is", self.field) - print("Self.field to", self.field.to) - print("Self.field model", self.field.model) - print("Self.field column", self.field.column) - print("Self.field to", self.field.__dict__) + def is_match(self, obj, attr_rules): + # m2m 的情况 + # 自定义的情况:比如 nodes, category + res = True + to_model = apps.get_model(self.field.to) + src_model = self.field.model + field_name = self.field.name + custom_attr_filter = getattr(src_model, "get_filter_{}_attr_q".format(field_name), None) - @staticmethod - def attr_to_regex(attr): - """将属性规则转换为正则表达式""" - name, value, match = attr['name'], attr['value'], attr['match'] - if match == 'contains': - return r'.*{}.*'.format(escape_regex(value)) - elif match == 'startswith': - return r'^{}.*'.format(escape_regex(value)) - elif match == 'endswith': - return r'.*{}$'.format(escape_regex(value)) - elif match == 'regex': - return value - elif match == 'not': - return r'^(?!^{}$)'.format(escape_regex(value)) - elif match == 'in': - values = '|'.join(map(escape_regex, value)) - return r'^(?:{})$'.format(values) - else: - return r'^{}$'.format(escape_regex(value)) - - def is_match(self, attr_dict, attr_rules): + custom_q = Q() for rule in attr_rules: - value = attr_dict.get(rule['name'], '') - regex = self.attr_to_regex(rule) - if not re.match(regex, value): - return False - return True + value = getattr(obj, rule['name'], '') + rule_value = rule.get('value', '') + rule_match = rule.get('match', 'exact') + + if custom_attr_filter: + q = custom_attr_filter(rule['name'], rule_value, rule_match) + if q: + custom_q &= q + continue + + if rule_match == 'in': + res &= value in rule_value + elif rule_match == 'exact': + res &= value == rule_value + elif rule_match == 'contains': + res &= rule_value in value + elif rule_match == 'startswith': + res &= str(value).startswith(str(rule_value)) + elif rule_match == 'endswith': + res &= str(value).endswith(str(rule_value)) + elif rule_match == 'regex': + res &= re.match(rule_value, value) + elif rule_match == 'not': + res &= value != rule_value + elif rule['match'] == 'gte': + res &= value >= rule_value + elif rule['match'] == 'lte': + res &= value <= rule_value + elif rule['match'] == 'gt': + res &= value > rule_value + elif rule['match'] == 'lt': + res &= value < rule_value + elif rule['match'] == 'ip_in': + if isinstance(rule_value, str): + rule_value = [rule_value] + res &= contains_ip(value, rule_value) + elif rule['match'] == 'm2m': + if isinstance(value, Manager): + value = value.values_list('id', flat=True) + value = set(map(str, value)) + rule_value = set(map(str, rule_value)) + res &= rule_value.issubset(value) + else: + logging.error("unknown match: {}".format(rule['match'])) + res &= False + + if not res: + return res + if custom_q: + res &= to_model.objects.filter(custom_q).filter(id=obj.id).exists() + return res def get_filter_q(self, instance): model_cls = self.field.model @@ -457,18 +510,12 @@ class JSONManyToManyDescriptor: queryset_id_attrs = model_cls.objects \ .filter(**{'{}__type'.format(field_name): 'attrs'}) \ .values_list('id', '{}__attrs'.format(field_name)) - instance_attr = {k: v for k, v in instance.__dict__.items() if not k.startswith('_')} - ids = [str(_id) for _id, attr_rules in queryset_id_attrs if self.is_match(instance_attr, attr_rules)] + ids = [str(_id) for _id, attr_rules in queryset_id_attrs if self.is_match(instance, attr_rules)] if ids: q |= Q(id__in=ids) return q -def escape_regex(s): - """转义字符串中的正则表达式特殊字符""" - return re.sub('[.*+?^${}()|[\\]]', r'\\\g<0>', s) - - class JSONManyToManyField(models.JSONField): def __init__(self, to, *args, **kwargs): self.to = to @@ -490,7 +537,7 @@ class JSONManyToManyField(models.JSONField): e = ValueError(_( "Invalid JSON data for JSONManyToManyField, should be like " "{'type': 'all'} or {'type': 'ids', 'ids': []} " - "or {'type': 'attrs', 'attrs': [{'name': 'ip', 'match': 'exact', 'value': 'value', 'rel': 'and|or|not'}}" + "or {'type': 'attrs', 'attrs': [{'name': 'ip', 'match': 'exact', 'value': '1.1.1.1'}}" )) if not isinstance(val, dict): raise e diff --git a/apps/common/utils/ip/utils.py b/apps/common/utils/ip/utils.py index e5d43911e..14851ff27 100644 --- a/apps/common/utils/ip/utils.py +++ b/apps/common/utils/ip/utils.py @@ -1,3 +1,4 @@ +import ipaddress import socket from ipaddress import ip_network, ip_address @@ -75,6 +76,23 @@ def contains_ip(ip, ip_group): return False +def is_ip(self, ip, rule_value): + if rule_value == '*': + return True + elif '/' in rule_value: + network = ipaddress.ip_network(rule_value) + return ip in network.hosts() + elif '-' in rule_value: + start_ip, end_ip = rule_value.split('-') + start_ip = ipaddress.ip_address(start_ip) + end_ip = ipaddress.ip_address(end_ip) + return start_ip <= ip <= end_ip + elif len(rule_value.split('.')) == 4: + return ip == rule_value + else: + return ip.startswith(rule_value) + + def get_ip_city(ip): if not ip or not isinstance(ip, str): return _("Invalid address") diff --git a/apps/users/models/user.py b/apps/users/models/user.py index b487365e5..5d1edb036 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -668,7 +668,33 @@ class MFAMixin: return backend -class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser): +class JSONFilterMixin: + """ + users = JSONManyToManyField('users.User', blank=True, null=True) + """ + + @staticmethod + def get_json_filter_attr_q(name, value, match): + from rbac.models import RoleBinding + from orgs.utils import current_org + + if name == 'system_roles': + user_id = RoleBinding.objects \ + .filter(role__in=value, scope='system') \ + .values_list('user_id', flat=True) + return models.Q(id__in=user_id) + elif name == 'org_roles': + kwargs = dict(role__in=value, scope='org') + if not current_org.is_root(): + kwargs['org_id'] = current_org.id + + user_id = RoleBinding.objects.filter(**kwargs) \ + .values_list('user_id', flat=True) + return models.Q(id__in=user_id) + return None + + +class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, JSONFilterMixin, AbstractUser): class Source(models.TextChoices): local = 'local', _('Local') ldap = 'ldap', 'LDAP/AD' From bb27be092487cf8682b11876ace4788a4404009d Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Thu, 18 May 2023 14:45:17 +0800 Subject: [PATCH 015/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=9F=90?= =?UTF-8?q?=E5=BE=85=E5=AE=A1=E6=A0=B8=E7=94=A8=E6=88=B7=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E7=99=BB=E5=BD=95=E5=85=B6=E4=BB=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E5=8F=AF=E7=BB=95=E5=BC=80mfa=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/mixins.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index 3bd872dbc..9fce76e57 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -221,7 +221,8 @@ class MFAMixin: self._do_check_user_mfa(code, mfa_type, user=user) def check_user_mfa_if_need(self, user): - if self.request.session.get('auth_mfa'): + if self.request.session.get('auth_mfa') and \ + self.request.session.get('auth_mfa_username') == user.username: return if not user.mfa_enabled: return @@ -229,15 +230,16 @@ class MFAMixin: active_mfa_names = user.active_mfa_backends_mapper.keys() raise errors.MFARequiredError(mfa_types=tuple(active_mfa_names)) - def mark_mfa_ok(self, mfa_type): + def mark_mfa_ok(self, mfa_type, user): self.request.session['auth_mfa'] = 1 + self.request.session['auth_mfa_username'] = user.username self.request.session['auth_mfa_time'] = time.time() self.request.session['auth_mfa_required'] = 0 self.request.session['auth_mfa_type'] = mfa_type - MFABlockUtils(self.request.user.username, self.get_request_ip()).clean_failed_count() + MFABlockUtils(user.username, self.get_request_ip()).clean_failed_count() def clean_mfa_mark(self): - keys = ['auth_mfa', 'auth_mfa_time', 'auth_mfa_required', 'auth_mfa_type'] + keys = ['auth_mfa', 'auth_mfa_time', 'auth_mfa_required', 'auth_mfa_type', 'auth_mfa_username'] for k in keys: self.request.session.pop(k, '') @@ -272,7 +274,7 @@ class MFAMixin: ok, msg = mfa_backend.check_code(code) if ok: - self.mark_mfa_ok(mfa_type) + self.mark_mfa_ok(mfa_type, user) return raise errors.MFAFailedError( From ebaa8d26377fca87f21dc22f42fd6b479233f0d8 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 18 May 2023 17:31:40 +0800 Subject: [PATCH 016/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20json=20err?= =?UTF-8?q?or?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 50 +++++++++++++++++++++----------------- apps/common/drf/filters.py | 25 +++++++++++++++++++ apps/users/api/user.py | 10 +++----- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index d2087f5d4..6039e943a 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -294,6 +294,29 @@ class RelatedManager: self.value = value self.instance.__dict__[self.field.name] = value + @classmethod + def get_filter_q(cls, value, to_model): + if not value or not isinstance(value, dict): + return Q() + + if value["type"] == "all": + return Q() + elif value["type"] == "ids" and isinstance(value.get("ids"), list): + return Q(id__in=value["ids"]) + elif value["type"] == "attrs" and isinstance(value.get("attrs"), list): + return cls._get_filter_attrs_q(value, to_model) + else: + return Q() + + @classmethod + def filter_queryset_by_model(cls, value, to_model): + if hasattr(to_model, "get_queryset"): + queryset = to_model.get_queryset() + else: + queryset = to_model.objects.all() + q = cls.get_filter_q(value, to_model) + return queryset.filter(q) + @staticmethod def get_ip_in_q(name, val): q = Q() @@ -322,7 +345,8 @@ class RelatedManager: continue return q - def _get_filter_attrs_q(self, value, to_model): + @classmethod + def _get_filter_attrs_q(cls, value, to_model): filters = Q() # 特殊情况有这几种, # 1. 像 资产中的 type 和 category,集成自 Platform。所以不能直接查询 @@ -340,16 +364,14 @@ class RelatedManager: if name is None or val is None: continue - print("Has custom filter: {}".format(custom_attr_filter)) if custom_attr_filter: custom_filter_q = custom_attr_filter(name, val, match) - print("Custom filter: {}".format(custom_filter_q)) if custom_filter_q: filters &= custom_filter_q continue if match == 'ip_in': - q = self.get_ip_in_q(name, val) + q = cls.get_ip_in_q(name, val) elif match in ("exact", "contains", "startswith", "endswith", "regex", "gte", "lte", "gt", "lt"): lookup = "{}__{}".format(name, match) q = Q(**{lookup: val}) @@ -377,26 +399,10 @@ class RelatedManager: def _get_queryset(self): to_model = apps.get_model(self.field.to) value = self.value - if hasattr(to_model, "get_queryset"): - queryset = to_model.get_queryset() - else: - queryset = to_model.objects.all() - - if not value or not isinstance(value, dict): - return queryset.none() - - if value["type"] == "all": - return queryset - elif value["type"] == "ids" and isinstance(value.get("ids"), list): - return queryset.filter(id__in=value["ids"]) - elif value["type"] == "attrs" and isinstance(value.get("attrs"), list): - q = self._get_filter_attrs_q(value, to_model) - return queryset.filter(q) - else: - return queryset.none() + return self.filter_queryset_by_model(value, to_model) def get_attr_q(self): - q = self._get_filter_attrs_q(self.value) + q = self._get_filter_attrs_q(self.value, apps.get_model(self.field.to)) return q def all(self): diff --git a/apps/common/drf/filters.py b/apps/common/drf/filters.py index 949260a47..6278efccf 100644 --- a/apps/common/drf/filters.py +++ b/apps/common/drf/filters.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- # +import base64 +import json import logging from django.core.cache import cache @@ -18,6 +20,8 @@ __all__ = [ "BaseFilterSet" ] +from common.db.fields import RelatedManager + class BaseFilterSet(drf_filters.FilterSet): def do_nothing(self, queryset, name, value): @@ -183,3 +187,24 @@ class UUIDInFilter(drf_filters.BaseInFilter, drf_filters.UUIDFilter): class NumberInFilter(drf_filters.BaseInFilter, drf_filters.NumberFilter): pass + + +class AttrRulesFilter(filters.BaseFilterBackend): + def get_schema_fields(self, view): + return [ + coreapi.Field( + name='attr_rules', location='query', required=False, + type='string', example='/api/v1/users/users?attr_rules=jsonbase64', + description='Filter by json like {"type": "attrs", "attrs": []} to base64' + ) + ] + + def filter_queryset(self, request, queryset, view): + attr_rules = request.query_params.get('attr_rules') + if not attr_rules: + return queryset + + attr_rules = base64.b64decode(attr_rules.encode('utf-8')) + attr_rules = json.loads(attr_rules) + q = RelatedManager.get_filter_q(attr_rules, queryset.model) + return queryset.filter(q) diff --git a/apps/users/api/user.py b/apps/users/api/user.py index d1eee8083..26a8e9d05 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -7,8 +7,8 @@ from rest_framework.decorators import action from rest_framework.response import Response from rest_framework_bulk import BulkModelViewSet -from common.api import CommonApiMixin -from common.api import SuggestionMixin +from common.api import CommonApiMixin, SuggestionMixin +from common.drf.filters import AttrRulesFilter from common.utils import get_logger from orgs.utils import current_org, tmp_to_root_org from rbac.models import Role, RoleBinding @@ -18,10 +18,7 @@ from .. import serializers from ..filters import UserFilter from ..models import User from ..notifications import ResetMFAMsg -from ..serializers import ( - UserSerializer, - MiniUserSerializer, InviteSerializer -) +from ..serializers import UserSerializer, MiniUserSerializer, InviteSerializer from ..signals import post_user_create logger = get_logger(__name__) @@ -33,6 +30,7 @@ __all__ = [ class UserViewSet(CommonApiMixin, UserQuerysetMixin, SuggestionMixin, BulkModelViewSet): filterset_class = UserFilter + extra_filter_backends = [AttrRulesFilter] search_fields = ('username', 'email', 'name') serializer_classes = { 'default': UserSerializer, From efb31d6f37fceef1bd7a5e8df7f55abbbf6051f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=AF=E6=9C=9D=E9=98=B3?= Date: Thu, 18 May 2023 20:40:41 +0800 Subject: [PATCH 017/153] fix: when request access_token is post method, http body has no json data --- apps/authentication/backends/oauth2/backends.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/authentication/backends/oauth2/backends.py b/apps/authentication/backends/oauth2/backends.py index 2214ba628..9f3b04ac3 100644 --- a/apps/authentication/backends/oauth2/backends.py +++ b/apps/authentication/backends/oauth2/backends.py @@ -104,7 +104,10 @@ class OAuth2Backend(JMSModelBackend): headers = { 'Accept': 'application/json' } - access_token_response = requests_func(access_token_url, headers=headers) + if token_method == 'post': + access_token_response = requests_func(access_token_url, headers=headers, json=query_dict) + else: + access_token_response = requests_func(access_token_url, headers=headers) try: access_token_response.raise_for_status() access_token_response_data = access_token_response.json() From a261d69cd2ce925b186300ed13d65cd10a81c51b Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 18 May 2023 21:34:19 +0800 Subject: [PATCH 018/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20m2m=20json?= =?UTF-8?q?=20field?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/asset/asset.py | 7 +++++-- apps/assets/models/asset/common.py | 28 +++++++++++++++++++++++++++- apps/assets/models/node.py | 13 +++++++++++++ apps/common/db/fields.py | 1 + apps/common/drf/filters.py | 16 ++++++++++++---- apps/users/api/user.py | 4 ++-- 6 files changed, 60 insertions(+), 9 deletions(-) diff --git a/apps/assets/api/asset/asset.py b/apps/assets/api/asset/asset.py index ba048e236..71d912188 100644 --- a/apps/assets/api/asset/asset.py +++ b/apps/assets/api/asset/asset.py @@ -15,7 +15,7 @@ from assets.filters import IpInFilterBackend, LabelFilterBackend, NodeFilterBack from assets.models import Asset, Gateway, Platform from assets.tasks import test_assets_connectivity_manual, update_assets_hardware_info_manual from common.api import SuggestionMixin -from common.drf.filters import BaseFilterSet +from common.drf.filters import BaseFilterSet, AttrRulesFilterBackend from common.utils import get_logger, is_uuid from orgs.mixins import generics from orgs.mixins.api import OrgBulkModelViewSet @@ -110,7 +110,10 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet): ("spec_info", "assets.view_asset"), ("gathered_info", "assets.view_asset"), ) - extra_filter_backends = [LabelFilterBackend, IpInFilterBackend, NodeFilterBackend] + extra_filter_backends = [ + LabelFilterBackend, IpInFilterBackend, + NodeFilterBackend, AttrRulesFilterBackend + ] def get_serializer_class(self): cls = super().get_serializer_class() diff --git a/apps/assets/models/asset/common.py b/apps/assets/models/asset/common.py index b39119b81..6e6d6b836 100644 --- a/apps/assets/models/asset/common.py +++ b/apps/assets/models/asset/common.py @@ -6,6 +6,7 @@ import logging from collections import defaultdict from django.db import models +from django.db.models import Q from django.forms import model_to_dict from django.utils.translation import ugettext_lazy as _ @@ -116,7 +117,32 @@ class Protocol(models.Model): return self.asset_platform_protocol.get('public', True) -class Asset(NodesRelationMixin, AbsConnectivity, JMSOrgBaseModel): +class JSONFilterMixin: + @staticmethod + def get_json_filter_attr_q(name, value, match): + """ + :param name: 属性名称 + :param value: 定义的结果 + :param match: 匹配方式 + :return: + """ + from ..node import Node + if not isinstance(value, (list, tuple)): + value = [value] + if name == 'nodes': + nodes = Node.objects.filter(id__in=value) + children = Node.get_nodes_all_children(nodes, with_self=True).values_list('id', flat=True) + return Q(nodes__in=children) + elif name == 'category': + return Q(platform__category__in=value) + elif name == 'type': + return Q(platform__type__in=value) + elif name == 'protocols': + return Q(protocols__name__in=value) + return None + + +class Asset(NodesRelationMixin, AbsConnectivity, JSONFilterMixin, JMSOrgBaseModel): Category = const.Category Type = const.AllTypes diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 32bfcaa09..3a729ba9f 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -63,6 +63,19 @@ class FamilyMixin: pattern += r'|^{0}$'.format(key) return pattern + @classmethod + def get_nodes_children_key_pattern(cls, nodes, with_self=True): + keys = [i.key for i in nodes] + keys = cls.clean_children_keys(keys) + patterns = [cls.get_node_all_children_key_pattern(key) for key in keys] + patterns = '|'.join(patterns) + return patterns + + @classmethod + def get_nodes_all_children(cls, nodes, with_self=True): + pattern = cls.get_nodes_children_key_pattern(nodes, with_self=with_self) + return Node.objects.filter(key__iregex=pattern) + @classmethod def get_node_children_key_pattern(cls, key, with_self=True): pattern = r'^{0}:[0-9]+$'.format(key) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 6039e943a..3897a8c5e 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -315,6 +315,7 @@ class RelatedManager: else: queryset = to_model.objects.all() q = cls.get_filter_q(value, to_model) + print("Q: ", q) return queryset.filter(q) @staticmethod diff --git a/apps/common/drf/filters.py b/apps/common/drf/filters.py index 6278efccf..cfdff0a6e 100644 --- a/apps/common/drf/filters.py +++ b/apps/common/drf/filters.py @@ -189,7 +189,7 @@ class NumberInFilter(drf_filters.BaseInFilter, drf_filters.NumberFilter): pass -class AttrRulesFilter(filters.BaseFilterBackend): +class AttrRulesFilterBackend(filters.BaseFilterBackend): def get_schema_fields(self, view): return [ coreapi.Field( @@ -204,7 +204,15 @@ class AttrRulesFilter(filters.BaseFilterBackend): if not attr_rules: return queryset - attr_rules = base64.b64decode(attr_rules.encode('utf-8')) - attr_rules = json.loads(attr_rules) + try: + attr_rules = base64.b64decode(attr_rules.encode('utf-8')) + except Exception: + raise ValidationError({'attr_rules': 'attr_rules should be base64'}) + try: + attr_rules = json.loads(attr_rules) + except Exception: + raise ValidationError({'attr_rules': 'attr_rules should be json'}) + + logging.debug('attr_rules: %s', attr_rules) q = RelatedManager.get_filter_q(attr_rules, queryset.model) - return queryset.filter(q) + return queryset.filter(q).distinct() diff --git a/apps/users/api/user.py b/apps/users/api/user.py index 26a8e9d05..c7882f6b2 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -8,7 +8,7 @@ from rest_framework.response import Response from rest_framework_bulk import BulkModelViewSet from common.api import CommonApiMixin, SuggestionMixin -from common.drf.filters import AttrRulesFilter +from common.drf.filters import AttrRulesFilterBackend from common.utils import get_logger from orgs.utils import current_org, tmp_to_root_org from rbac.models import Role, RoleBinding @@ -30,7 +30,7 @@ __all__ = [ class UserViewSet(CommonApiMixin, UserQuerysetMixin, SuggestionMixin, BulkModelViewSet): filterset_class = UserFilter - extra_filter_backends = [AttrRulesFilter] + extra_filter_backends = [AttrRulesFilterBackend] search_fields = ('username', 'email', 'name') serializer_classes = { 'default': UserSerializer, From 6eb9986c752c3ecbe5f40b4bf9e807431cb424fe Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 18 May 2023 22:08:41 +0800 Subject: [PATCH 019/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E8=BF=87?= =?UTF-8?q?=E6=9C=9F=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/api/connection_token.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/authentication/api/connection_token.py b/apps/authentication/api/connection_token.py index 53dffd906..0bc69b025 100644 --- a/apps/authentication/api/connection_token.py +++ b/apps/authentication/api/connection_token.py @@ -3,6 +3,7 @@ import json import os import urllib.parse +from django.conf import settings from django.http import HttpResponse from django.shortcuts import get_object_or_404 from django.utils import timezone @@ -379,19 +380,18 @@ class SuperConnectionTokenViewSet(ConnectionTokenViewSet): expire_now = request.data.get('expire_now', None) asset_type = token.asset.type - asset_category = token.asset.category # 设置默认值 if expire_now is None: # TODO 暂时特殊处理 k8s 不过期 if asset_type in ['k8s', 'kubernetes']: expire_now = False - elif asset_category in ['database', 'db']: - expire_now = False else: - expire_now = True + expire_now = not settings.CONNECTION_TOKEN_REUSABLE - if is_false(expire_now) or token.is_reusable: - logger.debug('Token is reusable or specify, not expire') + if is_false(expire_now): + logger.debug('Api specified, now expire now') + elif token.is_reusable and settings.CONNECTION_TOKEN_REUSABLE: + logger.debug('Token is reusable, not expire now') else: token.expire() From 197364d42d02931bcc0176e2b45f1cd23e16aa6f Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 19 May 2023 11:30:50 +0800 Subject: [PATCH 020/153] =?UTF-8?q?perf:=20=E6=9A=82=E5=AD=98=E4=B8=80?= =?UTF-8?q?=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 19 ++++--------------- apps/terminal/applets/chrome/app.py | 7 +++++-- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 3897a8c5e..adfe94769 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -315,8 +315,7 @@ class RelatedManager: else: queryset = to_model.objects.all() q = cls.get_filter_q(value, to_model) - print("Q: ", q) - return queryset.filter(q) + return queryset.filter(q).distinct() @staticmethod def get_ip_in_q(name, val): @@ -378,22 +377,12 @@ class RelatedManager: q = Q(**{lookup: val}) elif match == "not": q = ~Q(**{name: val}) - elif match == "m2m": + elif match in ['m2m', 'in']: if not isinstance(val, list): val = [val] - q = Q(**{"{}__in".format(name): val}) - elif match == "in" and isinstance(val, list): - if '*' not in val: - lookup = "{}__in".format(name) - q = Q(**{lookup: val}) - else: - q = Q() + q = Q() if '*' in val else Q(**{"{}__in".format(name): val}) else: - if val == '*': - q = Q() - else: - q = Q(**{name: val}) - + q = Q() if val == '*' else Q(**{name: val}) filters &= q return filters diff --git a/apps/terminal/applets/chrome/app.py b/apps/terminal/applets/chrome/app.py index ced2456c8..86a664c27 100644 --- a/apps/terminal/applets/chrome/app.py +++ b/apps/terminal/applets/chrome/app.py @@ -101,6 +101,7 @@ class StepAction: else: driver.switch_to.frame(target) + def execute_action(driver: webdriver.Chrome, step: StepAction) -> bool: try: return step.execute(driver) @@ -197,8 +198,10 @@ def default_chrome_driver_options(): # 禁用开发者工具 options.add_argument("--disable-dev-tools") # 禁用 密码管理器弹窗 - prefs = {"credentials_enable_service": False, - "profile.password_manager_enabled": False} + prefs = { + "credentials_enable_service": False, + "profile.password_manager_enabled": False + } options.add_experimental_option("prefs", prefs) options.add_experimental_option("excludeSwitches", ['enable-automation']) return options From c4b25fbdbdc07b5ecba18c5c20dd555b1021433c Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 19 May 2023 15:06:23 +0800 Subject: [PATCH 021/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20applet=20?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E9=80=89=E6=8B=A9=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/api/job.py | 1 + apps/terminal/models/applet/applet.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/ops/api/job.py b/apps/ops/api/job.py index 5d7012a8f..6fac1bc95 100644 --- a/apps/ops/api/job.py +++ b/apps/ops/api/job.py @@ -166,6 +166,7 @@ class UsernameHintsAPI(APIView): top_accounts = Account.objects \ .exclude(username__startswith='jms_') \ + .exclude(username__startswith='js_') \ .filter(username__icontains=query) \ .filter(asset__in=assets) \ .values('username') \ diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index be8f1e2cc..2114740ef 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -193,7 +193,7 @@ class Applet(JMSBaseModel): if private_account and private_account.username not in accounts_username_used: account = private_account else: - accounts = accounts.exclude(username__in=accounts_username_used) + accounts = accounts.exclude(username__in=accounts_username_used).filter(username__startswith='jms_') account = self.random_select_prefer_account(user, host, accounts) if not account: return From d4bb501ef9e798aba7ae58385aabe908920d0979 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Mon, 22 May 2023 11:29:20 +0800 Subject: [PATCH 022/153] =?UTF-8?q?fix:=20=E8=B4=A6=E5=8F=B7=E5=AF=BC?= =?UTF-8?q?=E5=85=A5500?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/serializers/account/account.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/accounts/serializers/account/account.py b/apps/accounts/serializers/account/account.py index 4ff294ee1..7b4abefa2 100644 --- a/apps/accounts/serializers/account/account.py +++ b/apps/accounts/serializers/account/account.py @@ -22,8 +22,8 @@ logger = get_logger(__name__) class AccountCreateUpdateSerializerMixin(serializers.Serializer): template = serializers.PrimaryKeyRelatedField( - queryset=AccountTemplate.objects, - required=False, label=_("Template"), write_only=True + queryset=AccountTemplate.objects, required=False, + label=_("Template"), write_only=True, allow_null=True ) push_now = serializers.BooleanField( default=False, label=_("Push now"), write_only=True @@ -33,7 +33,7 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer): ) on_invalid = LabeledChoiceField( choices=AccountInvalidPolicy.choices, default=AccountInvalidPolicy.ERROR, - write_only=True, label=_('Exist policy') + write_only=True, allow_null=True, label=_('Exist policy'), ) _template = None clean_auth_fields: callable From a3f472137fe045bfc9079b972decbbcc714e05a7 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Mon, 22 May 2023 14:24:22 +0800 Subject: [PATCH 023/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E8=BF=87=E6=BB=A4=E8=A7=84=E5=88=99=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/handler.py | 6 ++---- apps/audits/utils.py | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/audits/handler.py b/apps/audits/handler.py index 27b116488..290af552c 100644 --- a/apps/audits/handler.py +++ b/apps/audits/handler.py @@ -46,10 +46,8 @@ class OperatorLogHandler(metaclass=Singleton): pre_value, value = self._consistent_type_to_str(pre_value, value) if sorted(str(value)) == sorted(str(pre_value)): continue - if pre_value: - before[key] = pre_value - if value: - after[key] = value + before[key] = pre_value + after[key] = value return before, after def cache_instance_before_data(self, instance_dict): diff --git a/apps/audits/utils.py b/apps/audits/utils.py index 27cdd6e28..3865e9326 100644 --- a/apps/audits/utils.py +++ b/apps/audits/utils.py @@ -70,8 +70,10 @@ def _get_instance_field_value( if getattr(f, 'primary_key', False): f.verbose_name = 'id' - elif isinstance(value, (list, dict)): + elif isinstance(value, list): value = copy.deepcopy(value) + elif isinstance(value, dict): + value = dict(copy.deepcopy(value)) elif isinstance(value, datetime): value = as_current_tz(value).strftime('%Y-%m-%d %H:%M:%S') elif isinstance(f, models.OneToOneField) and isinstance(value, models.Model): From 3eaed621867adb91e7fe9f2c63a2979ec781a706 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Mon, 22 May 2023 17:29:17 +0800 Subject: [PATCH 024/153] =?UTF-8?q?=E9=AA=8C=E8=AF=81=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=E5=8F=AF=E8=BF=9E=E6=8E=A5=E6=80=A7(=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89ssh)=E4=BD=BF=E7=94=A8=E7=9A=84key=E5=80=BC=E9=94=99?= =?UTF-8?q?=E8=AF=AF=20(#10523)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/automations/verify_account/custom/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/accounts/automations/verify_account/custom/main.yml b/apps/accounts/automations/verify_account/custom/main.yml index 6ad8cd98b..cf4a937a7 100644 --- a/apps/accounts/automations/verify_account/custom/main.yml +++ b/apps/accounts/automations/verify_account/custom/main.yml @@ -10,5 +10,5 @@ login_port: "{{ jms_asset.port }}" login_user: "{{ account.username }}" login_password: "{{ account.secret }}" - login_secret_type: "{{ jms_account.secret_type }}" - login_private_key_path: "{{ jms_account.private_key_path }}" + login_secret_type: "{{ account.secret_type }}" + login_private_key_path: "{{ account.private_key_path }}" From feb42961ef2b12cf73deab50c953eb19f0bbeefb Mon Sep 17 00:00:00 2001 From: Bai Date: Mon, 22 May 2023 18:25:42 +0800 Subject: [PATCH 025/153] =?UTF-8?q?feat:=20=E8=B5=84=E4=BA=A7=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E6=90=9C=E7=B4=A2=E6=94=AF=E6=8C=81=20comment=20?= =?UTF-8?q?=E6=A8=A1=E7=B3=8A=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/asset/asset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/assets/api/asset/asset.py b/apps/assets/api/asset/asset.py index 3f0b21f19..0dbc1fc53 100644 --- a/apps/assets/api/asset/asset.py +++ b/apps/assets/api/asset/asset.py @@ -95,7 +95,7 @@ class AssetViewSet(SuggestionMixin, NodeFilterMixin, OrgBulkModelViewSet): """ model = Asset filterset_class = AssetFilterSet - search_fields = ("name", "address") + search_fields = ("name", "address", "comment") ordering_fields = ('name', 'connectivity', 'platform', 'date_updated') serializer_classes = ( ("default", serializers.AssetSerializer), From 20c1f4a293b5db8a8aede0800534206882c38e5a Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Fri, 19 May 2023 16:09:32 +0800 Subject: [PATCH 026/153] =?UTF-8?q?perf:=20=E6=94=B9=E5=AF=86=E8=BF=87?= =?UTF-8?q?=E7=A8=8B=E5=8E=9F=E5=AD=90=E6=80=A7=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../change_secret/host/aix/main.yml | 1 + .../change_secret/host/posix/main.yml | 1 + .../change_secret/host/windows/main.yml | 1 + .../push_account/host/aix/main.yml | 1 + .../push_account/host/posix/main.yml | 1 + .../push_account/host/windows/main.yml | 1 + apps/ops/ansible/callback.py | 39 ++++++++++++------- 7 files changed, 30 insertions(+), 15 deletions(-) diff --git a/apps/accounts/automations/change_secret/host/aix/main.yml b/apps/accounts/automations/change_secret/host/aix/main.yml index 4bb571f62..b51ddf69e 100644 --- a/apps/accounts/automations/change_secret/host/aix/main.yml +++ b/apps/accounts/automations/change_secret/host/aix/main.yml @@ -9,6 +9,7 @@ name: "{{ account.username }}" password: "{{ account.secret | password_hash('des') }}" update_password: always + ignore_errors: true when: account.secret_type == "password" - name: create user If it already exists, no operation will be performed diff --git a/apps/accounts/automations/change_secret/host/posix/main.yml b/apps/accounts/automations/change_secret/host/posix/main.yml index 8dea25c12..80f0aa01c 100644 --- a/apps/accounts/automations/change_secret/host/posix/main.yml +++ b/apps/accounts/automations/change_secret/host/posix/main.yml @@ -9,6 +9,7 @@ name: "{{ account.username }}" password: "{{ account.secret | password_hash('sha512') }}" update_password: always + ignore_errors: true when: account.secret_type == "password" - name: create user If it already exists, no operation will be performed diff --git a/apps/accounts/automations/change_secret/host/windows/main.yml b/apps/accounts/automations/change_secret/host/windows/main.yml index 66efb0801..86ea7a81f 100644 --- a/apps/accounts/automations/change_secret/host/windows/main.yml +++ b/apps/accounts/automations/change_secret/host/windows/main.yml @@ -21,6 +21,7 @@ groups: "{{ user_info.groups[0].name }}" groups_action: add update_password: always + ignore_errors: true when: account.secret_type == "password" - name: Refresh connection diff --git a/apps/accounts/automations/push_account/host/aix/main.yml b/apps/accounts/automations/push_account/host/aix/main.yml index 9ac68d20e..7c43c5220 100644 --- a/apps/accounts/automations/push_account/host/aix/main.yml +++ b/apps/accounts/automations/push_account/host/aix/main.yml @@ -43,6 +43,7 @@ name: "{{ account.username }}" password: "{{ account.secret | password_hash('sha512') }}" update_password: always + ignore_errors: true when: account.secret_type == "password" - name: remove jumpserver ssh key diff --git a/apps/accounts/automations/push_account/host/posix/main.yml b/apps/accounts/automations/push_account/host/posix/main.yml index 9ac68d20e..7c43c5220 100644 --- a/apps/accounts/automations/push_account/host/posix/main.yml +++ b/apps/accounts/automations/push_account/host/posix/main.yml @@ -43,6 +43,7 @@ name: "{{ account.username }}" password: "{{ account.secret | password_hash('sha512') }}" update_password: always + ignore_errors: true when: account.secret_type == "password" - name: remove jumpserver ssh key diff --git a/apps/accounts/automations/push_account/host/windows/main.yml b/apps/accounts/automations/push_account/host/windows/main.yml index 8a2a0aef0..17f68b660 100644 --- a/apps/accounts/automations/push_account/host/windows/main.yml +++ b/apps/accounts/automations/push_account/host/windows/main.yml @@ -17,6 +17,7 @@ groups: "{{ params.groups }}" groups_action: add update_password: always + ignore_errors: true when: account.secret_type == "password" - name: Refresh connection diff --git a/apps/ops/ansible/callback.py b/apps/ops/ansible/callback.py index 4bcb9be60..2045b6f29 100644 --- a/apps/ops/ansible/callback.py +++ b/apps/ops/ansible/callback.py @@ -1,4 +1,5 @@ from collections import defaultdict +from functools import reduce class DefaultCallback: @@ -18,6 +19,7 @@ class DefaultCallback: failures=defaultdict(dict), dark=defaultdict(dict), skipped=defaultdict(dict), + ignored=defaultdict(dict), ) self.summary = dict( ok=[], @@ -59,6 +61,14 @@ class DefaultCallback: } self.result['ok'][host][task] = detail + def runner_on_skipped(self, event_data, host=None, task=None, **kwargs): + detail = { + 'action': event_data.get('task_action', ''), + 'res': {}, + 'rc': 0, + } + self.result['skipped'][host][task] = detail + def runner_on_failed(self, event_data, host=None, task=None, res=None, **kwargs): detail = { 'action': event_data.get('task_action', ''), @@ -67,15 +77,9 @@ class DefaultCallback: 'stdout': res.get('stdout', ''), 'stderr': ';'.join([res.get('stderr', ''), res.get('msg', '')]).strip(';') } - self.result['failures'][host][task] = detail - - def runner_on_skipped(self, event_data, host=None, task=None, **kwargs): - detail = { - 'action': event_data.get('task_action', ''), - 'res': {}, - 'rc': 0, - } - self.result['skipped'][host][task] = detail + ignore_errors = event_data.get('ignore_errors', False) + error_key = 'ignored' if ignore_errors else 'failures' + self.result[error_key][host][task] = detail def runner_on_unreachable(self, event_data, host=None, task=None, res=None, **kwargs): detail = { @@ -106,13 +110,18 @@ class DefaultCallback: def playbook_on_stats(self, event_data, **kwargs): failed = [] - for i in ['dark', 'failures']: - for host, tasks in self.result[i].items(): + error_func = lambda err, task_detail: err + f"{task_detail[0]}: {task_detail[1]['stderr']};" + for tp in ['dark', 'failures']: + for host, tasks in self.result[tp].items(): failed.append(host) - error = '' - for task, detail in tasks.items(): - error += f'{task}: {detail["stderr"]};' - self.summary[i][host] = error.strip(';') + error = reduce(error_func, tasks.items(), '').strip(';') + self.summary[tp][host] = error + + for host, tasks in self.result.get('ignored', {}).items(): + ignore_errors = reduce(error_func, tasks.items(), '').strip(';') + if host in failed: + self.summary['failures'][host] += {ignore_errors} + self.summary['ok'] = list(set(self.result['ok'].keys()) - set(failed)) self.summary['skipped'] = list(set(self.result['skipped'].keys()) - set(failed)) From 440cd13fcc74081971d2ca3cb705669df0b65b01 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 24 May 2023 14:24:15 +0800 Subject: [PATCH 027/153] =?UTF-8?q?perf:=20=E5=90=8C=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=8D=8F=E4=BD=9C=E4=BC=9A=E8=AF=9D=E9=93=BE=E6=8E=A5=EF=BC=8C?= =?UTF-8?q?=E9=99=90=E5=88=B6=E5=90=8C=E4=B8=80=E7=94=A8=E6=88=B7=E4=BB=85?= =?UTF-8?q?=E5=8F=AF=E4=BD=BF=E7=94=A8=E4=B8=80=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/session/sharing.py | 6 +++--- apps/terminal/models/session/sharing.py | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/terminal/api/session/sharing.py b/apps/terminal/api/session/sharing.py index a3d324205..9a60734fa 100644 --- a/apps/terminal/api/session/sharing.py +++ b/apps/terminal/api/session/sharing.py @@ -1,8 +1,8 @@ -from rest_framework.exceptions import MethodNotAllowed, ValidationError -from rest_framework.decorators import action -from rest_framework.response import Response from django.conf import settings from django.utils.translation import ugettext_lazy as _ +from rest_framework.decorators import action +from rest_framework.exceptions import MethodNotAllowed, ValidationError +from rest_framework.response import Response from common.const.http import PATCH from orgs.mixins.api import OrgModelViewSet diff --git a/apps/terminal/models/session/sharing.py b/apps/terminal/models/session/sharing.py index a62e23a85..c0e83dfda 100644 --- a/apps/terminal/models/session/sharing.py +++ b/apps/terminal/models/session/sharing.py @@ -133,6 +133,13 @@ class SessionJoinRecord(JMSBaseModel, OrgModelMixin): # self if self.verify_code != self.sharing.verify_code: return False, _('Invalid verification code') + + # Link can only be joined once by the same user. + queryset = SessionJoinRecord.objects.filter( + verify_code=self.verify_code, sharing=self.sharing, + joiner=self.joiner, date_joined__lt=self.date_joined) + if queryset.exists(): + return False, _('You have already joined this session') return True, '' def join_failed(self, reason): From 653b996d846f79c9d5ff310289126f65e4c431be Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 24 May 2023 17:35:14 +0800 Subject: [PATCH 028/153] =?UTF-8?q?perf:=20=E8=B4=A6=E5=8F=B7=E6=8E=A8?= =?UTF-8?q?=E9=80=81=E6=94=AF=E6=8C=81=E8=AE=BE=E7=BD=AE=E6=8E=A8=E9=80=81?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E7=9A=84=20home=20=E7=9B=AE=E5=BD=95=20(#105?= =?UTF-8?q?41)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- .../automations/push_account/host/aix/main.yml | 16 +--------------- .../push_account/host/aix/manifest.yml | 6 ++++++ .../automations/push_account/host/posix/main.yml | 16 +--------------- .../push_account/host/posix/manifest.yml | 6 ++++++ 4 files changed, 14 insertions(+), 30 deletions(-) diff --git a/apps/accounts/automations/push_account/host/aix/main.yml b/apps/accounts/automations/push_account/host/aix/main.yml index 7c43c5220..2dc10fdc2 100644 --- a/apps/accounts/automations/push_account/host/aix/main.yml +++ b/apps/accounts/automations/push_account/host/aix/main.yml @@ -8,7 +8,7 @@ ansible.builtin.user: name: "{{ account.username }}" shell: "{{ params.shell }}" - home: "{{ '/home/' + account.username }}" + home: "{{ params.home | default('/home/' + account.username, true) }}" groups: "{{ params.groups }}" expires: -1 state: present @@ -18,20 +18,6 @@ name: "{{ account.username }}" state: present - - name: Check home dir exists - ansible.builtin.stat: - path: "{{ '/home/' + account.username }}" - register: home_existed - - - name: Set home dir permission - ansible.builtin.file: - path: "{{ '/home/' + account.username }}" - owner: "{{ account.username }}" - group: "{{ account.username }}" - mode: "0700" - when: - - home_existed.stat.exists == true - - name: Add user groups ansible.builtin.user: name: "{{ account.username }}" diff --git a/apps/accounts/automations/push_account/host/aix/manifest.yml b/apps/accounts/automations/push_account/host/aix/manifest.yml index 78a44a4e9..5421d24d8 100644 --- a/apps/accounts/automations/push_account/host/aix/manifest.yml +++ b/apps/accounts/automations/push_account/host/aix/manifest.yml @@ -16,6 +16,12 @@ params: label: 'Shell' default: '/bin/bash' + - name: home + type: str + label: '家目录' + default: '' + help_text: '默认家目录 /home/系统用户名: /home/username' + - name: groups type: str label: '用户组' diff --git a/apps/accounts/automations/push_account/host/posix/main.yml b/apps/accounts/automations/push_account/host/posix/main.yml index 7c43c5220..2dc10fdc2 100644 --- a/apps/accounts/automations/push_account/host/posix/main.yml +++ b/apps/accounts/automations/push_account/host/posix/main.yml @@ -8,7 +8,7 @@ ansible.builtin.user: name: "{{ account.username }}" shell: "{{ params.shell }}" - home: "{{ '/home/' + account.username }}" + home: "{{ params.home | default('/home/' + account.username, true) }}" groups: "{{ params.groups }}" expires: -1 state: present @@ -18,20 +18,6 @@ name: "{{ account.username }}" state: present - - name: Check home dir exists - ansible.builtin.stat: - path: "{{ '/home/' + account.username }}" - register: home_existed - - - name: Set home dir permission - ansible.builtin.file: - path: "{{ '/home/' + account.username }}" - owner: "{{ account.username }}" - group: "{{ account.username }}" - mode: "0700" - when: - - home_existed.stat.exists == true - - name: Add user groups ansible.builtin.user: name: "{{ account.username }}" diff --git a/apps/accounts/automations/push_account/host/posix/manifest.yml b/apps/accounts/automations/push_account/host/posix/manifest.yml index efeb11b93..1da168a44 100644 --- a/apps/accounts/automations/push_account/host/posix/manifest.yml +++ b/apps/accounts/automations/push_account/host/posix/manifest.yml @@ -18,6 +18,12 @@ params: default: '/bin/bash' help_text: '' + - name: home + type: str + label: '家目录' + default: '' + help_text: '默认家目录 /home/系统用户名: /home/username' + - name: groups type: str label: '用户组' From cabdc3ad426577378d70f7bb07c963228087a153 Mon Sep 17 00:00:00 2001 From: Bai Date: Wed, 24 May 2023 17:30:30 +0800 Subject: [PATCH 029/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=BB=88?= =?UTF-8?q?=E7=AB=AF=E7=AB=AF=E7=82=B9=E4=BD=BF=E7=94=A8=E8=B5=84=E4=BA=A7?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E5=8C=B9=E9=85=8D=E6=9C=BA=E5=88=B6=E6=97=B6?= =?UTF-8?q?=20500=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/models/component/endpoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/terminal/models/component/endpoint.py b/apps/terminal/models/component/endpoint.py index 8699eb898..c5aab12d9 100644 --- a/apps/terminal/models/component/endpoint.py +++ b/apps/terminal/models/component/endpoint.py @@ -82,7 +82,7 @@ class Endpoint(JMSBaseModel): return None endpoints = cls.objects.filter(name__in=values).order_by('-date_updated') for endpoint in endpoints: - if endpoint.is_valid_for(protocol): + if endpoint.is_valid_for(instance, protocol): return endpoint From 32a8e150da9bf5b6ecbe5ab3acc9afcaaa55fa88 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 25 May 2023 11:38:20 +0800 Subject: [PATCH 030/153] =?UTF-8?q?perf:=20=E5=88=A0=E9=99=A4=E5=85=A8?= =?UTF-8?q?=E9=83=A8=E7=94=A8=E6=88=B7=E9=94=99=E8=AF=AF=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=20(#10546)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 384 ++++++++++++++------------- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 384 ++++++++++++++------------- apps/users/api/user.py | 9 +- apps/users/exceptions.py | 6 +- 6 files changed, 422 insertions(+), 369 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 04807dc75..2d93e8efc 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:523a93e9703e62c39440d2e172c96fea7d8d04965cab43095fc8a378d157bf59 -size 141798 +oid sha256:fc0862f2a9091f2e06602d6db26cfc9cc7a6b067012ec56b41ebc1e26d5072e9 +size 142045 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 722d482d8..fdec83625 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-16 18:32+0800\n" +"POT-Creation-Date: 2023-05-25 11:30+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -49,7 +49,7 @@ msgstr "アクセスキー" msgid "Token" msgstr "トークン" -#: accounts/const/account.py:13 common/db/fields.py:236 +#: accounts/const/account.py:13 common/db/fields.py:244 #: settings/serializers/terminal.py:14 msgid "All" msgstr "すべて" @@ -62,7 +62,7 @@ msgstr "手動入力" msgid "Dynamic user" msgstr "動的コード" -#: accounts/const/account.py:19 users/models/user.py:673 +#: accounts/const/account.py:19 users/models/user.py:699 msgid "Local" msgstr "ローカル" @@ -181,16 +181,15 @@ msgstr "作成のみ" #: accounts/models/account.py:49 #: accounts/models/automations/gather_account.py:16 -#: accounts/serializers/account/account.py:201 -#: accounts/serializers/account/account.py:234 +#: accounts/serializers/account/account.py:203 +#: accounts/serializers/account/account.py:236 #: accounts/serializers/account/gathered_account.py:10 #: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:132 -#: acls/models/base.py:100 acls/serializers/base.py:76 -#: assets/models/asset/common.py:92 assets/models/asset/common.py:306 -#: assets/models/cmd_filter.py:36 assets/serializers/domain.py:19 -#: assets/serializers/label.py:27 audits/models.py:48 -#: authentication/models/connection_token.py:34 +#: acls/serializers/base.py:76 assets/models/asset/common.py:93 +#: assets/models/asset/common.py:332 assets/models/cmd_filter.py:36 +#: assets/serializers/domain.py:19 assets/serializers/label.py:27 +#: audits/models.py:48 authentication/models/connection_token.py:34 #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 @@ -199,8 +198,8 @@ msgid "Asset" msgstr "資産" #: accounts/models/account.py:53 accounts/models/account.py:113 -#: accounts/serializers/account/account.py:206 -#: accounts/serializers/account/account.py:244 +#: accounts/serializers/account/account.py:208 +#: accounts/serializers/account/account.py:246 #: accounts/serializers/account/template.py:16 #: authentication/serializers/connect_token_secret.py:49 msgid "Su from" @@ -211,8 +210,8 @@ msgstr "から切り替え" msgid "Version" msgstr "バージョン" -#: accounts/models/account.py:57 accounts/serializers/account/account.py:202 -#: users/models/user.py:778 +#: accounts/models/account.py:57 accounts/serializers/account/account.py:204 +#: users/models/user.py:804 msgid "Source" msgstr "ソース" @@ -222,10 +221,9 @@ msgstr "ソース ID" #: accounts/models/account.py:61 #: accounts/serializers/automations/change_secret.py:113 -#: accounts/serializers/automations/change_secret.py:133 -#: acls/models/base.py:102 acls/serializers/base.py:77 -#: assets/serializers/asset/common.py:125 assets/serializers/gateway.py:28 -#: audits/models.py:49 ops/models/base.py:18 +#: accounts/serializers/automations/change_secret.py:133 acls/models/base.py:59 +#: acls/serializers/base.py:77 assets/serializers/asset/common.py:125 +#: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: terminal/backends/command/models.py:21 terminal/models/session/session.py:34 #: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 @@ -358,7 +356,7 @@ msgid "Can add push account execution" msgstr "プッシュ アカウントの作成の実行" #: accounts/models/automations/change_secret.py:18 accounts/models/base.py:36 -#: accounts/serializers/account/account.py:412 +#: accounts/serializers/account/account.py:416 #: accounts/serializers/account/base.py:16 #: accounts/serializers/automations/change_secret.py:46 #: authentication/serializers/connect_token_secret.py:41 @@ -408,7 +406,7 @@ msgid "Date finished" msgstr "終了日" #: accounts/models/automations/change_secret.py:93 -#: accounts/serializers/account/account.py:236 assets/const/automation.py:8 +#: accounts/serializers/account/account.py:238 assets/const/automation.py:8 #: authentication/views/base.py:29 authentication/views/base.py:30 #: authentication/views/base.py:31 common/const/choices.py:20 msgid "Error" @@ -434,7 +432,7 @@ msgstr "最終ログイン日" #: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_oauth_bind.html:9 #: users/forms/profile.py:32 users/forms/profile.py:112 -#: users/models/user.py:725 users/templates/users/_msg_user_created.html:12 +#: users/models/user.py:751 users/templates/users/_msg_user_created.html:12 #: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" msgstr "ユーザー名" @@ -460,7 +458,7 @@ msgstr "アカウントのコレクション" msgid "Triggers" msgstr "トリガー方式" -#: accounts/models/automations/push_account.py:16 acls/models/base.py:81 +#: accounts/models/automations/push_account.py:16 acls/models/base.py:41 #: acls/serializers/base.py:57 assets/models/cmd_filter.py:81 #: audits/models.py:65 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:108 @@ -476,15 +474,15 @@ msgstr "アカウントプッシュ" msgid "Verify asset account" msgstr "アカウントの確認" -#: accounts/models/base.py:33 acls/models/base.py:75 +#: accounts/models/base.py:33 acls/models/base.py:35 #: acls/models/command_acl.py:21 acls/serializers/base.py:35 #: applications/models.py:9 assets/models/_user.py:22 -#: assets/models/asset/common.py:90 assets/models/asset/common.py:123 +#: assets/models/asset/common.py:91 assets/models/asset/common.py:149 #: assets/models/cmd_filter.py:21 assets/models/domain.py:18 #: assets/models/group.py:20 assets/models/label.py:18 #: assets/models/platform.py:13 assets/models/platform.py:81 #: assets/serializers/asset/common.py:145 assets/serializers/platform.py:92 -#: assets/serializers/platform.py:194 +#: assets/serializers/platform.py:192 #: authentication/serializers/connect_token_secret.py:102 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 @@ -494,7 +492,7 @@ msgstr "アカウントの確認" #: terminal/models/component/endpoint.py:90 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:15 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33 -#: users/models/group.py:13 users/models/user.py:727 +#: users/models/group.py:13 users/models/user.py:753 #: xpack/plugins/cloud/models.py:28 msgid "Name" msgstr "名前" @@ -503,11 +501,11 @@ msgstr "名前" msgid "Privileged" msgstr "特権アカウント" -#: accounts/models/base.py:40 assets/models/asset/common.py:130 +#: accounts/models/base.py:40 assets/models/asset/common.py:156 #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:106 -#: terminal/models/applet/applet.py:32 users/serializers/user.py:169 +#: terminal/models/applet/applet.py:32 users/serializers/user.py:170 msgid "Is active" msgstr "アクティブです。" @@ -560,16 +558,16 @@ msgstr "今すぐプッシュ" msgid "Exist policy" msgstr "アカウントの存在ポリシー" -#: accounts/serializers/account/account.py:181 applications/models.py:11 +#: accounts/serializers/account/account.py:183 applications/models.py:11 #: assets/models/label.py:21 assets/models/platform.py:82 #: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8 -#: assets/serializers/platform.py:110 assets/serializers/platform.py:195 +#: assets/serializers/platform.py:110 assets/serializers/platform.py:193 #: perms/serializers/user_permission.py:26 settings/models.py:35 #: tickets/models/ticket/apply_application.py:13 msgid "Category" msgstr "カテゴリ" -#: accounts/serializers/account/account.py:182 +#: accounts/serializers/account/account.py:184 #: accounts/serializers/automations/base.py:54 acls/models/command_acl.py:24 #: acls/serializers/command_acl.py:18 applications/models.py:14 #: assets/models/_user.py:50 assets/models/automations/base.py:20 @@ -588,28 +586,28 @@ msgstr "カテゴリ" msgid "Type" msgstr "タイプ" -#: accounts/serializers/account/account.py:197 +#: accounts/serializers/account/account.py:199 msgid "Asset not found" msgstr "資産が存在しません" -#: accounts/serializers/account/account.py:203 +#: accounts/serializers/account/account.py:205 #: accounts/serializers/account/base.py:64 msgid "Has secret" msgstr "エスクローされたパスワード" -#: accounts/serializers/account/account.py:235 ops/models/celery.py:60 +#: accounts/serializers/account/account.py:237 ops/models/celery.py:60 #: tickets/models/comment.py:13 tickets/models/ticket/general.py:45 #: tickets/models/ticket/general.py:279 tickets/serializers/super_ticket.py:14 #: tickets/serializers/ticket/ticket.py:21 msgid "State" msgstr "状態" -#: accounts/serializers/account/account.py:237 +#: accounts/serializers/account/account.py:239 msgid "Changed" msgstr "編集済み" -#: accounts/serializers/account/account.py:246 -#: accounts/serializers/automations/base.py:22 +#: accounts/serializers/account/account.py:249 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:58 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -617,31 +615,31 @@ msgstr "編集済み" msgid "Assets" msgstr "資産" -#: accounts/serializers/account/account.py:298 +#: accounts/serializers/account/account.py:301 msgid "Account already exists" msgstr "アカウントはすでに存在しています" -#: accounts/serializers/account/account.py:348 +#: accounts/serializers/account/account.py:351 #, python-format msgid "Asset does not support this secret type: %s" msgstr "アセットはアカウント タイプをサポートしていません: %s" -#: accounts/serializers/account/account.py:379 +#: accounts/serializers/account/account.py:383 msgid "Account has exist" msgstr "アカウントはすでに存在しています" -#: accounts/serializers/account/account.py:413 +#: accounts/serializers/account/account.py:417 #: authentication/serializers/connect_token_secret.py:146 #: authentication/templates/authentication/_access_key_modal.html:30 #: perms/models/perm_node.py:21 users/serializers/group.py:33 msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:420 acls/models/base.py:98 -#: acls/models/login_acl.py:13 acls/serializers/base.py:75 -#: acls/serializers/login_acl.py:21 assets/models/cmd_filter.py:24 -#: assets/models/label.py:16 audits/models.py:44 audits/models.py:63 -#: audits/models.py:141 authentication/models/connection_token.py:30 +#: accounts/serializers/account/account.py:424 acls/models/login_acl.py:13 +#: acls/serializers/base.py:75 acls/serializers/login_acl.py:21 +#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:44 +#: audits/models.py:63 audits/models.py:141 +#: authentication/models/connection_token.py:30 #: authentication/models/sso_token.py:16 #: notifications/models/notification.py:12 #: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:58 @@ -650,12 +648,12 @@ msgstr "ID" #: terminal/models/session/session.py:30 terminal/models/session/sharing.py:32 #: terminal/notifications.py:96 terminal/notifications.py:144 #: terminal/serializers/command.py:16 tickets/models/comment.py:21 -#: users/const.py:14 users/models/user.py:921 users/models/user.py:952 +#: users/const.py:14 users/models/user.py:947 users/models/user.py:978 #: users/serializers/group.py:18 msgid "User" msgstr "ユーザー" -#: accounts/serializers/account/account.py:421 +#: accounts/serializers/account/account.py:425 #: authentication/templates/authentication/_access_key_modal.html:33 #: terminal/notifications.py:98 terminal/notifications.py:146 msgid "Date" @@ -696,7 +694,7 @@ msgid "Tip: If no username is required for authentication, fill in `null`" msgstr "ヒント: 認証にユーザー名が必要ない場合は、null を入力してください" #: accounts/serializers/automations/base.py:23 -#: assets/models/asset/common.py:129 assets/models/automations/base.py:18 +#: assets/models/asset/common.py:155 assets/models/automations/base.py:18 #: assets/models/cmd_filter.py:32 assets/serializers/automations/base.py:21 #: perms/models/asset_permission.py:67 msgid "Nodes" @@ -781,36 +779,36 @@ msgstr "秘密鍵が無効またはpassphraseエラー" msgid "Acls" msgstr "Acls" -#: acls/models/base.py:20 tickets/const.py:45 +#: acls/models/base.py:15 tickets/const.py:45 #: tickets/templates/tickets/approve_check_password.html:49 msgid "Reject" msgstr "拒否" -#: acls/models/base.py:21 +#: acls/models/base.py:16 msgid "Accept" msgstr "受け入れられる" -#: acls/models/base.py:22 +#: acls/models/base.py:17 msgid "Review" msgstr "レビュー担当者" -#: acls/models/base.py:77 assets/models/_user.py:51 +#: acls/models/base.py:37 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:93 msgid "Priority" msgstr "優先順位" -#: acls/models/base.py:78 assets/models/_user.py:51 +#: acls/models/base.py:38 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:94 msgid "1-100, the lower the value will be match first" msgstr "1-100、低い値は最初に一致します" -#: acls/models/base.py:82 acls/serializers/base.py:95 +#: acls/models/base.py:42 acls/serializers/base.py:79 #: acls/serializers/login_acl.py:23 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:80 msgid "Reviewers" msgstr "レビュー担当者" -#: acls/models/base.py:83 authentication/models/access_key.py:17 +#: acls/models/base.py:43 authentication/models/access_key.py:17 #: authentication/models/connection_token.py:50 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 @@ -818,6 +816,10 @@ msgstr "レビュー担当者" msgid "Active" msgstr "アクティブ" +#: acls/models/base.py:57 users/apps.py:9 +msgid "Users" +msgstr "ユーザー" + #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 #: ops/serializers/job.py:55 terminal/const.py:68 #: terminal/models/session/session.py:43 terminal/serializers/command.py:18 @@ -873,11 +875,11 @@ msgstr "ログインacl" msgid "Login confirm" msgstr "ログイン確認" -#: acls/models/login_asset_acl.py:10 +#: acls/models/login_asset_acl.py:8 msgid "Login asset acl" msgstr "ログインasset acl" -#: acls/models/login_asset_acl.py:20 tickets/const.py:12 +#: acls/models/login_asset_acl.py:18 tickets/const.py:12 msgid "Login asset confirm" msgstr "ログイン資産の確認" @@ -899,31 +901,15 @@ msgstr "" msgid "IP/Host" msgstr "IP/ホスト" -#: acls/serializers/base.py:80 -msgid "User (username)" -msgstr "ユーザー (ユーザー名)" - -#: acls/serializers/base.py:84 -msgid "Asset (name)" -msgstr "資産(名前)" - -#: acls/serializers/base.py:88 -msgid "Asset (address)" -msgstr "資産(住所)" - -#: acls/serializers/base.py:92 -msgid "Account (username)" -msgstr "アカウント (ユーザー名)" - -#: acls/serializers/base.py:98 acls/serializers/login_acl.py:26 +#: acls/serializers/base.py:82 acls/serializers/login_acl.py:26 msgid "Reviewers amount" msgstr "承認者数" -#: acls/serializers/base.py:126 tickets/serializers/ticket/ticket.py:76 +#: acls/serializers/base.py:108 tickets/serializers/ticket/ticket.py:76 msgid "The organization `{}` does not exist" msgstr "組織 '{}'は存在しません" -#: acls/serializers/base.py:132 +#: acls/serializers/base.py:114 msgid "None of the reviewers belong to Organization `{}`" msgstr "いずれのレビューアも組織 '{}' に属していません" @@ -973,7 +959,7 @@ msgstr "アプリケーション" msgid "Can match application" msgstr "アプリケーションを一致させることができます" -#: assets/api/asset/asset.py:140 +#: assets/api/asset/asset.py:143 msgid "Cannot create asset directly, you should create a host or other" msgstr "" "資産を直接作成することはできません。ホストまたはその他を作成する必要がありま" @@ -1029,7 +1015,7 @@ msgstr "接続に失敗しました" #: assets/const/automation.py:6 audits/const.py:6 audits/const.py:35 #: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31 -#: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:86 +#: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104 msgid "Unknown" msgstr "不明" @@ -1147,32 +1133,32 @@ msgstr "SSHパブリックキー" #: assets/models/_user.py:27 assets/models/cmd_filter.py:40 #: assets/models/cmd_filter.py:88 assets/models/group.py:23 -#: common/db/models.py:37 ops/models/adhoc.py:27 ops/models/job.py:111 +#: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 #: terminal/models/applet/applet.py:37 terminal/models/applet/applet.py:218 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 -#: tickets/models/ticket/general.py:297 users/models/user.py:766 +#: tickets/models/ticket/general.py:297 users/models/user.py:792 #: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:111 msgid "Comment" msgstr "コメント" #: assets/models/_user.py:28 assets/models/automations/base.py:114 #: assets/models/cmd_filter.py:41 assets/models/group.py:22 -#: common/db/models.py:35 ops/models/base.py:54 ops/models/job.py:191 -#: users/models/user.py:953 +#: common/db/models.py:34 ops/models/base.py:54 ops/models/job.py:191 +#: users/models/user.py:979 msgid "Date created" msgstr "作成された日付" #: assets/models/_user.py:29 assets/models/cmd_filter.py:42 -#: common/db/models.py:36 users/models/user.py:787 +#: common/db/models.py:35 users/models/user.py:813 msgid "Date updated" msgstr "更新日" #: assets/models/_user.py:30 assets/models/cmd_filter.py:44 #: assets/models/cmd_filter.py:91 assets/models/group.py:21 -#: common/db/models.py:33 users/models/user.py:773 +#: common/db/models.py:32 users/models/user.py:799 #: users/serializers/group.py:31 msgid "Created by" msgstr "によって作成された" @@ -1252,55 +1238,55 @@ msgstr "システムユーザーに一致できます" msgid "Cloud" msgstr "クラウド サービス" -#: assets/models/asset/common.py:91 assets/models/platform.py:14 +#: assets/models/asset/common.py:92 assets/models/platform.py:14 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "ポート" -#: assets/models/asset/common.py:124 assets/serializers/asset/common.py:146 +#: assets/models/asset/common.py:150 assets/serializers/asset/common.py:146 msgid "Address" msgstr "アドレス" -#: assets/models/asset/common.py:125 assets/models/platform.py:112 +#: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:107 #: perms/serializers/user_permission.py:24 #: xpack/plugins/cloud/serializers/account_attrs.py:196 msgid "Platform" msgstr "プラットフォーム" -#: assets/models/asset/common.py:127 assets/models/domain.py:21 +#: assets/models/asset/common.py:153 assets/models/domain.py:21 #: authentication/serializers/connect_token_secret.py:125 #: perms/serializers/user_permission.py:29 msgid "Domain" msgstr "ドメイン" -#: assets/models/asset/common.py:131 +#: assets/models/asset/common.py:157 msgid "Labels" msgstr "ラベル" -#: assets/models/asset/common.py:132 assets/serializers/asset/common.py:307 +#: assets/models/asset/common.py:158 assets/serializers/asset/common.py:307 #: assets/serializers/asset/host.py:11 msgid "Gathered info" msgstr "資産ハードウェア情報の収集" -#: assets/models/asset/common.py:133 assets/serializers/asset/custom.py:14 +#: assets/models/asset/common.py:159 assets/serializers/asset/custom.py:14 msgid "Custom info" msgstr "自动化信息" -#: assets/models/asset/common.py:309 +#: assets/models/asset/common.py:335 msgid "Can refresh asset hardware info" msgstr "資産ハードウェア情報を更新できます" -#: assets/models/asset/common.py:310 +#: assets/models/asset/common.py:336 msgid "Can test asset connectivity" msgstr "資産接続をテストできます" -#: assets/models/asset/common.py:311 +#: assets/models/asset/common.py:337 msgid "Can match asset" msgstr "アセットを一致させることができます" -#: assets/models/asset/common.py:312 +#: assets/models/asset/common.py:338 msgid "Can change asset nodes" msgstr "資産ノードを変更できます" @@ -1391,7 +1377,7 @@ msgstr "確認済みの日付" #: assets/models/cmd_filter.py:28 perms/models/asset_permission.py:61 #: perms/serializers/permission.py:32 users/models/group.py:25 -#: users/models/user.py:733 +#: users/models/user.py:759 msgid "User group" msgstr "ユーザーグループ" @@ -1441,11 +1427,11 @@ msgstr "デフォルト" msgid "Default asset group" msgstr "デフォルトアセットグループ" -#: assets/models/label.py:15 rbac/const.py:6 users/models/user.py:938 +#: assets/models/label.py:15 rbac/const.py:6 users/models/user.py:964 msgid "System" msgstr "システム" -#: assets/models/label.py:19 assets/models/node.py:544 +#: assets/models/label.py:19 assets/models/node.py:557 #: assets/serializers/cagegory.py:7 assets/serializers/cagegory.py:14 #: authentication/models/connection_token.py:27 #: authentication/serializers/connect_token_secret.py:114 @@ -1462,32 +1448,32 @@ msgstr "値" msgid "Label" msgstr "ラベル" -#: assets/models/node.py:153 +#: assets/models/node.py:166 msgid "New node" msgstr "新しいノード" -#: assets/models/node.py:472 audits/backends/db.py:55 audits/backends/db.py:56 +#: assets/models/node.py:485 audits/backends/db.py:55 audits/backends/db.py:56 msgid "empty" msgstr "空" -#: assets/models/node.py:543 perms/models/perm_node.py:28 +#: assets/models/node.py:556 perms/models/perm_node.py:28 msgid "Key" msgstr "キー" -#: assets/models/node.py:545 assets/serializers/node.py:20 +#: assets/models/node.py:558 assets/serializers/node.py:20 msgid "Full value" msgstr "フルバリュー" -#: assets/models/node.py:549 perms/models/perm_node.py:30 +#: assets/models/node.py:562 perms/models/perm_node.py:30 msgid "Parent key" msgstr "親キー" -#: assets/models/node.py:558 perms/serializers/permission.py:35 +#: assets/models/node.py:571 perms/serializers/permission.py:35 #: tickets/models/ticket/apply_asset.py:14 xpack/plugins/cloud/models.py:96 msgid "Node" msgstr "ノード" -#: assets/models/node.py:561 +#: assets/models/node.py:574 msgid "Can match node" msgstr "ノードを一致させることができます" @@ -1655,7 +1641,7 @@ msgstr "プロトコルが必要です: {}" msgid "Default database" msgstr "デフォルトのストレージ" -#: assets/serializers/asset/database.py:28 common/serializers/fields.py:103 +#: assets/serializers/asset/database.py:28 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -1781,7 +1767,7 @@ msgstr "デフォルト ドメイン" msgid "type is required" msgstr "タイプ このフィールドは必須です." -#: assets/serializers/platform.py:183 +#: assets/serializers/platform.py:169 msgid "Protocols is required" msgstr "同意が必要です" @@ -1946,11 +1932,11 @@ msgstr "タスク" msgid "-" msgstr "-" -#: audits/handler.py:115 +#: audits/handler.py:114 msgid "Yes" msgstr "是" -#: audits/handler.py:115 +#: audits/handler.py:114 msgid "No" msgstr "否" @@ -2033,7 +2019,7 @@ msgstr "ユーザーエージェント" #: audits/models.py:169 audits/serializers.py:47 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 -#: users/forms/profile.py:65 users/models/user.py:750 +#: users/forms/profile.py:65 users/models/user.py:776 #: users/serializers/profile.py:126 msgid "MFA" msgstr "MFA" @@ -2089,22 +2075,22 @@ msgstr "認証トークン" #: audits/signal_handlers/login_log.py:31 authentication/notifications.py:73 #: authentication/views/login.py:74 authentication/views/wecom.py:159 #: notifications/backends/__init__.py:11 settings/serializers/auth/wecom.py:10 -#: users/models/user.py:680 users/models/user.py:788 +#: users/models/user.py:706 users/models/user.py:814 msgid "WeCom" msgstr "企業微信" #: audits/signal_handlers/login_log.py:32 authentication/views/feishu.py:123 #: authentication/views/login.py:86 notifications/backends/__init__.py:14 #: settings/serializers/auth/feishu.py:10 -#: settings/serializers/auth/feishu.py:13 users/models/user.py:682 -#: users/models/user.py:790 +#: settings/serializers/auth/feishu.py:13 users/models/user.py:708 +#: users/models/user.py:816 msgid "FeiShu" msgstr "本を飛ばす" #: audits/signal_handlers/login_log.py:33 authentication/views/dingtalk.py:160 #: authentication/views/login.py:80 notifications/backends/__init__.py:12 -#: settings/serializers/auth/dingtalk.py:10 users/models/user.py:681 -#: users/models/user.py:789 +#: settings/serializers/auth/dingtalk.py:10 users/models/user.py:707 +#: users/models/user.py:815 msgid "DingTalk" msgstr "DingTalk" @@ -2121,19 +2107,19 @@ msgstr "監査セッション タスク ログのクリーンアップ" msgid "This action require verify your MFA" msgstr "この操作には、MFAを検証する必要があります" -#: authentication/api/connection_token.py:303 +#: authentication/api/connection_token.py:305 msgid "Account not found" msgstr "アカウントが見つかりません" -#: authentication/api/connection_token.py:306 +#: authentication/api/connection_token.py:308 msgid "Permission expired" msgstr "承認の有効期限が切れています" -#: authentication/api/connection_token.py:318 +#: authentication/api/connection_token.py:320 msgid "ACL action is reject" msgstr "ACL アクションは拒否です" -#: authentication/api/connection_token.py:322 +#: authentication/api/connection_token.py:324 msgid "ACL action is review" msgstr "ACL アクションはレビューです" @@ -2172,7 +2158,7 @@ msgid "Authentication" msgstr "認証" #: authentication/backends/custom.py:58 -#: authentication/backends/oauth2/backends.py:167 +#: authentication/backends/oauth2/backends.py:170 msgid "User invalid, disabled or expired" msgstr "ユーザーが無効、無効、または期限切れです" @@ -2387,15 +2373,15 @@ msgstr "本を飛ばすは拘束されていません" msgid "Your password is invalid" msgstr "パスワードが無効です" -#: authentication/errors/redirect.py:85 authentication/mixins.py:316 +#: authentication/errors/redirect.py:85 authentication/mixins.py:318 msgid "Your password is too simple, please change it for security" msgstr "パスワードがシンプルすぎるので、セキュリティのために変更してください" -#: authentication/errors/redirect.py:93 authentication/mixins.py:323 +#: authentication/errors/redirect.py:93 authentication/mixins.py:325 msgid "You should to change your password before login" msgstr "ログインする前にパスワードを変更する必要があります" -#: authentication/errors/redirect.py:101 authentication/mixins.py:330 +#: authentication/errors/redirect.py:101 authentication/mixins.py:332 msgid "Your password has expired, please reset before logging in" msgstr "" "パスワードの有効期限が切れました。ログインする前にリセットしてください。" @@ -2506,11 +2492,11 @@ msgstr "" "管理者は「ユーザーソースからのみログインを許可」をオンにしており、現在のユー" "ザーソースは {} です。管理者に連絡してください。" -#: authentication/mixins.py:266 +#: authentication/mixins.py:268 msgid "The MFA type ({}) is not enabled" msgstr "MFAタイプ ({}) が有効になっていない" -#: authentication/mixins.py:306 +#: authentication/mixins.py:308 msgid "Please change your password" msgstr "パスワードを変更してください" @@ -2550,7 +2536,7 @@ msgstr "無効化" #: authentication/models/connection_token.py:44 #: authentication/models/temp_token.py:13 perms/models/asset_permission.py:74 #: tickets/models/ticket/apply_application.py:31 -#: tickets/models/ticket/apply_asset.py:20 users/models/user.py:771 +#: tickets/models/ticket/apply_asset.py:20 users/models/user.py:797 msgid "Date expired" msgstr "期限切れの日付" @@ -2583,7 +2569,7 @@ msgstr "ユーザーなしまたは期限切れのユーザー" msgid "No asset or inactive asset" msgstr "アセットがないか、有効化されていないアセット" -#: authentication/models/connection_token.py:261 +#: authentication/models/connection_token.py:262 msgid "Super connection token" msgstr "スーパー接続トークン" @@ -2637,15 +2623,15 @@ msgstr "作業指示情報" #: authentication/serializers/connection_token.py:23 #: perms/models/asset_permission.py:71 perms/serializers/permission.py:36 -#: perms/serializers/permission.py:69 +#: perms/serializers/permission.py:56 #: tickets/models/ticket/apply_application.py:28 #: tickets/models/ticket/apply_asset.py:18 msgid "Actions" msgstr "アクション" #: authentication/serializers/connection_token.py:44 -#: perms/serializers/permission.py:38 perms/serializers/permission.py:70 -#: users/serializers/user.py:97 users/serializers/user.py:172 +#: perms/serializers/permission.py:38 perms/serializers/permission.py:57 +#: users/serializers/user.py:97 users/serializers/user.py:173 msgid "Is expired" msgstr "期限切れです" @@ -2657,7 +2643,7 @@ msgstr "" #: authentication/serializers/password_mfa.py:24 #: notifications/backends/__init__.py:10 settings/serializers/email.py:19 #: settings/serializers/email.py:50 users/forms/profile.py:102 -#: users/forms/profile.py:106 users/models/user.py:729 +#: users/forms/profile.py:106 users/models/user.py:755 #: users/templates/users/forgot_password.html:116 #: users/views/profile/reset.py:73 msgid "Email" @@ -2669,8 +2655,8 @@ msgid "The {} cannot be empty" msgstr "{} 空にしてはならない" #: authentication/serializers/token.py:79 perms/serializers/permission.py:37 -#: perms/serializers/permission.py:71 users/serializers/user.py:98 -#: users/serializers/user.py:170 +#: perms/serializers/permission.py:58 users/serializers/user.py:98 +#: users/serializers/user.py:171 msgid "Is valid" msgstr "有効です" @@ -3077,34 +3063,57 @@ msgstr "%(name)s は正常に更新されました" msgid "ugettext_lazy" msgstr "ugettext_lazy" -#: common/db/fields.py:98 +#: common/db/fields.py:106 msgid "Marshal dict data to char field" msgstr "チャーフィールドへのマーシャルディクトデータ" -#: common/db/fields.py:102 +#: common/db/fields.py:110 msgid "Marshal dict data to text field" msgstr "テキストフィールドへのマーシャルディクトデータ" -#: common/db/fields.py:114 +#: common/db/fields.py:122 msgid "Marshal list data to char field" msgstr "元帥リストデータをチャーフィールドに" -#: common/db/fields.py:118 +#: common/db/fields.py:126 msgid "Marshal list data to text field" msgstr "マーシャルリストデータをテキストフィールドに" -#: common/db/fields.py:122 +#: common/db/fields.py:130 msgid "Marshal data to char field" msgstr "チャーフィールドへのマーシャルデータ" -#: common/db/fields.py:126 +#: common/db/fields.py:134 msgid "Marshal data to text field" msgstr "テキストフィールドへのマーシャルデータ" -#: common/db/fields.py:168 +#: common/db/fields.py:176 msgid "Encrypt field using Secret Key" msgstr "Secret Keyを使用したフィールドの暗号化" +#: common/db/fields.py:534 +msgid "" +"Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " +"{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " +"'match': 'exact', 'value': '1.1.1.1'}}" +msgstr "" + +#: common/db/fields.py:541 +msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" +msgstr "無効なタイプです。all、ids、またはattrsでなければなりません" + +#: common/db/fields.py:544 +msgid "Invalid ids for ids, should be a list" +msgstr "無効なID、リストでなければなりません" + +#: common/db/fields.py:547 common/db/fields.py:550 +msgid "Invalid attrs, should be a list of dict" +msgstr "無効な属性、dictリストでなければなりません" + +#: common/db/fields.py:552 +msgid "Invalid attrs, should be has name and value" +msgstr "名前と値が必要な無効な属性" + #: common/db/mixins.py:32 msgid "is discard" msgstr "は破棄されます" @@ -3113,7 +3122,7 @@ msgstr "は破棄されます" msgid "discard time" msgstr "時間を捨てる" -#: common/db/models.py:34 users/models/user.py:774 +#: common/db/models.py:33 users/models/user.py:800 msgid "Updated by" msgstr "によって更新" @@ -3141,7 +3150,7 @@ msgstr "解析ファイルエラー: {}" msgid "Invalid excel file" msgstr "無効 excel 書類" -#: common/drf/renders/base.py:209 +#: common/drf/renders/base.py:206 msgid "" "{} - The encryption password has not been set - please go to personal " "information -> file encryption password to set the encryption password" @@ -3250,21 +3259,21 @@ msgstr "" msgid "File" msgstr "書類" -#: common/serializers/fields.py:104 +#: common/serializers/fields.py:105 #, python-brace-format msgid "Invalid pk \"{pk_value}\" - object does not exist." msgstr "無効な pk \"{pk_value}\" - オブジェクトが存在しません" -#: common/serializers/fields.py:105 +#: common/serializers/fields.py:106 #, python-brace-format msgid "Incorrect type. Expected pk value, received {data_type}." msgstr "エラータイプ。 予想される pk 値、受信 {data_type}。" -#: common/serializers/fields.py:179 +#: common/serializers/fields.py:180 msgid "Invalid data type, should be list" msgstr "間違ったデータ タイプです。リストにする必要があります" -#: common/serializers/fields.py:194 +#: common/serializers/fields.py:195 msgid "Invalid choice: {}" msgstr "無効なオプション: {}" @@ -3280,7 +3289,7 @@ msgstr "メールの添付ファイルを送信" msgid "Invalid ip" msgstr "無効な IP" -#: common/utils/ip/utils.py:80 +#: common/utils/ip/utils.py:98 msgid "Invalid address" msgstr "無効なアドレス。" @@ -3973,7 +3982,7 @@ msgid "Scope" msgstr "スコープ" #: rbac/models/role.py:46 rbac/models/rolebinding.py:52 -#: users/models/user.py:737 +#: users/models/user.py:763 msgid "Role" msgstr "ロール" @@ -5899,6 +5908,10 @@ msgstr "セッション参加記録" msgid "Invalid verification code" msgstr "検証コードが無効" +#: terminal/models/session/sharing.py:142 +msgid "You have already joined this session" +msgstr "" + #: terminal/notifications.py:21 msgid "Sessions" msgstr "セッション" @@ -6509,14 +6522,10 @@ msgstr "無効な承認アクション" msgid "This user is not authorized to approve this ticket" msgstr "このユーザーはこの作業指示を承認する権限がありません" -#: users/api/user.py:185 +#: users/api/user.py:191 msgid "Could not reset self otp, use profile reset instead" msgstr "自己otpをリセットできませんでした、代わりにプロファイルリセットを使用" -#: users/apps.py:9 -msgid "Users" -msgstr "ユーザー" - #: users/const.py:10 msgid "System administrator" msgstr "システム管理者" @@ -6546,8 +6555,8 @@ msgid "MFA not enabled" msgstr "MFAが有効化されていません" #: users/exceptions.py:20 -msgid "MFA method not support" -msgstr "MFAメソッドはサポートしていません" +msgid "Unable to delete all users" +msgstr "すべてのユーザーを削除できません" #: users/forms/profile.py:50 msgid "" @@ -6620,7 +6629,7 @@ msgstr "公開鍵は古いものと同じであってはなりません。" msgid "Not a valid ssh public key" msgstr "有効なssh公開鍵ではありません" -#: users/forms/profile.py:170 users/models/user.py:760 +#: users/forms/profile.py:170 users/models/user.py:786 msgid "Public key" msgstr "公開キー" @@ -6628,68 +6637,68 @@ msgstr "公開キー" msgid "Force enable" msgstr "強制有効" -#: users/models/user.py:739 users/serializers/user.py:171 +#: users/models/user.py:765 users/serializers/user.py:172 msgid "Is service account" msgstr "サービスアカウントです" -#: users/models/user.py:741 +#: users/models/user.py:767 msgid "Avatar" msgstr "アバター" -#: users/models/user.py:744 +#: users/models/user.py:770 msgid "Wechat" msgstr "微信" -#: users/models/user.py:747 users/serializers/user.py:109 +#: users/models/user.py:773 users/serializers/user.py:109 msgid "Phone" msgstr "電話" -#: users/models/user.py:753 +#: users/models/user.py:779 msgid "OTP secret key" msgstr "OTP 秘密" -#: users/models/user.py:757 +#: users/models/user.py:783 msgid "Private key" msgstr "ssh秘密鍵" -#: users/models/user.py:763 +#: users/models/user.py:789 msgid "Secret key" msgstr "秘密キー" -#: users/models/user.py:768 users/serializers/profile.py:149 -#: users/serializers/user.py:168 +#: users/models/user.py:794 users/serializers/profile.py:149 +#: users/serializers/user.py:169 msgid "Is first login" msgstr "最初のログインです" -#: users/models/user.py:782 +#: users/models/user.py:808 msgid "Date password last updated" msgstr "最終更新日パスワード" -#: users/models/user.py:785 +#: users/models/user.py:811 msgid "Need update password" msgstr "更新パスワードが必要" -#: users/models/user.py:923 +#: users/models/user.py:949 msgid "Can invite user" msgstr "ユーザーを招待できます" -#: users/models/user.py:924 +#: users/models/user.py:950 msgid "Can remove user" msgstr "ユーザーを削除できます" -#: users/models/user.py:925 +#: users/models/user.py:951 msgid "Can match user" msgstr "ユーザーに一致できます" -#: users/models/user.py:934 +#: users/models/user.py:960 msgid "Administrator" msgstr "管理者" -#: users/models/user.py:937 +#: users/models/user.py:963 msgid "Administrator is the super user of system" msgstr "管理者はシステムのスーパーユーザーです" -#: users/models/user.py:962 +#: users/models/user.py:988 msgid "User password history" msgstr "ユーザーパスワード履歴" @@ -6764,7 +6773,7 @@ msgstr "MFAフォース有効化" msgid "Login blocked" msgstr "ログインがロックされました" -#: users/serializers/user.py:99 users/serializers/user.py:176 +#: users/serializers/user.py:99 users/serializers/user.py:177 msgid "Is OTP bound" msgstr "仮想MFAがバインドされているか" @@ -6772,23 +6781,23 @@ msgstr "仮想MFAがバインドされているか" msgid "Can public key authentication" msgstr "公開鍵認証が可能" -#: users/serializers/user.py:173 +#: users/serializers/user.py:174 msgid "Avatar url" msgstr "アバターURL" -#: users/serializers/user.py:177 +#: users/serializers/user.py:178 msgid "MFA level" msgstr "MFA レベル" -#: users/serializers/user.py:283 +#: users/serializers/user.py:284 msgid "Select users" msgstr "ユーザーの選択" -#: users/serializers/user.py:284 +#: users/serializers/user.py:285 msgid "For security, only list several users" msgstr "セキュリティのために、複数のユーザーのみをリストします" -#: users/serializers/user.py:317 +#: users/serializers/user.py:318 msgid "name not unique" msgstr "名前が一意ではない" @@ -7644,6 +7653,21 @@ msgstr "究極のエディション" msgid "Community edition" msgstr "コミュニティ版" +#~ msgid "User (username)" +#~ msgstr "ユーザー (ユーザー名)" + +#~ msgid "Asset (name)" +#~ msgstr "資産(名前)" + +#~ msgid "Asset (address)" +#~ msgstr "資産(住所)" + +#~ msgid "Account (username)" +#~ msgstr "アカウント (ユーザー名)" + +#~ msgid "MFA method not support" +#~ msgstr "MFAメソッドはサポートしていません" + #, fuzzy #~| msgid "Trigger mode" #~ msgid "Trigger type" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index ac7231fc1..b986dcb5b 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bd60ca8b6c43b9b5940b14a8ca8073ae26062a5402f663ac39043cbc669199bd -size 116040 +oid sha256:1fabd2ec950291422c14b66af097bd73cce52bbc4b7913c1b9ea732eee855901 +size 116210 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 91582121a..f71c1b831 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-16 18:32+0800\n" +"POT-Creation-Date: 2023-05-25 11:30+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -48,7 +48,7 @@ msgstr "Access key" msgid "Token" msgstr "Token" -#: accounts/const/account.py:13 common/db/fields.py:236 +#: accounts/const/account.py:13 common/db/fields.py:244 #: settings/serializers/terminal.py:14 msgid "All" msgstr "全部" @@ -61,7 +61,7 @@ msgstr "手动输入" msgid "Dynamic user" msgstr "同名账号" -#: accounts/const/account.py:19 users/models/user.py:673 +#: accounts/const/account.py:19 users/models/user.py:699 msgid "Local" msgstr "数据库" @@ -180,16 +180,15 @@ msgstr "仅创建" #: accounts/models/account.py:49 #: accounts/models/automations/gather_account.py:16 -#: accounts/serializers/account/account.py:201 -#: accounts/serializers/account/account.py:234 +#: accounts/serializers/account/account.py:203 +#: accounts/serializers/account/account.py:236 #: accounts/serializers/account/gathered_account.py:10 #: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:132 -#: acls/models/base.py:100 acls/serializers/base.py:76 -#: assets/models/asset/common.py:92 assets/models/asset/common.py:306 -#: assets/models/cmd_filter.py:36 assets/serializers/domain.py:19 -#: assets/serializers/label.py:27 audits/models.py:48 -#: authentication/models/connection_token.py:34 +#: acls/serializers/base.py:76 assets/models/asset/common.py:93 +#: assets/models/asset/common.py:332 assets/models/cmd_filter.py:36 +#: assets/serializers/domain.py:19 assets/serializers/label.py:27 +#: audits/models.py:48 authentication/models/connection_token.py:34 #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 @@ -198,8 +197,8 @@ msgid "Asset" msgstr "资产" #: accounts/models/account.py:53 accounts/models/account.py:113 -#: accounts/serializers/account/account.py:206 -#: accounts/serializers/account/account.py:244 +#: accounts/serializers/account/account.py:208 +#: accounts/serializers/account/account.py:246 #: accounts/serializers/account/template.py:16 #: authentication/serializers/connect_token_secret.py:49 msgid "Su from" @@ -210,8 +209,8 @@ msgstr "切换自" msgid "Version" msgstr "版本" -#: accounts/models/account.py:57 accounts/serializers/account/account.py:202 -#: users/models/user.py:778 +#: accounts/models/account.py:57 accounts/serializers/account/account.py:204 +#: users/models/user.py:804 msgid "Source" msgstr "来源" @@ -221,10 +220,9 @@ msgstr "来源 ID" #: accounts/models/account.py:61 #: accounts/serializers/automations/change_secret.py:113 -#: accounts/serializers/automations/change_secret.py:133 -#: acls/models/base.py:102 acls/serializers/base.py:77 -#: assets/serializers/asset/common.py:125 assets/serializers/gateway.py:28 -#: audits/models.py:49 ops/models/base.py:18 +#: accounts/serializers/automations/change_secret.py:133 acls/models/base.py:59 +#: acls/serializers/base.py:77 assets/serializers/asset/common.py:125 +#: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: terminal/backends/command/models.py:21 terminal/models/session/session.py:34 #: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 @@ -357,7 +355,7 @@ msgid "Can add push account execution" msgstr "创建推送账号执行" #: accounts/models/automations/change_secret.py:18 accounts/models/base.py:36 -#: accounts/serializers/account/account.py:412 +#: accounts/serializers/account/account.py:416 #: accounts/serializers/account/base.py:16 #: accounts/serializers/automations/change_secret.py:46 #: authentication/serializers/connect_token_secret.py:41 @@ -407,7 +405,7 @@ msgid "Date finished" msgstr "结束日期" #: accounts/models/automations/change_secret.py:93 -#: accounts/serializers/account/account.py:236 assets/const/automation.py:8 +#: accounts/serializers/account/account.py:238 assets/const/automation.py:8 #: authentication/views/base.py:29 authentication/views/base.py:30 #: authentication/views/base.py:31 common/const/choices.py:20 msgid "Error" @@ -433,7 +431,7 @@ msgstr "最后登录日期" #: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_oauth_bind.html:9 #: users/forms/profile.py:32 users/forms/profile.py:112 -#: users/models/user.py:725 users/templates/users/_msg_user_created.html:12 +#: users/models/user.py:751 users/templates/users/_msg_user_created.html:12 #: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" msgstr "用户名" @@ -459,7 +457,7 @@ msgstr "收集账号" msgid "Triggers" msgstr "触发方式" -#: accounts/models/automations/push_account.py:16 acls/models/base.py:81 +#: accounts/models/automations/push_account.py:16 acls/models/base.py:41 #: acls/serializers/base.py:57 assets/models/cmd_filter.py:81 #: audits/models.py:65 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:108 @@ -475,15 +473,15 @@ msgstr "账号推送" msgid "Verify asset account" msgstr "账号验证" -#: accounts/models/base.py:33 acls/models/base.py:75 +#: accounts/models/base.py:33 acls/models/base.py:35 #: acls/models/command_acl.py:21 acls/serializers/base.py:35 #: applications/models.py:9 assets/models/_user.py:22 -#: assets/models/asset/common.py:90 assets/models/asset/common.py:123 +#: assets/models/asset/common.py:91 assets/models/asset/common.py:149 #: assets/models/cmd_filter.py:21 assets/models/domain.py:18 #: assets/models/group.py:20 assets/models/label.py:18 #: assets/models/platform.py:13 assets/models/platform.py:81 #: assets/serializers/asset/common.py:145 assets/serializers/platform.py:92 -#: assets/serializers/platform.py:194 +#: assets/serializers/platform.py:192 #: authentication/serializers/connect_token_secret.py:102 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 @@ -493,7 +491,7 @@ msgstr "账号验证" #: terminal/models/component/endpoint.py:90 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:15 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33 -#: users/models/group.py:13 users/models/user.py:727 +#: users/models/group.py:13 users/models/user.py:753 #: xpack/plugins/cloud/models.py:28 msgid "Name" msgstr "名称" @@ -502,11 +500,11 @@ msgstr "名称" msgid "Privileged" msgstr "特权账号" -#: accounts/models/base.py:40 assets/models/asset/common.py:130 +#: accounts/models/base.py:40 assets/models/asset/common.py:156 #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:106 -#: terminal/models/applet/applet.py:32 users/serializers/user.py:169 +#: terminal/models/applet/applet.py:32 users/serializers/user.py:170 msgid "Is active" msgstr "激活" @@ -556,16 +554,16 @@ msgstr "立即推送" msgid "Exist policy" msgstr "账号存在策略" -#: accounts/serializers/account/account.py:181 applications/models.py:11 +#: accounts/serializers/account/account.py:183 applications/models.py:11 #: assets/models/label.py:21 assets/models/platform.py:82 #: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8 -#: assets/serializers/platform.py:110 assets/serializers/platform.py:195 +#: assets/serializers/platform.py:110 assets/serializers/platform.py:193 #: perms/serializers/user_permission.py:26 settings/models.py:35 #: tickets/models/ticket/apply_application.py:13 msgid "Category" msgstr "类别" -#: accounts/serializers/account/account.py:182 +#: accounts/serializers/account/account.py:184 #: accounts/serializers/automations/base.py:54 acls/models/command_acl.py:24 #: acls/serializers/command_acl.py:18 applications/models.py:14 #: assets/models/_user.py:50 assets/models/automations/base.py:20 @@ -584,28 +582,28 @@ msgstr "类别" msgid "Type" msgstr "类型" -#: accounts/serializers/account/account.py:197 +#: accounts/serializers/account/account.py:199 msgid "Asset not found" msgstr "资产不存在" -#: accounts/serializers/account/account.py:203 +#: accounts/serializers/account/account.py:205 #: accounts/serializers/account/base.py:64 msgid "Has secret" msgstr "已托管密码" -#: accounts/serializers/account/account.py:235 ops/models/celery.py:60 +#: accounts/serializers/account/account.py:237 ops/models/celery.py:60 #: tickets/models/comment.py:13 tickets/models/ticket/general.py:45 #: tickets/models/ticket/general.py:279 tickets/serializers/super_ticket.py:14 #: tickets/serializers/ticket/ticket.py:21 msgid "State" msgstr "状态" -#: accounts/serializers/account/account.py:237 +#: accounts/serializers/account/account.py:239 msgid "Changed" msgstr "已修改" -#: accounts/serializers/account/account.py:246 -#: accounts/serializers/automations/base.py:22 +#: accounts/serializers/account/account.py:249 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:58 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -613,31 +611,31 @@ msgstr "已修改" msgid "Assets" msgstr "资产" -#: accounts/serializers/account/account.py:298 +#: accounts/serializers/account/account.py:301 msgid "Account already exists" msgstr "账号已存在" -#: accounts/serializers/account/account.py:348 +#: accounts/serializers/account/account.py:351 #, python-format msgid "Asset does not support this secret type: %s" msgstr "资产不支持账号类型: %s" -#: accounts/serializers/account/account.py:379 +#: accounts/serializers/account/account.py:383 msgid "Account has exist" msgstr "账号已存在" -#: accounts/serializers/account/account.py:413 +#: accounts/serializers/account/account.py:417 #: authentication/serializers/connect_token_secret.py:146 #: authentication/templates/authentication/_access_key_modal.html:30 #: perms/models/perm_node.py:21 users/serializers/group.py:33 msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:420 acls/models/base.py:98 -#: acls/models/login_acl.py:13 acls/serializers/base.py:75 -#: acls/serializers/login_acl.py:21 assets/models/cmd_filter.py:24 -#: assets/models/label.py:16 audits/models.py:44 audits/models.py:63 -#: audits/models.py:141 authentication/models/connection_token.py:30 +#: accounts/serializers/account/account.py:424 acls/models/login_acl.py:13 +#: acls/serializers/base.py:75 acls/serializers/login_acl.py:21 +#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:44 +#: audits/models.py:63 audits/models.py:141 +#: authentication/models/connection_token.py:30 #: authentication/models/sso_token.py:16 #: notifications/models/notification.py:12 #: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:58 @@ -646,12 +644,12 @@ msgstr "ID" #: terminal/models/session/session.py:30 terminal/models/session/sharing.py:32 #: terminal/notifications.py:96 terminal/notifications.py:144 #: terminal/serializers/command.py:16 tickets/models/comment.py:21 -#: users/const.py:14 users/models/user.py:921 users/models/user.py:952 +#: users/const.py:14 users/models/user.py:947 users/models/user.py:978 #: users/serializers/group.py:18 msgid "User" msgstr "用户" -#: accounts/serializers/account/account.py:421 +#: accounts/serializers/account/account.py:425 #: authentication/templates/authentication/_access_key_modal.html:33 #: terminal/notifications.py:98 terminal/notifications.py:146 msgid "Date" @@ -692,7 +690,7 @@ msgid "Tip: If no username is required for authentication, fill in `null`" msgstr "提示: 如果认证时不需要用户名,则填写为 null" #: accounts/serializers/automations/base.py:23 -#: assets/models/asset/common.py:129 assets/models/automations/base.py:18 +#: assets/models/asset/common.py:155 assets/models/automations/base.py:18 #: assets/models/cmd_filter.py:32 assets/serializers/automations/base.py:21 #: perms/models/asset_permission.py:67 msgid "Nodes" @@ -777,36 +775,36 @@ msgstr "密钥不合法或密钥密码错误" msgid "Acls" msgstr "访问控制" -#: acls/models/base.py:20 tickets/const.py:45 +#: acls/models/base.py:15 tickets/const.py:45 #: tickets/templates/tickets/approve_check_password.html:49 msgid "Reject" msgstr "拒绝" -#: acls/models/base.py:21 +#: acls/models/base.py:16 msgid "Accept" msgstr "接受" -#: acls/models/base.py:22 +#: acls/models/base.py:17 msgid "Review" msgstr "审批" -#: acls/models/base.py:77 assets/models/_user.py:51 +#: acls/models/base.py:37 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:93 msgid "Priority" msgstr "优先级" -#: acls/models/base.py:78 assets/models/_user.py:51 +#: acls/models/base.py:38 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:94 msgid "1-100, the lower the value will be match first" msgstr "优先级可选范围为 1-100 (数值越小越优先)" -#: acls/models/base.py:82 acls/serializers/base.py:95 +#: acls/models/base.py:42 acls/serializers/base.py:79 #: acls/serializers/login_acl.py:23 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:80 msgid "Reviewers" msgstr "审批人" -#: acls/models/base.py:83 authentication/models/access_key.py:17 +#: acls/models/base.py:43 authentication/models/access_key.py:17 #: authentication/models/connection_token.py:50 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 @@ -814,6 +812,10 @@ msgstr "审批人" msgid "Active" msgstr "激活中" +#: acls/models/base.py:57 users/apps.py:9 +msgid "Users" +msgstr "用户管理" + #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 #: ops/serializers/job.py:55 terminal/const.py:68 #: terminal/models/session/session.py:43 terminal/serializers/command.py:18 @@ -869,11 +871,11 @@ msgstr "登录访问控制" msgid "Login confirm" msgstr "登录复核" -#: acls/models/login_asset_acl.py:10 +#: acls/models/login_asset_acl.py:8 msgid "Login asset acl" msgstr "登录资产访问控制" -#: acls/models/login_asset_acl.py:20 tickets/const.py:12 +#: acls/models/login_asset_acl.py:18 tickets/const.py:12 msgid "Login asset confirm" msgstr "登录资产复核" @@ -894,31 +896,15 @@ msgstr "" msgid "IP/Host" msgstr "IP/主机" -#: acls/serializers/base.py:80 -msgid "User (username)" -msgstr "用户(用户名)" - -#: acls/serializers/base.py:84 -msgid "Asset (name)" -msgstr "资产(名称)" - -#: acls/serializers/base.py:88 -msgid "Asset (address)" -msgstr "资产(地址)" - -#: acls/serializers/base.py:92 -msgid "Account (username)" -msgstr "账号(用户名)" - -#: acls/serializers/base.py:98 acls/serializers/login_acl.py:26 +#: acls/serializers/base.py:82 acls/serializers/login_acl.py:26 msgid "Reviewers amount" msgstr "审批人数量" -#: acls/serializers/base.py:126 tickets/serializers/ticket/ticket.py:76 +#: acls/serializers/base.py:108 tickets/serializers/ticket/ticket.py:76 msgid "The organization `{}` does not exist" msgstr "组织 `{}` 不存在" -#: acls/serializers/base.py:132 +#: acls/serializers/base.py:114 msgid "None of the reviewers belong to Organization `{}`" msgstr "所有复核人都不属于组织 `{}`" @@ -968,7 +954,7 @@ msgstr "应用程序" msgid "Can match application" msgstr "匹配应用" -#: assets/api/asset/asset.py:140 +#: assets/api/asset/asset.py:143 msgid "Cannot create asset directly, you should create a host or other" msgstr "不能直接创建资产, 你应该创建主机或其他资产" @@ -1022,7 +1008,7 @@ msgstr "连接失败" #: assets/const/automation.py:6 audits/const.py:6 audits/const.py:35 #: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31 -#: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:86 +#: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104 msgid "Unknown" msgstr "未知" @@ -1140,32 +1126,32 @@ msgstr "SSH公钥" #: assets/models/_user.py:27 assets/models/cmd_filter.py:40 #: assets/models/cmd_filter.py:88 assets/models/group.py:23 -#: common/db/models.py:37 ops/models/adhoc.py:27 ops/models/job.py:111 +#: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 #: terminal/models/applet/applet.py:37 terminal/models/applet/applet.py:218 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 -#: tickets/models/ticket/general.py:297 users/models/user.py:766 +#: tickets/models/ticket/general.py:297 users/models/user.py:792 #: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:111 msgid "Comment" msgstr "备注" #: assets/models/_user.py:28 assets/models/automations/base.py:114 #: assets/models/cmd_filter.py:41 assets/models/group.py:22 -#: common/db/models.py:35 ops/models/base.py:54 ops/models/job.py:191 -#: users/models/user.py:953 +#: common/db/models.py:34 ops/models/base.py:54 ops/models/job.py:191 +#: users/models/user.py:979 msgid "Date created" msgstr "创建日期" #: assets/models/_user.py:29 assets/models/cmd_filter.py:42 -#: common/db/models.py:36 users/models/user.py:787 +#: common/db/models.py:35 users/models/user.py:813 msgid "Date updated" msgstr "更新日期" #: assets/models/_user.py:30 assets/models/cmd_filter.py:44 #: assets/models/cmd_filter.py:91 assets/models/group.py:21 -#: common/db/models.py:33 users/models/user.py:773 +#: common/db/models.py:32 users/models/user.py:799 #: users/serializers/group.py:31 msgid "Created by" msgstr "创建者" @@ -1245,55 +1231,55 @@ msgstr "可以匹配系统用户" msgid "Cloud" msgstr "云服务" -#: assets/models/asset/common.py:91 assets/models/platform.py:14 +#: assets/models/asset/common.py:92 assets/models/platform.py:14 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "端口" -#: assets/models/asset/common.py:124 assets/serializers/asset/common.py:146 +#: assets/models/asset/common.py:150 assets/serializers/asset/common.py:146 msgid "Address" msgstr "地址" -#: assets/models/asset/common.py:125 assets/models/platform.py:112 +#: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:107 #: perms/serializers/user_permission.py:24 #: xpack/plugins/cloud/serializers/account_attrs.py:196 msgid "Platform" msgstr "系统平台" -#: assets/models/asset/common.py:127 assets/models/domain.py:21 +#: assets/models/asset/common.py:153 assets/models/domain.py:21 #: authentication/serializers/connect_token_secret.py:125 #: perms/serializers/user_permission.py:29 msgid "Domain" msgstr "网域" -#: assets/models/asset/common.py:131 +#: assets/models/asset/common.py:157 msgid "Labels" msgstr "标签管理" -#: assets/models/asset/common.py:132 assets/serializers/asset/common.py:307 +#: assets/models/asset/common.py:158 assets/serializers/asset/common.py:307 #: assets/serializers/asset/host.py:11 msgid "Gathered info" msgstr "收集资产硬件信息" -#: assets/models/asset/common.py:133 assets/serializers/asset/custom.py:14 +#: assets/models/asset/common.py:159 assets/serializers/asset/custom.py:14 msgid "Custom info" msgstr "自动化信息" -#: assets/models/asset/common.py:309 +#: assets/models/asset/common.py:335 msgid "Can refresh asset hardware info" msgstr "可以更新资产硬件信息" -#: assets/models/asset/common.py:310 +#: assets/models/asset/common.py:336 msgid "Can test asset connectivity" msgstr "可以测试资产连接性" -#: assets/models/asset/common.py:311 +#: assets/models/asset/common.py:337 msgid "Can match asset" msgstr "可以匹配资产" -#: assets/models/asset/common.py:312 +#: assets/models/asset/common.py:338 msgid "Can change asset nodes" msgstr "可以修改资产节点" @@ -1384,7 +1370,7 @@ msgstr "校验日期" #: assets/models/cmd_filter.py:28 perms/models/asset_permission.py:61 #: perms/serializers/permission.py:32 users/models/group.py:25 -#: users/models/user.py:733 +#: users/models/user.py:759 msgid "User group" msgstr "用户组" @@ -1434,11 +1420,11 @@ msgstr "默认" msgid "Default asset group" msgstr "默认资产组" -#: assets/models/label.py:15 rbac/const.py:6 users/models/user.py:938 +#: assets/models/label.py:15 rbac/const.py:6 users/models/user.py:964 msgid "System" msgstr "系统" -#: assets/models/label.py:19 assets/models/node.py:544 +#: assets/models/label.py:19 assets/models/node.py:557 #: assets/serializers/cagegory.py:7 assets/serializers/cagegory.py:14 #: authentication/models/connection_token.py:27 #: authentication/serializers/connect_token_secret.py:114 @@ -1455,32 +1441,32 @@ msgstr "值" msgid "Label" msgstr "标签" -#: assets/models/node.py:153 +#: assets/models/node.py:166 msgid "New node" msgstr "新节点" -#: assets/models/node.py:472 audits/backends/db.py:55 audits/backends/db.py:56 +#: assets/models/node.py:485 audits/backends/db.py:55 audits/backends/db.py:56 msgid "empty" msgstr "空" -#: assets/models/node.py:543 perms/models/perm_node.py:28 +#: assets/models/node.py:556 perms/models/perm_node.py:28 msgid "Key" msgstr "键" -#: assets/models/node.py:545 assets/serializers/node.py:20 +#: assets/models/node.py:558 assets/serializers/node.py:20 msgid "Full value" msgstr "全称" -#: assets/models/node.py:549 perms/models/perm_node.py:30 +#: assets/models/node.py:562 perms/models/perm_node.py:30 msgid "Parent key" msgstr "ssh私钥" -#: assets/models/node.py:558 perms/serializers/permission.py:35 +#: assets/models/node.py:571 perms/serializers/permission.py:35 #: tickets/models/ticket/apply_asset.py:14 xpack/plugins/cloud/models.py:96 msgid "Node" msgstr "节点" -#: assets/models/node.py:561 +#: assets/models/node.py:574 msgid "Can match node" msgstr "可以匹配节点" @@ -1646,7 +1632,7 @@ msgstr "协议是必填的: {}" msgid "Default database" msgstr "默认存储" -#: assets/serializers/asset/database.py:28 common/serializers/fields.py:103 +#: assets/serializers/asset/database.py:28 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -1772,7 +1758,7 @@ msgstr "默认网域" msgid "type is required" msgstr "类型 该字段是必填项。" -#: assets/serializers/platform.py:183 +#: assets/serializers/platform.py:169 msgid "Protocols is required" msgstr "协议是必填的" @@ -1935,11 +1921,11 @@ msgstr "任务" msgid "-" msgstr "-" -#: audits/handler.py:115 +#: audits/handler.py:114 msgid "Yes" msgstr "是" -#: audits/handler.py:115 +#: audits/handler.py:114 msgid "No" msgstr "否" @@ -2022,7 +2008,7 @@ msgstr "用户代理" #: audits/models.py:169 audits/serializers.py:47 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 -#: users/forms/profile.py:65 users/models/user.py:750 +#: users/forms/profile.py:65 users/models/user.py:776 #: users/serializers/profile.py:126 msgid "MFA" msgstr "MFA" @@ -2078,22 +2064,22 @@ msgstr "认证令牌" #: audits/signal_handlers/login_log.py:31 authentication/notifications.py:73 #: authentication/views/login.py:74 authentication/views/wecom.py:159 #: notifications/backends/__init__.py:11 settings/serializers/auth/wecom.py:10 -#: users/models/user.py:680 users/models/user.py:788 +#: users/models/user.py:706 users/models/user.py:814 msgid "WeCom" msgstr "企业微信" #: audits/signal_handlers/login_log.py:32 authentication/views/feishu.py:123 #: authentication/views/login.py:86 notifications/backends/__init__.py:14 #: settings/serializers/auth/feishu.py:10 -#: settings/serializers/auth/feishu.py:13 users/models/user.py:682 -#: users/models/user.py:790 +#: settings/serializers/auth/feishu.py:13 users/models/user.py:708 +#: users/models/user.py:816 msgid "FeiShu" msgstr "飞书" #: audits/signal_handlers/login_log.py:33 authentication/views/dingtalk.py:160 #: authentication/views/login.py:80 notifications/backends/__init__.py:12 -#: settings/serializers/auth/dingtalk.py:10 users/models/user.py:681 -#: users/models/user.py:789 +#: settings/serializers/auth/dingtalk.py:10 users/models/user.py:707 +#: users/models/user.py:815 msgid "DingTalk" msgstr "钉钉" @@ -2110,19 +2096,19 @@ msgstr "清理审计会话任务日志" msgid "This action require verify your MFA" msgstr "该操作需要验证您的 MFA, 请先开启并配置" -#: authentication/api/connection_token.py:303 +#: authentication/api/connection_token.py:305 msgid "Account not found" msgstr "账号未找到" -#: authentication/api/connection_token.py:306 +#: authentication/api/connection_token.py:308 msgid "Permission expired" msgstr "授权已过期" -#: authentication/api/connection_token.py:318 +#: authentication/api/connection_token.py:320 msgid "ACL action is reject" msgstr "ACL 动作是拒绝" -#: authentication/api/connection_token.py:322 +#: authentication/api/connection_token.py:324 msgid "ACL action is review" msgstr "ACL 动作是复核" @@ -2159,7 +2145,7 @@ msgid "Authentication" msgstr "认证" #: authentication/backends/custom.py:58 -#: authentication/backends/oauth2/backends.py:167 +#: authentication/backends/oauth2/backends.py:170 msgid "User invalid, disabled or expired" msgstr "用户无效,已禁用或已过期" @@ -2366,15 +2352,15 @@ msgstr "没有绑定飞书" msgid "Your password is invalid" msgstr "您的密码无效" -#: authentication/errors/redirect.py:85 authentication/mixins.py:316 +#: authentication/errors/redirect.py:85 authentication/mixins.py:318 msgid "Your password is too simple, please change it for security" msgstr "你的密码过于简单,为了安全,请修改" -#: authentication/errors/redirect.py:93 authentication/mixins.py:323 +#: authentication/errors/redirect.py:93 authentication/mixins.py:325 msgid "You should to change your password before login" msgstr "登录完成前,请先修改密码" -#: authentication/errors/redirect.py:101 authentication/mixins.py:330 +#: authentication/errors/redirect.py:101 authentication/mixins.py:332 msgid "Your password has expired, please reset before logging in" msgstr "您的密码已过期,先修改再登录" @@ -2481,11 +2467,11 @@ msgid "" " The current user source is {}. Please contact the administrator." msgstr "管理员已开启'仅允许从用户来源登录',当前用户来源为{},请联系管理员。" -#: authentication/mixins.py:266 +#: authentication/mixins.py:268 msgid "The MFA type ({}) is not enabled" msgstr "该 MFA ({}) 方式没有启用" -#: authentication/mixins.py:306 +#: authentication/mixins.py:308 msgid "Please change your password" msgstr "请修改密码" @@ -2525,7 +2511,7 @@ msgstr "禁用" #: authentication/models/connection_token.py:44 #: authentication/models/temp_token.py:13 perms/models/asset_permission.py:74 #: tickets/models/ticket/apply_application.py:31 -#: tickets/models/ticket/apply_asset.py:20 users/models/user.py:771 +#: tickets/models/ticket/apply_asset.py:20 users/models/user.py:797 msgid "Date expired" msgstr "失效日期" @@ -2558,7 +2544,7 @@ msgstr "没有用户或用户失效" msgid "No asset or inactive asset" msgstr "没有资产或资产未激活" -#: authentication/models/connection_token.py:261 +#: authentication/models/connection_token.py:262 msgid "Super connection token" msgstr "超级连接令牌" @@ -2612,15 +2598,15 @@ msgstr "工单信息" #: authentication/serializers/connection_token.py:23 #: perms/models/asset_permission.py:71 perms/serializers/permission.py:36 -#: perms/serializers/permission.py:69 +#: perms/serializers/permission.py:56 #: tickets/models/ticket/apply_application.py:28 #: tickets/models/ticket/apply_asset.py:18 msgid "Actions" msgstr "动作" #: authentication/serializers/connection_token.py:44 -#: perms/serializers/permission.py:38 perms/serializers/permission.py:70 -#: users/serializers/user.py:97 users/serializers/user.py:172 +#: perms/serializers/permission.py:38 perms/serializers/permission.py:57 +#: users/serializers/user.py:97 users/serializers/user.py:173 msgid "Is expired" msgstr "已过期" @@ -2632,7 +2618,7 @@ msgstr "" #: authentication/serializers/password_mfa.py:24 #: notifications/backends/__init__.py:10 settings/serializers/email.py:19 #: settings/serializers/email.py:50 users/forms/profile.py:102 -#: users/forms/profile.py:106 users/models/user.py:729 +#: users/forms/profile.py:106 users/models/user.py:755 #: users/templates/users/forgot_password.html:116 #: users/views/profile/reset.py:73 msgid "Email" @@ -2644,8 +2630,8 @@ msgid "The {} cannot be empty" msgstr "{} 不能为空" #: authentication/serializers/token.py:79 perms/serializers/permission.py:37 -#: perms/serializers/permission.py:71 users/serializers/user.py:98 -#: users/serializers/user.py:170 +#: perms/serializers/permission.py:58 users/serializers/user.py:98 +#: users/serializers/user.py:171 msgid "Is valid" msgstr "是否有效" @@ -3044,34 +3030,57 @@ msgstr "%(name)s 更新成功" msgid "ugettext_lazy" msgstr "ugettext_lazy" -#: common/db/fields.py:98 +#: common/db/fields.py:106 msgid "Marshal dict data to char field" msgstr "编码 dict 为 char" -#: common/db/fields.py:102 +#: common/db/fields.py:110 msgid "Marshal dict data to text field" msgstr "编码 dict 为 text" -#: common/db/fields.py:114 +#: common/db/fields.py:122 msgid "Marshal list data to char field" msgstr "编码 list 为 char" -#: common/db/fields.py:118 +#: common/db/fields.py:126 msgid "Marshal list data to text field" msgstr "编码 list 为 text" -#: common/db/fields.py:122 +#: common/db/fields.py:130 msgid "Marshal data to char field" msgstr "编码数据为 char" -#: common/db/fields.py:126 +#: common/db/fields.py:134 msgid "Marshal data to text field" msgstr "编码数据为 text" -#: common/db/fields.py:168 +#: common/db/fields.py:176 msgid "Encrypt field using Secret Key" msgstr "加密的字段" +#: common/db/fields.py:534 +msgid "" +"Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " +"{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " +"'match': 'exact', 'value': '1.1.1.1'}}" +msgstr "" + +#: common/db/fields.py:541 +msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" +msgstr "无效类型,应为 all、ids 或 attrs" + +#: common/db/fields.py:544 +msgid "Invalid ids for ids, should be a list" +msgstr "无效的ID,应为列表" + +#: common/db/fields.py:547 common/db/fields.py:550 +msgid "Invalid attrs, should be a list of dict" +msgstr "无效的属性,应为dict列表" + +#: common/db/fields.py:552 +msgid "Invalid attrs, should be has name and value" +msgstr "无效属性,应具有名称和值" + #: common/db/mixins.py:32 msgid "is discard" msgstr "忽略的" @@ -3080,7 +3089,7 @@ msgstr "忽略的" msgid "discard time" msgstr "忽略时间" -#: common/db/models.py:34 users/models/user.py:774 +#: common/db/models.py:33 users/models/user.py:800 msgid "Updated by" msgstr "最后更新者" @@ -3108,7 +3117,7 @@ msgstr "解析文件错误: {}" msgid "Invalid excel file" msgstr "无效的 excel 文件" -#: common/drf/renders/base.py:209 +#: common/drf/renders/base.py:206 msgid "" "{} - The encryption password has not been set - please go to personal " "information -> file encryption password to set the encryption password" @@ -3215,21 +3224,21 @@ msgstr "节点" msgid "File" msgstr "文件" -#: common/serializers/fields.py:104 +#: common/serializers/fields.py:105 #, python-brace-format msgid "Invalid pk \"{pk_value}\" - object does not exist." msgstr "错误的 pk \"{pk_value}\" - 对象不存在" -#: common/serializers/fields.py:105 +#: common/serializers/fields.py:106 #, python-brace-format msgid "Incorrect type. Expected pk value, received {data_type}." msgstr "错误类型。期望 pk 值,收到 {data_type}。" -#: common/serializers/fields.py:179 +#: common/serializers/fields.py:180 msgid "Invalid data type, should be list" msgstr "错误的数据类型,应该是列表" -#: common/serializers/fields.py:194 +#: common/serializers/fields.py:195 msgid "Invalid choice: {}" msgstr "无效选项: {}" @@ -3245,7 +3254,7 @@ msgstr "发送邮件附件" msgid "Invalid ip" msgstr "无效 IP" -#: common/utils/ip/utils.py:80 +#: common/utils/ip/utils.py:98 msgid "Invalid address" msgstr "无效地址" @@ -3932,7 +3941,7 @@ msgid "Scope" msgstr "范围" #: rbac/models/role.py:46 rbac/models/rolebinding.py:52 -#: users/models/user.py:737 +#: users/models/user.py:763 msgid "Role" msgstr "角色" @@ -5818,6 +5827,10 @@ msgstr "会话加入记录" msgid "Invalid verification code" msgstr "验证码不正确" +#: terminal/models/session/sharing.py:142 +msgid "You have already joined this session" +msgstr "" + #: terminal/notifications.py:21 msgid "Sessions" msgstr "会话管理" @@ -6416,14 +6429,10 @@ msgstr "无效的审批动作" msgid "This user is not authorized to approve this ticket" msgstr "此用户无权审批此工单" -#: users/api/user.py:185 +#: users/api/user.py:191 msgid "Could not reset self otp, use profile reset instead" msgstr "不能在该页面重置 MFA 多因子认证, 请去个人信息页面重置" -#: users/apps.py:9 -msgid "Users" -msgstr "用户管理" - #: users/const.py:10 msgid "System administrator" msgstr "系统管理员" @@ -6453,8 +6462,8 @@ msgid "MFA not enabled" msgstr "MFA 多因子认证没有开启" #: users/exceptions.py:20 -msgid "MFA method not support" -msgstr "不支持该 MFA 方式" +msgid "Unable to delete all users" +msgstr "无法删除全部用户" #: users/forms/profile.py:50 msgid "" @@ -6527,7 +6536,7 @@ msgstr "不能和原来的密钥相同" msgid "Not a valid ssh public key" msgstr "SSH密钥不合法" -#: users/forms/profile.py:170 users/models/user.py:760 +#: users/forms/profile.py:170 users/models/user.py:786 msgid "Public key" msgstr "SSH公钥" @@ -6535,68 +6544,68 @@ msgstr "SSH公钥" msgid "Force enable" msgstr "强制启用" -#: users/models/user.py:739 users/serializers/user.py:171 +#: users/models/user.py:765 users/serializers/user.py:172 msgid "Is service account" msgstr "服务账号" -#: users/models/user.py:741 +#: users/models/user.py:767 msgid "Avatar" msgstr "头像" -#: users/models/user.py:744 +#: users/models/user.py:770 msgid "Wechat" msgstr "微信" -#: users/models/user.py:747 users/serializers/user.py:109 +#: users/models/user.py:773 users/serializers/user.py:109 msgid "Phone" msgstr "手机" -#: users/models/user.py:753 +#: users/models/user.py:779 msgid "OTP secret key" msgstr "OTP 密钥" -#: users/models/user.py:757 +#: users/models/user.py:783 msgid "Private key" msgstr "ssh私钥" -#: users/models/user.py:763 +#: users/models/user.py:789 msgid "Secret key" msgstr "Secret key" -#: users/models/user.py:768 users/serializers/profile.py:149 -#: users/serializers/user.py:168 +#: users/models/user.py:794 users/serializers/profile.py:149 +#: users/serializers/user.py:169 msgid "Is first login" msgstr "首次登录" -#: users/models/user.py:782 +#: users/models/user.py:808 msgid "Date password last updated" msgstr "最后更新密码日期" -#: users/models/user.py:785 +#: users/models/user.py:811 msgid "Need update password" msgstr "需要更新密码" -#: users/models/user.py:923 +#: users/models/user.py:949 msgid "Can invite user" msgstr "可以邀请用户" -#: users/models/user.py:924 +#: users/models/user.py:950 msgid "Can remove user" msgstr "可以移除用户" -#: users/models/user.py:925 +#: users/models/user.py:951 msgid "Can match user" msgstr "可以匹配用户" -#: users/models/user.py:934 +#: users/models/user.py:960 msgid "Administrator" msgstr "管理员" -#: users/models/user.py:937 +#: users/models/user.py:963 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" -#: users/models/user.py:962 +#: users/models/user.py:988 msgid "User password history" msgstr "用户密码历史" @@ -6671,7 +6680,7 @@ msgstr "强制 MFA" msgid "Login blocked" msgstr "登录被锁定" -#: users/serializers/user.py:99 users/serializers/user.py:176 +#: users/serializers/user.py:99 users/serializers/user.py:177 msgid "Is OTP bound" msgstr "是否绑定了虚拟 MFA" @@ -6679,23 +6688,23 @@ msgstr "是否绑定了虚拟 MFA" msgid "Can public key authentication" msgstr "可以使用公钥认证" -#: users/serializers/user.py:173 +#: users/serializers/user.py:174 msgid "Avatar url" msgstr "头像路径" -#: users/serializers/user.py:177 +#: users/serializers/user.py:178 msgid "MFA level" msgstr "MFA 级别" -#: users/serializers/user.py:283 +#: users/serializers/user.py:284 msgid "Select users" msgstr "选择用户" -#: users/serializers/user.py:284 +#: users/serializers/user.py:285 msgid "For security, only list several users" msgstr "为了安全,仅列出几个用户" -#: users/serializers/user.py:317 +#: users/serializers/user.py:318 msgid "name not unique" msgstr "名称重复" @@ -7535,6 +7544,21 @@ msgstr "旗舰版" msgid "Community edition" msgstr "社区版" +#~ msgid "User (username)" +#~ msgstr "用户(用户名)" + +#~ msgid "Asset (name)" +#~ msgstr "资产(名称)" + +#~ msgid "Asset (address)" +#~ msgstr "资产(地址)" + +#~ msgid "Account (username)" +#~ msgstr "账号(用户名)" + +#~ msgid "MFA method not support" +#~ msgstr "不支持该 MFA 方式" + #, fuzzy #~| msgid "Trigger mode" #~ msgid "Trigger type" diff --git a/apps/users/api/user.py b/apps/users/api/user.py index 7d964977c..7bb8a7d8f 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -16,6 +16,7 @@ from rbac.permissions import RBACPermission from users.utils import LoginBlockUtil, MFABlockUtils from .mixins import UserQuerysetMixin from .. import serializers +from ..exceptions import UnableToDeleteAllUsers from ..filters import UserFilter from ..models import User from ..notifications import ResetMFAMsg @@ -55,6 +56,12 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, SuggestionMixin, BulkModelV queryset = super().get_queryset().prefetch_related('groups') return queryset + def allow_bulk_destroy(self, qs, filtered): + is_valid = filtered.count() < qs.count() + if not is_valid: + raise UnableToDeleteAllUsers() + return True + @action(methods=['get'], detail=False, url_path='suggestions') def match(self, request, *args, **kwargs): with tmp_to_root_org(): @@ -111,8 +118,6 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, SuggestionMixin, BulkModelV self.check_object_permissions(self.request, user) return super().perform_bulk_update(serializer) - def allow_bulk_destroy(self, qs, filtered): - return filtered.count() < qs.count() def perform_bulk_destroy(self, objects): for obj in objects: diff --git a/apps/users/exceptions.py b/apps/users/exceptions.py index e69e65966..e062e367a 100644 --- a/apps/users/exceptions.py +++ b/apps/users/exceptions.py @@ -15,6 +15,6 @@ class PhoneNotSet(JMSException): default_detail = _('Phone not set') -class MFAMethodNotSupport(JMSException): - default_code = 'mfa_not_support' - default_detail = _('MFA method not support') +class UnableToDeleteAllUsers(JMSException): + default_code = 'unable_to_delete_all_users' + default_detail = _('Unable to delete all users') From dcd35310cd3205a640b176406cb1f3679885e1c4 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 25 May 2023 11:42:39 +0800 Subject: [PATCH 031/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20filter=5Fq?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/api/command_acl.py | 13 +++++++++-- apps/acls/api/common.py | 39 ++++++++++++++++++++++++++++++++ apps/acls/api/login_asset_acl.py | 13 ++++++++--- apps/common/db/fields.py | 3 ++- 4 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 apps/acls/api/common.py diff --git a/apps/acls/api/command_acl.py b/apps/acls/api/command_acl.py index e78b18572..349190d00 100644 --- a/apps/acls/api/command_acl.py +++ b/apps/acls/api/command_acl.py @@ -1,6 +1,9 @@ from rest_framework.decorators import action from rest_framework.response import Response + +from common.drf.filters import BaseFilterSet from orgs.mixins.api import OrgBulkModelViewSet +from .common import ACLFiltersetMixin from .. import models, serializers __all__ = ['CommandFilterACLViewSet', 'CommandGroupViewSet'] @@ -13,10 +16,16 @@ class CommandGroupViewSet(OrgBulkModelViewSet): serializer_class = serializers.CommandGroupSerializer +class CommandACLFilter(ACLFiltersetMixin, BaseFilterSet): + class Meta: + model = models.CommandFilterACL + fields = ['name', 'users', 'assets'] + + class CommandFilterACLViewSet(OrgBulkModelViewSet): model = models.CommandFilterACL - filterset_fields = ('name',) - search_fields = filterset_fields + filterset_class = CommandACLFilter + search_fields = ['name'] serializer_class = serializers.CommandFilterACLSerializer rbac_perms = { 'command_review': 'tickets.add_superticket' diff --git a/apps/acls/api/common.py b/apps/acls/api/common.py new file mode 100644 index 000000000..621901471 --- /dev/null +++ b/apps/acls/api/common.py @@ -0,0 +1,39 @@ +from django_filters import rest_framework as drf_filters + +from common.drf.filters import BaseFilterSet +from common.utils import is_uuid + + +class ACLFiltersetMixin(BaseFilterSet): + users = drf_filters.CharFilter(method='filter_user') + assets = drf_filters.CharFilter(method='filter_asset') + + @staticmethod + def filter_user(queryset, name, value): + from users.models import User + if not value: + return queryset + if is_uuid(value): + user = User.objects.filter(id=value).first() + else: + user = User.objects.filter(name=value).first() + if not user: + return queryset.none() + q = queryset.model.users.get_filter_q(user) + return queryset.filter(q).distinct() + + @staticmethod + def filter_asset(queryset, name, value): + from assets.models import Asset + if not value: + return queryset + + if is_uuid(value): + asset = Asset.objects.filter(id=value).first() + else: + asset = Asset.objects.filter(name=value).first() + if not asset: + return queryset.none() + + q = queryset.model.assets.get_filter_q(asset) + return queryset.filter(q).distinct() diff --git a/apps/acls/api/login_asset_acl.py b/apps/acls/api/login_asset_acl.py index 1447c16d5..a2a662bfa 100644 --- a/apps/acls/api/login_asset_acl.py +++ b/apps/acls/api/login_asset_acl.py @@ -1,12 +1,19 @@ +from common.drf.filters import BaseFilterSet from orgs.mixins.api import OrgBulkModelViewSet +from .common import ACLFiltersetMixin from .. import models, serializers - __all__ = ['LoginAssetACLViewSet'] +class CommandACLFilter(ACLFiltersetMixin, BaseFilterSet): + class Meta: + model = models.LoginAssetACL + fields = ['name', 'users', 'assets'] + + class LoginAssetACLViewSet(OrgBulkModelViewSet): model = models.LoginAssetACL - filterset_fields = ('name', ) - search_fields = filterset_fields + filterset_class = CommandACLFilter + search_fields = ['name'] serializer_class = serializers.LoginAssetACLSerializer diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index adfe94769..bc0795eab 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -502,7 +502,8 @@ class JSONManyToManyDescriptor: def get_filter_q(self, instance): model_cls = self.field.model field_name = self.field.column - q = Q(users__type='all') | Q(users__type='ids', users__ids__contains=[str(instance.id)]) + q = Q(**{f'{field_name}__type': 'all'}) | \ + Q(**{f'{field_name}__type': 'ids', f'{field_name}__ids__contains': [str(instance.id)]}) queryset_id_attrs = model_cls.objects \ .filter(**{'{}__type'.format(field_name): 'attrs'}) \ .values_list('id', '{}__attrs'.format(field_name)) From b72f8a724172744bc345342f2ef250271c80af37 Mon Sep 17 00:00:00 2001 From: halo Date: Tue, 23 May 2023 16:04:14 +0800 Subject: [PATCH 032/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E6=94=B6=E9=9B=86=EF=BC=8C=E4=BD=BF=E7=94=A8=E6=AD=A3?= =?UTF-8?q?=E5=88=99=E5=A4=84=E7=90=86=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../automations/gather_accounts/filter.py | 27 ++++++++++++------- .../gather_accounts/host/posix/main.yml | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/apps/accounts/automations/gather_accounts/filter.py b/apps/accounts/automations/gather_accounts/filter.py index c6db6dbd4..f3b111d36 100644 --- a/apps/accounts/automations/gather_accounts/filter.py +++ b/apps/accounts/automations/gather_accounts/filter.py @@ -1,3 +1,5 @@ +import re + from django.utils import timezone __all__ = ['GatherAccountsFilter'] @@ -27,18 +29,25 @@ class GatherAccountsFilter: @staticmethod def posix_filter(info): + username_pattern = re.compile(r'^(\S+)') + ip_pattern = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})') + login_time_pattern = re.compile(r'\w{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}') result = {} for line in info: - data = line.split('@') - if len(data) == 1: - result[line] = {} + usernames = username_pattern.findall(line) + username = ''.join(usernames) + if username: + result[username] = {} + else: continue - - if len(data) != 3: - continue - username, address, dt = data - date = timezone.datetime.strptime(f'{dt} +0800', '%b %d %H:%M:%S %Y %z') - result[username] = {'address': address, 'date': date} + ip_addrs = ip_pattern.findall(line) + ip_addr = ''.join(ip_addrs) + if ip_addr: + result[username].update({'address': ip_addr}) + login_times = login_time_pattern.findall(line) + if login_times: + date = timezone.datetime.strptime(f'{login_times[0]} +0800', '%b %d %H:%M:%S %Y %z') + result[username].update({'date': date}) return result @staticmethod diff --git a/apps/accounts/automations/gather_accounts/host/posix/main.yml b/apps/accounts/automations/gather_accounts/host/posix/main.yml index 910b1213d..d3cbe9c75 100644 --- a/apps/accounts/automations/gather_accounts/host/posix/main.yml +++ b/apps/accounts/automations/gather_accounts/host/posix/main.yml @@ -5,7 +5,7 @@ ansible.builtin.shell: cmd: > users=$(getent passwd | grep -v nologin | grep -v shutdown | awk -F":" '{ print $1 }');for i in $users; - do k=$(last -w -F $i -1 | head -1 | grep -v ^$ | awk '{ print $1"@"$3"@"$5,$6,$7,$8 }') + do k=$(last -w -F $i -1 | head -1 | grep -v ^$ | awk '{ print $0 }') if [ -n "$k" ]; then echo $k else From 5e7d474bb73538924f0e30100a02bb0e395fbce2 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 25 May 2023 13:57:02 +0800 Subject: [PATCH 033/153] =?UTF-8?q?perf:=20RemoteAppHost=20=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E6=94=AF=E6=8C=81=20winrm=20(#10542)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ibuler --- .../migrations/0118_auto_20230524_1647.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 apps/assets/migrations/0118_auto_20230524_1647.py diff --git a/apps/assets/migrations/0118_auto_20230524_1647.py b/apps/assets/migrations/0118_auto_20230524_1647.py new file mode 100644 index 000000000..cfe8c9f99 --- /dev/null +++ b/apps/assets/migrations/0118_auto_20230524_1647.py @@ -0,0 +1,33 @@ +# Generated by Django 3.2.17 on 2023-05-24 08:45 + +from django.db import migrations + + +def migrate_remote_applet_host_support_winrm(apps, *args): + platform_cls = apps.get_model('assets', 'Platform') + protocol_cls = apps.get_model('assets', 'PlatformProtocol') + applet_host_platform = platform_cls.objects.filter(name='RemoteAppHost').first() + if not applet_host_platform: + return + + protocols = applet_host_platform.protocols.all() + if not protocols.filter(name='winrm').exists(): + protocol = protocol_cls(name='winrm', port=5985, public=False, platform=applet_host_platform) + protocol.save() + applet_host_platform.protocols.add(protocol) + + ssh_protocol = protocols.filter(name='ssh').first() + if ssh_protocol: + ssh_protocol.required = False + ssh_protocol.default = True + ssh_protocol.save() + + +class Migration(migrations.Migration): + dependencies = [ + ('assets', '0117_alter_baseautomation_params'), + ] + + operations = [ + migrations.RunPython(migrate_remote_applet_host_support_winrm) + ] From 20cc4ea320b810932915ae7caea61fc04083686a Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Wed, 24 May 2023 17:32:57 +0800 Subject: [PATCH 034/153] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E7=9F=AD=E4=BF=A1=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/sdk/sms/custom.py | 48 +++++++++++++++++++ apps/common/sdk/sms/endpoint.py | 6 ++- apps/jumpserver/conf.py | 4 ++ apps/settings/api/settings.py | 1 + apps/settings/api/sms.py | 9 +++- apps/settings/serializers/auth/sms.py | 27 ++++++++++- apps/settings/serializers/settings.py | 4 +- apps/users/forms/profile.py | 5 +- .../templates/users/forgot_password.html | 1 + 9 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 apps/common/sdk/sms/custom.py diff --git a/apps/common/sdk/sms/custom.py b/apps/common/sdk/sms/custom.py new file mode 100644 index 000000000..6eb0748ed --- /dev/null +++ b/apps/common/sdk/sms/custom.py @@ -0,0 +1,48 @@ +import requests + +from collections import OrderedDict + +from django.conf import settings + +from common.utils import get_logger +from common.exceptions import JMSException + +from .base import BaseSMSClient + + +logger = get_logger(__file__) + + +class CustomSMS(BaseSMSClient): + @classmethod + def new_from_settings(cls): + return cls() + + @staticmethod + def need_pre_check(): + return False + + def send_sms(self, phone_numbers: list, template_param: OrderedDict, **kwargs): + phone_numbers_str = ','.join(phone_numbers) + params = {} + for k, v in settings.CUSTOM_SMS_API_PARAMS.items(): + params[k] = v.format( + code=template_param.get('code'), phone_numbers=phone_numbers_str + ) + + logger.info(f'Custom sms send: phone_numbers={phone_numbers}param={params}') + if settings.CUSTOM_SMS_REQUEST_METHOD == 'post': + action = requests.post + kwargs = {'json': params} + else: + action = requests.get + kwargs = {'params': params} + try: + response = action(url=settings.CUSTOM_SMS_URL, **kwargs) + if response.reason != 'OK': + raise JMSException(detail=response.text, code=response.status_code) + except Exception as exc: + logger.error('Custom sms error: {}'.format(exc)) + + +client = CustomSMS diff --git a/apps/common/sdk/sms/endpoint.py b/apps/common/sdk/sms/endpoint.py index 044cf28a2..ce016888a 100644 --- a/apps/common/sdk/sms/endpoint.py +++ b/apps/common/sdk/sms/endpoint.py @@ -17,6 +17,7 @@ class BACKENDS(TextChoices): TENCENT = 'tencent', _('Tencent cloud') HUAWEI = 'huawei', _('Huawei Cloud') CMPP2 = 'cmpp2', _('CMPP v2.0') + Custom = 'custom', _('Custom type') class SMS: @@ -42,8 +43,9 @@ class SMS: ) def send_verify_code(self, phone_number, code): - sign_name = getattr(settings, f'{self.client.SIGN_AND_TMPL_SETTING_FIELD_PREFIX}_VERIFY_SIGN_NAME') - template_code = getattr(settings, f'{self.client.SIGN_AND_TMPL_SETTING_FIELD_PREFIX}_VERIFY_TEMPLATE_CODE') + prefix = getattr(self.client, 'SIGN_AND_TMPL_SETTING_FIELD_PREFIX', '') + sign_name = getattr(settings, f'{prefix}_VERIFY_SIGN_NAME', None) + template_code = getattr(settings, f'{prefix}_VERIFY_TEMPLATE_CODE', None) if self.client.need_pre_check() and not (sign_name and template_code): raise JMSException( diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 18872058a..ee4ee690a 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -414,6 +414,10 @@ class Config(dict): 'CMPP2_VERIFY_SIGN_NAME': '', 'CMPP2_VERIFY_TEMPLATE_CODE': '{code}', + 'CUSTOM_SMS_URL': '', + 'CUSTOM_SMS_API_PARAMS': {'phone_numbers': '{phone_numbers}', 'code': '{code}'}, + 'CUSTOM_SMS_REQUEST_METHOD': 'get', + # Email 'EMAIL_CUSTOM_USER_CREATED_SUBJECT': _('Create account successfully'), 'EMAIL_CUSTOM_USER_CREATED_HONORIFIC': _('Hello'), diff --git a/apps/settings/api/settings.py b/apps/settings/api/settings.py index 5a516491c..6cc2743e2 100644 --- a/apps/settings/api/settings.py +++ b/apps/settings/api/settings.py @@ -43,6 +43,7 @@ class SettingsApi(generics.RetrieveUpdateAPIView): 'tencent': serializers.TencentSMSSettingSerializer, 'huawei': serializers.HuaweiSMSSettingSerializer, 'cmpp2': serializers.CMPP2SMSSettingSerializer, + 'custom': serializers.CustomSMSSettingSerializer, } rbac_category_permissions = { diff --git a/apps/settings/api/sms.py b/apps/settings/api/sms.py index 301f4e203..01fca4436 100644 --- a/apps/settings/api/sms.py +++ b/apps/settings/api/sms.py @@ -39,7 +39,8 @@ class SMSTestingAPI(GenericAPIView): 'alibaba': serializers.AlibabaSMSSettingSerializer, 'tencent': serializers.TencentSMSSettingSerializer, 'huawei': serializers.HuaweiSMSSettingSerializer, - 'cmpp2': serializers.CMPP2SMSSettingSerializer + 'cmpp2': serializers.CMPP2SMSSettingSerializer, + 'custom': serializers.CustomSMSSettingSerializer, } rbac_perms = { 'POST': 'settings.change_sms' @@ -115,6 +116,12 @@ class SMSTestingAPI(GenericAPIView): } return init_params, send_sms_params + @staticmethod + def get_custom_params(data): + init_params = {} + send_sms_params = {'template_param': OrderedDict(code='666666')} + return init_params, send_sms_params + def get_params_by_backend(self, backend, data): """ 返回两部分参数 diff --git a/apps/settings/serializers/auth/sms.py b/apps/settings/serializers/auth/sms.py index cb5085386..41d7d5ac6 100644 --- a/apps/settings/serializers/auth/sms.py +++ b/apps/settings/serializers/auth/sms.py @@ -1,4 +1,5 @@ from django.utils.translation import ugettext_lazy as _ +from django.db import models from rest_framework import serializers from common.serializers.fields import EncryptedField @@ -7,7 +8,7 @@ from common.sdk.sms import BACKENDS __all__ = [ 'SMSSettingSerializer', 'AlibabaSMSSettingSerializer', 'TencentSMSSettingSerializer', - 'HuaweiSMSSettingSerializer', 'CMPP2SMSSettingSerializer' + 'HuaweiSMSSettingSerializer', 'CMPP2SMSSettingSerializer', 'CustomSMSSettingSerializer', ] @@ -87,3 +88,27 @@ class CMPP2SMSSettingSerializer(BaseSMSSettingSerializer): # 保证验证码内容在一条短信中(长度小于70字), 签名两边的括号和空格占3个字,再减去2个即可(验证码占用4个但占位符6个 raise serializers.ValidationError(_('Signature + Template must not exceed 65 words')) return attrs + + +class CustomSMSSettingSerializer(BaseSMSSettingSerializer): + class RequestType(models.TextChoices): + get = 'get', 'Get' + post = 'post', 'Post' + + CUSTOM_SMS_URL = serializers.URLField(required=True, label=_("URL")) + CUSTOM_SMS_API_PARAMS = serializers.DictField( + label=_('Parameters'), default={'phone_number': '{phone_number}', 'code': '{code}'} + ) + CUSTOM_SMS_REQUEST_METHOD = serializers.ChoiceField( + default=RequestType.get, choices=RequestType.choices, label=_("Request method") + ) + + @staticmethod + def validate(attrs): + need_params = {'{phone_numbers}', '{code}'} + params = attrs.get('CUSTOM_SMS_API_PARAMS', {}) + if len(set(params.values()) & need_params) != len(need_params): + raise serializers.ValidationError( + _('The value in the parameter must contain %s') % ','.join(need_params) + ) + return attrs diff --git a/apps/settings/serializers/settings.py b/apps/settings/serializers/settings.py index 21ca6d461..2fb15b0af 100644 --- a/apps/settings/serializers/settings.py +++ b/apps/settings/serializers/settings.py @@ -12,7 +12,8 @@ from .auth import ( CASSettingSerializer, RadiusSettingSerializer, FeiShuSettingSerializer, WeComSettingSerializer, DingTalkSettingSerializer, AlibabaSMSSettingSerializer, TencentSMSSettingSerializer, CMPP2SMSSettingSerializer, AuthSettingSerializer, - SAML2SettingSerializer, OAuth2SettingSerializer, SSOSettingSerializer + SAML2SettingSerializer, OAuth2SettingSerializer, SSOSettingSerializer, + CustomSMSSettingSerializer, ) from .terminal import TerminalSettingSerializer from .security import SecuritySettingSerializer @@ -47,6 +48,7 @@ class SettingsSerializer( AlibabaSMSSettingSerializer, TencentSMSSettingSerializer, CMPP2SMSSettingSerializer, + CustomSMSSettingSerializer, ): CACHE_KEY = 'SETTING_FIELDS_MAPPING' diff --git a/apps/users/forms/profile.py b/apps/users/forms/profile.py index 56c496ce4..48dcb6220 100644 --- a/apps/users/forms/profile.py +++ b/apps/users/forms/profile.py @@ -100,7 +100,10 @@ class UserTokenResetPasswordForm(forms.Form): class UserForgotPasswordForm(forms.Form): email = forms.CharField(label=_("Email"), required=False) - sms = forms.CharField(label=_('SMS'), required=False, max_length=11) + sms = forms.CharField( + label=_('SMS'), required=False, + help_text=_('The phone number must contain an area code, for example, +86') + ) code = forms.CharField(label=_('Verify code'), max_length=6, required=False) form_type = forms.ChoiceField( choices=[('sms', _('SMS')), ('email', _('Email'))], diff --git a/apps/users/templates/users/forgot_password.html b/apps/users/templates/users/forgot_password.html index 755e48dcf..64137ea8a 100644 --- a/apps/users/templates/users/forgot_password.html +++ b/apps/users/templates/users/forgot_password.html @@ -59,6 +59,7 @@
+ {{ form.sms.help_text }}
Date: Wed, 24 May 2023 18:28:37 +0800 Subject: [PATCH 035/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E7=BF=BB?= =?UTF-8?q?=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.po | 19 ++++++++++++++++++- apps/locale/zh/LC_MESSAGES/django.po | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index fdec83625..3af8d3656 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -4576,6 +4576,19 @@ msgstr "テンプレートには{code}を含める必要があります" msgid "Signature + Template must not exceed 65 words" msgstr "署名+テンプレートの長さは65文字以内" +#: settings/serializers/auth/sms.py:98 +msgid "URL" +msgstr "" + +#: settings/serializers/auth/sms.py:103 +msgid "Request method" +msgstr "請求方法です" + +#: settings/serializers/auth/sms.py:112 +#, python-format +msgid "The value in the parameter must contain %s" +msgstr "パラメータの値には必ず %s が含まれます" + #: settings/serializers/auth/sso.py:13 msgid "Enable SSO auth" msgstr "SSO Token認証の有効化" @@ -6596,7 +6609,11 @@ msgstr "パスワードの確認" msgid "Password does not match" msgstr "パスワードが一致しない" -#: users/forms/profile.py:118 +#: users/forms/profile.py:105 +msgid "The phone number must contain an area code, for example, +86" +msgstr "電話番号には市外局番が必要です例えば「+86」" + +#: users/forms/profile.py:121 msgid "Old password" msgstr "古いパスワード" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index f71c1b831..d6ba4d94f 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -4533,6 +4533,19 @@ msgstr "模板需要包含 {code}" msgid "Signature + Template must not exceed 65 words" msgstr "模板+签名不能超过65个字" +#: settings/serializers/auth/sms.py:98 +msgid "URL" +msgstr "" + +#: settings/serializers/auth/sms.py:103 +msgid "Request method" +msgstr "请求方式" + +#: settings/serializers/auth/sms.py:112 +#, python-format +msgid "The value in the parameter must contain %s" +msgstr "参数中的值必须包含 %s" + #: settings/serializers/auth/sso.py:13 msgid "Enable SSO auth" msgstr "启用 SSO 令牌认证" @@ -6503,7 +6516,11 @@ msgstr "确认密码" msgid "Password does not match" msgstr "密码不一致" -#: users/forms/profile.py:118 +#: users/forms/profile.py:105 +msgid "The phone number must contain an area code, for example, +86" +msgstr "手机号码必须包含区号,例如 +86" + +#: users/forms/profile.py:121 msgid "Old password" msgstr "原来密码" From bcb4e04200a9cec1438bd94d753e1a09f8948e4d Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Thu, 25 May 2023 10:17:29 +0800 Subject: [PATCH 036/153] =?UTF-8?q?perf:=20=E5=BF=BD=E7=95=A5=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E7=9F=AD=E4=BF=A1=E8=AE=A4=E8=AF=81=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E8=AF=81=E4=B9=A6=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/sdk/sms/custom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/common/sdk/sms/custom.py b/apps/common/sdk/sms/custom.py index 6eb0748ed..64f9a0246 100644 --- a/apps/common/sdk/sms/custom.py +++ b/apps/common/sdk/sms/custom.py @@ -38,7 +38,7 @@ class CustomSMS(BaseSMSClient): action = requests.get kwargs = {'params': params} try: - response = action(url=settings.CUSTOM_SMS_URL, **kwargs) + response = action(url=settings.CUSTOM_SMS_URL, verify=False, **kwargs) if response.reason != 'OK': raise JMSException(detail=response.text, code=response.status_code) except Exception as exc: From cc2e42c77a813de14afbae443c26f2249b4aa6b4 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 23 May 2023 11:24:44 +0800 Subject: [PATCH 037/153] =?UTF-8?q?perf:=20chrome=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/applets/chrome/app.py | 8 +++--- .../disable_new_tab_window_menu/background.js | 16 ++++++++++++ .../content_script.js | 23 ++++++++++++++++ .../disable_new_tab_window_menu/manifest.json | 26 +++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/background.js create mode 100644 apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js create mode 100644 apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/manifest.json diff --git a/apps/terminal/applets/chrome/app.py b/apps/terminal/applets/chrome/app.py index 86a664c27..c92a3ff55 100644 --- a/apps/terminal/applets/chrome/app.py +++ b/apps/terminal/applets/chrome/app.py @@ -186,9 +186,9 @@ class WebAPP(object): def default_chrome_driver_options(): options = webdriver.ChromeOptions() - options.add_argument("start-maximized") - # 禁用 扩展 - options.add_argument("--disable-extensions") + options.add_argument("--start-maximized") + options.add_argument("--new-window") + # 忽略证书错误相关 options.add_argument('--ignore-ssl-errors') options.add_argument('--ignore-certificate-errors') @@ -215,6 +215,7 @@ class AppletApplication(BaseApplication): self.app = WebAPP(app_name=self.app_name, user=self.user, account=self.account, asset=self.asset, platform=self.platform) self._chrome_options = default_chrome_driver_options() + self._chrome_options.add_argument("--app={}".format(self.asset.address)) def run(self): service = Service() @@ -223,7 +224,6 @@ class AppletApplication(BaseApplication): self.driver = webdriver.Chrome(options=self._chrome_options, service=service) self.driver.implicitly_wait(10) if self.app.asset.address != "": - self.driver.get(self.app.asset.address) ok = self.app.execute(self.driver) if not ok: print("执行失败") diff --git a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/background.js b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/background.js new file mode 100644 index 000000000..5a9a13b6b --- /dev/null +++ b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/background.js @@ -0,0 +1,16 @@ +// background.js + +// 监听标签页的创建事件 +chrome.tabs.onCreated.addListener(function (tab) { + // 获取当前窗口的所有标签页 + chrome.tabs.query({currentWindow: true}, function (tabs) { + // 如果当前窗口的标签页数量大于1,则关闭新创建的标签页 + if (tabs.length > 1) { + chrome.tabs.remove(tab.id); + } + }); +}); + +document.addEventListener("contextmenu", function (event) { + event.preventDefault(); +}); diff --git a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js new file mode 100644 index 000000000..f51c40254 --- /dev/null +++ b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js @@ -0,0 +1,23 @@ +// content_script.js + +// 获取所有的 标签元素 +const links = document.getElementsByTagName('a'); + +// 遍历 标签元素并修改链接属性 +for (let i = 0; i < links.length; i++) { + links[i].target = '_self'; // 将 target 属性设置为 _self,当前窗口打开 +} + +chrome.runtime.onMessage.addListener( + function (request, sender, sendResponse) { + $("iframe").attr("src", request.url); + sendResponse({farewell: "goodbye"}); + } +) + +document.addEventListener("contextmenu", function (event) { + event.preventDefault(); +}); + +chrome.runtime.sendMessage({greeting: "hello"}, function (response) { +}); diff --git a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/manifest.json b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/manifest.json new file mode 100644 index 000000000..58ad2b4a1 --- /dev/null +++ b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/manifest.json @@ -0,0 +1,26 @@ +{ + "manifest_version": 2, + "name": "禁止新标签窗口菜单", + "version": "1.0", + "description": "将所有链接替换为当前窗口打开, 并禁止新窗口和标签,隐藏右击菜单", + "background": { + "scripts": [ + "background.js" + ], + "persistent": false + }, + "content_scripts": [ + { + "matches": [ + "*://*/*" + ], + "js": [ + "content_script.js" + ], + "run_at": "document_end" + } + ], + "permissions": [ + "tabs" + ] +} From f20a4beef39687f6ec4afa42e3b280a62b388da9 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Thu, 25 May 2023 15:11:54 +0800 Subject: [PATCH 038/153] =?UTF-8?q?fix:=20=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=B9=B3=E5=8F=B0=E6=97=A0=E8=87=AA=E5=8A=A8=E5=8C=96=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/models/applet/applet.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index 2114740ef..a83ead302 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -94,6 +94,7 @@ class Applet(JMSBaseModel): @classmethod def load_platform_if_need(cls, d): from assets.serializers import PlatformSerializer + from assets.const import CustomTypes if not os.path.exists(os.path.join(d, 'platform.yml')): return @@ -111,6 +112,9 @@ class Applet(JMSBaseModel): except KeyError: raise ValidationError({'error': _('Missing type in platform.yml')}) + if not data.get('automation'): + data['automation'] = CustomTypes._get_automation_constrains()['*'] + s = PlatformSerializer(data=data) s.add_type_choices(tp, tp) s.is_valid(raise_exception=True) From fa21c83db3b7a18fcc3c9aea82edb2c5a4ffe7a7 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 25 May 2023 16:26:35 +0800 Subject: [PATCH 039/153] =?UTF-8?q?perf:=20LDAP=20=E6=B5=8B=E8=AF=95=20api?= =?UTF-8?q?=20=E6=94=B9=E4=B8=BA=E5=BC=82=E6=AD=A5=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/settings/api/ldap.py | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/settings/api/ldap.py b/apps/settings/api/ldap.py index e45414b81..9a377eb75 100644 --- a/apps/settings/api/ldap.py +++ b/apps/settings/api/ldap.py @@ -2,37 +2,44 @@ # import threading -from rest_framework import generics -from rest_framework.views import Response, APIView -from orgs.models import Organization -from django.utils.translation import ugettext_lazy as _ -from django.conf import settings -from ..models import Setting -from ..utils import ( - LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil, - LDAP_USE_CACHE_FLAGS, LDAPTestUtil -) -from ..tasks import sync_ldap_user +from django.conf import settings +from django.utils.translation import ugettext_lazy as _ +from rest_framework import generics +from rest_framework.generics import CreateAPIView +from rest_framework.views import Response, APIView + +from common.api import AsyncApiMixin from common.utils import get_logger, is_uuid +from orgs.models import Organization +from orgs.utils import current_org +from users.models import User +from ..models import Setting from ..serializers import ( LDAPTestConfigSerializer, LDAPUserSerializer, LDAPTestLoginSerializer ) -from orgs.utils import current_org -from users.models import User +from ..tasks import sync_ldap_user +from ..utils import ( + LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil, + LDAP_USE_CACHE_FLAGS, LDAPTestUtil +) logger = get_logger(__file__) -class LDAPTestingConfigAPI(APIView): +class LDAPTestingConfigAPI(AsyncApiMixin, CreateAPIView): serializer_class = LDAPTestConfigSerializer perm_model = Setting rbac_perms = { - 'POST': 'settings.change_auth' + 'POST': 'settings.change_auth', + 'create': 'settings.change_auth', } - def post(self, request): + def is_need_async(self): + return True + + def create(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data) if not serializer.is_valid(): return Response({"error": str(serializer.errors)}, status=400) From a6366a2dd4a027707b199292cb085718c023f767 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 25 May 2023 17:35:36 +0800 Subject: [PATCH 040/153] =?UTF-8?q?perf:=20ldap=20=E8=83=BD=E5=A4=9A?= =?UTF-8?q?=E7=BB=84=E7=BB=87=E5=90=8C=E6=AD=A5=E7=94=A8=E6=88=B7=20(#1054?= =?UTF-8?q?3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com> --- apps/jumpserver/conf.py | 2 +- apps/jumpserver/settings/auth.py | 3 +- apps/orgs/api.py | 2 +- apps/settings/api/ldap.py | 19 ++++----- .../0007_migrate_ldap_sync_org_ids.py | 29 ++++++++++++++ apps/settings/serializers/auth/ldap.py | 2 +- apps/settings/serializers/public.py | 2 +- apps/settings/tasks/ldap.py | 10 ++--- apps/settings/utils/ldap.py | 39 +++++++++++-------- 9 files changed, 72 insertions(+), 36 deletions(-) create mode 100644 apps/settings/migrations/0007_migrate_ldap_sync_org_ids.py diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index ee4ee690a..d0a1470ff 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -255,7 +255,7 @@ class Config(dict): 'AUTH_LDAP_SYNC_IS_PERIODIC': False, 'AUTH_LDAP_SYNC_INTERVAL': None, 'AUTH_LDAP_SYNC_CRONTAB': None, - 'AUTH_LDAP_SYNC_ORG_ID': '00000000-0000-0000-0000-000000000002', + 'AUTH_LDAP_SYNC_ORG_IDS': ['00000000-0000-0000-0000-000000000002'], 'AUTH_LDAP_USER_LOGIN_ONLY_IN_USERS': False, 'AUTH_LDAP_OPTIONS_OPT_REFERRALS': -1, diff --git a/apps/jumpserver/settings/auth.py b/apps/jumpserver/settings/auth.py index 2eab9ebd8..2a45555bd 100644 --- a/apps/jumpserver/settings/auth.py +++ b/apps/jumpserver/settings/auth.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # import os + import ldap from ..const import CONFIG, PROJECT_DIR, BASE_DIR @@ -48,7 +49,7 @@ AUTH_LDAP_SEARCH_PAGED_SIZE = CONFIG.AUTH_LDAP_SEARCH_PAGED_SIZE AUTH_LDAP_SYNC_IS_PERIODIC = CONFIG.AUTH_LDAP_SYNC_IS_PERIODIC AUTH_LDAP_SYNC_INTERVAL = CONFIG.AUTH_LDAP_SYNC_INTERVAL AUTH_LDAP_SYNC_CRONTAB = CONFIG.AUTH_LDAP_SYNC_CRONTAB -AUTH_LDAP_SYNC_ORG_ID = CONFIG.AUTH_LDAP_SYNC_ORG_ID +AUTH_LDAP_SYNC_ORG_IDS = CONFIG.AUTH_LDAP_SYNC_ORG_IDS AUTH_LDAP_USER_LOGIN_ONLY_IN_USERS = CONFIG.AUTH_LDAP_USER_LOGIN_ONLY_IN_USERS # ============================================================================== diff --git a/apps/orgs/api.py b/apps/orgs/api.py index b49bb08db..b0d8386e8 100644 --- a/apps/orgs/api.py +++ b/apps/orgs/api.py @@ -62,7 +62,7 @@ class OrgViewSet(JMSBulkModelViewSet): msg = _('The current organization ({}) cannot be deleted').format(current_org) raise PermissionDenied(detail=msg) - if str(instance.id) == settings.AUTH_LDAP_SYNC_ORG_ID: + if str(instance.id) in settings.AUTH_LDAP_SYNC_ORG_IDS: msg = _( 'LDAP synchronization is set to the current organization. ' 'Please switch to another organization before deleting' diff --git a/apps/settings/api/ldap.py b/apps/settings/api/ldap.py index 9a377eb75..256d21d31 100644 --- a/apps/settings/api/ldap.py +++ b/apps/settings/api/ldap.py @@ -191,13 +191,13 @@ class LDAPUserImportAPI(APIView): 'POST': 'settings.change_auth' } - def get_org(self): - org_id = self.request.data.get('org_id') - if is_uuid(org_id): - org = Organization.objects.get(id=org_id) + def get_orgs(self): + org_ids = self.request.data.get('org_ids') + if org_ids: + orgs = list(Organization.objects.filter(id__in=org_ids)) else: - org = current_org - return org + orgs = [current_org] + return orgs def get_ldap_users(self): username_list = self.request.data.get('username_list', []) @@ -219,14 +219,15 @@ class LDAPUserImportAPI(APIView): if users is None: return Response({'msg': _('Get ldap users is None')}, status=400) - org = self.get_org() - errors = LDAPImportUtil().perform_import(users, org) + orgs = self.get_orgs() + errors = LDAPImportUtil().perform_import(users, orgs) if errors: return Response({'errors': errors}, status=400) count = users if users is None else len(users) + orgs_name = ', '.join([str(org) for org in orgs]) return Response({ - 'msg': _('Imported {} users successfully (Organization: {})').format(count, org) + 'msg': _('Imported {} users successfully (Organization: {})').format(count, orgs_name) }) diff --git a/apps/settings/migrations/0007_migrate_ldap_sync_org_ids.py b/apps/settings/migrations/0007_migrate_ldap_sync_org_ids.py new file mode 100644 index 000000000..44b696b25 --- /dev/null +++ b/apps/settings/migrations/0007_migrate_ldap_sync_org_ids.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.19 on 2023-05-25 09:00 +import json + +from django.db import migrations + + +def migrate_ldap_sync_org_ids(apps, schema_editor): + setting_model = apps.get_model("settings", "Setting") + db_alias = schema_editor.connection.alias + + instance = setting_model.objects.using(db_alias).filter(name='AUTH_LDAP_SYNC_ORG_ID').first() + if not instance: + return + ldap_sync_org_id = json.loads(instance.value) + setting_model.objects.using(db_alias).update_or_create( + name='AUTH_LDAP_SYNC_ORG_IDS', category='ldap', + value=json.dumps([ldap_sync_org_id]) + ) + instance.delete() + + +class Migration(migrations.Migration): + dependencies = [ + ('settings', '0006_remove_setting_enabled'), + ] + + operations = [ + migrations.RunPython(migrate_ldap_sync_org_ids) + ] diff --git a/apps/settings/serializers/auth/ldap.py b/apps/settings/serializers/auth/ldap.py index c40aec530..016301558 100644 --- a/apps/settings/serializers/auth/ldap.py +++ b/apps/settings/serializers/auth/ldap.py @@ -59,7 +59,7 @@ class LDAPSettingSerializer(serializers.Serializer): help_text=_('User attr map present how to map LDAP user attr to ' 'jumpserver, username,name,email is jumpserver attr') ) - AUTH_LDAP_SYNC_ORG_ID = serializers.CharField( + AUTH_LDAP_SYNC_ORG_IDS = serializers.ListField( required=False, label=_('Organization'), max_length=36 ) AUTH_LDAP_SYNC_IS_PERIODIC = serializers.BooleanField( diff --git a/apps/settings/serializers/public.py b/apps/settings/serializers/public.py index c195b5e4e..82f73bc03 100644 --- a/apps/settings/serializers/public.py +++ b/apps/settings/serializers/public.py @@ -16,7 +16,7 @@ class PrivateSettingSerializer(PublicSettingSerializer): OLD_PASSWORD_HISTORY_LIMIT_COUNT = serializers.IntegerField() TICKET_AUTHORIZE_DEFAULT_TIME = serializers.IntegerField() TICKET_AUTHORIZE_DEFAULT_TIME_UNIT = serializers.CharField() - AUTH_LDAP_SYNC_ORG_ID = serializers.CharField() + AUTH_LDAP_SYNC_ORG_IDS = serializers.ListField() SECURITY_MAX_IDLE_TIME = serializers.IntegerField() SECURITY_VIEW_AUTH_NEED_MFA = serializers.BooleanField() SECURITY_MFA_VERIFY_TTL = serializers.IntegerField() diff --git a/apps/settings/tasks/ldap.py b/apps/settings/tasks/ldap.py index 8a4658f2b..b165d1015 100644 --- a/apps/settings/tasks/ldap.py +++ b/apps/settings/tasks/ldap.py @@ -2,8 +2,8 @@ # from celery import shared_task from django.conf import settings -from django.utils.translation import ugettext_lazy as _ from django.db import transaction +from django.utils.translation import ugettext_lazy as _ from common.utils import get_logger from ops.celery.decorator import after_app_ready_start @@ -30,14 +30,14 @@ def import_ldap_user(): util_import = LDAPImportUtil() users = util_server.search() if settings.XPACK_ENABLED: - org_id = settings.AUTH_LDAP_SYNC_ORG_ID + org_ids = settings.AUTH_LDAP_SYNC_ORG_IDS default_org = None else: # 社区版默认导入Default组织 - org_id = Organization.DEFAULT_ID + org_ids = [Organization.DEFAULT_ID] default_org = Organization.default() - org = Organization.get_instance(org_id, default=default_org) - errors = util_import.perform_import(users, org) + orgs = list(set([Organization.get_instance(org_id, default=default_org) for org_id in org_ids])) + errors = util_import.perform_import(users, orgs) if errors: logger.error("Imported LDAP users errors: {}".format(errors)) else: diff --git a/apps/settings/utils/ldap.py b/apps/settings/utils/ldap.py index da08d5664..2d91306ad 100644 --- a/apps/settings/utils/ldap.py +++ b/apps/settings/utils/ldap.py @@ -1,8 +1,13 @@ # coding: utf-8 # -import os import json +from collections import defaultdict +from copy import deepcopy + +from django.conf import settings +from django.core.cache import cache +from django.utils.translation import ugettext_lazy as _ from ldap3 import Server, Connection, SIMPLE from ldap3.core.exceptions import ( LDAPSocketOpenError, @@ -18,19 +23,14 @@ from ldap3.core.exceptions import ( LDAPConfigurationError, LDAPAttributeError, ) -from django.conf import settings -from django.core.cache import cache -from django.utils.translation import ugettext_lazy as _ -from copy import deepcopy -from collections import defaultdict -from orgs.utils import tmp_to_org -from common.const import LDAP_AD_ACCOUNT_DISABLE -from common.utils import timeit, get_logger -from common.db.utils import close_old_connections -from users.utils import construct_user_email -from users.models import User, UserGroup from authentication.backends.ldap import LDAPAuthorizationBackend, LDAPUser +from common.const import LDAP_AD_ACCOUNT_DISABLE +from common.db.utils import close_old_connections +from common.utils import timeit, get_logger +from orgs.utils import tmp_to_org +from users.models import User, UserGroup +from users.utils import construct_user_email logger = get_logger(__file__) @@ -394,7 +394,7 @@ class LDAPImportUtil(object): group_names.append(group_name) return group_names - def perform_import(self, users, org=None): + def perform_import(self, users, orgs): logger.info('Start perform import ldap users, count: {}'.format(len(users))) errors = [] objs = [] @@ -416,13 +416,20 @@ class LDAPImportUtil(object): errors.append({user['username']: str(e)}) logger.error(e) continue + for org in orgs: + self.bind_org(org, objs, group_users_mapper) + logger.info('End perform import ldap users') + return errors + + @staticmethod + def bind_org(org, users, group_users_mapper): if not org: return if org.is_root(): return # add user to org - for obj in objs: - org.add_member(obj) + for user in users: + org.add_member(user) # add user to group with tmp_to_org(org): for group_name, users in group_users_mapper.items(): @@ -430,8 +437,6 @@ class LDAPImportUtil(object): name=group_name, defaults={'name': group_name} ) group.users.add(*users) - logger.info('End perform import ldap users') - return errors class LDAPTestUtil(object): From 38b121421ff41ed29ee9cfda2f8adc375fdf69ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=B0=8F=E7=99=BD?= <296015668@qq.com> Date: Thu, 25 May 2023 17:42:19 +0800 Subject: [PATCH 041/153] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=20Chrome=20?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/automations/deploy_applet_host/playbook.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/terminal/automations/deploy_applet_host/playbook.yml b/apps/terminal/automations/deploy_applet_host/playbook.yml index 730f8e54f..3e63bd175 100644 --- a/apps/terminal/automations/deploy_applet_host/playbook.yml +++ b/apps/terminal/automations/deploy_applet_host/playbook.yml @@ -182,7 +182,7 @@ - name: Set chromium and driver on the global system path (Chromium) ansible.windows.win_path: elements: - - 'C:\Program Files\Chrome\chrome-win' + - 'C:\Program Files\Chrome\chrome-win32' - 'C:\Program Files\JumpServer\drivers\chromedriver_win32' - name: Set Chromium variables disable Google Api (Chromium) From 5e177b6ce5e5183fb6a136ae76a7ff6398fd531f Mon Sep 17 00:00:00 2001 From: Bai Date: Thu, 25 May 2023 18:21:55 +0800 Subject: [PATCH 042/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=99=BB=E5=BD=95=E8=AE=A4=E8=AF=81=20MFA=20=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E9=94=99=E8=AF=AF=E6=97=B6=E6=B2=A1=E6=9C=89=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=85=B7=E4=BD=93=E9=94=99=E8=AF=AF=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/backends/custom.py | 1 + apps/authentication/errors/failed.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/authentication/backends/custom.py b/apps/authentication/backends/custom.py index c98d1742c..d05e097d5 100644 --- a/apps/authentication/backends/custom.py +++ b/apps/authentication/backends/custom.py @@ -1,5 +1,6 @@ from django.conf import settings from django.utils.module_loading import import_string +from django.utils.translation import ugettext_lazy as _ from common.utils import get_logger from django.contrib.auth import get_user_model from authentication.signals import user_auth_failed, user_auth_success diff --git a/apps/authentication/errors/failed.py b/apps/authentication/errors/failed.py index c85695fe5..3e0848524 100644 --- a/apps/authentication/errors/failed.py +++ b/apps/authentication/errors/failed.py @@ -89,8 +89,6 @@ class MFAFailedError(AuthFailedNeedLogMixin, AuthFailedError): msg: str def __init__(self, username, request, ip, mfa_type, error): - super().__init__(username=username, request=request) - util = MFABlockUtils(username, ip) times_remainder = util.incr_failed_count() block_time = settings.SECURITY_LOGIN_LIMIT_TIME @@ -101,6 +99,7 @@ class MFAFailedError(AuthFailedNeedLogMixin, AuthFailedError): ) else: self.msg = const.block_mfa_msg.format(settings.SECURITY_LOGIN_LIMIT_TIME) + super().__init__(username=username, request=request) class BlockMFAError(AuthFailedNeedLogMixin, AuthFailedError): From 73102fceb065efc60cde1c89aca925fa41161ac5 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 25 May 2023 18:38:14 +0800 Subject: [PATCH 043/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=A6=81?= =?UTF-8?q?=E7=94=A8=E5=B9=B3=E5=8F=B0=E7=9A=84=E8=B4=A6=E5=8F=B7=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=8E=86=E5=8F=B2=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E7=9A=84=E5=88=87=E6=8D=A2=E8=B4=A6=E5=8F=B7=E4=BE=9D?= =?UTF-8?q?=E7=84=B6=E5=8F=AF=E4=BB=A5=E6=AD=A3=E5=B8=B8=E5=88=87=E6=8D=A2?= =?UTF-8?q?=20(#10560)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- .../authentication/serializers/connect_token_secret.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/authentication/serializers/connect_token_secret.py b/apps/authentication/serializers/connect_token_secret.py index b96a99171..feb032665 100644 --- a/apps/authentication/serializers/connect_token_secret.py +++ b/apps/authentication/serializers/connect_token_secret.py @@ -46,7 +46,7 @@ class _SimpleAccountSerializer(serializers.ModelSerializer): class _ConnectionTokenAccountSerializer(serializers.ModelSerializer): - su_from = _SimpleAccountSerializer(required=False, label=_('Su from')) + su_from = serializers.SerializerMethodField(label=_('Su from')) secret_type = LabeledChoiceField(choices=SecretType.choices, required=False, label=_('Secret type')) class Meta: @@ -56,6 +56,14 @@ class _ConnectionTokenAccountSerializer(serializers.ModelSerializer): 'secret', 'su_from', 'privileged' ] + @staticmethod + def get_su_from(account): + su_enabled = account.asset.platform.su_enabled + su_from = account.su_from + if not su_from or not su_enabled: + return + return _SimpleAccountSerializer(su_from).data + class _ConnectionTokenGatewaySerializer(serializers.ModelSerializer): account = _SimpleAccountSerializer( From 9932e7eaddaf4fc6645904575a437b097e919a4b Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 25 May 2023 18:42:54 +0800 Subject: [PATCH 044/153] =?UTF-8?q?perf:=20=E8=B5=84=E4=BA=A7=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E6=94=AF=E6=8C=81=20delete=20=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/models/base.py | 25 +++++++++++++++++++ apps/authentication/api/connection_token.py | 2 +- apps/locale/zh/LC_MESSAGES/django.po | 4 +-- apps/perms/const.py | 5 ++-- .../migrations/0034_auto_20230525_1734.py | 18 +++++++++++++ 5 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 apps/perms/migrations/0034_auto_20230525_1734.py diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 80f0affe6..4b05f887c 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -61,3 +61,28 @@ class UserAssetAccountBaseACL(BaseACL, OrgModelMixin): class Meta(BaseACL.Meta): unique_together = ('name', 'org_id') abstract = True + + @classmethod + def filter_queryset(cls, user=None, asset=None, account=None, account_username=None, **kwargs): + queryset = cls.objects.all() + org_id = None + + if user: + q = cls.users.get_filter_q(user) + queryset = queryset.filter(q) + if asset: + org_id = asset.org_id + q = cls.assets.get_filter_q(asset) + queryset = queryset.filter(q) + if account and not account_username: + account_username = account.username + if account_username: + q = models.Q(accounts__contains=account_username) | \ + models.Q(accounts__contains='*') | \ + models.Q(accounts__contains='@ALL') + queryset = queryset.filter(q) + if org_id: + kwargs['org_id'] = org_id + if kwargs: + queryset = queryset.filter(**kwargs) + return queryset.distinct() diff --git a/apps/authentication/api/connection_token.py b/apps/authentication/api/connection_token.py index 0bc69b025..7c1bbb3f8 100644 --- a/apps/authentication/api/connection_token.py +++ b/apps/authentication/api/connection_token.py @@ -317,7 +317,7 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView if acl.is_action(acl.ActionChoices.accept): return if acl.is_action(acl.ActionChoices.reject): - msg = _('ACL action is reject') + msg = _('ACL action is reject: {}({})'.format(acl.name, acl.id)) raise JMSException(code='acl_reject', detail=msg) if acl.is_action(acl.ActionChoices.review): if not self.request.query_params.get('create_ticket'): diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index d6ba4d94f..217772011 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -1856,7 +1856,7 @@ msgstr "删除" #: audits/const.py:15 perms/const.py:13 msgid "Upload" -msgstr "上传文件" +msgstr "上传" #: audits/const.py:16 msgid "Rename" @@ -1868,7 +1868,7 @@ msgstr "建立软链接" #: audits/const.py:18 perms/const.py:14 msgid "Download" -msgstr "下载文件" +msgstr "下载" #: audits/const.py:22 rbac/tree.py:228 msgid "View" diff --git a/apps/perms/const.py b/apps/perms/const.py index 21fe2d763..70006053e 100644 --- a/apps/perms/const.py +++ b/apps/perms/const.py @@ -14,6 +14,7 @@ class ActionChoices(BitChoices): download = bit(3), _("Download") copy = bit(4), _("Copy") paste = bit(5), _("Paste") + delete = bit(6), _("Delete") @classmethod def is_tree(cls): @@ -23,13 +24,13 @@ class ActionChoices(BitChoices): def branches(cls): return ( cls.connect, - (_("Transfer"), [cls.upload, cls.download]), + (_("Transfer"), [cls.upload, cls.download, cls.delete]), (_("Clipboard"), [cls.copy, cls.paste]), ) @classmethod def transfer(cls): - return cls.upload | cls.download + return cls.upload | cls.download | cls.delete @classmethod def clipboard(cls): diff --git a/apps/perms/migrations/0034_auto_20230525_1734.py b/apps/perms/migrations/0034_auto_20230525_1734.py new file mode 100644 index 000000000..f1e842315 --- /dev/null +++ b/apps/perms/migrations/0034_auto_20230525_1734.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.17 on 2023-05-25 09:34 + +from django.db import migrations + + +def migrate_asset_permission_delete_perm(apps, *args): + asset_permission_cls = apps.get_model('perms', 'AssetPermission') + asset_permission_cls.objects.filter(actions__gte=31).update(actions=63) + + +class Migration(migrations.Migration): + dependencies = [ + ('perms', '0033_auto_20221220_1956'), + ] + + operations = [ + migrations.RunPython(migrate_asset_permission_delete_perm) + ] From 24a98eb747eceb01754d175ce8926f5127791dff Mon Sep 17 00:00:00 2001 From: Bai Date: Fri, 26 May 2023 15:15:21 +0800 Subject: [PATCH 045/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=9F=AD?= =?UTF-8?q?=E4=BF=A1=E8=AE=BE=E7=BD=AE=E7=9A=84=E5=AD=97=E6=AE=B5=E5=90=8D?= =?UTF-8?q?=E7=A7=B0=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/settings/serializers/auth/sms.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/settings/serializers/auth/sms.py b/apps/settings/serializers/auth/sms.py index 41d7d5ac6..60033c476 100644 --- a/apps/settings/serializers/auth/sms.py +++ b/apps/settings/serializers/auth/sms.py @@ -39,25 +39,25 @@ class BaseSMSSettingSerializer(serializers.Serializer): class AlibabaSMSSettingSerializer(BaseSMSSettingSerializer): - ALIBABA_ACCESS_KEY_ID = serializers.CharField(max_length=256, required=True, label='AccessKeyId') + ALIBABA_ACCESS_KEY_ID = serializers.CharField(max_length=256, required=True, label='Access Key ID') ALIBABA_ACCESS_KEY_SECRET = EncryptedField( - max_length=256, required=False, label='access_key_secret', + max_length=256, required=False, label='Access Key Secret', ) ALIBABA_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature')) ALIBABA_VERIFY_TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code')) class TencentSMSSettingSerializer(BaseSMSSettingSerializer): - TENCENT_SECRET_ID = serializers.CharField(max_length=256, required=True, label='Secret id') - TENCENT_SECRET_KEY = EncryptedField(max_length=256, required=False, label='Secret key') - TENCENT_SDKAPPID = serializers.CharField(max_length=256, required=True, label='SDK app id') + TENCENT_SECRET_ID = serializers.CharField(max_length=256, required=True, label='Secret ID') + TENCENT_SECRET_KEY = EncryptedField(max_length=256, required=False, label='Secret Key') + TENCENT_SDKAPPID = serializers.CharField(max_length=256, required=True, label='SDK APP ID') TENCENT_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature')) TENCENT_VERIFY_TEMPLATE_CODE = serializers.CharField(max_length=256, required=True, label=_('Template code')) class HuaweiSMSSettingSerializer(BaseSMSSettingSerializer): - HUAWEI_APP_KEY = serializers.CharField(max_length=256, required=True, label='App key') - HUAWEI_APP_SECRET = EncryptedField(max_length=256, required=False, label='App secret') + HUAWEI_APP_KEY = serializers.CharField(max_length=256, required=True, label='App Key') + HUAWEI_APP_SECRET = EncryptedField(max_length=256, required=False, label='App Secret') HUAWEI_SMS_ENDPOINT = serializers.CharField(max_length=1024, required=True, label=_('App Access Address')) HUAWEI_SIGN_CHANNEL_NUM = serializers.CharField(max_length=1024, required=True, label=_('Signature channel number')) HUAWEI_VERIFY_SIGN_NAME = serializers.CharField(max_length=256, required=True, label=_('Signature')) From 7708812556e9fdb055489775dcab38870f58eddc Mon Sep 17 00:00:00 2001 From: Bai Date: Fri, 26 May 2023 17:13:22 +0800 Subject: [PATCH 046/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=BB=88?= =?UTF-8?q?=E7=AB=AF=E7=AB=AF=E7=82=B9=20Host=20=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=B8=AE=E5=8A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.po | 263 +++++++++++++------------- apps/locale/zh/LC_MESSAGES/django.po | 262 ++++++++++++------------- apps/terminal/serializers/endpoint.py | 7 +- 3 files changed, 276 insertions(+), 256 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 3af8d3656..6164e3b1c 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-25 11:30+0800\n" +"POT-Creation-Date: 2023-05-26 17:11+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -71,7 +71,7 @@ msgid "Collected" msgstr "集めました" #: accounts/const/account.py:21 accounts/serializers/account/account.py:26 -#: settings/serializers/auth/sms.py:75 +#: settings/serializers/auth/sms.py:76 msgid "Template" msgstr "テンプレート" @@ -431,7 +431,7 @@ msgstr "最終ログイン日" #: authentication/forms.py:27 authentication/models/temp_token.py:9 #: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_oauth_bind.html:9 -#: users/forms/profile.py:32 users/forms/profile.py:112 +#: users/forms/profile.py:32 users/forms/profile.py:115 #: users/models/user.py:751 users/templates/users/_msg_user_created.html:12 #: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" @@ -461,7 +461,7 @@ msgstr "トリガー方式" #: accounts/models/automations/push_account.py:16 acls/models/base.py:41 #: acls/serializers/base.py:57 assets/models/cmd_filter.py:81 #: audits/models.py:65 audits/serializers.py:82 -#: authentication/serializers/connect_token_secret.py:108 +#: authentication/serializers/connect_token_secret.py:116 #: authentication/templates/authentication/_access_key_modal.html:34 msgid "Action" msgstr "アクション" @@ -483,7 +483,7 @@ msgstr "アカウントの確認" #: assets/models/platform.py:13 assets/models/platform.py:81 #: assets/serializers/asset/common.py:145 assets/serializers/platform.py:92 #: assets/serializers/platform.py:192 -#: authentication/serializers/connect_token_secret.py:102 ops/mixin.py:21 +#: authentication/serializers/connect_token_secret.py:110 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 #: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29 @@ -504,7 +504,7 @@ msgstr "特権アカウント" #: accounts/models/base.py:40 assets/models/asset/common.py:156 #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 -#: authentication/serializers/connect_token_secret.py:106 +#: authentication/serializers/connect_token_secret.py:114 #: terminal/models/applet/applet.py:32 users/serializers/user.py:170 msgid "Is active" msgstr "アクティブです。" @@ -574,7 +574,7 @@ msgstr "カテゴリ" #: assets/models/cmd_filter.py:74 assets/models/platform.py:83 #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 #: assets/serializers/platform.py:109 audits/serializers.py:48 -#: authentication/serializers/connect_token_secret.py:115 ops/models/job.py:103 +#: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:31 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 @@ -629,7 +629,7 @@ msgid "Account has exist" msgstr "アカウントはすでに存在しています" #: accounts/serializers/account/account.py:417 -#: authentication/serializers/connect_token_secret.py:146 +#: authentication/serializers/connect_token_secret.py:154 #: authentication/templates/authentication/_access_key_modal.html:30 #: perms/models/perm_node.py:21 users/serializers/group.py:33 msgid "ID" @@ -804,7 +804,7 @@ msgstr "1-100、低い値は最初に一致します" #: acls/models/base.py:42 acls/serializers/base.py:79 #: acls/serializers/login_acl.py:23 assets/models/cmd_filter.py:86 -#: authentication/serializers/connect_token_secret.py:80 +#: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "レビュー担当者" @@ -847,7 +847,7 @@ msgstr "家を無視する" #: acls/models/command_acl.py:33 acls/models/command_acl.py:96 #: acls/serializers/command_acl.py:28 -#: authentication/serializers/connect_token_secret.py:77 +#: authentication/serializers/connect_token_secret.py:85 msgid "Command group" msgstr "コマンドグループ" @@ -934,7 +934,7 @@ msgstr "" #: authentication/templates/authentication/_msg_oauth_bind.html:12 #: authentication/templates/authentication/_msg_rest_password_success.html:8 #: authentication/templates/authentication/_msg_rest_public_key_success.html:8 -#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:62 +#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:67 msgid "IP" msgstr "IP" @@ -1036,7 +1036,7 @@ msgid "Gather facts" msgstr "資産情報の収集" #: assets/const/category.py:10 assets/models/asset/host.py:8 -#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 +#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:68 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 #: xpack/plugins/cloud/serializers/account_attrs.py:72 msgid "Host" @@ -1060,7 +1060,7 @@ msgstr "クラウド サービス" msgid "Web" msgstr "Web" -#: assets/const/category.py:15 +#: assets/const/category.py:15 common/sdk/sms/endpoint.py:20 msgid "Custom type" msgstr "カスタムタイプ" @@ -1135,7 +1135,7 @@ msgstr "SSHパブリックキー" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:37 terminal/models/applet/applet.py:218 +#: terminal/models/applet/applet.py:37 terminal/models/applet/applet.py:222 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 @@ -1184,7 +1184,7 @@ msgid "Username same with user" msgstr "ユーザーと同じユーザー名" #: assets/models/_user.py:52 authentication/models/connection_token.py:39 -#: authentication/serializers/connect_token_secret.py:103 +#: authentication/serializers/connect_token_secret.py:111 #: terminal/models/applet/applet.py:34 terminal/serializers/session.py:20 #: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 msgid "Protocol" @@ -1239,7 +1239,7 @@ msgid "Cloud" msgstr "クラウド サービス" #: assets/models/asset/common.py:92 assets/models/platform.py:14 -#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 +#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:69 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "ポート" @@ -1249,14 +1249,14 @@ msgid "Address" msgstr "アドレス" #: assets/models/asset/common.py:151 assets/models/platform.py:112 -#: authentication/serializers/connect_token_secret.py:107 +#: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 #: xpack/plugins/cloud/serializers/account_attrs.py:196 msgid "Platform" msgstr "プラットフォーム" #: assets/models/asset/common.py:153 assets/models/domain.py:21 -#: authentication/serializers/connect_token_secret.py:125 +#: authentication/serializers/connect_token_secret.py:133 #: perms/serializers/user_permission.py:29 msgid "Domain" msgstr "ドメイン" @@ -1337,6 +1337,7 @@ msgid "Accounts" msgstr "アカウント" #: assets/models/automations/base.py:22 ops/models/job.py:187 +#: settings/serializers/auth/sms.py:100 msgid "Parameters" msgstr "パラメータ" @@ -1350,7 +1351,7 @@ msgstr "アセットの自動化タスク" #: assets/models/automations/base.py:113 audits/models.py:177 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:217 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:221 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 @@ -1434,7 +1435,7 @@ msgstr "システム" #: assets/models/label.py:19 assets/models/node.py:557 #: assets/serializers/cagegory.py:7 assets/serializers/cagegory.py:14 #: authentication/models/connection_token.py:27 -#: authentication/serializers/connect_token_secret.py:114 +#: authentication/serializers/connect_token_secret.py:122 #: common/serializers/common.py:86 settings/models.py:34 msgid "Value" msgstr "値" @@ -1442,7 +1443,7 @@ msgstr "値" #: assets/models/label.py:40 assets/serializers/asset/common.py:123 #: assets/serializers/cagegory.py:6 assets/serializers/cagegory.py:13 #: assets/serializers/platform.py:93 -#: authentication/serializers/connect_token_secret.py:113 +#: authentication/serializers/connect_token_secret.py:121 #: common/serializers/common.py:85 perms/serializers/user_permission.py:28 #: settings/serializers/sms.py:7 msgid "Label" @@ -1489,7 +1490,7 @@ msgstr "必要" msgid "Public" msgstr "開ける" -#: assets/models/platform.py:19 settings/serializers/settings.py:65 +#: assets/models/platform.py:19 settings/serializers/settings.py:67 #: users/templates/users/reset_password.html:29 msgid "Setting" msgstr "設定" @@ -1608,7 +1609,7 @@ msgstr "" #: assets/serializers/asset/common.py:124 assets/serializers/platform.py:111 #: authentication/serializers/connect_token_secret.py:29 -#: authentication/serializers/connect_token_secret.py:64 +#: authentication/serializers/connect_token_secret.py:72 #: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 msgid "Protocols" msgstr "プロトコル" @@ -1687,7 +1688,7 @@ msgid "Disk total" msgstr "ディスクの合計" #: assets/serializers/asset/info/gathered.py:16 -#: authentication/serializers/connect_token_secret.py:104 +#: authentication/serializers/connect_token_secret.py:112 msgid "OS" msgstr "OS" @@ -1861,7 +1862,7 @@ msgstr "Rmdir" #: audits/const.py:14 audits/const.py:24 #: authentication/templates/authentication/_access_key_modal.html:65 -#: rbac/tree.py:230 +#: perms/const.py:17 rbac/tree.py:230 msgid "Delete" msgstr "削除" @@ -2116,7 +2117,9 @@ msgid "Permission expired" msgstr "承認の有効期限が切れています" #: authentication/api/connection_token.py:320 -msgid "ACL action is reject" +#, fuzzy +#| msgid "ACL action is reject" +msgid "ACL action is reject: {}({})" msgstr "ACL アクションは拒否です" #: authentication/api/connection_token.py:324 @@ -2157,7 +2160,7 @@ msgstr "パスワードを忘れた" msgid "Authentication" msgstr "認証" -#: authentication/backends/custom.py:58 +#: authentication/backends/custom.py:59 #: authentication/backends/oauth2/backends.py:170 msgid "User invalid, disabled or expired" msgstr "ユーザーが無効、無効、または期限切れです" @@ -2331,19 +2334,19 @@ msgstr "受け入れのためのログイン確認チケットを待つ" msgid "Login confirm ticket was {}" msgstr "ログイン確認チケットは {} でした" -#: authentication/errors/failed.py:146 +#: authentication/errors/failed.py:145 msgid "Current IP and Time period is not allowed" msgstr "現在の IP と期間はログインを許可されていません" -#: authentication/errors/failed.py:151 +#: authentication/errors/failed.py:150 msgid "Please enter MFA code" msgstr "MFAコードを入力してください" -#: authentication/errors/failed.py:156 +#: authentication/errors/failed.py:155 msgid "Please enter SMS code" msgstr "SMSコードを入力してください" -#: authentication/errors/failed.py:161 users/exceptions.py:15 +#: authentication/errors/failed.py:160 users/exceptions.py:15 msgid "Phone not set" msgstr "電話が設定されていない" @@ -2462,8 +2465,8 @@ msgstr "メッセージ検証コードが無効" #: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16 #: authentication/serializers/password_mfa.py:24 -#: settings/serializers/auth/sms.py:27 users/forms/profile.py:103 -#: users/forms/profile.py:106 users/templates/users/forgot_password.html:111 +#: settings/serializers/auth/sms.py:28 users/forms/profile.py:104 +#: users/forms/profile.py:109 users/templates/users/forgot_password.html:112 #: users/views/profile/reset.py:79 msgid "SMS" msgstr "メッセージ" @@ -2480,7 +2483,7 @@ msgstr "電話番号を設定して有効にする" msgid "Clear phone number to disable" msgstr "無効にする電話番号をクリアする" -#: authentication/middleware.py:93 settings/utils/ldap.py:652 +#: authentication/middleware.py:93 settings/utils/ldap.py:657 msgid "Authentication failed (before login check failed): {}" msgstr "認証に失敗しました (ログインチェックが失敗する前): {}" @@ -2597,19 +2600,19 @@ msgstr "異なる都市ログインのリマインダー" msgid "binding reminder" msgstr "バインディングリマインダー" -#: authentication/serializers/connect_token_secret.py:105 +#: authentication/serializers/connect_token_secret.py:113 msgid "Is builtin" msgstr "ビルトイン" -#: authentication/serializers/connect_token_secret.py:109 +#: authentication/serializers/connect_token_secret.py:117 msgid "Options" msgstr "オプション" -#: authentication/serializers/connect_token_secret.py:116 +#: authentication/serializers/connect_token_secret.py:124 msgid "Component" msgstr "コンポーネント" -#: authentication/serializers/connect_token_secret.py:127 +#: authentication/serializers/connect_token_secret.py:135 msgid "Expired now" msgstr "すぐに期限切れ" @@ -2643,14 +2646,14 @@ msgstr "" #: authentication/serializers/password_mfa.py:24 #: notifications/backends/__init__.py:10 settings/serializers/email.py:19 #: settings/serializers/email.py:50 users/forms/profile.py:102 -#: users/forms/profile.py:106 users/models/user.py:755 -#: users/templates/users/forgot_password.html:116 +#: users/forms/profile.py:109 users/models/user.py:755 +#: users/templates/users/forgot_password.html:117 #: users/views/profile/reset.py:73 msgid "Email" msgstr "メール" #: authentication/serializers/password_mfa.py:29 -#: users/templates/users/forgot_password.html:107 +#: users/templates/users/forgot_password.html:108 msgid "The {} cannot be empty" msgstr "{} 空にしてはならない" @@ -2733,7 +2736,7 @@ msgstr "コードエラー" #: authentication/templates/authentication/_msg_reset_password_code.html:9 #: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_public_key_success.html:2 -#: jumpserver/conf.py:419 +#: jumpserver/conf.py:423 #: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3 #: tickets/templates/tickets/approve_check_password.html:33 @@ -2792,7 +2795,7 @@ msgstr "新しいものを要求する" #: authentication/templates/authentication/_msg_reset_password_code.html:12 #: terminal/models/session/sharing.py:25 terminal/models/session/sharing.py:83 -#: users/forms/profile.py:104 users/templates/users/forgot_password.html:65 +#: users/forms/profile.py:107 users/templates/users/forgot_password.html:66 msgid "Verify code" msgstr "コードの確認" @@ -3091,26 +3094,26 @@ msgstr "テキストフィールドへのマーシャルデータ" msgid "Encrypt field using Secret Key" msgstr "Secret Keyを使用したフィールドの暗号化" -#: common/db/fields.py:534 +#: common/db/fields.py:535 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" -#: common/db/fields.py:541 +#: common/db/fields.py:542 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "無効なタイプです。all、ids、またはattrsでなければなりません" -#: common/db/fields.py:544 +#: common/db/fields.py:545 msgid "Invalid ids for ids, should be a list" msgstr "無効なID、リストでなければなりません" -#: common/db/fields.py:547 common/db/fields.py:550 +#: common/db/fields.py:548 common/db/fields.py:551 msgid "Invalid attrs, should be a list of dict" msgstr "無効な属性、dictリストでなければなりません" -#: common/db/fields.py:552 +#: common/db/fields.py:553 msgid "Invalid attrs, should be has name and value" msgstr "名前と値が必要な無効な属性" @@ -3231,11 +3234,11 @@ msgstr "華為雲" msgid "CMPP v2.0" msgstr "CMPP v2.0" -#: common/sdk/sms/endpoint.py:30 +#: common/sdk/sms/endpoint.py:31 msgid "SMS provider not support: {}" msgstr "SMSプロバイダーはサポートしていません: {}" -#: common/sdk/sms/endpoint.py:51 +#: common/sdk/sms/endpoint.py:53 msgid "SMS verification code signature or template invalid" msgstr "SMS検証コードの署名またはテンプレートが無効" @@ -3328,11 +3331,11 @@ msgstr "検索のエクスポート: %s" msgid "User %s view/export secret" msgstr "ユーザー %s がパスワードを閲覧/導き出しました" -#: jumpserver/conf.py:418 +#: jumpserver/conf.py:422 msgid "Create account successfully" msgstr "アカウントを正常に作成" -#: jumpserver/conf.py:420 +#: jumpserver/conf.py:424 msgid "Your account has been created successfully" msgstr "アカウントが正常に作成されました" @@ -3824,11 +3827,11 @@ msgstr "コピー" msgid "Paste" msgstr "貼り付け" -#: perms/const.py:26 +#: perms/const.py:27 msgid "Transfer" msgstr "転送" -#: perms/const.py:27 +#: perms/const.py:28 msgid "Clipboard" msgstr "クリップボード" @@ -4090,7 +4093,7 @@ msgid "My assets" msgstr "私の資産" #: rbac/tree.py:56 terminal/models/applet/applet.py:44 -#: terminal/models/applet/applet.py:214 terminal/models/applet/host.py:28 +#: terminal/models/applet/applet.py:218 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "リモートアプリケーション" @@ -4112,7 +4115,7 @@ msgid "View permission tree" msgstr "権限ツリーの表示" #: settings/api/dingtalk.py:31 settings/api/feishu.py:36 -#: settings/api/sms.py:148 settings/api/wecom.py:37 +#: settings/api/sms.py:155 settings/api/wecom.py:37 msgid "Test success" msgstr "テストの成功" @@ -4120,31 +4123,31 @@ msgstr "テストの成功" msgid "Test mail sent to {}, please check" msgstr "{}に送信されたテストメールを確認してください" -#: settings/api/ldap.py:166 +#: settings/api/ldap.py:173 msgid "Synchronization start, please wait." msgstr "同期開始、お待ちください。" -#: settings/api/ldap.py:170 +#: settings/api/ldap.py:177 msgid "Synchronization is running, please wait." msgstr "同期が実行中です。しばらくお待ちください。" -#: settings/api/ldap.py:175 +#: settings/api/ldap.py:182 msgid "Synchronization error: {}" msgstr "同期エラー: {}" -#: settings/api/ldap.py:213 +#: settings/api/ldap.py:220 msgid "Get ldap users is None" msgstr "Ldapユーザーを取得するにはNone" -#: settings/api/ldap.py:222 +#: settings/api/ldap.py:230 msgid "Imported {} users successfully (Organization: {})" msgstr "{} 人のユーザーを正常にインポートしました (組織: {})" -#: settings/api/sms.py:130 +#: settings/api/sms.py:137 msgid "Invalid SMS platform" msgstr "無効なショートメッセージプラットフォーム" -#: settings/api/sms.py:136 +#: settings/api/sms.py:143 msgid "test_phone is required" msgstr "携帯番号をテストこのフィールドは必須です" @@ -4509,54 +4512,54 @@ msgstr "SP プライベートキー" msgid "SP cert" msgstr "SP 証明書" -#: settings/serializers/auth/sms.py:15 +#: settings/serializers/auth/sms.py:16 msgid "Enable SMS" msgstr "SMSの有効化" -#: settings/serializers/auth/sms.py:17 +#: settings/serializers/auth/sms.py:18 msgid "SMS provider / Protocol" msgstr "SMSプロバイダ / プロトコル" -#: settings/serializers/auth/sms.py:22 settings/serializers/auth/sms.py:45 -#: settings/serializers/auth/sms.py:53 settings/serializers/auth/sms.py:62 -#: settings/serializers/auth/sms.py:73 settings/serializers/email.py:69 +#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:46 +#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 +#: settings/serializers/auth/sms.py:74 settings/serializers/email.py:69 msgid "Signature" msgstr "署名" -#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:46 -#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 +#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:47 +#: settings/serializers/auth/sms.py:55 settings/serializers/auth/sms.py:64 msgid "Template code" msgstr "テンプレートコード" -#: settings/serializers/auth/sms.py:31 +#: settings/serializers/auth/sms.py:32 msgid "Test phone" msgstr "テスト電話" -#: settings/serializers/auth/sms.py:60 +#: settings/serializers/auth/sms.py:61 msgid "App Access Address" msgstr "アプリケーションアドレス" -#: settings/serializers/auth/sms.py:61 +#: settings/serializers/auth/sms.py:62 msgid "Signature channel number" msgstr "署名チャネル番号" -#: settings/serializers/auth/sms.py:69 +#: settings/serializers/auth/sms.py:70 msgid "Enterprise code(SP id)" msgstr "企業コード(SP id)" -#: settings/serializers/auth/sms.py:70 +#: settings/serializers/auth/sms.py:71 msgid "Shared secret(Shared secret)" msgstr "パスワードを共有する(Shared secret)" -#: settings/serializers/auth/sms.py:71 +#: settings/serializers/auth/sms.py:72 msgid "Original number(Src id)" msgstr "元の番号(Src id)" -#: settings/serializers/auth/sms.py:72 +#: settings/serializers/auth/sms.py:73 msgid "Business type(Service id)" msgstr "ビジネス・タイプ(Service id)" -#: settings/serializers/auth/sms.py:76 +#: settings/serializers/auth/sms.py:77 #, python-brace-format msgid "" "Template need contain {code} and Signature + template length does not exceed " @@ -4567,12 +4570,12 @@ msgstr "" "満です。たとえば、認証コードは{code}で、有効期間は5分です。他の人には言わない" "でください。" -#: settings/serializers/auth/sms.py:85 +#: settings/serializers/auth/sms.py:86 #, python-brace-format msgid "The template needs to contain {code}" msgstr "テンプレートには{code}を含める必要があります" -#: settings/serializers/auth/sms.py:88 +#: settings/serializers/auth/sms.py:89 msgid "Signature + Template must not exceed 65 words" msgstr "署名+テンプレートの長さは65文字以内" @@ -5139,7 +5142,7 @@ msgstr "" "します。アカウントが共通のログイン都市からログインしている場合、システムはリ" "モートログインリマインダーを送信します" -#: settings/serializers/settings.py:69 +#: settings/serializers/settings.py:71 #, python-format msgid "[%s] %s" msgstr "" @@ -5219,100 +5222,100 @@ msgstr "LDAP ユーザーのインポート" msgid "Periodic import ldap user" msgstr "LDAP ユーザーを定期的にインポートする" -#: settings/utils/ldap.py:467 +#: settings/utils/ldap.py:472 msgid "ldap:// or ldaps:// protocol is used." msgstr "ldap:// または ldaps:// プロトコルが使用されます。" -#: settings/utils/ldap.py:478 +#: settings/utils/ldap.py:483 msgid "Host or port is disconnected: {}" msgstr "ホストまたはポートが切断されました: {}" -#: settings/utils/ldap.py:480 +#: settings/utils/ldap.py:485 msgid "The port is not the port of the LDAP service: {}" msgstr "ポートはLDAPサービスのポートではありません: {}" -#: settings/utils/ldap.py:482 +#: settings/utils/ldap.py:487 msgid "Please add certificate: {}" msgstr "証明書を追加してください: {}" -#: settings/utils/ldap.py:486 settings/utils/ldap.py:513 -#: settings/utils/ldap.py:543 settings/utils/ldap.py:571 +#: settings/utils/ldap.py:491 settings/utils/ldap.py:518 +#: settings/utils/ldap.py:548 settings/utils/ldap.py:576 msgid "Unknown error: {}" msgstr "不明なエラー: {}" -#: settings/utils/ldap.py:500 +#: settings/utils/ldap.py:505 msgid "Bind DN or Password incorrect" msgstr "DNまたはパスワードのバインドが正しくありません" -#: settings/utils/ldap.py:507 +#: settings/utils/ldap.py:512 msgid "Please enter Bind DN: {}" msgstr "バインドDN: {} を入力してください" -#: settings/utils/ldap.py:509 +#: settings/utils/ldap.py:514 msgid "Please enter Password: {}" msgstr "パスワードを入力してください: {}" -#: settings/utils/ldap.py:511 +#: settings/utils/ldap.py:516 msgid "Please enter correct Bind DN and Password: {}" msgstr "正しいバインドDNとパスワードを入力してください: {}" -#: settings/utils/ldap.py:529 +#: settings/utils/ldap.py:534 msgid "Invalid User OU or User search filter: {}" msgstr "無効なユーザー OU またはユーザー検索フィルター: {}" -#: settings/utils/ldap.py:560 +#: settings/utils/ldap.py:565 msgid "LDAP User attr map not include: {}" msgstr "LDAP ユーザーattrマップは含まれません: {}" -#: settings/utils/ldap.py:567 +#: settings/utils/ldap.py:572 msgid "LDAP User attr map is not dict" msgstr "LDAPユーザーattrマップはdictではありません" -#: settings/utils/ldap.py:586 +#: settings/utils/ldap.py:591 msgid "LDAP authentication is not enabled" msgstr "LDAP 認証が有効になっていない" -#: settings/utils/ldap.py:604 +#: settings/utils/ldap.py:609 msgid "Error (Invalid LDAP server): {}" msgstr "エラー (LDAPサーバーが無効): {}" -#: settings/utils/ldap.py:606 +#: settings/utils/ldap.py:611 msgid "Error (Invalid Bind DN): {}" msgstr "エラー (DNのバインドが無効): {}" -#: settings/utils/ldap.py:608 +#: settings/utils/ldap.py:613 msgid "Error (Invalid LDAP User attr map): {}" msgstr "エラー (LDAPユーザーattrマップが無効): {}" -#: settings/utils/ldap.py:610 +#: settings/utils/ldap.py:615 msgid "Error (Invalid User OU or User search filter): {}" msgstr "エラー (ユーザーOUまたはユーザー検索フィルターが無効): {}" -#: settings/utils/ldap.py:612 +#: settings/utils/ldap.py:617 msgid "Error (Not enabled LDAP authentication): {}" msgstr "エラー (LDAP認証が有効化されていません): {}" -#: settings/utils/ldap.py:614 +#: settings/utils/ldap.py:619 msgid "Error (Unknown): {}" msgstr "エラー (不明): {}" -#: settings/utils/ldap.py:617 +#: settings/utils/ldap.py:622 msgid "Succeed: Match {} s user" msgstr "成功: {} 人のユーザーに一致" -#: settings/utils/ldap.py:650 +#: settings/utils/ldap.py:655 msgid "Authentication failed (configuration incorrect): {}" msgstr "認証に失敗しました (設定が正しくありません): {}" -#: settings/utils/ldap.py:654 +#: settings/utils/ldap.py:659 msgid "Authentication failed (username or password incorrect): {}" msgstr "認証に失敗しました (ユーザー名またはパスワードが正しくありません): {}" -#: settings/utils/ldap.py:656 +#: settings/utils/ldap.py:661 msgid "Authentication failed (Unknown): {}" msgstr "認証に失敗しました (不明): {}" -#: settings/utils/ldap.py:659 +#: settings/utils/ldap.py:664 msgid "Authentication success: {}" msgstr "認証成功: {}" @@ -5463,12 +5466,12 @@ msgid "Send verification code" msgstr "確認コードを送信" #: templates/_mfa_login_field.html:106 -#: users/templates/users/forgot_password.html:129 +#: users/templates/users/forgot_password.html:130 msgid "Wait: " msgstr "待つ:" #: templates/_mfa_login_field.html:116 -#: users/templates/users/forgot_password.html:145 +#: users/templates/users/forgot_password.html:146 msgid "The verification code has been sent" msgstr "確認コードが送信されました" @@ -5677,19 +5680,19 @@ msgstr "ホスト" msgid "Applet pkg not valid, Missing file {}" msgstr "無効なアプレット パッケージ、ファイル {} がありません" -#: terminal/models/applet/applet.py:104 +#: terminal/models/applet/applet.py:105 msgid "Load platform.yml failed: {}" msgstr "" -#: terminal/models/applet/applet.py:107 +#: terminal/models/applet/applet.py:108 msgid "Only support custom platform" msgstr "" -#: terminal/models/applet/applet.py:112 +#: terminal/models/applet/applet.py:113 msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:216 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:220 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "ホスト マシン" @@ -5747,7 +5750,7 @@ msgid "Redis port" msgstr "Redis ポート" #: terminal/models/component/endpoint.py:29 -#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:66 +#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:71 #: terminal/serializers/storage.py:38 terminal/serializers/storage.py:50 #: terminal/serializers/storage.py:80 terminal/serializers/storage.py:90 #: terminal/serializers/storage.py:98 @@ -6036,13 +6039,17 @@ msgstr "" "Oracle プロキシサーバーがリッスンするポートは動的です。追加の Oracle データ" "ベースインスタンスはポートリスナーを追加します" -#: terminal/serializers/endpoint.py:36 -msgid "Visit IP/Host, if empty, use the current request instead" +#: terminal/serializers/endpoint.py:37 +msgid "" +"The host address accessed when connecting to assets, if it is empty, the " +"access address of the current browser will be used (the default endpoint " +"does not allow modification of the host)" msgstr "" -"IP/ホストにアクセスします。空の場合は、代わりに現在のリクエストのアドレスを使" -"用します" +"アセットに接続するときにアクセスされるホスト アドレス。空の場合は、現在のブラ" +"ウザのアクセス アドレスが使用されます (デフォルトのエンドポイントではホストの" +"変更は許可されません)。" -#: terminal/serializers/endpoint.py:59 +#: terminal/serializers/endpoint.py:64 msgid "" "If asset IP addresses under different endpoints conflict, use asset labels" msgstr "" @@ -6617,36 +6624,36 @@ msgstr "電話番号には市外局番が必要です例えば「+86」" msgid "Old password" msgstr "古いパスワード" -#: users/forms/profile.py:128 +#: users/forms/profile.py:131 msgid "Old password error" msgstr "古いパスワードエラー" -#: users/forms/profile.py:138 +#: users/forms/profile.py:141 msgid "Automatically configure and download the SSH key" msgstr "SSHキーの自動設定とダウンロード" -#: users/forms/profile.py:140 +#: users/forms/profile.py:143 msgid "ssh public key" msgstr "ssh公開キー" -#: users/forms/profile.py:141 +#: users/forms/profile.py:144 msgid "ssh-rsa AAAA..." msgstr "ssh-rsa AAAA.." -#: users/forms/profile.py:142 +#: users/forms/profile.py:145 msgid "Paste your id_rsa.pub here." msgstr "ここにid_rsa.pubを貼り付けます。" -#: users/forms/profile.py:155 +#: users/forms/profile.py:158 msgid "Public key should not be the same as your old one." msgstr "公開鍵は古いものと同じであってはなりません。" -#: users/forms/profile.py:159 users/serializers/profile.py:100 +#: users/forms/profile.py:162 users/serializers/profile.py:100 #: users/serializers/profile.py:183 users/serializers/profile.py:210 msgid "Not a valid ssh public key" msgstr "有効なssh公開鍵ではありません" -#: users/forms/profile.py:170 users/models/user.py:786 +#: users/forms/profile.py:173 users/models/user.py:786 msgid "Public key" msgstr "公開キー" @@ -6914,11 +6921,11 @@ msgstr "メールアドレス" msgid "Mobile number" msgstr "携帯番号" -#: users/templates/users/forgot_password.html:68 +#: users/templates/users/forgot_password.html:69 msgid "Send" msgstr "送信" -#: users/templates/users/forgot_password.html:72 +#: users/templates/users/forgot_password.html:73 #: users/templates/users/forgot_password_previewing.html:30 msgid "Submit" msgstr "送信" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 217772011..d7aaf420f 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-25 11:30+0800\n" +"POT-Creation-Date: 2023-05-26 17:11+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -70,7 +70,7 @@ msgid "Collected" msgstr "收集" #: accounts/const/account.py:21 accounts/serializers/account/account.py:26 -#: settings/serializers/auth/sms.py:75 +#: settings/serializers/auth/sms.py:76 msgid "Template" msgstr "模板" @@ -430,7 +430,7 @@ msgstr "最后登录日期" #: authentication/forms.py:27 authentication/models/temp_token.py:9 #: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_oauth_bind.html:9 -#: users/forms/profile.py:32 users/forms/profile.py:112 +#: users/forms/profile.py:32 users/forms/profile.py:115 #: users/models/user.py:751 users/templates/users/_msg_user_created.html:12 #: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" @@ -460,7 +460,7 @@ msgstr "触发方式" #: accounts/models/automations/push_account.py:16 acls/models/base.py:41 #: acls/serializers/base.py:57 assets/models/cmd_filter.py:81 #: audits/models.py:65 audits/serializers.py:82 -#: authentication/serializers/connect_token_secret.py:108 +#: authentication/serializers/connect_token_secret.py:116 #: authentication/templates/authentication/_access_key_modal.html:34 msgid "Action" msgstr "动作" @@ -482,7 +482,7 @@ msgstr "账号验证" #: assets/models/platform.py:13 assets/models/platform.py:81 #: assets/serializers/asset/common.py:145 assets/serializers/platform.py:92 #: assets/serializers/platform.py:192 -#: authentication/serializers/connect_token_secret.py:102 ops/mixin.py:21 +#: authentication/serializers/connect_token_secret.py:110 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 #: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29 @@ -503,7 +503,7 @@ msgstr "特权账号" #: accounts/models/base.py:40 assets/models/asset/common.py:156 #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 -#: authentication/serializers/connect_token_secret.py:106 +#: authentication/serializers/connect_token_secret.py:114 #: terminal/models/applet/applet.py:32 users/serializers/user.py:170 msgid "Is active" msgstr "激活" @@ -570,7 +570,7 @@ msgstr "类别" #: assets/models/cmd_filter.py:74 assets/models/platform.py:83 #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 #: assets/serializers/platform.py:109 audits/serializers.py:48 -#: authentication/serializers/connect_token_secret.py:115 ops/models/job.py:103 +#: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:31 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 @@ -625,7 +625,7 @@ msgid "Account has exist" msgstr "账号已存在" #: accounts/serializers/account/account.py:417 -#: authentication/serializers/connect_token_secret.py:146 +#: authentication/serializers/connect_token_secret.py:154 #: authentication/templates/authentication/_access_key_modal.html:30 #: perms/models/perm_node.py:21 users/serializers/group.py:33 msgid "ID" @@ -800,7 +800,7 @@ msgstr "优先级可选范围为 1-100 (数值越小越优先)" #: acls/models/base.py:42 acls/serializers/base.py:79 #: acls/serializers/login_acl.py:23 assets/models/cmd_filter.py:86 -#: authentication/serializers/connect_token_secret.py:80 +#: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "审批人" @@ -843,7 +843,7 @@ msgstr "忽略大小写" #: acls/models/command_acl.py:33 acls/models/command_acl.py:96 #: acls/serializers/command_acl.py:28 -#: authentication/serializers/connect_token_secret.py:77 +#: authentication/serializers/connect_token_secret.py:85 msgid "Command group" msgstr "命令组" @@ -929,7 +929,7 @@ msgstr "" #: authentication/templates/authentication/_msg_oauth_bind.html:12 #: authentication/templates/authentication/_msg_rest_password_success.html:8 #: authentication/templates/authentication/_msg_rest_public_key_success.html:8 -#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:62 +#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:67 msgid "IP" msgstr "IP" @@ -1029,7 +1029,7 @@ msgid "Gather facts" msgstr "收集资产信息" #: assets/const/category.py:10 assets/models/asset/host.py:8 -#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 +#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:68 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 #: xpack/plugins/cloud/serializers/account_attrs.py:72 msgid "Host" @@ -1053,7 +1053,7 @@ msgstr "云服务" msgid "Web" msgstr "Web" -#: assets/const/category.py:15 +#: assets/const/category.py:15 common/sdk/sms/endpoint.py:20 msgid "Custom type" msgstr "自定义" @@ -1128,7 +1128,7 @@ msgstr "SSH公钥" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:37 terminal/models/applet/applet.py:218 +#: terminal/models/applet/applet.py:37 terminal/models/applet/applet.py:222 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 @@ -1177,7 +1177,7 @@ msgid "Username same with user" msgstr "用户名与用户相同" #: assets/models/_user.py:52 authentication/models/connection_token.py:39 -#: authentication/serializers/connect_token_secret.py:103 +#: authentication/serializers/connect_token_secret.py:111 #: terminal/models/applet/applet.py:34 terminal/serializers/session.py:20 #: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 msgid "Protocol" @@ -1232,7 +1232,7 @@ msgid "Cloud" msgstr "云服务" #: assets/models/asset/common.py:92 assets/models/platform.py:14 -#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 +#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:69 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "端口" @@ -1242,14 +1242,14 @@ msgid "Address" msgstr "地址" #: assets/models/asset/common.py:151 assets/models/platform.py:112 -#: authentication/serializers/connect_token_secret.py:107 +#: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 #: xpack/plugins/cloud/serializers/account_attrs.py:196 msgid "Platform" msgstr "系统平台" #: assets/models/asset/common.py:153 assets/models/domain.py:21 -#: authentication/serializers/connect_token_secret.py:125 +#: authentication/serializers/connect_token_secret.py:133 #: perms/serializers/user_permission.py:29 msgid "Domain" msgstr "网域" @@ -1330,6 +1330,7 @@ msgid "Accounts" msgstr "账号管理" #: assets/models/automations/base.py:22 ops/models/job.py:187 +#: settings/serializers/auth/sms.py:100 msgid "Parameters" msgstr "参数" @@ -1343,7 +1344,7 @@ msgstr "资产自动化任务" #: assets/models/automations/base.py:113 audits/models.py:177 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:217 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:221 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 @@ -1427,7 +1428,7 @@ msgstr "系统" #: assets/models/label.py:19 assets/models/node.py:557 #: assets/serializers/cagegory.py:7 assets/serializers/cagegory.py:14 #: authentication/models/connection_token.py:27 -#: authentication/serializers/connect_token_secret.py:114 +#: authentication/serializers/connect_token_secret.py:122 #: common/serializers/common.py:86 settings/models.py:34 msgid "Value" msgstr "值" @@ -1435,7 +1436,7 @@ msgstr "值" #: assets/models/label.py:40 assets/serializers/asset/common.py:123 #: assets/serializers/cagegory.py:6 assets/serializers/cagegory.py:13 #: assets/serializers/platform.py:93 -#: authentication/serializers/connect_token_secret.py:113 +#: authentication/serializers/connect_token_secret.py:121 #: common/serializers/common.py:85 perms/serializers/user_permission.py:28 #: settings/serializers/sms.py:7 msgid "Label" @@ -1482,7 +1483,7 @@ msgstr "必须的" msgid "Public" msgstr "开放的" -#: assets/models/platform.py:19 settings/serializers/settings.py:65 +#: assets/models/platform.py:19 settings/serializers/settings.py:67 #: users/templates/users/reset_password.html:29 msgid "Setting" msgstr "设置" @@ -1599,7 +1600,7 @@ msgstr "资产中批量更新平台,不符合平台类型跳过的资产" #: assets/serializers/asset/common.py:124 assets/serializers/platform.py:111 #: authentication/serializers/connect_token_secret.py:29 -#: authentication/serializers/connect_token_secret.py:64 +#: authentication/serializers/connect_token_secret.py:72 #: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 msgid "Protocols" msgstr "协议组" @@ -1678,7 +1679,7 @@ msgid "Disk total" msgstr "硬盘大小" #: assets/serializers/asset/info/gathered.py:16 -#: authentication/serializers/connect_token_secret.py:104 +#: authentication/serializers/connect_token_secret.py:112 msgid "OS" msgstr "操作系统" @@ -1850,7 +1851,7 @@ msgstr "删除目录" #: audits/const.py:14 audits/const.py:24 #: authentication/templates/authentication/_access_key_modal.html:65 -#: rbac/tree.py:230 +#: perms/const.py:17 rbac/tree.py:230 msgid "Delete" msgstr "删除" @@ -2105,7 +2106,9 @@ msgid "Permission expired" msgstr "授权已过期" #: authentication/api/connection_token.py:320 -msgid "ACL action is reject" +#, fuzzy +#| msgid "ACL action is reject" +msgid "ACL action is reject: {}({})" msgstr "ACL 动作是拒绝" #: authentication/api/connection_token.py:324 @@ -2144,7 +2147,7 @@ msgstr "忘记密码" msgid "Authentication" msgstr "认证" -#: authentication/backends/custom.py:58 +#: authentication/backends/custom.py:59 #: authentication/backends/oauth2/backends.py:170 msgid "User invalid, disabled or expired" msgstr "用户无效,已禁用或已过期" @@ -2310,19 +2313,19 @@ msgstr "等待登录复核处理" msgid "Login confirm ticket was {}" msgstr "登录复核: {}" -#: authentication/errors/failed.py:146 +#: authentication/errors/failed.py:145 msgid "Current IP and Time period is not allowed" msgstr "当前 IP 和时间段不被允许登录" -#: authentication/errors/failed.py:151 +#: authentication/errors/failed.py:150 msgid "Please enter MFA code" msgstr "请输入 MFA 验证码" -#: authentication/errors/failed.py:156 +#: authentication/errors/failed.py:155 msgid "Please enter SMS code" msgstr "请输入短信验证码" -#: authentication/errors/failed.py:161 users/exceptions.py:15 +#: authentication/errors/failed.py:160 users/exceptions.py:15 msgid "Phone not set" msgstr "手机号没有设置" @@ -2439,8 +2442,8 @@ msgstr "短信验证码校验失败" #: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16 #: authentication/serializers/password_mfa.py:24 -#: settings/serializers/auth/sms.py:27 users/forms/profile.py:103 -#: users/forms/profile.py:106 users/templates/users/forgot_password.html:111 +#: settings/serializers/auth/sms.py:28 users/forms/profile.py:104 +#: users/forms/profile.py:109 users/templates/users/forgot_password.html:112 #: users/views/profile/reset.py:79 msgid "SMS" msgstr "短信" @@ -2457,7 +2460,7 @@ msgstr "设置手机号码启用" msgid "Clear phone number to disable" msgstr "清空手机号码禁用" -#: authentication/middleware.py:93 settings/utils/ldap.py:652 +#: authentication/middleware.py:93 settings/utils/ldap.py:657 msgid "Authentication failed (before login check failed): {}" msgstr "认证失败(登录前检查失败): {}" @@ -2572,19 +2575,19 @@ msgstr "异地登录提醒" msgid "binding reminder" msgstr "绑定提醒" -#: authentication/serializers/connect_token_secret.py:105 +#: authentication/serializers/connect_token_secret.py:113 msgid "Is builtin" msgstr "内置的" -#: authentication/serializers/connect_token_secret.py:109 +#: authentication/serializers/connect_token_secret.py:117 msgid "Options" msgstr "选项" -#: authentication/serializers/connect_token_secret.py:116 +#: authentication/serializers/connect_token_secret.py:124 msgid "Component" msgstr "组件" -#: authentication/serializers/connect_token_secret.py:127 +#: authentication/serializers/connect_token_secret.py:135 msgid "Expired now" msgstr "立刻过期" @@ -2618,14 +2621,14 @@ msgstr "" #: authentication/serializers/password_mfa.py:24 #: notifications/backends/__init__.py:10 settings/serializers/email.py:19 #: settings/serializers/email.py:50 users/forms/profile.py:102 -#: users/forms/profile.py:106 users/models/user.py:755 -#: users/templates/users/forgot_password.html:116 +#: users/forms/profile.py:109 users/models/user.py:755 +#: users/templates/users/forgot_password.html:117 #: users/views/profile/reset.py:73 msgid "Email" msgstr "邮箱" #: authentication/serializers/password_mfa.py:29 -#: users/templates/users/forgot_password.html:107 +#: users/templates/users/forgot_password.html:108 msgid "The {} cannot be empty" msgstr "{} 不能为空" @@ -2708,7 +2711,7 @@ msgstr "代码错误" #: authentication/templates/authentication/_msg_reset_password_code.html:9 #: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_public_key_success.html:2 -#: jumpserver/conf.py:419 +#: jumpserver/conf.py:423 #: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3 #: tickets/templates/tickets/approve_check_password.html:33 @@ -2763,7 +2766,7 @@ msgstr "重新申请" #: authentication/templates/authentication/_msg_reset_password_code.html:12 #: terminal/models/session/sharing.py:25 terminal/models/session/sharing.py:83 -#: users/forms/profile.py:104 users/templates/users/forgot_password.html:65 +#: users/forms/profile.py:107 users/templates/users/forgot_password.html:66 msgid "Verify code" msgstr "验证码" @@ -3058,26 +3061,26 @@ msgstr "编码数据为 text" msgid "Encrypt field using Secret Key" msgstr "加密的字段" -#: common/db/fields.py:534 +#: common/db/fields.py:535 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" -#: common/db/fields.py:541 +#: common/db/fields.py:542 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "无效类型,应为 all、ids 或 attrs" -#: common/db/fields.py:544 +#: common/db/fields.py:545 msgid "Invalid ids for ids, should be a list" msgstr "无效的ID,应为列表" -#: common/db/fields.py:547 common/db/fields.py:550 +#: common/db/fields.py:548 common/db/fields.py:551 msgid "Invalid attrs, should be a list of dict" msgstr "无效的属性,应为dict列表" -#: common/db/fields.py:552 +#: common/db/fields.py:553 msgid "Invalid attrs, should be has name and value" msgstr "无效属性,应具有名称和值" @@ -3196,11 +3199,11 @@ msgstr "华为云" msgid "CMPP v2.0" msgstr "CMPP v2.0" -#: common/sdk/sms/endpoint.py:30 +#: common/sdk/sms/endpoint.py:31 msgid "SMS provider not support: {}" msgstr "短信服务商不支持:{}" -#: common/sdk/sms/endpoint.py:51 +#: common/sdk/sms/endpoint.py:53 msgid "SMS verification code signature or template invalid" msgstr "短信验证码签名或模版无效" @@ -3293,11 +3296,11 @@ msgstr "导出搜素: %s" msgid "User %s view/export secret" msgstr "用户 %s 查看/导出 了密码" -#: jumpserver/conf.py:418 +#: jumpserver/conf.py:422 msgid "Create account successfully" msgstr "创建账号成功" -#: jumpserver/conf.py:420 +#: jumpserver/conf.py:424 msgid "Your account has been created successfully" msgstr "你的账号已创建成功" @@ -3783,11 +3786,11 @@ msgstr "复制" msgid "Paste" msgstr "粘贴" -#: perms/const.py:26 +#: perms/const.py:27 msgid "Transfer" msgstr "文件传输" -#: perms/const.py:27 +#: perms/const.py:28 msgid "Clipboard" msgstr "剪贴板" @@ -4048,7 +4051,7 @@ msgid "My assets" msgstr "我的资产" #: rbac/tree.py:56 terminal/models/applet/applet.py:44 -#: terminal/models/applet/applet.py:214 terminal/models/applet/host.py:28 +#: terminal/models/applet/applet.py:218 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "远程应用" @@ -4070,7 +4073,7 @@ msgid "View permission tree" msgstr "查看授权树" #: settings/api/dingtalk.py:31 settings/api/feishu.py:36 -#: settings/api/sms.py:148 settings/api/wecom.py:37 +#: settings/api/sms.py:155 settings/api/wecom.py:37 msgid "Test success" msgstr "测试成功" @@ -4078,31 +4081,31 @@ msgstr "测试成功" msgid "Test mail sent to {}, please check" msgstr "邮件已经发送{}, 请检查" -#: settings/api/ldap.py:166 +#: settings/api/ldap.py:173 msgid "Synchronization start, please wait." msgstr "同步开始,请稍等" -#: settings/api/ldap.py:170 +#: settings/api/ldap.py:177 msgid "Synchronization is running, please wait." msgstr "同步正在运行,请稍等" -#: settings/api/ldap.py:175 +#: settings/api/ldap.py:182 msgid "Synchronization error: {}" msgstr "同步错误: {}" -#: settings/api/ldap.py:213 +#: settings/api/ldap.py:220 msgid "Get ldap users is None" msgstr "获取 LDAP 用户为 None" -#: settings/api/ldap.py:222 +#: settings/api/ldap.py:230 msgid "Imported {} users successfully (Organization: {})" msgstr "成功导入 {} 个用户 ( 组织: {} )" -#: settings/api/sms.py:130 +#: settings/api/sms.py:137 msgid "Invalid SMS platform" msgstr "无效的短信平台" -#: settings/api/sms.py:136 +#: settings/api/sms.py:143 msgid "test_phone is required" msgstr "测试手机号 该字段是必填项。" @@ -4467,54 +4470,54 @@ msgstr "SP 密钥" msgid "SP cert" msgstr "SP 证书" -#: settings/serializers/auth/sms.py:15 +#: settings/serializers/auth/sms.py:16 msgid "Enable SMS" msgstr "启用 SMS" -#: settings/serializers/auth/sms.py:17 +#: settings/serializers/auth/sms.py:18 msgid "SMS provider / Protocol" msgstr "短信服务商 / 协议" -#: settings/serializers/auth/sms.py:22 settings/serializers/auth/sms.py:45 -#: settings/serializers/auth/sms.py:53 settings/serializers/auth/sms.py:62 -#: settings/serializers/auth/sms.py:73 settings/serializers/email.py:69 +#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:46 +#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 +#: settings/serializers/auth/sms.py:74 settings/serializers/email.py:69 msgid "Signature" msgstr "签名" -#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:46 -#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 +#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:47 +#: settings/serializers/auth/sms.py:55 settings/serializers/auth/sms.py:64 msgid "Template code" msgstr "模板" -#: settings/serializers/auth/sms.py:31 +#: settings/serializers/auth/sms.py:32 msgid "Test phone" msgstr "测试手机号" -#: settings/serializers/auth/sms.py:60 +#: settings/serializers/auth/sms.py:61 msgid "App Access Address" msgstr "应用地址" -#: settings/serializers/auth/sms.py:61 +#: settings/serializers/auth/sms.py:62 msgid "Signature channel number" msgstr "签名通道号" -#: settings/serializers/auth/sms.py:69 +#: settings/serializers/auth/sms.py:70 msgid "Enterprise code(SP id)" msgstr "企业代码(SP id)" -#: settings/serializers/auth/sms.py:70 +#: settings/serializers/auth/sms.py:71 msgid "Shared secret(Shared secret)" msgstr "共享密码(Shared secret)" -#: settings/serializers/auth/sms.py:71 +#: settings/serializers/auth/sms.py:72 msgid "Original number(Src id)" msgstr "原始号码(Src id)" -#: settings/serializers/auth/sms.py:72 +#: settings/serializers/auth/sms.py:73 msgid "Business type(Service id)" msgstr "业务类型(Service id)" -#: settings/serializers/auth/sms.py:76 +#: settings/serializers/auth/sms.py:77 #, python-brace-format msgid "" "Template need contain {code} and Signature + template length does not exceed " @@ -4524,12 +4527,12 @@ msgstr "" "模板需要包含 {code},并且模板+签名长度不能超过67个字。例如, 您的验证码是 " "{code}, 有效期为5分钟。请不要泄露给其他人。" -#: settings/serializers/auth/sms.py:85 +#: settings/serializers/auth/sms.py:86 #, python-brace-format msgid "The template needs to contain {code}" msgstr "模板需要包含 {code}" -#: settings/serializers/auth/sms.py:88 +#: settings/serializers/auth/sms.py:89 msgid "Signature + Template must not exceed 65 words" msgstr "模板+签名不能超过65个字" @@ -5071,7 +5074,7 @@ msgstr "" "根据登录 IP 是否所属常用登录城市进行判断,若账号在非常用城市登录,会发送异地" "登录提醒" -#: settings/serializers/settings.py:69 +#: settings/serializers/settings.py:71 #, python-format msgid "[%s] %s" msgstr "" @@ -5148,100 +5151,100 @@ msgstr "导入 LDAP 用户" msgid "Periodic import ldap user" msgstr "周期导入 LDAP 用户" -#: settings/utils/ldap.py:467 +#: settings/utils/ldap.py:472 msgid "ldap:// or ldaps:// protocol is used." msgstr "使用 ldap:// 或 ldaps:// 协议" -#: settings/utils/ldap.py:478 +#: settings/utils/ldap.py:483 msgid "Host or port is disconnected: {}" msgstr "主机或端口不可连接: {}" -#: settings/utils/ldap.py:480 +#: settings/utils/ldap.py:485 msgid "The port is not the port of the LDAP service: {}" msgstr "端口不是LDAP服务端口: {}" -#: settings/utils/ldap.py:482 +#: settings/utils/ldap.py:487 msgid "Please add certificate: {}" msgstr "请添加证书" -#: settings/utils/ldap.py:486 settings/utils/ldap.py:513 -#: settings/utils/ldap.py:543 settings/utils/ldap.py:571 +#: settings/utils/ldap.py:491 settings/utils/ldap.py:518 +#: settings/utils/ldap.py:548 settings/utils/ldap.py:576 msgid "Unknown error: {}" msgstr "未知错误: {}" -#: settings/utils/ldap.py:500 +#: settings/utils/ldap.py:505 msgid "Bind DN or Password incorrect" msgstr "绑定DN或密码错误" -#: settings/utils/ldap.py:507 +#: settings/utils/ldap.py:512 msgid "Please enter Bind DN: {}" msgstr "请输入绑定DN: {}" -#: settings/utils/ldap.py:509 +#: settings/utils/ldap.py:514 msgid "Please enter Password: {}" msgstr "请输入密码: {}" -#: settings/utils/ldap.py:511 +#: settings/utils/ldap.py:516 msgid "Please enter correct Bind DN and Password: {}" msgstr "请输入正确的绑定DN和密码: {}" -#: settings/utils/ldap.py:529 +#: settings/utils/ldap.py:534 msgid "Invalid User OU or User search filter: {}" msgstr "不合法的用户OU或用户过滤器: {}" -#: settings/utils/ldap.py:560 +#: settings/utils/ldap.py:565 msgid "LDAP User attr map not include: {}" msgstr "LDAP属性映射没有包含: {}" -#: settings/utils/ldap.py:567 +#: settings/utils/ldap.py:572 msgid "LDAP User attr map is not dict" msgstr "LDAP属性映射不合法" -#: settings/utils/ldap.py:586 +#: settings/utils/ldap.py:591 msgid "LDAP authentication is not enabled" msgstr "LDAP认证没有启用" -#: settings/utils/ldap.py:604 +#: settings/utils/ldap.py:609 msgid "Error (Invalid LDAP server): {}" msgstr "错误 (不合法的LDAP服务器地址): {}" -#: settings/utils/ldap.py:606 +#: settings/utils/ldap.py:611 msgid "Error (Invalid Bind DN): {}" msgstr "错误(不合法的绑定DN): {}" -#: settings/utils/ldap.py:608 +#: settings/utils/ldap.py:613 msgid "Error (Invalid LDAP User attr map): {}" msgstr "错误(不合法的LDAP属性映射): {}" -#: settings/utils/ldap.py:610 +#: settings/utils/ldap.py:615 msgid "Error (Invalid User OU or User search filter): {}" msgstr "错误(不合法的用户OU或用户过滤器): {}" -#: settings/utils/ldap.py:612 +#: settings/utils/ldap.py:617 msgid "Error (Not enabled LDAP authentication): {}" msgstr "错误(没有启用LDAP认证): {}" -#: settings/utils/ldap.py:614 +#: settings/utils/ldap.py:619 msgid "Error (Unknown): {}" msgstr "错误(未知): {}" -#: settings/utils/ldap.py:617 +#: settings/utils/ldap.py:622 msgid "Succeed: Match {} s user" msgstr "成功匹配 {} 个用户" -#: settings/utils/ldap.py:650 +#: settings/utils/ldap.py:655 msgid "Authentication failed (configuration incorrect): {}" msgstr "认证失败(配置错误): {}" -#: settings/utils/ldap.py:654 +#: settings/utils/ldap.py:659 msgid "Authentication failed (username or password incorrect): {}" msgstr "认证失败 (用户名或密码不正确): {}" -#: settings/utils/ldap.py:656 +#: settings/utils/ldap.py:661 msgid "Authentication failed (Unknown): {}" msgstr "认证失败: (未知): {}" -#: settings/utils/ldap.py:659 +#: settings/utils/ldap.py:664 msgid "Authentication success: {}" msgstr "认证成功: {}" @@ -5387,12 +5390,12 @@ msgid "Send verification code" msgstr "发送验证码" #: templates/_mfa_login_field.html:106 -#: users/templates/users/forgot_password.html:129 +#: users/templates/users/forgot_password.html:130 msgid "Wait: " msgstr "等待:" #: templates/_mfa_login_field.html:116 -#: users/templates/users/forgot_password.html:145 +#: users/templates/users/forgot_password.html:146 msgid "The verification code has been sent" msgstr "验证码已发送" @@ -5596,19 +5599,19 @@ msgstr "主机" msgid "Applet pkg not valid, Missing file {}" msgstr "Applet pkg 无效,缺少文件 {}" -#: terminal/models/applet/applet.py:104 +#: terminal/models/applet/applet.py:105 msgid "Load platform.yml failed: {}" msgstr "" -#: terminal/models/applet/applet.py:107 +#: terminal/models/applet/applet.py:108 msgid "Only support custom platform" msgstr "" -#: terminal/models/applet/applet.py:112 +#: terminal/models/applet/applet.py:113 msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:216 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:220 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "宿主机" @@ -5666,7 +5669,7 @@ msgid "Redis port" msgstr "Redis 端口" #: terminal/models/component/endpoint.py:29 -#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:66 +#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:71 #: terminal/serializers/storage.py:38 terminal/serializers/storage.py:50 #: terminal/serializers/storage.py:80 terminal/serializers/storage.py:90 #: terminal/serializers/storage.py:98 @@ -5953,11 +5956,16 @@ msgstr "" "Oracle 代理服务器监听端口是动态的,每增加一个 Oracle 数据库实例,就会增加一个" "端口监听" -#: terminal/serializers/endpoint.py:36 -msgid "Visit IP/Host, if empty, use the current request instead" -msgstr "访问IP/Host,如果为空,则使用当前请求的地址代替" +#: terminal/serializers/endpoint.py:37 +msgid "" +"The host address accessed when connecting to assets, if it is empty, the " +"access address of the current browser will be used (the default endpoint " +"does not allow modification of the host)" +msgstr "" +"连接资产时访问的主机地址,如果为空则使用当前浏览器的访问地址(默认端点不允许" +"修改主机)" -#: terminal/serializers/endpoint.py:59 +#: terminal/serializers/endpoint.py:64 msgid "" "If asset IP addresses under different endpoints conflict, use asset labels" msgstr "如果不同端点下的资产 IP 有冲突,使用资产标签实现" @@ -6524,36 +6532,36 @@ msgstr "手机号码必须包含区号,例如 +86" msgid "Old password" msgstr "原来密码" -#: users/forms/profile.py:128 +#: users/forms/profile.py:131 msgid "Old password error" msgstr "原来密码错误" -#: users/forms/profile.py:138 +#: users/forms/profile.py:141 msgid "Automatically configure and download the SSH key" msgstr "自动配置并下载SSH密钥" -#: users/forms/profile.py:140 +#: users/forms/profile.py:143 msgid "ssh public key" msgstr "SSH公钥" -#: users/forms/profile.py:141 +#: users/forms/profile.py:144 msgid "ssh-rsa AAAA..." msgstr "ssh-rsa AAAA..." -#: users/forms/profile.py:142 +#: users/forms/profile.py:145 msgid "Paste your id_rsa.pub here." msgstr "复制你的公钥到这里" -#: users/forms/profile.py:155 +#: users/forms/profile.py:158 msgid "Public key should not be the same as your old one." msgstr "不能和原来的密钥相同" -#: users/forms/profile.py:159 users/serializers/profile.py:100 +#: users/forms/profile.py:162 users/serializers/profile.py:100 #: users/serializers/profile.py:183 users/serializers/profile.py:210 msgid "Not a valid ssh public key" msgstr "SSH密钥不合法" -#: users/forms/profile.py:170 users/models/user.py:786 +#: users/forms/profile.py:173 users/models/user.py:786 msgid "Public key" msgstr "SSH公钥" @@ -6818,11 +6826,11 @@ msgstr "邮箱账号" msgid "Mobile number" msgstr "手机号码" -#: users/templates/users/forgot_password.html:68 +#: users/templates/users/forgot_password.html:69 msgid "Send" msgstr "发送" -#: users/templates/users/forgot_password.html:72 +#: users/templates/users/forgot_password.html:73 #: users/templates/users/forgot_password_previewing.html:30 msgid "Submit" msgstr "提交" diff --git a/apps/terminal/serializers/endpoint.py b/apps/terminal/serializers/endpoint.py index 77ba1d0db..5058b292f 100644 --- a/apps/terminal/serializers/endpoint.py +++ b/apps/terminal/serializers/endpoint.py @@ -33,7 +33,12 @@ class EndpointSerializer(BulkModelSerializer): 'comment', 'date_created', 'date_updated', 'created_by' ] extra_kwargs = { - 'host': {'help_text': _('Visit IP/Host, if empty, use the current request instead')}, + 'host': {'help_text': _( + 'The host address accessed when connecting to assets, if it is empty, ' + 'the access address of the current browser will be used ' + '(the default endpoint does not allow modification of the host)' + ) + }, } def get_oracle_port(self, obj: Endpoint): From a1ed59d1169238c1a3323f8a5f5f31d6d534ef9f Mon Sep 17 00:00:00 2001 From: halo Date: Sat, 27 May 2023 11:53:00 +0800 Subject: [PATCH 047/153] =?UTF-8?q?perf:=20yaml=E6=96=87=E4=BB=B6=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E4=BD=BF=E7=94=A8utf-8=E7=BC=96=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/automations/methods.py | 2 +- apps/terminal/models/applet/applet.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/assets/automations/methods.py b/apps/assets/automations/methods.py index 332923534..8db474d7b 100644 --- a/apps/assets/automations/methods.py +++ b/apps/assets/automations/methods.py @@ -39,7 +39,7 @@ def get_platform_automation_methods(path): if not path.endswith('manifest.yml'): continue - with open(path, 'r') as f: + with open(path, 'r', encoding='utf8') as f: manifest = yaml_load_with_i18n(f) check_platform_method(manifest, path) manifest['dir'] = os.path.dirname(path) diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index a83ead302..8293668ed 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -84,7 +84,7 @@ class Applet(JMSBaseModel): if not os.path.exists(path): raise ValidationError({'error': _('Applet pkg not valid, Missing file {}').format(name)}) - with open(os.path.join(d, 'manifest.yml')) as f: + with open(os.path.join(d, 'manifest.yml'), encoding='utf8') as f: manifest = yaml_load_with_i18n(f) if not manifest.get('name', ''): @@ -99,7 +99,7 @@ class Applet(JMSBaseModel): if not os.path.exists(os.path.join(d, 'platform.yml')): return try: - with open(os.path.join(d, 'platform.yml')) as f: + with open(os.path.join(d, 'platform.yml'), encoding='utf8') as f: data = yaml_load_with_i18n(f) except Exception as e: raise ValidationError({'error': _('Load platform.yml failed: {}').format(e)}) From 3c568510cf49b91f27d5c80e4e10a681ca7b1039 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 04:17:07 +0000 Subject: [PATCH 048/153] chore(deps): bump requests from 2.28.0 to 2.31.0 in /requirements Bumps [requests](https://github.com/psf/requests) from 2.28.0 to 2.31.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.28.0...v2.31.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index a8ed07b01..fc4d495b8 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -36,7 +36,7 @@ pyotp==2.6.0 PyNaCl==1.5.0 python-dateutil==2.8.2 PyYAML==6.0 -requests==2.28.0 +requests==2.31.0 jms-storage==0.0.44 simplejson==3.17.6 six==1.16.0 From b0b174bb2a2265447ddc28efd589c8dac0d4f1f6 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 29 May 2023 15:04:21 +0800 Subject: [PATCH 049/153] =?UTF-8?q?perf:=20connection=20token=20=E7=9A=84?= =?UTF-8?q?=20account=20=E5=A2=9E=E5=8A=A0=20asset=20=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/models/connection_token.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/authentication/models/connection_token.py b/apps/authentication/models/connection_token.py index 3604d49e5..6b8cd4d8e 100644 --- a/apps/authentication/models/connection_token.py +++ b/apps/authentication/models/connection_token.py @@ -215,7 +215,8 @@ class ConnectionToken(JMSOrgBaseModel): 'secret_type': 'password', 'secret': self.input_secret, 'su_from': None, - 'org_id': self.asset.org_id + 'org_id': self.asset.org_id, + 'asset': self.asset } else: data = { @@ -225,7 +226,8 @@ class ConnectionToken(JMSOrgBaseModel): 'secret': account.secret or self.input_secret, 'su_from': account.su_from, 'org_id': account.org_id, - 'privileged': account.privileged + 'privileged': account.privileged, + 'asset': self.asset } return Account(**data) From ac3415d95cc847b649b8d98eb362c8925b11d837 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 29 May 2023 15:09:00 +0800 Subject: [PATCH 050/153] =?UTF-8?q?perf:=20=E5=AE=8C=E5=96=84=E8=BF=9C?= =?UTF-8?q?=E7=A8=8B=E5=BA=94=E7=94=A8=20chrome=20=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/applets/chrome/app.py | 20 +++++++++++++++++++- apps/terminal/applets/chrome/manifest.yml | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/terminal/applets/chrome/app.py b/apps/terminal/applets/chrome/app.py index c92a3ff55..c6a8a25c8 100644 --- a/apps/terminal/applets/chrome/app.py +++ b/apps/terminal/applets/chrome/app.py @@ -1,3 +1,5 @@ +import os +import tempfile import time from enum import Enum from subprocess import CREATE_NO_WINDOW @@ -184,10 +186,16 @@ class WebAPP(object): return True +def load_extensions(): + extensions_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'extensions') + extension_names = os.listdir(extensions_root) + extension_paths = [os.path.join(extensions_root, name) for name in extension_names] + return extension_paths + + def default_chrome_driver_options(): options = webdriver.ChromeOptions() options.add_argument("--start-maximized") - options.add_argument("--new-window") # 忽略证书错误相关 options.add_argument('--ignore-ssl-errors') @@ -195,6 +203,10 @@ def default_chrome_driver_options(): options.add_argument('--ignore-certificate-errors-spki-list') options.add_argument('--allow-running-insecure-content') + # 加载 extensions + extension_paths = load_extensions() + for extension_path in extension_paths: + options.add_argument('--load-extension={}'.format(extension_path)) # 禁用开发者工具 options.add_argument("--disable-dev-tools") # 禁用 密码管理器弹窗 @@ -214,8 +226,10 @@ class AppletApplication(BaseApplication): self.driver = None self.app = WebAPP(app_name=self.app_name, user=self.user, account=self.account, asset=self.asset, platform=self.platform) + self._tmp_user_dir = tempfile.TemporaryDirectory() self._chrome_options = default_chrome_driver_options() self._chrome_options.add_argument("--app={}".format(self.asset.address)) + self._chrome_options.add_argument("--user-data-dir={}".format(self._tmp_user_dir.name)) def run(self): service = Service() @@ -253,3 +267,7 @@ class AppletApplication(BaseApplication): self.driver.quit() except Exception as e: print(e) + try: + self._tmp_user_dir.cleanup() + except Exception as e: + print(e) diff --git a/apps/terminal/applets/chrome/manifest.yml b/apps/terminal/applets/chrome/manifest.yml index 1662a0422..523f9f3a1 100644 --- a/apps/terminal/applets/chrome/manifest.yml +++ b/apps/terminal/applets/chrome/manifest.yml @@ -1,6 +1,6 @@ name: chrome display_name: "{{ 'Chrome Browser' | trans }}" -version: 0.2 +version: 0.3 comment: "{{ 'Chrome Browser Open URL Page Address' | trans }}" author: JumpServer Team exec_type: python From fd7e821f111243dc326f9180d667b011170678b8 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Mon, 29 May 2023 15:30:06 +0800 Subject: [PATCH 051/153] =?UTF-8?q?feat:=20=E7=94=A8=E6=88=B7=E7=BB=84?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E6=89=80=E6=9C=89=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/users/api/group.py | 15 ++++++++++++++- apps/users/filters.py | 9 +++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/apps/users/api/group.py b/apps/users/api/group.py index 1107a7eb8..a87f964e9 100644 --- a/apps/users/api/group.py +++ b/apps/users/api/group.py @@ -1,8 +1,11 @@ # -*- coding: utf-8 -*- # +from rest_framework import status +from rest_framework.decorators import action +from rest_framework.response import Response from orgs.mixins.api import OrgBulkModelViewSet -from ..models import UserGroup +from ..models import UserGroup, User from ..serializers import UserGroupSerializer __all__ = ['UserGroupViewSet'] @@ -14,3 +17,13 @@ class UserGroupViewSet(OrgBulkModelViewSet): search_fields = filterset_fields serializer_class = UserGroupSerializer ordering = ('name',) + rbac_perms = ( + ("add_all_users", "users.change_usergroup"), + ) + + @action(methods=['post'], detail=True, url_path='add-all-users') + def add_all_users(self, request, *args, **kwargs): + instance = self.get_object() + users = User.get_org_users().exclude(groups__id=instance.id) + instance.users.add(*users) + return Response(status=status.HTTP_200_OK) diff --git a/apps/users/filters.py b/apps/users/filters.py index 1bcc1c683..9715a14af 100644 --- a/apps/users/filters.py +++ b/apps/users/filters.py @@ -11,12 +11,17 @@ class UserFilter(BaseFilterSet): system_roles = filters.CharFilter(method='filter_system_roles') org_roles = filters.CharFilter(method='filter_org_roles') groups = filters.CharFilter(field_name="groups__name", lookup_expr='exact') + group_id = filters.CharFilter(field_name="groups__id", lookup_expr='exact') + exclude_group_id = filters.CharFilter( + field_name="groups__id", lookup_expr='exact', exclude=True + ) class Meta: model = User fields = ( - 'id', 'username', 'email', 'name', 'groups', 'source', - 'org_roles', 'system_roles', 'is_active', + 'id', 'username', 'email', 'name', + 'groups', 'group_id', 'exclude_group_id', + 'source', 'org_roles', 'system_roles', 'is_active', ) @staticmethod From 0901b95ce056ab326e19bcd3b4cc89b3fc8049f4 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 29 May 2023 18:23:26 +0800 Subject: [PATCH 052/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E4=B8=AD=E5=8A=A8=E4=BD=9C=E7=9A=84=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 70 ++++++++++++++--------- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 83 +++++++++++++++++++--------- apps/perms/const.py | 12 ++-- 5 files changed, 113 insertions(+), 60 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 2d93e8efc..40198acca 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc0862f2a9091f2e06602d6db26cfc9cc7a6b067012ec56b41ebc1e26d5072e9 -size 142045 +oid sha256:40f43cc773ecf5da0637ba302144e1b81ee837a835bda4a6c2cb1eedf5ccc5f1 +size 141722 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 6164e3b1c..b5adea7e0 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-26 17:11+0800\n" +"POT-Creation-Date: 2023-05-29 18:19+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -833,7 +833,7 @@ msgid "Regex" msgstr "正規情報" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 msgid "Content" msgstr "コンテンツ" @@ -1251,7 +1251,7 @@ msgstr "アドレス" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:196 +#: xpack/plugins/cloud/serializers/account_attrs.py:187 msgid "Platform" msgstr "プラットフォーム" @@ -2572,7 +2572,7 @@ msgstr "ユーザーなしまたは期限切れのユーザー" msgid "No asset or inactive asset" msgstr "アセットがないか、有効化されていないアセット" -#: authentication/models/connection_token.py:262 +#: authentication/models/connection_token.py:264 msgid "Super connection token" msgstr "スーパー接続トークン" @@ -3819,6 +3819,10 @@ msgstr "組織キャッシュを更新する" msgid "App permissions" msgstr "アプリの権限" +#: perms/const.py:12 +msgid "All protocols" +msgstr "すべてのプロトコル" + #: perms/const.py:15 msgid "Copy" msgstr "コピー" @@ -4606,7 +4610,7 @@ msgid "SSO auth key TTL" msgstr "Token有効期間" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Unit: second" msgstr "単位: 秒" @@ -7248,7 +7252,7 @@ msgstr "クラウドアカウント" msgid "Test cloud account" msgstr "クラウドアカウントのテスト" -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 msgid "Regions" msgstr "リージョン" @@ -7256,15 +7260,15 @@ msgstr "リージョン" msgid "Hostname strategy" msgstr "ホスト名戦略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 msgid "IP network segment group" msgstr "IPネットワークセグメントグループ" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 msgid "Sync IP type" msgstr "同期IPタイプ" -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 msgid "Always update" msgstr "常に更新" @@ -7549,11 +7553,15 @@ msgstr "ファイルはJSON形式です。" msgid "IP address invalid `{}`, {}" msgstr "IPアドレスが無効: '{}', {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:172 -msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +#: xpack/plugins/cloud/serializers/account_attrs.py:162 +#, fuzzy +#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgid "" +"Format for comma-delimited string,Such as: 192.168.1.0/24, " +"10.0.0.0-10.0.0.255" msgstr "例:192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/account_attrs.py:175 +#: xpack/plugins/cloud/serializers/account_attrs.py:166 msgid "" "The port is used to detect the validity of the IP address. When the " "synchronization task is executed, only the valid IP address will be " @@ -7563,29 +7571,36 @@ msgstr "" "実行されると、有効な IP アドレスのみが同期されます。
ポートが0の場合、す" "べてのIPアドレスが有効です。" -#: xpack/plugins/cloud/serializers/account_attrs.py:183 +#: xpack/plugins/cloud/serializers/account_attrs.py:174 msgid "Hostname prefix" msgstr "ホスト名プレフィックス" -#: xpack/plugins/cloud/serializers/account_attrs.py:186 +#: xpack/plugins/cloud/serializers/account_attrs.py:177 msgid "IP segment" msgstr "IP セグメント" -#: xpack/plugins/cloud/serializers/account_attrs.py:190 +#: xpack/plugins/cloud/serializers/account_attrs.py:181 msgid "Test port" msgstr "テストポート" -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Test timeout" msgstr "テストタイムアウト" #: xpack/plugins/cloud/serializers/task.py:28 +#, fuzzy +#| msgid "" +#| "Only instances matching the IP range will be synced.
If the instance " +#| "contains multiple IP addresses, the first IP address that matches will be " +#| "used as the IP for the created asset.
The default value of * means " +#| "sync all instances and randomly match IP addresses.
Such as: " +#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" msgid "" "Only instances matching the IP range will be synced.
If the instance " "contains multiple IP addresses, the first IP address that matches will be " "used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " -"10.1.1.1-10.1.1.20" +"all instances and randomly match IP addresses.
Format for comma-" +"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" msgstr "" "IP範囲に一致するインスタンスのみが同期されます。
インスタンスに複数のIPア" "ドレスが含まれている場合、一致する最初のIPアドレスが作成されたアセットのIPと" @@ -7593,11 +7608,11 @@ msgstr "" "ドレスをランダムに一致させることを意味します。
例:" "192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/cloud/serializers/task.py:34 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "History count" msgstr "実行回数" -#: xpack/plugins/cloud/serializers/task.py:35 +#: xpack/plugins/cloud/serializers/task.py:36 msgid "Instance count" msgstr "インスタンス数" @@ -7657,26 +7672,31 @@ msgstr "ライセンスのインポートに成功" msgid "License is invalid" msgstr "ライセンスが無効です" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 msgid "License" msgstr "ライセンス" -#: xpack/plugins/license/models.py:80 +#: xpack/plugins/license/models.py:79 msgid "Standard edition" msgstr "標準版" -#: xpack/plugins/license/models.py:82 +#: xpack/plugins/license/models.py:81 msgid "Enterprise edition" msgstr "エンタープライズ版" -#: xpack/plugins/license/models.py:84 +#: xpack/plugins/license/models.py:83 msgid "Ultimate edition" msgstr "究極のエディション" -#: xpack/plugins/license/models.py:86 +#: xpack/plugins/license/models.py:85 msgid "Community edition" msgstr "コミュニティ版" +#, fuzzy +#~| msgid "Delete" +#~ msgid "Delete (SFTP)" +#~ msgstr "削除" + #~ msgid "User (username)" #~ msgstr "ユーザー (ユーザー名)" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index b986dcb5b..b0ab06a57 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1fabd2ec950291422c14b66af097bd73cce52bbc4b7913c1b9ea732eee855901 -size 116210 +oid sha256:4819183bc06cc0e33c741be855881d093e2936f99dadadde38bfdb8ef1cae4dd +size 115922 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index d7aaf420f..1905e5bdd 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-26 17:11+0800\n" +"POT-Creation-Date: 2023-05-29 18:19+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -829,7 +829,7 @@ msgid "Regex" msgstr "正则表达式" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 msgid "Content" msgstr "内容" @@ -1244,7 +1244,7 @@ msgstr "地址" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:196 +#: xpack/plugins/cloud/serializers/account_attrs.py:187 msgid "Platform" msgstr "系统平台" @@ -2547,7 +2547,7 @@ msgstr "没有用户或用户失效" msgid "No asset or inactive asset" msgstr "没有资产或资产未激活" -#: authentication/models/connection_token.py:262 +#: authentication/models/connection_token.py:264 msgid "Super connection token" msgstr "超级连接令牌" @@ -3778,6 +3778,10 @@ msgstr "刷新组织缓存" msgid "App permissions" msgstr "授权管理" +#: perms/const.py:12 +msgid "All protocols" +msgstr "所有协议" + #: perms/const.py:15 msgid "Copy" msgstr "复制" @@ -4562,7 +4566,7 @@ msgid "SSO auth key TTL" msgstr "令牌有效期" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Unit: second" msgstr "单位: 秒" @@ -7143,7 +7147,7 @@ msgstr "云账号" msgid "Test cloud account" msgstr "测试云账号" -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 msgid "Regions" msgstr "地域" @@ -7151,15 +7155,15 @@ msgstr "地域" msgid "Hostname strategy" msgstr "主机名策略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 msgid "IP network segment group" msgstr "IP网段组" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 msgid "Sync IP type" msgstr "同步IP类型" -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 msgid "Always update" msgstr "总是更新" @@ -7444,11 +7448,15 @@ msgstr "JSON 格式的文件" msgid "IP address invalid `{}`, {}" msgstr "IP 地址无效: `{}`, {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:172 -msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +#: xpack/plugins/cloud/serializers/account_attrs.py:162 +#, fuzzy +#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgid "" +"Format for comma-delimited string,Such as: 192.168.1.0/24, " +"10.0.0.0-10.0.0.255" msgstr "如:192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/account_attrs.py:175 +#: xpack/plugins/cloud/serializers/account_attrs.py:166 msgid "" "The port is used to detect the validity of the IP address. When the " "synchronization task is executed, only the valid IP address will be " @@ -7457,39 +7465,46 @@ msgstr "" "端口用来检测 IP 地址的有效性,在同步任务执行时,只会同步有效的 IP 地址。
" "如果端口为 0,则表示所有 IP 地址均有效。" -#: xpack/plugins/cloud/serializers/account_attrs.py:183 +#: xpack/plugins/cloud/serializers/account_attrs.py:174 msgid "Hostname prefix" msgstr "主机名前缀" -#: xpack/plugins/cloud/serializers/account_attrs.py:186 +#: xpack/plugins/cloud/serializers/account_attrs.py:177 msgid "IP segment" msgstr "IP 网段" -#: xpack/plugins/cloud/serializers/account_attrs.py:190 +#: xpack/plugins/cloud/serializers/account_attrs.py:181 msgid "Test port" msgstr "测试端口" -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Test timeout" msgstr "测试超时时间" #: xpack/plugins/cloud/serializers/task.py:28 +#, fuzzy +#| msgid "" +#| "Only instances matching the IP range will be synced.
If the instance " +#| "contains multiple IP addresses, the first IP address that matches will be " +#| "used as the IP for the created asset.
The default value of * means " +#| "sync all instances and randomly match IP addresses.
Such as: " +#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" msgid "" "Only instances matching the IP range will be synced.
If the instance " "contains multiple IP addresses, the first IP address that matches will be " "used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " -"10.1.1.1-10.1.1.20" +"all instances and randomly match IP addresses.
Format for comma-" +"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" msgstr "" "只有匹配到 IP 段的实例会被同步。
如果实例包含多个 IP 地址,那么第一个匹配" "到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示同步所有实例和随机匹配 " "IP 地址。
例如:192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/cloud/serializers/task.py:34 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "History count" msgstr "执行次数" -#: xpack/plugins/cloud/serializers/task.py:35 +#: xpack/plugins/cloud/serializers/task.py:36 msgid "Instance count" msgstr "实例个数" @@ -7549,26 +7564,44 @@ msgstr "许可证导入成功" msgid "License is invalid" msgstr "无效的许可证" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 msgid "License" msgstr "许可证" -#: xpack/plugins/license/models.py:80 +#: xpack/plugins/license/models.py:79 msgid "Standard edition" msgstr "标准版" -#: xpack/plugins/license/models.py:82 +#: xpack/plugins/license/models.py:81 msgid "Enterprise edition" msgstr "企业版" -#: xpack/plugins/license/models.py:84 +#: xpack/plugins/license/models.py:83 msgid "Ultimate edition" msgstr "旗舰版" -#: xpack/plugins/license/models.py:86 +#: xpack/plugins/license/models.py:85 msgid "Community edition" msgstr "社区版" +#~ msgid "Connect (All Protocols)" +#~ msgstr "连接 (所以协议)" + +#~ msgid "Upload (RDP, SFTP)" +#~ msgstr "上传 (RDP, SFTP)" + +#~ msgid "Download (RDP, SFTP)" +#~ msgstr "下载 (RDP, SFTP)" + +#~ msgid "Copy (RDP, VNC)" +#~ msgstr "复制 (RDP, VNC)" + +#~ msgid "Paste (RDP, VNC)" +#~ msgstr "粘贴 (RDP, VNC)" + +#~ msgid "Delete (SFTP)" +#~ msgstr "删除 (SFTP)" + #~ msgid "User (username)" #~ msgstr "用户(用户名)" diff --git a/apps/perms/const.py b/apps/perms/const.py index 70006053e..60e1ae493 100644 --- a/apps/perms/const.py +++ b/apps/perms/const.py @@ -9,12 +9,12 @@ __all__ = ["ActionChoices"] class ActionChoices(BitChoices): - connect = bit(1), _("Connect") - upload = bit(2), _("Upload") - download = bit(3), _("Download") - copy = bit(4), _("Copy") - paste = bit(5), _("Paste") - delete = bit(6), _("Delete") + connect = bit(1), _("Connect") + " ({})".format(_("All protocols")) + upload = bit(2), _("Upload") + " (RDP, SFTP)" + download = bit(3), _("Download") + " (RDP, SFTP)" + copy = bit(4), _("Copy") + " (RDP, VNC)" + paste = bit(5), _("Paste") + " (RDP, VNC)" + delete = bit(6), _("Delete") + " (SFTP)" @classmethod def is_tree(cls): From e61227d69421b881a5ae1b8040e06668fb0c3a8b Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 29 May 2023 19:45:55 +0800 Subject: [PATCH 053/153] =?UTF-8?q?perf:=20=E7=99=BB=E5=BD=95=E8=B5=84?= =?UTF-8?q?=E4=BA=A7=E7=9A=84=20ACL=20=E6=94=AF=E6=8C=81=20ip=20=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20(#10581)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ibuler --- .../migrations/0011_auto_20230425_1704.py | 6 +- .../migrations/0014_loginassetacl_rules.py | 18 +++ apps/acls/models/base.py | 30 ++++- apps/acls/models/login_acl.py | 25 +---- apps/acls/models/login_asset_acl.py | 4 + apps/acls/serializers/login_asset_acl.py | 11 +- .../gather_facts/host/windows/manifest.yml | 2 +- .../migrations/0005_auto_20190228_1715.py | 8 +- apps/audits/models.py | 2 +- apps/authentication/api/connection_token.py | 6 +- apps/authentication/mixins.py | 7 +- apps/common/utils/time_period.py | 8 +- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 101 +++++++++++------ apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 103 +++++++++++------- apps/terminal/serializers/endpoint.py | 13 ++- .../migrations/0016_auto_20220609_1758.py | 4 +- ...23_alter_applyassetticket_apply_actions.py | 2 +- apps/tickets/models/ticket/apply_asset.py | 2 +- apps/tickets/models/ticket/login_confirm.py | 2 +- apps/users/migrations/0001_initial.py | 2 +- 22 files changed, 235 insertions(+), 129 deletions(-) create mode 100644 apps/acls/migrations/0014_loginassetacl_rules.py diff --git a/apps/acls/migrations/0011_auto_20230425_1704.py b/apps/acls/migrations/0011_auto_20230425_1704.py index 2a8682129..f5d7dee6c 100644 --- a/apps/acls/migrations/0011_auto_20230425_1704.py +++ b/apps/acls/migrations/0011_auto_20230425_1704.py @@ -1,6 +1,6 @@ # Generated by Django 3.2.17 on 2023-04-25 09:04 -from django.db import migrations +from django.db import migrations, models import common.db.fields @@ -14,7 +14,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='commandfilteracl', name='new_accounts', - field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Account', verbose_name='Accounts'), + field=models.JSONField(default=list, verbose_name='Accounts'), ), migrations.AddField( model_name='commandfilteracl', @@ -29,7 +29,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='loginassetacl', name='new_accounts', - field=common.db.fields.JSONManyToManyField(default=dict, to='assets.Account', verbose_name='Accounts'), + field=models.JSONField(default=list, verbose_name='Accounts') ), migrations.AddField( model_name='loginassetacl', diff --git a/apps/acls/migrations/0014_loginassetacl_rules.py b/apps/acls/migrations/0014_loginassetacl_rules.py new file mode 100644 index 000000000..d7574ffd0 --- /dev/null +++ b/apps/acls/migrations/0014_loginassetacl_rules.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.17 on 2023-05-26 09:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('acls', '0013_auto_20230426_1759'), + ] + + operations = [ + migrations.AddField( + model_name='loginassetacl', + name='rules', + field=models.JSONField(default=dict, verbose_name='Rule'), + ), + ] diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 4b05f887c..12c66167c 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -4,6 +4,8 @@ from django.utils.translation import gettext_lazy as _ from common.db.fields import JSONManyToManyField from common.db.models import JMSBaseModel +from common.utils import contains_ip +from common.utils.time_period import contains_time_period from orgs.mixins.models import OrgModelMixin __all__ = [ @@ -52,11 +54,35 @@ class BaseACL(JMSBaseModel): def is_action(self, action): return self.action == action + @classmethod + def get_user_acls(cls, user): + return cls.objects.none() + + @classmethod + def get_match_rule_acls(cls, user, ip, acl_qs=None): + if acl_qs is None: + acl_qs = cls.get_user_acls(user) + if not acl_qs: + return + + for acl in acl_qs: + if acl.is_action(ActionChoices.review) and not acl.reviewers.exists(): + continue + ip_group = acl.rules.get('ip_group') + time_periods = acl.rules.get('time_period') + is_contain_ip = contains_ip(ip, ip_group) if ip_group else True + is_contain_time_period = contains_time_period(time_periods) if time_periods else True + + if is_contain_ip and is_contain_time_period: + # 满足条件,则返回 + return acl + return None + class UserAssetAccountBaseACL(BaseACL, OrgModelMixin): users = JSONManyToManyField('users.User', default=dict, verbose_name=_('Users')) assets = JSONManyToManyField('assets.Asset', default=dict, verbose_name=_('Assets')) - accounts = models.JSONField(default=list, verbose_name=_("Account")) + accounts = models.JSONField(default=list, verbose_name=_("Accounts")) class Meta(BaseACL.Meta): unique_together = ('name', 'org_id') @@ -85,4 +111,4 @@ class UserAssetAccountBaseACL(BaseACL, OrgModelMixin): kwargs['org_id'] = org_id if kwargs: queryset = queryset.filter(**kwargs) - return queryset.distinct() + return queryset.valid().distinct().order_by('priority', 'date_created') diff --git a/apps/acls/models/login_acl.py b/apps/acls/models/login_acl.py index 1178993c8..143196d78 100644 --- a/apps/acls/models/login_acl.py +++ b/apps/acls/models/login_acl.py @@ -2,15 +2,14 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ from common.utils import get_request_ip, get_ip_city -from common.utils.ip import contains_ip -from common.utils.time_period import contains_time_period from common.utils.timezone import local_now_display from .base import BaseACL class LoginACL(BaseACL): user = models.ForeignKey( - 'users.User', on_delete=models.CASCADE, related_name='login_acls', verbose_name=_('User') + 'users.User', on_delete=models.CASCADE, + related_name='login_acls', verbose_name=_('User') ) # 规则, ip_group, time_period rules = models.JSONField(default=dict, verbose_name=_('Rule')) @@ -29,23 +28,9 @@ class LoginACL(BaseACL): def filter_acl(cls, user): return user.login_acls.all().valid().distinct() - @staticmethod - def match(user, ip): - acl_qs = LoginACL.filter_acl(user) - if not acl_qs: - return - - for acl in acl_qs: - if acl.is_action(LoginACL.ActionChoices.review) and \ - not acl.reviewers.exists(): - continue - ip_group = acl.rules.get('ip_group') - time_periods = acl.rules.get('time_period') - is_contain_ip = contains_ip(ip, ip_group) - is_contain_time_period = contains_time_period(time_periods) - if is_contain_ip and is_contain_time_period: - # 满足条件,则返回 - return acl + @classmethod + def get_user_acls(cls, user): + return cls.filter_acl(user) def create_confirm_ticket(self, request): from tickets import const diff --git a/apps/acls/models/login_asset_acl.py b/apps/acls/models/login_asset_acl.py index fc5da088b..5d2293a18 100644 --- a/apps/acls/models/login_asset_acl.py +++ b/apps/acls/models/login_asset_acl.py @@ -1,9 +1,13 @@ +from django.db import models from django.utils.translation import ugettext_lazy as _ from .base import UserAssetAccountBaseACL class LoginAssetACL(UserAssetAccountBaseACL): + # 规则, ip_group, time_period + rules = models.JSONField(default=dict, verbose_name=_('Rule')) + class Meta(UserAssetAccountBaseACL.Meta): verbose_name = _('Login asset acl') abstract = False diff --git a/apps/acls/serializers/login_asset_acl.py b/apps/acls/serializers/login_asset_acl.py index de160d124..7480100f8 100644 --- a/apps/acls/serializers/login_asset_acl.py +++ b/apps/acls/serializers/login_asset_acl.py @@ -1,11 +1,20 @@ -from orgs.mixins.serializers import BulkOrgResourceModelSerializer +from django.utils.translation import gettext_lazy as _ +from common.serializers import MethodSerializer +from orgs.mixins.serializers import BulkOrgResourceModelSerializer from .base import BaseUserAssetAccountACLSerializerMixin as BaseSerializer +from .rules import RuleSerializer from ..models import LoginAssetACL __all__ = ["LoginAssetACLSerializer"] class LoginAssetACLSerializer(BaseSerializer, BulkOrgResourceModelSerializer): + rules = MethodSerializer(label=_('Rule')) + class Meta(BaseSerializer.Meta): model = LoginAssetACL + fields = BaseSerializer.Meta.fields + ['rules'] + + def get_rules_serializer(self): + return RuleSerializer() diff --git a/apps/assets/automations/gather_facts/host/windows/manifest.yml b/apps/assets/automations/gather_facts/host/windows/manifest.yml index af7c50f68..bf2b4e0fd 100644 --- a/apps/assets/automations/gather_facts/host/windows/manifest.yml +++ b/apps/assets/automations/gather_facts/host/windows/manifest.yml @@ -7,6 +7,6 @@ type: - windows i18n: Gather facts windows: - zh: 从 Windows 获取信息 + zh: 从 Windows 获取硬件信息 en: Gather facts windows ja: Windowsから事実を取得する diff --git a/apps/audits/migrations/0005_auto_20190228_1715.py b/apps/audits/migrations/0005_auto_20190228_1715.py index 40636ed8c..aac747e9b 100644 --- a/apps/audits/migrations/0005_auto_20190228_1715.py +++ b/apps/audits/migrations/0005_auto_20190228_1715.py @@ -1,12 +1,12 @@ # Generated by Django 2.1.7 on 2019-02-28 09:15 -from django.db import migrations, models, connection -import django.utils.timezone import uuid +import django.utils.timezone +from django.db import migrations, models + class Migration(migrations.Migration): - dependencies = [ ('audits', '0004_operatelog_passwordchangelog_userloginlog'), ('users', '0019_auto_20190304_1459'), @@ -22,7 +22,7 @@ class Migration(migrations.Migration): ('type', models.CharField(choices=[('W', 'Web'), ('T', 'Terminal')], max_length=2, verbose_name='Login type')), - ('ip', models.GenericIPAddressField(verbose_name='Login ip')), + ('ip', models.GenericIPAddressField(verbose_name='Login IP')), ('city', models.CharField(blank=True, max_length=254, null=True, verbose_name='Login city')), ('user_agent', diff --git a/apps/audits/models.py b/apps/audits/models.py index c20e6cb4b..099bde56e 100644 --- a/apps/audits/models.py +++ b/apps/audits/models.py @@ -158,7 +158,7 @@ class UserLoginLog(models.Model): type = models.CharField( choices=LoginTypeChoices.choices, max_length=2, verbose_name=_("Login type") ) - ip = models.GenericIPAddressField(verbose_name=_("Login ip")) + ip = models.GenericIPAddressField(verbose_name=_("Login IP")) city = models.CharField( max_length=254, blank=True, null=True, verbose_name=_("Login city") ) diff --git a/apps/authentication/api/connection_token.py b/apps/authentication/api/connection_token.py index 7c1bbb3f8..23344c9fb 100644 --- a/apps/authentication/api/connection_token.py +++ b/apps/authentication/api/connection_token.py @@ -16,7 +16,7 @@ from rest_framework.response import Response from common.api import JMSModelViewSet from common.exceptions import JMSException -from common.utils import random_string, get_logger +from common.utils import random_string, get_logger, get_request_ip from common.utils.django import get_request_os from common.utils.http import is_true, is_false from orgs.mixins.api import RootOrgViewMixin @@ -311,7 +311,9 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView def _validate_acl(self, user, asset, account): from acls.models import LoginAssetACL - acl = LoginAssetACL.filter_queryset(user, asset, account).valid().first() + acls = LoginAssetACL.filter_queryset(user, asset, account) + ip = get_request_ip(self.request) + acl = LoginAssetACL.get_match_rule_acls(user, ip, acls) if not acl: return if acl.is_action(acl.ActionChoices.accept): diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index 9fce76e57..c1fb2720d 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -340,15 +340,14 @@ class AuthACLMixin: def _check_login_acl(self, user, ip): # ACL 限制用户登录 - acl = LoginACL.match(user, ip) + acl = LoginACL.get_match_rule_acls(user, ip) if not acl: return - acl: LoginACL - if acl.is_action(acl.ActionChoices.accept): + if acl.is_action(LoginACL.ActionChoices.accept): return - if acl.is_action(acl.ActionChoices.reject): + if acl.is_action(LoginACL.ActionChoices.reject): raise errors.LoginACLIPAndTimePeriodNotAllowed(user.username, request=self.request) if acl.is_action(acl.ActionChoices.review): diff --git a/apps/common/utils/time_period.py b/apps/common/utils/time_period.py index cf4f0f0b9..0b25b4e34 100644 --- a/apps/common/utils/time_period.py +++ b/apps/common/utils/time_period.py @@ -1,14 +1,16 @@ from common.utils.timezone import local_now -def contains_time_period(time_periods): +def contains_time_period(time_periods, ctime=None): """ time_periods: [{"id": 1, "value": "00:00~07:30、10:00~13:00"}, {"id": 2, "value": "00:00~00:00"}] """ if not time_periods: - return False + return None - current_time = local_now().strftime('%H:%M') + if ctime is None: + ctime = local_now() + current_time = ctime.strftime('%H:%M') today_time_period = next(filter(lambda x: str(x['id']) == local_now().strftime("%w"), time_periods)) today_time_period = today_time_period['value'] if not today_time_period: diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 2d93e8efc..5988ab745 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc0862f2a9091f2e06602d6db26cfc9cc7a6b067012ec56b41ebc1e26d5072e9 -size 142045 +oid sha256:8e5c8032359c81278ddea64227bd4492fb49ea6b48587e6a0f406824238d6d46 +size 141638 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 6164e3b1c..be447ea8a 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-26 17:11+0800\n" +"POT-Creation-Date: 2023-05-26 16:18+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -221,7 +221,7 @@ msgstr "ソース ID" #: accounts/models/account.py:61 #: accounts/serializers/automations/change_secret.py:113 -#: accounts/serializers/automations/change_secret.py:133 acls/models/base.py:59 +#: accounts/serializers/automations/change_secret.py:133 #: acls/serializers/base.py:77 assets/serializers/asset/common.py:125 #: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 @@ -820,6 +820,12 @@ msgstr "アクティブ" msgid "Users" msgstr "ユーザー" +#: acls/models/base.py:59 assets/models/automations/base.py:17 +#: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 +#: rbac/tree.py:35 +msgid "Accounts" +msgstr "アカウント" + #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 #: ops/serializers/job.py:55 terminal/const.py:68 #: terminal/models/session/session.py:43 terminal/serializers/command.py:18 @@ -833,7 +839,7 @@ msgid "Regex" msgstr "正規情報" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 msgid "Content" msgstr "コンテンツ" @@ -876,10 +882,16 @@ msgid "Login confirm" msgstr "ログイン確認" #: acls/models/login_asset_acl.py:8 +#, fuzzy +#| msgid "User ID" +msgid "User IP" +msgstr "ユーザーID" + +#: acls/models/login_asset_acl.py:11 msgid "Login asset acl" msgstr "ログインasset acl" -#: acls/models/login_asset_acl.py:18 tickets/const.py:12 +#: acls/models/login_asset_acl.py:21 tickets/const.py:12 msgid "Login asset confirm" msgstr "ログイン資産の確認" @@ -917,6 +929,11 @@ msgstr "いずれのレビューアも組織 '{}' に属していません" msgid "Command group amount" msgstr "コマンドグループ数" +#: acls/serializers/login_asset_acl.py:12 audits/models.py:161 +#: tickets/models/ticket/login_confirm.py:10 +msgid "Login IP" +msgstr "ログインIP" + #: acls/serializers/rules/rules.py:20 #: xpack/plugins/cloud/serializers/task.py:22 msgid "IP address invalid: `{}`" @@ -1251,7 +1268,7 @@ msgstr "アドレス" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:196 +#: xpack/plugins/cloud/serializers/account_attrs.py:187 msgid "Platform" msgstr "プラットフォーム" @@ -1331,11 +1348,6 @@ msgstr "パスワードセレクター" msgid "Submit selector" msgstr "ボタンセレクターを確認する" -#: assets/models/automations/base.py:17 assets/models/cmd_filter.py:38 -#: assets/serializers/asset/common.py:305 rbac/tree.py:35 -msgid "Accounts" -msgstr "アカウント" - #: assets/models/automations/base.py:22 ops/models/job.py:187 #: settings/serializers/auth/sms.py:100 msgid "Parameters" @@ -2004,10 +2016,6 @@ msgstr "パスワード変更ログ" msgid "Login type" msgstr "ログインタイプ" -#: audits/models.py:161 tickets/models/ticket/login_confirm.py:10 -msgid "Login ip" -msgstr "ログインIP" - #: audits/models.py:163 #: authentication/templates/authentication/_msg_different_city.html:11 #: tickets/models/ticket/login_confirm.py:11 @@ -4606,7 +4614,7 @@ msgid "SSO auth key TTL" msgstr "Token有効期間" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Unit: second" msgstr "単位: 秒" @@ -5750,7 +5758,7 @@ msgid "Redis port" msgstr "Redis ポート" #: terminal/models/component/endpoint.py:29 -#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:71 +#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:68 #: terminal/serializers/storage.py:38 terminal/serializers/storage.py:50 #: terminal/serializers/storage.py:80 terminal/serializers/storage.py:90 #: terminal/serializers/storage.py:98 @@ -6051,11 +6059,21 @@ msgstr "" #: terminal/serializers/endpoint.py:64 msgid "" +"The assets within this IP range, the following endpoint will be used for the " +"connection" +msgstr "このIP範囲内のアセットは、以下のエンドポイントを使用して接続されます" + +#: terminal/serializers/endpoint.py:60 +msgid "" "If asset IP addresses under different endpoints conflict, use asset labels" msgstr "" "異なるエンドポイントの下に競合するアセットIPがある場合は、アセットタグを使用" "して実装します" +#: terminal/serializers/endpoint.py:64 +msgid "Asset IP" +msgstr "資産 IP" + #: terminal/serializers/session.py:24 terminal/serializers/session.py:46 msgid "Can replay" msgstr "再生できます" @@ -7248,7 +7266,7 @@ msgstr "クラウドアカウント" msgid "Test cloud account" msgstr "クラウドアカウントのテスト" -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 msgid "Regions" msgstr "リージョン" @@ -7256,15 +7274,15 @@ msgstr "リージョン" msgid "Hostname strategy" msgstr "ホスト名戦略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 msgid "IP network segment group" msgstr "IPネットワークセグメントグループ" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 msgid "Sync IP type" msgstr "同期IPタイプ" -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 msgid "Always update" msgstr "常に更新" @@ -7549,11 +7567,15 @@ msgstr "ファイルはJSON形式です。" msgid "IP address invalid `{}`, {}" msgstr "IPアドレスが無効: '{}', {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:172 -msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +#: xpack/plugins/cloud/serializers/account_attrs.py:162 +#, fuzzy +#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgid "" +"Format for comma-delimited string,Such as: 192.168.1.0/24, " +"10.0.0.0-10.0.0.255" msgstr "例:192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/account_attrs.py:175 +#: xpack/plugins/cloud/serializers/account_attrs.py:166 msgid "" "The port is used to detect the validity of the IP address. When the " "synchronization task is executed, only the valid IP address will be " @@ -7563,29 +7585,36 @@ msgstr "" "実行されると、有効な IP アドレスのみが同期されます。
ポートが0の場合、す" "べてのIPアドレスが有効です。" -#: xpack/plugins/cloud/serializers/account_attrs.py:183 +#: xpack/plugins/cloud/serializers/account_attrs.py:174 msgid "Hostname prefix" msgstr "ホスト名プレフィックス" -#: xpack/plugins/cloud/serializers/account_attrs.py:186 +#: xpack/plugins/cloud/serializers/account_attrs.py:177 msgid "IP segment" msgstr "IP セグメント" -#: xpack/plugins/cloud/serializers/account_attrs.py:190 +#: xpack/plugins/cloud/serializers/account_attrs.py:181 msgid "Test port" msgstr "テストポート" -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Test timeout" msgstr "テストタイムアウト" #: xpack/plugins/cloud/serializers/task.py:28 +#, fuzzy +#| msgid "" +#| "Only instances matching the IP range will be synced.
If the instance " +#| "contains multiple IP addresses, the first IP address that matches will be " +#| "used as the IP for the created asset.
The default value of * means " +#| "sync all instances and randomly match IP addresses.
Such as: " +#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" msgid "" "Only instances matching the IP range will be synced.
If the instance " "contains multiple IP addresses, the first IP address that matches will be " "used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " -"10.1.1.1-10.1.1.20" +"all instances and randomly match IP addresses.
Format for comma-" +"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" msgstr "" "IP範囲に一致するインスタンスのみが同期されます。
インスタンスに複数のIPア" "ドレスが含まれている場合、一致する最初のIPアドレスが作成されたアセットのIPと" @@ -7593,11 +7622,11 @@ msgstr "" "ドレスをランダムに一致させることを意味します。
例:" "192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/cloud/serializers/task.py:34 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "History count" msgstr "実行回数" -#: xpack/plugins/cloud/serializers/task.py:35 +#: xpack/plugins/cloud/serializers/task.py:36 msgid "Instance count" msgstr "インスタンス数" @@ -7657,23 +7686,23 @@ msgstr "ライセンスのインポートに成功" msgid "License is invalid" msgstr "ライセンスが無効です" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 msgid "License" msgstr "ライセンス" -#: xpack/plugins/license/models.py:80 +#: xpack/plugins/license/models.py:79 msgid "Standard edition" msgstr "標準版" -#: xpack/plugins/license/models.py:82 +#: xpack/plugins/license/models.py:81 msgid "Enterprise edition" msgstr "エンタープライズ版" -#: xpack/plugins/license/models.py:84 +#: xpack/plugins/license/models.py:83 msgid "Ultimate edition" msgstr "究極のエディション" -#: xpack/plugins/license/models.py:86 +#: xpack/plugins/license/models.py:85 msgid "Community edition" msgstr "コミュニティ版" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index b986dcb5b..256aed8c9 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1fabd2ec950291422c14b66af097bd73cce52bbc4b7913c1b9ea732eee855901 -size 116210 +oid sha256:f4cf57efef290fb80f5159a628b8cde7861cb2bd3fcc247fcf7255fbd2757fb9 +size 115892 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index d7aaf420f..9949ec5aa 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-26 17:11+0800\n" +"POT-Creation-Date: 2023-05-26 16:18+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -220,7 +220,7 @@ msgstr "来源 ID" #: accounts/models/account.py:61 #: accounts/serializers/automations/change_secret.py:113 -#: accounts/serializers/automations/change_secret.py:133 acls/models/base.py:59 +#: accounts/serializers/automations/change_secret.py:133 #: acls/serializers/base.py:77 assets/serializers/asset/common.py:125 #: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 @@ -816,6 +816,12 @@ msgstr "激活中" msgid "Users" msgstr "用户管理" +#: acls/models/base.py:59 assets/models/automations/base.py:17 +#: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 +#: rbac/tree.py:35 +msgid "Accounts" +msgstr "账号管理" + #: acls/models/command_acl.py:16 assets/models/cmd_filter.py:60 #: ops/serializers/job.py:55 terminal/const.py:68 #: terminal/models/session/session.py:43 terminal/serializers/command.py:18 @@ -829,7 +835,7 @@ msgid "Regex" msgstr "正则表达式" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 msgid "Content" msgstr "内容" @@ -872,10 +878,16 @@ msgid "Login confirm" msgstr "登录复核" #: acls/models/login_asset_acl.py:8 +#, fuzzy +#| msgid "User ID" +msgid "User IP" +msgstr "用户 ID" + +#: acls/models/login_asset_acl.py:11 msgid "Login asset acl" msgstr "登录资产访问控制" -#: acls/models/login_asset_acl.py:18 tickets/const.py:12 +#: acls/models/login_asset_acl.py:21 tickets/const.py:12 msgid "Login asset confirm" msgstr "登录资产复核" @@ -912,6 +924,11 @@ msgstr "所有复核人都不属于组织 `{}`" msgid "Command group amount" msgstr "命令组数量" +#: acls/serializers/login_asset_acl.py:12 audits/models.py:161 +#: tickets/models/ticket/login_confirm.py:10 +msgid "Login IP" +msgstr "登录 IP" + #: acls/serializers/rules/rules.py:20 #: xpack/plugins/cloud/serializers/task.py:22 msgid "IP address invalid: `{}`" @@ -929,7 +946,7 @@ msgstr "" #: authentication/templates/authentication/_msg_oauth_bind.html:12 #: authentication/templates/authentication/_msg_rest_password_success.html:8 #: authentication/templates/authentication/_msg_rest_public_key_success.html:8 -#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:67 +#: settings/serializers/terminal.py:10 msgid "IP" msgstr "IP" @@ -1244,7 +1261,7 @@ msgstr "地址" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:196 +#: xpack/plugins/cloud/serializers/account_attrs.py:187 msgid "Platform" msgstr "系统平台" @@ -1324,11 +1341,6 @@ msgstr "密码选择器" msgid "Submit selector" msgstr "确认按钮选择器" -#: assets/models/automations/base.py:17 assets/models/cmd_filter.py:38 -#: assets/serializers/asset/common.py:305 rbac/tree.py:35 -msgid "Accounts" -msgstr "账号管理" - #: assets/models/automations/base.py:22 ops/models/job.py:187 #: settings/serializers/auth/sms.py:100 msgid "Parameters" @@ -1993,10 +2005,6 @@ msgstr "改密日志" msgid "Login type" msgstr "登录方式" -#: audits/models.py:161 tickets/models/ticket/login_confirm.py:10 -msgid "Login ip" -msgstr "登录IP" - #: audits/models.py:163 #: authentication/templates/authentication/_msg_different_city.html:11 #: tickets/models/ticket/login_confirm.py:11 @@ -4562,7 +4570,7 @@ msgid "SSO auth key TTL" msgstr "令牌有效期" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Unit: second" msgstr "单位: 秒" @@ -5669,7 +5677,7 @@ msgid "Redis port" msgstr "Redis 端口" #: terminal/models/component/endpoint.py:29 -#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:71 +#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:68 #: terminal/serializers/storage.py:38 terminal/serializers/storage.py:50 #: terminal/serializers/storage.py:80 terminal/serializers/storage.py:90 #: terminal/serializers/storage.py:98 @@ -5967,9 +5975,19 @@ msgstr "" #: terminal/serializers/endpoint.py:64 msgid "" +"The assets within this IP range, the following endpoint will be used for the " +"connection" +msgstr "该 IP 范围内的资产,将使用下面的端点进行连接" + +#: terminal/serializers/endpoint.py:60 +msgid "" "If asset IP addresses under different endpoints conflict, use asset labels" msgstr "如果不同端点下的资产 IP 有冲突,使用资产标签实现" +#: terminal/serializers/endpoint.py:64 +msgid "Asset IP" +msgstr "资产 IP" + #: terminal/serializers/session.py:24 terminal/serializers/session.py:46 msgid "Can replay" msgstr "是否可重放" @@ -7143,7 +7161,7 @@ msgstr "云账号" msgid "Test cloud account" msgstr "测试云账号" -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 msgid "Regions" msgstr "地域" @@ -7151,15 +7169,15 @@ msgstr "地域" msgid "Hostname strategy" msgstr "主机名策略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 msgid "IP network segment group" msgstr "IP网段组" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 msgid "Sync IP type" msgstr "同步IP类型" -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 msgid "Always update" msgstr "总是更新" @@ -7444,11 +7462,15 @@ msgstr "JSON 格式的文件" msgid "IP address invalid `{}`, {}" msgstr "IP 地址无效: `{}`, {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:172 -msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +#: xpack/plugins/cloud/serializers/account_attrs.py:162 +#, fuzzy +#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgid "" +"Format for comma-delimited string,Such as: 192.168.1.0/24, " +"10.0.0.0-10.0.0.255" msgstr "如:192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/account_attrs.py:175 +#: xpack/plugins/cloud/serializers/account_attrs.py:166 msgid "" "The port is used to detect the validity of the IP address. When the " "synchronization task is executed, only the valid IP address will be " @@ -7457,39 +7479,46 @@ msgstr "" "端口用来检测 IP 地址的有效性,在同步任务执行时,只会同步有效的 IP 地址。
" "如果端口为 0,则表示所有 IP 地址均有效。" -#: xpack/plugins/cloud/serializers/account_attrs.py:183 +#: xpack/plugins/cloud/serializers/account_attrs.py:174 msgid "Hostname prefix" msgstr "主机名前缀" -#: xpack/plugins/cloud/serializers/account_attrs.py:186 +#: xpack/plugins/cloud/serializers/account_attrs.py:177 msgid "IP segment" msgstr "IP 网段" -#: xpack/plugins/cloud/serializers/account_attrs.py:190 +#: xpack/plugins/cloud/serializers/account_attrs.py:181 msgid "Test port" msgstr "测试端口" -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Test timeout" msgstr "测试超时时间" #: xpack/plugins/cloud/serializers/task.py:28 +#, fuzzy +#| msgid "" +#| "Only instances matching the IP range will be synced.
If the instance " +#| "contains multiple IP addresses, the first IP address that matches will be " +#| "used as the IP for the created asset.
The default value of * means " +#| "sync all instances and randomly match IP addresses.
Such as: " +#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" msgid "" "Only instances matching the IP range will be synced.
If the instance " "contains multiple IP addresses, the first IP address that matches will be " "used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " -"10.1.1.1-10.1.1.20" +"all instances and randomly match IP addresses.
Format for comma-" +"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" msgstr "" "只有匹配到 IP 段的实例会被同步。
如果实例包含多个 IP 地址,那么第一个匹配" "到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示同步所有实例和随机匹配 " "IP 地址。
例如:192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/cloud/serializers/task.py:34 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "History count" msgstr "执行次数" -#: xpack/plugins/cloud/serializers/task.py:35 +#: xpack/plugins/cloud/serializers/task.py:36 msgid "Instance count" msgstr "实例个数" @@ -7549,23 +7578,23 @@ msgstr "许可证导入成功" msgid "License is invalid" msgstr "无效的许可证" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 msgid "License" msgstr "许可证" -#: xpack/plugins/license/models.py:80 +#: xpack/plugins/license/models.py:79 msgid "Standard edition" msgstr "标准版" -#: xpack/plugins/license/models.py:82 +#: xpack/plugins/license/models.py:81 msgid "Enterprise edition" msgstr "企业版" -#: xpack/plugins/license/models.py:84 +#: xpack/plugins/license/models.py:83 msgid "Ultimate edition" msgstr "旗舰版" -#: xpack/plugins/license/models.py:86 +#: xpack/plugins/license/models.py:85 msgid "Community edition" msgstr "社区版" diff --git a/apps/terminal/serializers/endpoint.py b/apps/terminal/serializers/endpoint.py index 5058b292f..d7534adeb 100644 --- a/apps/terminal/serializers/endpoint.py +++ b/apps/terminal/serializers/endpoint.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from acls.serializers.rules import ip_group_child_validator, ip_group_help_text @@ -17,7 +17,8 @@ class EndpointSerializer(BulkModelSerializer): max_length=128, default=db_port_manager.oracle_port_range, read_only=True, label=_('Oracle port range'), help_text=_( - 'Oracle proxy server listen port is dynamic, Each additional Oracle database instance adds a port listener' + 'Oracle proxy server listen port is dynamic, Each additional Oracle ' + 'database instance adds a port listener' ) ) @@ -59,12 +60,13 @@ class EndpointSerializer(BulkModelSerializer): class EndpointRuleSerializer(BulkModelSerializer): - _ip_group_help_text = '{}
{}'.format( + _ip_group_help_text = '{}, {}
{}'.format( + _('The assets within this IP range, the following endpoint will be used for the connection'), + _('If asset IP addresses under different endpoints conflict, use asset labels'), ip_group_help_text, - _('If asset IP addresses under different endpoints conflict, use asset labels') ) ip_group = serializers.ListField( - default=['*'], label=_('IP'), help_text=_ip_group_help_text, + default=['*'], label=_('Asset IP'), help_text=_ip_group_help_text, child=serializers.CharField(max_length=1024, validators=[ip_group_child_validator]) ) endpoint = ObjectRelatedField( @@ -80,4 +82,5 @@ class EndpointRuleSerializer(BulkModelSerializer): 'comment', 'date_created', 'date_updated', 'created_by' ] extra_kwargs = { + 'priority': {'default': 50} } diff --git a/apps/tickets/migrations/0016_auto_20220609_1758.py b/apps/tickets/migrations/0016_auto_20220609_1758.py index e5e6f61ce..20f9674f7 100644 --- a/apps/tickets/migrations/0016_auto_20220609_1758.py +++ b/apps/tickets/migrations/0016_auto_20220609_1758.py @@ -1,8 +1,8 @@ # Generated by Django 3.1.14 on 2022-06-09 09:58 +import django.db.models.deletion from django.conf import settings from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): @@ -21,7 +21,7 @@ class Migration(migrations.Migration): ('ticket_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tickets.ticket')), - ('apply_login_ip', models.GenericIPAddressField(null=True, verbose_name='Login ip')), + ('apply_login_ip', models.GenericIPAddressField(null=True, verbose_name='Login IP')), ('apply_login_city', models.CharField(max_length=64, null=True, verbose_name='Login city')), ('apply_login_datetime', models.DateTimeField(null=True, verbose_name='Login datetime')), ], diff --git a/apps/tickets/migrations/0023_alter_applyassetticket_apply_actions.py b/apps/tickets/migrations/0023_alter_applyassetticket_apply_actions.py index f401fe298..b4121ce51 100644 --- a/apps/tickets/migrations/0023_alter_applyassetticket_apply_actions.py +++ b/apps/tickets/migrations/0023_alter_applyassetticket_apply_actions.py @@ -12,7 +12,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='applyassetticket', name='apply_actions', - field=models.IntegerField(default=31, verbose_name='Actions'), + field=models.IntegerField(default=1, verbose_name='Actions'), ), migrations.AlterField( model_name='approvalrule', diff --git a/apps/tickets/models/ticket/apply_asset.py b/apps/tickets/models/ticket/apply_asset.py index ef29c607f..39784201b 100644 --- a/apps/tickets/models/ticket/apply_asset.py +++ b/apps/tickets/models/ticket/apply_asset.py @@ -15,7 +15,7 @@ class ApplyAssetTicket(Ticket): # 申请信息 apply_assets = models.ManyToManyField('assets.Asset', verbose_name=_('Asset')) apply_accounts = models.JSONField(default=list, verbose_name=_('Apply accounts')) - apply_actions = models.IntegerField(verbose_name=_('Actions'), default=ActionChoices.all()) + apply_actions = models.IntegerField(verbose_name=_('Actions'), default=ActionChoices.connect) apply_date_start = models.DateTimeField(verbose_name=_('Date start'), null=True) apply_date_expired = models.DateTimeField(verbose_name=_('Date expired'), null=True) diff --git a/apps/tickets/models/ticket/login_confirm.py b/apps/tickets/models/ticket/login_confirm.py index ee9d9fa80..024761ac7 100644 --- a/apps/tickets/models/ticket/login_confirm.py +++ b/apps/tickets/models/ticket/login_confirm.py @@ -7,6 +7,6 @@ __all__ = ['ApplyLoginTicket'] class ApplyLoginTicket(Ticket): - apply_login_ip = models.GenericIPAddressField(verbose_name=_('Login ip'), null=True) + apply_login_ip = models.GenericIPAddressField(verbose_name=_('Login IP'), null=True) apply_login_city = models.CharField(max_length=64, verbose_name=_('Login city'), null=True) apply_login_datetime = models.DateTimeField(verbose_name=_('Login datetime'), null=True) diff --git a/apps/users/migrations/0001_initial.py b/apps/users/migrations/0001_initial.py index d5c584181..5c0f28a38 100644 --- a/apps/users/migrations/0001_initial.py +++ b/apps/users/migrations/0001_initial.py @@ -97,7 +97,7 @@ class Migration(migrations.Migration): ('username', models.CharField(max_length=20, verbose_name='Username')), ('type', models.CharField(choices=[('W', 'Web'), ('T', 'Terminal')], max_length=2, verbose_name='Login type')), - ('ip', models.GenericIPAddressField(verbose_name='Login ip')), + ('ip', models.GenericIPAddressField(verbose_name='Login IP')), ('city', models.CharField(blank=True, max_length=254, null=True, verbose_name='Login city')), ('user_agent', models.CharField(blank=True, max_length=254, null=True, verbose_name='User agent')), ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date login')), From 50d8389ffffe788966ab5a10bdb122daceffe36e Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 May 2023 10:59:16 +0800 Subject: [PATCH 054/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20chrome=20?= =?UTF-8?q?=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../disable_new_tab_window_menu/background.js | 11 +++++++++-- .../disable_new_tab_window_menu/content_script.js | 13 +++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/background.js b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/background.js index 5a9a13b6b..57b0cca1a 100644 --- a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/background.js +++ b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/background.js @@ -11,6 +11,13 @@ chrome.tabs.onCreated.addListener(function (tab) { }); }); -document.addEventListener("contextmenu", function (event) { - event.preventDefault(); +// 监听窗口的创建事件 +chrome.windows.onCreated.addListener(function (window) { +// 获取当前所有窗口 + chrome.windows.getAll(function (windows) { + // 如果当前窗口数量大于1,则关闭新创建的窗口 + if (windows.length > 1) { + chrome.windows.remove(window.id); + } + }); }); diff --git a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js index f51c40254..d1a6bf8ea 100644 --- a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js +++ b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js @@ -8,16 +8,29 @@ for (let i = 0; i < links.length; i++) { links[i].target = '_self'; // 将 target 属性设置为 _self,当前窗口打开 } + chrome.runtime.onMessage.addListener( function (request, sender, sendResponse) { + console.log(request.url); $("iframe").attr("src", request.url); sendResponse({farewell: "goodbye"}); } ) document.addEventListener("contextmenu", function (event) { + console.log('On contextmenu event') event.preventDefault(); }); +var AllowedKeys = ['P', 'F', 'p', 'f'] +window.addEventListener("keydown", function (e) { + if (e.key === "F12" || (e.ctrlKey && !AllowedKeys.includes(e.key))) { + e.preventDefault(); + e.stopPropagation(); + console.log('Press key: ', e.ctrlKey ? 'Ctrl' : '', e.shiftKey ? ' Shift' : '', e.key) + } +}, true); + + chrome.runtime.sendMessage({greeting: "hello"}, function (response) { }); From 89b42ce51bb5882a6f45659e447bf1288572f4ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=AB=E6=98=9F=E5=B0=8F=E5=88=98?= Date: Sat, 27 May 2023 18:01:37 +0800 Subject: [PATCH 055/153] =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E6=89=AB=E6=8F=8F=E7=99=BB=E5=BD=95=E4=BF=AE=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=8E=A5=E5=8F=A3=EF=BC=8C=E5=9C=A8PC?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E7=9A=84=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E5=86=8D=E9=9C=80=E8=A6=81=E6=89=8B=E6=9C=BA=E6=89=AB?= =?UTF-8?q?=E7=A0=81=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 企业微信官方api https://developer.work.weixin.qq.com/document/path/98151 --- apps/common/sdk/im/wecom/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/common/sdk/im/wecom/__init__.py b/apps/common/sdk/im/wecom/__init__.py index 5d2d6a4c1..b58e4ab3b 100644 --- a/apps/common/sdk/im/wecom/__init__.py +++ b/apps/common/sdk/im/wecom/__init__.py @@ -19,7 +19,7 @@ class WeComError(APIException): class URL: GET_TOKEN = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken' SEND_MESSAGE = 'https://qyapi.weixin.qq.com/cgi-bin/message/send' - QR_CONNECT = 'https://open.work.weixin.qq.com/wwopen/sso/qrConnect' + QR_CONNECT = 'https://login.work.weixin.qq.com/wwlogin/sso/login' OAUTH_CONNECT = 'https://open.weixin.qq.com/connect/oauth2/authorize' # https://open.work.weixin.qq.com/api/doc/90000/90135/91437 From ef7886b25b3f5d91e000880b97f167626b327b73 Mon Sep 17 00:00:00 2001 From: Bai Date: Tue, 30 May 2023 15:05:48 +0800 Subject: [PATCH 056/153] =?UTF-8?q?perf:=20=E5=8D=87=E7=BA=A7=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=20jms-storage=3D=3D0.0.46?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index fc4d495b8..cd57abbdd 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -37,7 +37,7 @@ PyNaCl==1.5.0 python-dateutil==2.8.2 PyYAML==6.0 requests==2.31.0 -jms-storage==0.0.44 +jms-storage==0.0.46 simplejson==3.17.6 six==1.16.0 sshtunnel==0.4.0 From b98ccf8b3de1ef2fb42145535ad241ae176b199b Mon Sep 17 00:00:00 2001 From: fangfangdong Date: Tue, 30 May 2023 17:02:16 +0800 Subject: [PATCH 057/153] =?UTF-8?q?style:=20=E8=B0=83=E6=95=B4=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=E6=96=87=E4=BB=B6=E4=B8=AD=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E5=8D=95=E4=BD=8D=E6=98=BE=E7=A4=BA=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.po | 78 ++++++++++++--------------- apps/locale/zh/LC_MESSAGES/django.po | 78 ++++++++++++--------------- apps/settings/serializers/cleaning.py | 16 +++--- apps/settings/serializers/security.py | 18 +++---- 4 files changed, 87 insertions(+), 103 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index abe7ba584..2f7cb65b4 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -4683,46 +4683,38 @@ msgid "Period clean" msgstr "定時清掃" #: settings/serializers/cleaning.py:12 -msgid "Login log keep days" -msgstr "ログインログは日数を保持します" - -#: settings/serializers/cleaning.py:12 settings/serializers/cleaning.py:16 -#: settings/serializers/cleaning.py:20 settings/serializers/cleaning.py:24 -#: settings/serializers/cleaning.py:28 settings/serializers/cleaning.py:36 -msgid "Unit: day" -msgstr "単位: 日" +msgid "Login log keep days (day)" +msgstr "ログインログは日数を保持します(天)" #: settings/serializers/cleaning.py:16 -msgid "Task log keep days" -msgstr "タスクログは日数を保持します" +msgid "Task log keep days (day)" +msgstr "タスクログは日数を保持します(天)" #: settings/serializers/cleaning.py:20 -msgid "Operate log keep days" -msgstr "ログ管理日を操作する" +msgid "Operate log keep days (day)" +msgstr "ログ管理日を操作する(天)" #: settings/serializers/cleaning.py:24 -msgid "FTP log keep days" -msgstr "ダウンロードのアップロード" +msgid "FTP log keep days (day)" +msgstr "ダウンロードのアップロード(天)" #: settings/serializers/cleaning.py:28 -msgid "Cloud sync record keep days" -msgstr "クラウド同期レコードは日数を保持します" +msgid "Cloud sync record keep days (day)" +msgstr "クラウド同期レコードは日数を保持します(天)" #: settings/serializers/cleaning.py:31 -msgid "Session keep duration" -msgstr "セッション維持期間" +msgid "Session keep duration (day)" +msgstr "セッション維持期間(天)" #: settings/serializers/cleaning.py:32 msgid "" -"Unit: days, Session, record, command will be delete if more than duration, " -"only in database" +"Session, record, command will be delete if more than duration, only in database, OSS will not be affected." msgstr "" -"単位:日。セッション、録画、コマンドレコードがそれを超えると削除されます(デー" -"タベースストレージにのみ影響します。ossなどは影響しません」影響を受ける)" +"この期間を超えるセッション、録音、およびコマンド レコードは削除されます (データベースのバックアップに影響し、OSS などには影響しません)" #: settings/serializers/cleaning.py:36 -msgid "Activity log keep days" -msgstr "活動ログは日数を保持します" +msgid "Activity log keep days (day)" +msgstr "活動ログは日数を保持します(天)" #: settings/serializers/email.py:21 msgid "SMTP host" @@ -4906,10 +4898,10 @@ msgstr "特別な" #: settings/serializers/security.py:31 msgid "" -"Unit: minute, If the user has failed to log in for a limited number of " +"If the user has failed to log in for a limited number of " "times, no login is allowed during this time interval." msgstr "" -"単位: 分。ユーザーが限られた回数だけログインできなかった場合、この時間間隔で" +"ユーザーが限られた回数だけログインできなかった場合、この時間間隔で" "はログインはできません。" #: settings/serializers/security.py:40 @@ -4937,16 +4929,16 @@ msgid "Limit the number of user login failures" msgstr "ユーザーログインの失敗数を制限する" #: settings/serializers/security.py:56 -msgid "Block user login interval" -msgstr "ユーザーのログイン間隔をブロックする" +msgid "Block user login interval (minute)" +msgstr "ユーザーのログイン間隔をブロックする(分)" #: settings/serializers/security.py:61 msgid "Limit the number of IP login failures" msgstr "IPログイン失敗の数を制限する" #: settings/serializers/security.py:65 -msgid "Block IP login interval" -msgstr "IPログイン間隔をブロックする" +msgid "Block IP login interval (minute)" +msgstr "IPログイン間隔をブロックする(分)" #: settings/serializers/security.py:69 msgid "Login IP White List" @@ -4957,17 +4949,17 @@ msgid "Login IP Black List" msgstr "ログインIPブラックリスト" #: settings/serializers/security.py:80 -msgid "User password expiration" -msgstr "ユーザーパスワードの有効期限" +msgid "User password expiration (day)" +msgstr "ユーザーパスワードの有効期限(天)" #: settings/serializers/security.py:82 msgid "" -"Unit: day, If the user does not update the password during the time, the " +"If the user does not update the password during the time, the " "user password will expire failure;The password expiration reminder mail will " "be automatic sent to the user by system within 5 days (daily) before the " "password expires" msgstr "" -"単位: 日。ユーザーがその期間中にパスワードを更新しなかった場合、ユーザーパス" +"ユーザーがその期間中にパスワードを更新しなかった場合、ユーザーパス" "ワードの有効期限が切れます。パスワードの有効期限が切れる前の5日 (毎日) 以内" "に、パスワードの有効期限が切れるリマインダーメールがシステムからユーザーに自" "動的に送信されます。" @@ -5027,15 +5019,15 @@ msgstr "" "ての認証方法を特定の順序で認証します。 、直接ログインできます" #: settings/serializers/security.py:109 -msgid "MFA verify TTL" -msgstr "MFAはTTLを確認します" +msgid "MFA verify TTL (secend)" +msgstr "MFAはTTLを確認します(秒)" #: settings/serializers/security.py:111 msgid "" -"Unit: second, The verification MFA takes effect only when you view the " +"The verification MFA takes effect only when you view the " "account password" msgstr "" -"単位: 2番目に、検証MFAはアカウントのパスワードを表示したときにのみ有効になり" +"検証MFAはアカウントのパスワードを表示したときにのみ有効になり" "ます。" #: settings/serializers/security.py:116 @@ -5044,7 +5036,7 @@ msgstr "認証コード有効時間" #: settings/serializers/security.py:117 msgid "Unit: second, reset password and send SMS code expiration time" -msgstr "単位: 2番目に、パスワードをリセットしてSMSコードの有効期限を送信します" +msgstr "パスワードをリセットしてSMSコードの有効期限を送信します" #: settings/serializers/security.py:121 msgid "Enable Login dynamic code" @@ -5100,12 +5092,12 @@ msgid "Enabled, the web session and replay contains watermark information" msgstr "Webセッションとリプレイには透かし情報が含まれています。" #: settings/serializers/security.py:165 -msgid "Connection max idle time" -msgstr "接続最大アイドル時間" +msgid "Connection max idle time (minute)" +msgstr "接続最大アイドル時間(分)" #: settings/serializers/security.py:166 -msgid "If idle time more than it, disconnect connection Unit: minute" -msgstr "アイドル時間がそれ以上の場合は、接続単位を切断します: 分" +msgid "If idle time more than it, disconnect connection." +msgstr "この設定以上の操作がない場合、接続は切断されます" #: settings/serializers/security.py:169 msgid "Remember manual auth" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 3906b85e1..7b429aa50 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -4639,46 +4639,38 @@ msgid "Period clean" msgstr "定時清掃" #: settings/serializers/cleaning.py:12 -msgid "Login log keep days" -msgstr "登录日志" - -#: settings/serializers/cleaning.py:12 settings/serializers/cleaning.py:16 -#: settings/serializers/cleaning.py:20 settings/serializers/cleaning.py:24 -#: settings/serializers/cleaning.py:28 settings/serializers/cleaning.py:36 -msgid "Unit: day" -msgstr "单位: 天" +msgid "Login log keep days (day)" +msgstr "登录日志(天)" #: settings/serializers/cleaning.py:16 -msgid "Task log keep days" -msgstr "任务日志" +msgid "Task log keep days (day)" +msgstr "任务日志(天)" #: settings/serializers/cleaning.py:20 -msgid "Operate log keep days" -msgstr "操作日志" +msgid "Operate log keep days (day)" +msgstr "操作日志(天)" #: settings/serializers/cleaning.py:24 -msgid "FTP log keep days" -msgstr "上传下载" +msgid "FTP log keep days (day)" +msgstr "上传下载(天)" #: settings/serializers/cleaning.py:28 -msgid "Cloud sync record keep days" -msgstr "云同步记录" +msgid "Cloud sync record keep days (day)" +msgstr "云同步记录(天)" #: settings/serializers/cleaning.py:31 -msgid "Session keep duration" -msgstr "会话日志" +msgid "Session keep duration (day)" +msgstr "会话日志(天)" #: settings/serializers/cleaning.py:32 msgid "" -"Unit: days, Session, record, command will be delete if more than duration, " -"only in database" +"Session, record, command will be delete if more than duration, only in database, OSS will not be affected." msgstr "" -"单位:天。 会话、录像、命令记录超过该时长将会被删除(仅影响数据库存储, oss等不" -"受影响)" +"会话、录像,命令记录超过该时长将会被洲除(影响数据库存備,OSS 等不受影响)" #: settings/serializers/cleaning.py:36 -msgid "Activity log keep days" -msgstr "活动记录" +msgid "Activity log keep days (day)" +msgstr "活动记录(天)" #: settings/serializers/email.py:21 msgid "SMTP host" @@ -4855,9 +4847,9 @@ msgstr "必须包含特殊字符" #: settings/serializers/security.py:31 msgid "" -"Unit: minute, If the user has failed to log in for a limited number of " +"If the user has failed to log in for a limited number of " "times, no login is allowed during this time interval." -msgstr "单位:分, 当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录" +msgstr "当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录" #: settings/serializers/security.py:40 msgid "All users" @@ -4884,16 +4876,16 @@ msgid "Limit the number of user login failures" msgstr "限制用户登录失败次数" #: settings/serializers/security.py:56 -msgid "Block user login interval" -msgstr "禁止用户登录时间间隔" +msgid "Block user login interval (minute)" +msgstr "禁止用户登录时间间隔(分)" #: settings/serializers/security.py:61 msgid "Limit the number of IP login failures" msgstr "限制 IP 登录失败次数" #: settings/serializers/security.py:65 -msgid "Block IP login interval" -msgstr "禁止 IP 登录时间间隔" +msgid "Block IP login interval (minute)" +msgstr "禁止 IP 登录时间间隔(分)" #: settings/serializers/security.py:69 msgid "Login IP White List" @@ -4904,17 +4896,17 @@ msgid "Login IP Black List" msgstr "IP 登录黑名单" #: settings/serializers/security.py:80 -msgid "User password expiration" -msgstr "用户密码过期时间" +msgid "User password expiration (day)" +msgstr "用户密码过期时间(天)" #: settings/serializers/security.py:82 msgid "" -"Unit: day, If the user does not update the password during the time, the " +"If the user does not update the password during the time, the " "user password will expire failure;The password expiration reminder mail will " "be automatic sent to the user by system within 5 days (daily) before the " "password expires" msgstr "" -"单位:天, 如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期提醒邮件" +"如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期提醒邮件" "将在密码过期前5天内由系统(每天)自动发送给用户" #: settings/serializers/security.py:89 @@ -4966,14 +4958,14 @@ msgstr "" "序对所有已开启的认证方式进行顺序认证,只要有一个认证成功就可以直接登录" #: settings/serializers/security.py:109 -msgid "MFA verify TTL" -msgstr "MFA 校验有效期" +msgid "MFA verify TTL (secend)" +msgstr "MFA 校验有效期(秒)" #: settings/serializers/security.py:111 msgid "" -"Unit: second, The verification MFA takes effect only when you view the " +"The verification MFA takes effect only when you view the " "account password" -msgstr "单位: 秒, 目前仅在查看账号密码校验 MFA 时生效" +msgstr "目前仅在查看账号密码校验 MFA 时生效" #: settings/serializers/security.py:116 msgid "Verify code TTL" @@ -4981,7 +4973,7 @@ msgstr "验证码有效时间" #: settings/serializers/security.py:117 msgid "Unit: second, reset password and send SMS code expiration time" -msgstr "单位: 秒, 重置密码的验证码及发送短信的验证码过期时间" +msgstr "重置密码的验证码及发送短信的验证码过期时间" #: settings/serializers/security.py:121 msgid "Enable Login dynamic code" @@ -5034,12 +5026,12 @@ msgid "Enabled, the web session and replay contains watermark information" msgstr "启用后,Web 会话和录像将包含水印信息" #: settings/serializers/security.py:165 -msgid "Connection max idle time" -msgstr "连接最大空闲时间" +msgid "Connection max idle time (minute)" +msgstr "连接最大空闲时间(分)" #: settings/serializers/security.py:166 -msgid "If idle time more than it, disconnect connection Unit: minute" -msgstr "提示:如果超过该配置没有操作,连接会被断开 (单位:分)" +msgid "If idle time more than it, disconnect connection." +msgstr "提示:如果超过该配置没有操作,连接会被断开)" #: settings/serializers/security.py:169 msgid "Remember manual auth" diff --git a/apps/settings/serializers/cleaning.py b/apps/settings/serializers/cleaning.py index cc6fb00bf..dfc568c99 100644 --- a/apps/settings/serializers/cleaning.py +++ b/apps/settings/serializers/cleaning.py @@ -9,29 +9,29 @@ class CleaningSerializer(serializers.Serializer): LOGIN_LOG_KEEP_DAYS = serializers.IntegerField( min_value=1, max_value=9999, - label=_("Login log keep days"), help_text=_("Unit: day") + label=_("Login log keep days (day)"), ) TASK_LOG_KEEP_DAYS = serializers.IntegerField( min_value=1, max_value=9999, - label=_("Task log keep days"), help_text=_("Unit: day") + label=_("Task log keep days (day)"), ) OPERATE_LOG_KEEP_DAYS = serializers.IntegerField( min_value=1, max_value=9999, - label=_("Operate log keep days"), help_text=_("Unit: day") + label=_("Operate log keep days (day)"), ) FTP_LOG_KEEP_DAYS = serializers.IntegerField( min_value=1, max_value=9999, - label=_("FTP log keep days"), help_text=_("Unit: day") + label=_("FTP log keep days (day)"), ) CLOUD_SYNC_TASK_EXECUTION_KEEP_DAYS = serializers.IntegerField( min_value=1, max_value=9999, - label=_("Cloud sync record keep days"), help_text=_("Unit: day") + label=_("Cloud sync record keep days (day)"), ) TERMINAL_SESSION_KEEP_DURATION = serializers.IntegerField( - min_value=1, max_value=99999, required=True, label=_('Session keep duration'), - help_text=_('Unit: days, Session, record, command will be delete if more than duration, only in database') + min_value=1, max_value=99999, required=True, label=_('Session keep duration (day)'), + help_text=_('Session, record, command will be delete if more than duration, only in database, OSS will not be affected.') ) ACTIVITY_LOG_KEEP_DAYS = serializers.IntegerField( min_value=1, max_value=9999, - label=_("Activity log keep days"), help_text=_("Unit: day") + label=_("Activity log keep days (day)"), ) diff --git a/apps/settings/serializers/security.py b/apps/settings/serializers/security.py index 891149add..7a84c9a00 100644 --- a/apps/settings/serializers/security.py +++ b/apps/settings/serializers/security.py @@ -28,7 +28,7 @@ class SecurityPasswordRuleSerializer(serializers.Serializer): login_ip_limit_time_help_text = _( - 'Unit: minute, If the user has failed to log in for a limited number of times, ' + 'If the user has failed to log in for a limited number of times, ' 'no login is allowed during this time interval.' ) @@ -53,7 +53,7 @@ class SecurityAuthSerializer(serializers.Serializer): ) SECURITY_LOGIN_LIMIT_TIME = serializers.IntegerField( min_value=5, max_value=99999, required=True, - label=_('Block user login interval'), + label=_('Block user login interval (minute)'), help_text=login_ip_limit_time_help_text ) SECURITY_LOGIN_IP_LIMIT_COUNT = serializers.IntegerField( @@ -62,7 +62,7 @@ class SecurityAuthSerializer(serializers.Serializer): ) SECURITY_LOGIN_IP_LIMIT_TIME = serializers.IntegerField( min_value=5, max_value=99999, required=True, - label=_('Block IP login interval'), + label=_('Block IP login interval (minute)'), help_text=login_ip_limit_time_help_text ) SECURITY_LOGIN_IP_WHITE_LIST = serializers.ListField( @@ -77,9 +77,9 @@ class SecurityAuthSerializer(serializers.Serializer): ) SECURITY_PASSWORD_EXPIRATION_TIME = serializers.IntegerField( min_value=1, max_value=99999, required=True, - label=_('User password expiration'), + label=_('User password expiration (day)'), help_text=_( - 'Unit: day, If the user does not update the password during the time, ' + 'If the user does not update the password during the time, ' 'the user password will expire failure;The password expiration reminder mail will be ' 'automatic sent to the user by system within 5 days (daily) before the password expires' ) @@ -106,9 +106,9 @@ class SecurityAuthSerializer(serializers.Serializer): ) SECURITY_MFA_VERIFY_TTL = serializers.IntegerField( min_value=5, max_value=60 * 60 * 10, - label=_("MFA verify TTL"), + label=_("MFA verify TTL (secend)"), help_text=_( - "Unit: second, The verification MFA takes effect only when you view the account password" + "The verification MFA takes effect only when you view the account password" ) ) VERIFY_CODE_TTL = serializers.IntegerField( @@ -162,8 +162,8 @@ class SecuritySettingSerializer(SecurityPasswordRuleSerializer, SecurityAuthSeri ) SECURITY_MAX_IDLE_TIME = serializers.IntegerField( min_value=1, max_value=99999, required=False, - label=_('Connection max idle time'), - help_text=_('If idle time more than it, disconnect connection Unit: minute') + label=_('Connection max idle time (minute)'), + help_text=_('If idle time more than it, disconnect connection.') ) SECURITY_LUNA_REMEMBER_AUTH = serializers.BooleanField( label=_("Remember manual auth") From f4c29a262a741a468d6922dc3366b5471004e644 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 May 2023 16:42:20 +0800 Subject: [PATCH 058/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=8C=96=E4=BB=BB=E5=8A=A1=E5=9C=A8=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=90=8D=E7=A7=B0=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../automations/change_secret/custom/ssh/manifest.yml | 5 +++-- .../change_secret/database/mongodb/manifest.yml | 5 +++-- .../automations/change_secret/database/mysql/manifest.yml | 5 +++-- .../automations/change_secret/host/aix/manifest.yml | 5 +++-- .../automations/change_secret/host/posix/manifest.yml | 5 +++-- .../automations/change_secret/host/windows/manifest.yml | 5 +++-- .../automations/gather_accounts/host/posix/manifest.yml | 5 +++-- .../automations/gather_accounts/host/windows/manifest.yml | 5 +++-- .../automations/push_account/database/mongodb/manifest.yml | 5 +++-- .../automations/push_account/database/mysql/manifest.yml | 5 +++-- .../automations/push_account/database/oracle/manifest.yml | 5 +++-- .../push_account/database/postgresql/manifest.yml | 5 +++-- .../push_account/database/sqlserver/manifest.yml | 5 +++-- .../automations/push_account/host/aix/manifest.yml | 5 +++-- .../automations/push_account/host/posix/manifest.yml | 5 +++-- .../automations/push_account/host/windows/manifest.yml | 5 +++-- .../automations/verify_account/custom/manifest.yml | 5 +++-- .../verify_account/database/mongodb/manifest.yml | 5 +++-- .../automations/verify_account/database/mysql/manifest.yml | 6 ++++-- .../verify_account/database/oracle/manifest.yml | 5 +++-- .../verify_account/database/postgresql/manifest.yml | 5 +++-- .../verify_account/database/sqlserver/manifest.yml | 5 +++-- .../automations/verify_account/host/posix/manifest.yml | 5 +++-- .../automations/verify_account/host/windows/manifest.yml | 7 ++++--- .../automations/gather_facts/database/mongodb/manifest.yml | 6 +++--- .../automations/gather_facts/database/mysql/manifest.yml | 6 +++--- .../automations/gather_facts/database/oracle/manifest.yml | 6 +++--- .../gather_facts/database/postgresql/manifest.yml | 6 +++--- .../automations/gather_facts/host/posix/manifest.yml | 6 +++--- .../automations/gather_facts/host/windows/manifest.yml | 6 +++--- apps/assets/automations/ping/custom/manifest.yml | 7 ++++++- apps/assets/automations/ping/database/mongodb/manifest.yml | 6 +++--- apps/assets/automations/ping/database/mysql/manifest.yml | 6 +++--- apps/assets/automations/ping/database/oracle/manifest.yml | 6 +++--- .../automations/ping/database/postgresql/manifest.yml | 6 +++--- .../automations/ping/database/sqlserver/manifest.yml | 6 +++--- apps/assets/automations/ping/host/posix/manifest.yml | 6 +++--- apps/assets/automations/ping/host/windows/manifest.yml | 6 +++--- 38 files changed, 119 insertions(+), 89 deletions(-) diff --git a/apps/accounts/automations/change_secret/custom/ssh/manifest.yml b/apps/accounts/automations/change_secret/custom/ssh/manifest.yml index 3ac25a231..c46511344 100644 --- a/apps/accounts/automations/change_secret/custom/ssh/manifest.yml +++ b/apps/accounts/automations/change_secret/custom/ssh/manifest.yml @@ -15,5 +15,6 @@ params: i18n: SSH account change secret: - zh: SSH 账号改密 - ja: SSH アカウントのパスワード変更 + zh: 使用 SSH 命令行自定义改密 + ja: SSH コマンドライン方式でカスタムパスワード変更 + en: Custom password change by SSH command line diff --git a/apps/accounts/automations/change_secret/database/mongodb/manifest.yml b/apps/accounts/automations/change_secret/database/mongodb/manifest.yml index ce4f6fecf..320b09476 100644 --- a/apps/accounts/automations/change_secret/database/mongodb/manifest.yml +++ b/apps/accounts/automations/change_secret/database/mongodb/manifest.yml @@ -7,5 +7,6 @@ method: change_secret i18n: MongoDB account change secret: - zh: MongoDB 账号改密 - ja: MongoDB アカウントのパスワード変更 + zh: 使用 Ansible 模块 mongodb 执行 MongoDB 账号改密 + ja: Ansible mongodb モジュールを使用して MongoDB アカウントのパスワード変更 + en: Using Ansible module mongodb to change MongoDB account secret diff --git a/apps/accounts/automations/change_secret/database/mysql/manifest.yml b/apps/accounts/automations/change_secret/database/mysql/manifest.yml index 554acd8ba..c7b8253f4 100644 --- a/apps/accounts/automations/change_secret/database/mysql/manifest.yml +++ b/apps/accounts/automations/change_secret/database/mysql/manifest.yml @@ -8,5 +8,6 @@ method: change_secret i18n: MySQL account change secret: - zh: MySQL 账号改密 - ja: MySQL アカウントのパスワード変更 + zh: 使用 Ansible 模块 mysql 执行 MySQL 账号改密 + ja: Ansible mysql モジュールを使用して MySQL アカウントのパスワード変更 + en: Using Ansible module mysql to change MySQL account secret diff --git a/apps/accounts/automations/change_secret/host/aix/manifest.yml b/apps/accounts/automations/change_secret/host/aix/manifest.yml index d95c07032..e84a9b42b 100644 --- a/apps/accounts/automations/change_secret/host/aix/manifest.yml +++ b/apps/accounts/automations/change_secret/host/aix/manifest.yml @@ -7,5 +7,6 @@ method: change_secret i18n: AIX account change secret: - zh: AIX 账号改密 - ja: AIX アカウントのパスワード変更 + zh: 使用 Ansible 模块 user 执行账号改密 (DES) + ja: Ansible user モジュールを使用してアカウントのパスワード変更 (DES) + en: Using Ansible module user to change account secret (DES) diff --git a/apps/accounts/automations/change_secret/host/posix/manifest.yml b/apps/accounts/automations/change_secret/host/posix/manifest.yml index 8c6c0d48d..6aa1bba10 100644 --- a/apps/accounts/automations/change_secret/host/posix/manifest.yml +++ b/apps/accounts/automations/change_secret/host/posix/manifest.yml @@ -8,5 +8,6 @@ method: change_secret i18n: Posix account change secret: - zh: Posix 账号改密 - ja: Posix アカウントのパスワード変更 + zh: 使用 Ansible 模块 user 执行账号改密 (SHA512) + ja: Ansible user モジュールを使用して アカウントのパスワード変更 (SHA512) + en: Using Ansible module user to change account secret (SHA512) diff --git a/apps/accounts/automations/change_secret/host/windows/manifest.yml b/apps/accounts/automations/change_secret/host/windows/manifest.yml index f04666c66..4480a9ecf 100644 --- a/apps/accounts/automations/change_secret/host/windows/manifest.yml +++ b/apps/accounts/automations/change_secret/host/windows/manifest.yml @@ -8,5 +8,6 @@ type: i18n: Windows account change secret: - zh: Windows 账号改密 - ja: Windows アカウントのパスワード変更 + zh: 使用 Ansible 模块 win_user 执行 Windows 账号改密 + ja: Ansible win_user モジュールを使用して Windows アカウントのパスワード変更 + en: Using Ansible module win_user to change Windows account secret diff --git a/apps/accounts/automations/gather_accounts/host/posix/manifest.yml b/apps/accounts/automations/gather_accounts/host/posix/manifest.yml index 33534e183..09240351b 100644 --- a/apps/accounts/automations/gather_accounts/host/posix/manifest.yml +++ b/apps/accounts/automations/gather_accounts/host/posix/manifest.yml @@ -8,5 +8,6 @@ method: gather_accounts i18n: Posix account gather: - zh: Posix 账号收集 - ja: Posix アカウントの収集 + zh: 使用命令 getent passwd 收集 Posix 资产账号 + ja: コマンド getent を使用してアセットアカウントを収集する + en: Using command getent to gather accounts diff --git a/apps/accounts/automations/gather_accounts/host/windows/manifest.yml b/apps/accounts/automations/gather_accounts/host/windows/manifest.yml index 281f095fe..c98fb0b2b 100644 --- a/apps/accounts/automations/gather_accounts/host/windows/manifest.yml +++ b/apps/accounts/automations/gather_accounts/host/windows/manifest.yml @@ -8,5 +8,6 @@ type: i18n: Windows account gather: - zh: Windows 账号收集 - ja: Windows アカウントの収集 + zh: 使用命令 net user 收集 Windows 账号 + ja: コマンド net user を使用して Windows アカウントを収集する + en: Using command net user to gather accounts diff --git a/apps/accounts/automations/push_account/database/mongodb/manifest.yml b/apps/accounts/automations/push_account/database/mongodb/manifest.yml index b4c237f78..b5728bee8 100644 --- a/apps/accounts/automations/push_account/database/mongodb/manifest.yml +++ b/apps/accounts/automations/push_account/database/mongodb/manifest.yml @@ -7,5 +7,6 @@ method: push_account i18n: MongoDB account push: - zh: MongoDB 账号推送 - ja: MongoDB アカウントのプッシュ + zh: 使用 Ansible 模块 mongodb 执行 MongoDB 账号推送 + ja: Ansible mongodb モジュールを使用してアカウントをプッシュする + en: Using Ansible module mongodb to push account diff --git a/apps/accounts/automations/push_account/database/mysql/manifest.yml b/apps/accounts/automations/push_account/database/mysql/manifest.yml index 56e144a3f..5c96d6f1b 100644 --- a/apps/accounts/automations/push_account/database/mysql/manifest.yml +++ b/apps/accounts/automations/push_account/database/mysql/manifest.yml @@ -8,5 +8,6 @@ method: push_account i18n: MySQL account push: - zh: MySQL 账号推送 - ja: MySQL アカウントのプッシュ + zh: 使用 Ansible 模块 mysql 执行 MySQL 账号推送 + ja: Ansible mysql モジュールを使用してアカウントをプッシュする + en: Using Ansible module mysql to push account diff --git a/apps/accounts/automations/push_account/database/oracle/manifest.yml b/apps/accounts/automations/push_account/database/oracle/manifest.yml index 729dc4ec7..c88b91e8c 100644 --- a/apps/accounts/automations/push_account/database/oracle/manifest.yml +++ b/apps/accounts/automations/push_account/database/oracle/manifest.yml @@ -7,5 +7,6 @@ method: push_account i18n: Oracle account push: - zh: Oracle 账号推送 - ja: Oracle アカウントのプッシュ \ No newline at end of file + zh: 使用 Python 模块 oracledb 执行 Oracle 账号推送 + ja: Python oracledb モジュールを使用してアカウントをプッシュする + en: Using Python module oracledb to push account diff --git a/apps/accounts/automations/push_account/database/postgresql/manifest.yml b/apps/accounts/automations/push_account/database/postgresql/manifest.yml index 4c8e7febb..5a595185b 100644 --- a/apps/accounts/automations/push_account/database/postgresql/manifest.yml +++ b/apps/accounts/automations/push_account/database/postgresql/manifest.yml @@ -7,5 +7,6 @@ method: push_account i18n: PostgreSQL account push: - zh: PostgreSQL 账号推送 - ja: PostgreSQL アカウントのプッシュ \ No newline at end of file + zh: 使用 Ansible 模块 postgresql 执行 PostgreSQL 账号推送 + ja: Ansible postgresql モジュールを使用してアカウントをプッシュする + en: Using Ansible module postgresql to push account diff --git a/apps/accounts/automations/push_account/database/sqlserver/manifest.yml b/apps/accounts/automations/push_account/database/sqlserver/manifest.yml index 058e75ca7..c6cf7c807 100644 --- a/apps/accounts/automations/push_account/database/sqlserver/manifest.yml +++ b/apps/accounts/automations/push_account/database/sqlserver/manifest.yml @@ -7,5 +7,6 @@ method: push_account i18n: SQLServer account push: - zh: SQLServer 账号推送 - ja: SQLServer アカウントのプッシュ + zh: 使用 Ansible 模块 mssql 执行 SQLServer 账号推送 + ja: Ansible mssql モジュールを使用してアカウントをプッシュする + en: Using Ansible module mssql to push account diff --git a/apps/accounts/automations/push_account/host/aix/manifest.yml b/apps/accounts/automations/push_account/host/aix/manifest.yml index 5421d24d8..949d49758 100644 --- a/apps/accounts/automations/push_account/host/aix/manifest.yml +++ b/apps/accounts/automations/push_account/host/aix/manifest.yml @@ -30,6 +30,7 @@ params: i18n: Aix account push: - zh: Aix 账号推送 - ja: Aix アカウントのプッシュ + zh: 使用 Ansible 模块 user 执行 Aix 账号推送 (DES) + ja: Ansible user モジュールを使用して Aix アカウントをプッシュする (DES) + en: Using Ansible module user to push account (DES) diff --git a/apps/accounts/automations/push_account/host/posix/manifest.yml b/apps/accounts/automations/push_account/host/posix/manifest.yml index 1da168a44..0c1d31845 100644 --- a/apps/accounts/automations/push_account/host/posix/manifest.yml +++ b/apps/accounts/automations/push_account/host/posix/manifest.yml @@ -32,5 +32,6 @@ params: i18n: Posix account push: - zh: Posix 账号推送 - ja: Posix アカウントのプッシュ + zh: 使用 Ansible 模块 user 执行账号推送 (sha512) + ja: Ansible user モジュールを使用してアカウントをプッシュする (sha512) + en: Using Ansible module user to push account (sha512) diff --git a/apps/accounts/automations/push_account/host/windows/manifest.yml b/apps/accounts/automations/push_account/host/windows/manifest.yml index 28745245f..7866e3c13 100644 --- a/apps/accounts/automations/push_account/host/windows/manifest.yml +++ b/apps/accounts/automations/push_account/host/windows/manifest.yml @@ -14,5 +14,6 @@ params: i18n: Windows account push: - zh: Windows 账号推送 - ja: Windows アカウントのプッシュ + zh: 使用 Ansible 模块 win_user 执行 Windows 账号推送 + ja: Ansible win_user モジュールを使用して Windows アカウントをプッシュする + en: Using Ansible module win_user to push account diff --git a/apps/accounts/automations/verify_account/custom/manifest.yml b/apps/accounts/automations/verify_account/custom/manifest.yml index ceef8e50d..666266416 100644 --- a/apps/accounts/automations/verify_account/custom/manifest.yml +++ b/apps/accounts/automations/verify_account/custom/manifest.yml @@ -9,5 +9,6 @@ method: verify_account i18n: SSH account verify: - zh: SSH 账号验证 - ja: SSH アカウントの検証 + zh: 使用 Python 模块 paramiko 验证账号 + ja: Python モジュール paramiko を使用してアカウントを検証する + en: Using Python module paramiko to verify account diff --git a/apps/accounts/automations/verify_account/database/mongodb/manifest.yml b/apps/accounts/automations/verify_account/database/mongodb/manifest.yml index fd5a31294..941e19a6a 100644 --- a/apps/accounts/automations/verify_account/database/mongodb/manifest.yml +++ b/apps/accounts/automations/verify_account/database/mongodb/manifest.yml @@ -7,5 +7,6 @@ method: verify_account i18n: MongoDB account verify: - zh: MongoDB 账号验证 - ja: MongoDB アカウントの検証 + zh: 使用 Ansible 模块 mongodb 验证账号 + ja: Ansible mongodb モジュールを使用してアカウントを検証する + en: Using Ansible module mongodb to verify account diff --git a/apps/accounts/automations/verify_account/database/mysql/manifest.yml b/apps/accounts/automations/verify_account/database/mysql/manifest.yml index bd381de0b..281954f74 100644 --- a/apps/accounts/automations/verify_account/database/mysql/manifest.yml +++ b/apps/accounts/automations/verify_account/database/mysql/manifest.yml @@ -8,5 +8,7 @@ method: verify_account i18n: MySQL account verify: - zh: MySQL 账号验证 - ja: MySQL アカウントの検証 + zh: 使用 Ansible 模块 mysql 验证账号 + ja: Ansible mysql モジュールを使用してアカウントを検証する + en: Using Ansible module mysql to verify account + diff --git a/apps/accounts/automations/verify_account/database/oracle/manifest.yml b/apps/accounts/automations/verify_account/database/oracle/manifest.yml index 220445daa..48f343749 100644 --- a/apps/accounts/automations/verify_account/database/oracle/manifest.yml +++ b/apps/accounts/automations/verify_account/database/oracle/manifest.yml @@ -7,5 +7,6 @@ method: verify_account i18n: Oracle account verify: - zh: Oracle 账号验证 - ja: Oracle アカウントの検証 + zh: 使用 Python 模块 oracledb 验证账号 + ja: Python モジュール oracledb を使用してアカウントを検証する + en: Using Python module oracledb to verify account diff --git a/apps/accounts/automations/verify_account/database/postgresql/manifest.yml b/apps/accounts/automations/verify_account/database/postgresql/manifest.yml index 6ce7175b3..edc035562 100644 --- a/apps/accounts/automations/verify_account/database/postgresql/manifest.yml +++ b/apps/accounts/automations/verify_account/database/postgresql/manifest.yml @@ -7,5 +7,6 @@ method: verify_account i18n: PostgreSQL account verify: - zh: PostgreSQL 账号验证 - ja: PostgreSQL アカウントの検証 + zh: 使用 Ansible 模块 postgresql 验证账号 + ja: Ansible postgresql モジュールを使用してアカウントを検証する + en: Using Ansible module postgresql to verify account diff --git a/apps/accounts/automations/verify_account/database/sqlserver/manifest.yml b/apps/accounts/automations/verify_account/database/sqlserver/manifest.yml index 8effdcfeb..d98555184 100644 --- a/apps/accounts/automations/verify_account/database/sqlserver/manifest.yml +++ b/apps/accounts/automations/verify_account/database/sqlserver/manifest.yml @@ -7,5 +7,6 @@ method: verify_account i18n: SQLServer account verify: - zh: SQLServer 账号验证 - ja: SQLServer アカウントの検証 \ No newline at end of file + zh: 使用 Ansible 模块 mssql 验证账号 + ja: Ansible mssql モジュールを使用してアカウントを検証する + en: Using Ansible module mssql to verify account diff --git a/apps/accounts/automations/verify_account/host/posix/manifest.yml b/apps/accounts/automations/verify_account/host/posix/manifest.yml index 26ee3b025..1c1d531a4 100644 --- a/apps/accounts/automations/verify_account/host/posix/manifest.yml +++ b/apps/accounts/automations/verify_account/host/posix/manifest.yml @@ -8,5 +8,6 @@ method: verify_account i18n: Posix account verify: - zh: Posix 账号验证 - ja: Posix アカウントの検証 \ No newline at end of file + zh: 使用 Ansible 模块 ping 验证账号 + ja: Ansible ping モジュールを使用してアカウントを検証する + en: Using Ansible module ping to verify account diff --git a/apps/accounts/automations/verify_account/host/windows/manifest.yml b/apps/accounts/automations/verify_account/host/windows/manifest.yml index 28b914d10..a277f8c62 100644 --- a/apps/accounts/automations/verify_account/host/windows/manifest.yml +++ b/apps/accounts/automations/verify_account/host/windows/manifest.yml @@ -7,6 +7,7 @@ type: - windows i18n: - Windows account verify: - zh: Windows 账号验证 - ja: Windows アカウントの検証 + Windows account verify: + zh: 使用 Ansible 模块 win_ping 验证账号 + ja: Ansible win_ping モジュールを使用してアカウントを検証する + en: Using Ansible module win_ping to verify account diff --git a/apps/assets/automations/gather_facts/database/mongodb/manifest.yml b/apps/assets/automations/gather_facts/database/mongodb/manifest.yml index 0f1a497b1..7f7367188 100644 --- a/apps/assets/automations/gather_facts/database/mongodb/manifest.yml +++ b/apps/assets/automations/gather_facts/database/mongodb/manifest.yml @@ -6,6 +6,6 @@ type: method: gather_facts i18n: Gather facts from MongoDB: - zh: 从 MongoDB 获取信息 - en: Gather facts from MongoDB - ja: MongoDBから事実を取得する + zh: 使用 Ansible 模块 mongodb 获取 mongodb 信息 + en: Gather facts from MongoDB using mongodb module + ja: mongodbモジュールを使用して MongoDBから情報を収集する diff --git a/apps/assets/automations/gather_facts/database/mysql/manifest.yml b/apps/assets/automations/gather_facts/database/mysql/manifest.yml index d2f005859..c4a266fca 100644 --- a/apps/assets/automations/gather_facts/database/mysql/manifest.yml +++ b/apps/assets/automations/gather_facts/database/mysql/manifest.yml @@ -7,6 +7,6 @@ type: method: gather_facts i18n: Gather facts from MySQL: - zh: 从 MySQL 获取信息 - en: Gather facts from MySQL - ja: MySQLから事実を取得する + zh: 使用 Ansible 模块 mysql 从 MySQL server 获取信息 + en: Gather facts from MySQL server using mysql module + ja: mysqlモジュールを使用して MySQL serverから情報を収集する diff --git a/apps/assets/automations/gather_facts/database/oracle/manifest.yml b/apps/assets/automations/gather_facts/database/oracle/manifest.yml index e39522b75..ad214cd5f 100644 --- a/apps/assets/automations/gather_facts/database/oracle/manifest.yml +++ b/apps/assets/automations/gather_facts/database/oracle/manifest.yml @@ -6,6 +6,6 @@ type: method: gather_facts i18n: Gather facts from Oracle: - zh: 从 Oracle 获取信息 - en: Gather facts from Oracle - ja: Oracleから事実を取得する + zh: 使用 oracledb 模块获取 Oracle 信息 + en: Gather facts from Oracle using oracledb module + ja: oracledbモジュールを使用して Oracleから情報を収集する diff --git a/apps/assets/automations/gather_facts/database/postgresql/manifest.yml b/apps/assets/automations/gather_facts/database/postgresql/manifest.yml index 288298d96..3b272e4af 100644 --- a/apps/assets/automations/gather_facts/database/postgresql/manifest.yml +++ b/apps/assets/automations/gather_facts/database/postgresql/manifest.yml @@ -6,6 +6,6 @@ type: method: gather_facts i18n: Gather facts for PostgreSQL: - zh: 从 PostgreSQL 获取信息 - en: Gather facts for PostgreSQL - ja: PostgreSQLから事実を取得する + zh: 使用 Ansible 模块 postgresql 获取 PostgreSQL 信息 + en: Gather facts for PostgreSQL using postgresql module + ja: postgresqlモジュールを使用して PostgreSQLから情報を収集する diff --git a/apps/assets/automations/gather_facts/host/posix/manifest.yml b/apps/assets/automations/gather_facts/host/posix/manifest.yml index 78eb1d897..a92c496e9 100644 --- a/apps/assets/automations/gather_facts/host/posix/manifest.yml +++ b/apps/assets/automations/gather_facts/host/posix/manifest.yml @@ -7,6 +7,6 @@ type: method: gather_facts i18n: Gather posix facts: - zh: 从 Posix 主机获取信息 - en: Gather posix facts - ja: Posixから事実を取得する + zh: 使用 Ansible 指令 gather_facts 从主机获取设备信息 + en: Gather facts from asset using gather_facts + ja: gather_factsを使用してPosixから情報を収集する diff --git a/apps/assets/automations/gather_facts/host/windows/manifest.yml b/apps/assets/automations/gather_facts/host/windows/manifest.yml index bf2b4e0fd..809208e10 100644 --- a/apps/assets/automations/gather_facts/host/windows/manifest.yml +++ b/apps/assets/automations/gather_facts/host/windows/manifest.yml @@ -7,6 +7,6 @@ type: - windows i18n: Gather facts windows: - zh: 从 Windows 获取硬件信息 - en: Gather facts windows - ja: Windowsから事実を取得する + zh: 使用 Ansible 指令 gather_facts 从 Windows 获取设备信息 + en: Gather facts from Windows using gather_facts + ja: gather_factsを使用してWindowsから情報を収集する diff --git a/apps/assets/automations/ping/custom/manifest.yml b/apps/assets/automations/ping/custom/manifest.yml index a67cca17d..d57a50a2e 100644 --- a/apps/assets/automations/ping/custom/manifest.yml +++ b/apps/assets/automations/ping/custom/manifest.yml @@ -1,8 +1,13 @@ id: ping_by_ssh -name: Ping by SSH +name: "{{ 'Ping by paramiko' | trans }}" category: - device - host type: - all method: ping +i18n: + Ping by paramiko: + zh: 使用 Python 模块 paramiko 测试主机可连接性 + en: Ping by paramiko module + ja: Paramikoモジュールを使用してホストにPingする diff --git a/apps/assets/automations/ping/database/mongodb/manifest.yml b/apps/assets/automations/ping/database/mongodb/manifest.yml index bdc0d73db..38af73318 100644 --- a/apps/assets/automations/ping/database/mongodb/manifest.yml +++ b/apps/assets/automations/ping/database/mongodb/manifest.yml @@ -6,6 +6,6 @@ type: method: ping i18n: Ping MongoDB: - zh: 测试 MongoDB 可连接性 - en: Ping MongoDB - ja: MongoDBにPingする + zh: 使用 Ansible 模块 mongodb 来测试 MongoDB 可连接性 + en: Use ansible mongodb module to test MongoDB + ja: Ansible mongodbモジュールを使用してテストする MongoDB diff --git a/apps/assets/automations/ping/database/mysql/manifest.yml b/apps/assets/automations/ping/database/mysql/manifest.yml index 0452a8293..701f9942e 100644 --- a/apps/assets/automations/ping/database/mysql/manifest.yml +++ b/apps/assets/automations/ping/database/mysql/manifest.yml @@ -7,6 +7,6 @@ type: method: ping i18n: Ping MySQL: - zh: 测试 MySQL 可连接性 - en: Ping MySQL - ja: MySQLにPingする + zh: 使用 Ansible 模块 mysql 来测试 MySQL 可连接性 + en: Use ansible mysql module to test MySQL + ja: Ansible mysqlモジュールを使用してテストする MySQL diff --git a/apps/assets/automations/ping/database/oracle/manifest.yml b/apps/assets/automations/ping/database/oracle/manifest.yml index bc55805b3..20515374e 100644 --- a/apps/assets/automations/ping/database/oracle/manifest.yml +++ b/apps/assets/automations/ping/database/oracle/manifest.yml @@ -6,6 +6,6 @@ type: method: ping i18n: Ping Oracle: - zh: 测试 Oracle 可连接性 - en: Ping Oracle - ja: OracleにPingする + zh: 使用 python oracledb 模块来测试 Oracle 可连接性 + en: Use python oracledb module to test Oracle + ja: Python oracledbモジュールを使用してテストする Oracle diff --git a/apps/assets/automations/ping/database/postgresql/manifest.yml b/apps/assets/automations/ping/database/postgresql/manifest.yml index f7d7c3602..3ae6c2186 100644 --- a/apps/assets/automations/ping/database/postgresql/manifest.yml +++ b/apps/assets/automations/ping/database/postgresql/manifest.yml @@ -6,6 +6,6 @@ type: method: ping i18n: Ping PostgreSQL: - zh: 测试 PostgreSQL 可连接性 - en: Ping PostgreSQL - ja: PostgreSQLにPingする + zh: 使用 Ansible 模块 postgresql 来测试 PostgreSQL 连接性 + en: Ping PostgreSQL using ansible postgresql module + ja: ansible postgresql モジュールを使用して PostgreSQL に ping を送信する diff --git a/apps/assets/automations/ping/database/sqlserver/manifest.yml b/apps/assets/automations/ping/database/sqlserver/manifest.yml index fe11e7486..2556c4e1b 100644 --- a/apps/assets/automations/ping/database/sqlserver/manifest.yml +++ b/apps/assets/automations/ping/database/sqlserver/manifest.yml @@ -6,6 +6,6 @@ type: method: ping i18n: Ping SQLServer: - zh: 测试 SQLServer 可连接性 - en: Ping SQLServer - ja: SQLServerにPingする + zh: 使用 Ansible 模块 mssql 来测试 SQLServer 连接性 + en: Ping SQLServer using ansible mssql module + ja: ansible mssql モジュールを使用して SQLServer に ping を送信する diff --git a/apps/assets/automations/ping/host/posix/manifest.yml b/apps/assets/automations/ping/host/posix/manifest.yml index ebc1046db..720ada630 100644 --- a/apps/assets/automations/ping/host/posix/manifest.yml +++ b/apps/assets/automations/ping/host/posix/manifest.yml @@ -8,6 +8,6 @@ method: ping i18n: Posix ping: - zh: 测试 Posix 可连接性 - en: Posix ping - ja: Posix ピング + zh: 使用 Ansible 模块 ping 来测试可连接性 + en: Use Ansible builtin module ping to test Posix + ja: Ansible 組み込みモジュール ping を使用してテストする Posix diff --git a/apps/assets/automations/ping/host/windows/manifest.yml b/apps/assets/automations/ping/host/windows/manifest.yml index 6798c1198..7c42e03ba 100644 --- a/apps/assets/automations/ping/host/windows/manifest.yml +++ b/apps/assets/automations/ping/host/windows/manifest.yml @@ -7,6 +7,6 @@ type: - windows i18n: Windows ping: - zh: 测试 Windows 可连接性 - en: Windows ping - ja: Windows ピング + zh: 使用 Ansible 模块 内置模块 win_ping 来测试可连接性 + en: Use Ansible builtin module win_ping to test Windows + ja: Ansible 組み込みモジュール win_ping を使用してテストする Windows From d285daa1c1525beaf1f33b6759447afd92597dd2 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 May 2023 17:12:14 +0800 Subject: [PATCH 059/153] =?UTF-8?q?perf:=20=E8=B5=84=E4=BA=A7=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=A0=B9=E6=8D=AE=E5=8D=8F=E8=AE=AE=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/asset/asset.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/assets/api/asset/asset.py b/apps/assets/api/asset/asset.py index ce5d8f9ac..82733b03e 100644 --- a/apps/assets/api/asset/asset.py +++ b/apps/assets/api/asset/asset.py @@ -35,6 +35,7 @@ class AssetFilterSet(BaseFilterSet): domain = django_filters.CharFilter(method='filter_domain') type = django_filters.CharFilter(field_name="platform__type", lookup_expr="exact") category = django_filters.CharFilter(field_name="platform__category", lookup_expr="exact") + protocols = django_filters.CharFilter(method='filter_protocols') domain_enabled = django_filters.BooleanFilter( field_name="platform__domain_enabled", lookup_expr="exact" ) @@ -78,6 +79,11 @@ class AssetFilterSet(BaseFilterSet): else: return queryset.filter(domain__name__contains=value) + @staticmethod + def filter_protocols(queryset, name, value): + value = value.split(',') + return queryset.filter(protocols__name__in=value) + @staticmethod def filter_labels(queryset, name, value): if ':' in value: From 312213f1c55d61da400793bcb124de626d13df0f Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 30 May 2023 17:54:28 +0800 Subject: [PATCH 060/153] =?UTF-8?q?perf:=20=E5=85=81=E8=AE=B8=20web=20?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E6=89=93=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/models/applet/applet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index 8293668ed..b420b3bf0 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -180,7 +180,7 @@ class Applet(JMSBaseModel): host = self.select_host(user) if not host: return None - can_concurrent = self.can_concurrent and self.type == 'general' + can_concurrent = self.can_concurrent or self.type == 'web' accounts = host.accounts.all().filter(is_active=True, privileged=False) private_account = accounts.filter(username='js_{}'.format(user.username)).first() From 3626bf8df680feba2602e6870cc7b3733c179fcb Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Tue, 30 May 2023 18:45:51 +0800 Subject: [PATCH 061/153] =?UTF-8?q?feat:=20=E5=91=BD=E4=BB=A4=E5=8F=8A?= =?UTF-8?q?=E5=BD=95=E5=83=8F=E5=AD=98=E5=82=A8=E5=8F=AF=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E6=80=A7=E5=AE=9A=E6=97=B6=E6=A3=80=E6=9F=A5=20(#10594)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/notifications/api/notifications.py | 12 +++--- apps/notifications/notifications.py | 12 +++--- apps/ops/celery/decorator.py | 2 +- apps/terminal/notifications.py | 40 ++++++++++++++++++- apps/terminal/tasks.py | 40 ++++++++++++++++++- ...k_command_replay_storage_connectivity.html | 13 ++++++ 6 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 apps/terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html diff --git a/apps/notifications/api/notifications.py b/apps/notifications/api/notifications.py index bbac4b49a..827cb9d19 100644 --- a/apps/notifications/api/notifications.py +++ b/apps/notifications/api/notifications.py @@ -1,12 +1,12 @@ from rest_framework.mixins import ListModelMixin, UpdateModelMixin, RetrieveModelMixin -from rest_framework.views import APIView from rest_framework.response import Response +from rest_framework.views import APIView from common.api import JMSGenericViewSet from common.permissions import IsValidUser -from notifications.notifications import system_msgs -from notifications.models import SystemMsgSubscription, UserMsgSubscription from notifications.backends import BACKEND +from notifications.models import SystemMsgSubscription, UserMsgSubscription +from notifications.notifications import system_msgs from notifications.serializers import ( SystemMsgSubscriptionSerializer, SystemMsgSubscriptionByCategorySerializer, UserMsgSubscriptionSerializer, @@ -32,9 +32,9 @@ class BackendListView(APIView): return Response(data=data) -class SystemMsgSubscriptionViewSet(ListModelMixin, - UpdateModelMixin, - JMSGenericViewSet): +class SystemMsgSubscriptionViewSet( + ListModelMixin, UpdateModelMixin, JMSGenericViewSet +): lookup_field = 'message_type' queryset = SystemMsgSubscription.objects.all() serializer_classes = { diff --git a/apps/notifications/notifications.py b/apps/notifications/notifications.py index 55f1cdbad..6c631ec16 100644 --- a/apps/notifications/notifications.py +++ b/apps/notifications/notifications.py @@ -1,17 +1,17 @@ -import traceback -from html2text import HTML2Text -from typing import Iterable -from itertools import chain import textwrap +import traceback +from itertools import chain +from typing import Iterable from celery import shared_task from django.utils.translation import gettext_lazy as _ +from html2text import HTML2Text -from common.utils.timezone import local_now from common.utils import lazyproperty +from common.utils.timezone import local_now +from notifications.backends import BACKEND from settings.utils import get_login_title from users.models import User -from notifications.backends import BACKEND from .models import SystemMsgSubscription, UserMsgSubscription __all__ = ('SystemMessage', 'UserMessage', 'system_msgs', 'Message') diff --git a/apps/ops/celery/decorator.py b/apps/ops/celery/decorator.py index 971d5b863..45626bb0f 100644 --- a/apps/ops/celery/decorator.py +++ b/apps/ops/celery/decorator.py @@ -36,7 +36,7 @@ def register_as_period_task( args=(), kwargs=None, description=''): """ - Warning: Task must be have not any args and kwargs + Warning: Task must have not any args and kwargs :param crontab: "* * * * *" :param interval: 60*60*60 :param args: () diff --git a/apps/terminal/notifications.py b/apps/terminal/notifications.py index a6b1a69a6..919bf9c65 100644 --- a/apps/terminal/notifications.py +++ b/apps/terminal/notifications.py @@ -15,7 +15,7 @@ from users.models import User logger = get_logger(__name__) -__all__ = ('CommandAlertMessage', 'CommandExecutionAlert') +__all__ = ('CommandAlertMessage', 'CommandExecutionAlert', 'StorageConnectivityMessage') CATEGORY = 'terminal' CATEGORY_LABEL = _('Sessions') @@ -156,3 +156,41 @@ class CommandExecutionAlert(CommandAlertMixin, SystemMessage): 'subject': self.subject, 'message': message } + + +class StorageConnectivityMessage(SystemMessage): + category = 'storage' + category_label = _('Command and replay storage') + message_type_label = _('Connectivity alarm') + + def __init__(self, errors): + self.errors = errors + + @classmethod + def post_insert_to_db(cls, subscription: SystemMsgSubscription): + subscription.receive_backends = [b for b in BACKEND if b.is_enable] + subscription.save() + + @classmethod + def gen_test_msg(cls): + from terminal.models import ReplayStorage + replay = ReplayStorage.objects.first() + errors = [{ + 'msg': str(_("Test failure: Account invalid")), + 'type': replay.get_type_display(), + 'name': replay.name + }] + return cls(errors) + + def get_html_msg(self) -> dict: + context = { + 'items': self.errors, + } + subject = str(_("Invalid storage")) + message = render_to_string( + 'terminal/_msg_check_command_replay_storage_connectivity.html', context + ) + return { + 'subject': subject, + 'message': message + } diff --git a/apps/terminal/tasks.py b/apps/terminal/tasks.py index 66e6871d7..d53380923 100644 --- a/apps/terminal/tasks.py +++ b/apps/terminal/tasks.py @@ -2,6 +2,7 @@ # import datetime +from itertools import chain from celery import shared_task from celery.utils.log import get_task_logger @@ -14,10 +15,14 @@ from ops.celery.decorator import ( after_app_shutdown_clean_periodic ) from orgs.utils import tmp_to_builtin_org +from orgs.utils import tmp_to_root_org from .backends import server_replay_storage +from .const import ReplayStorageType, CommandStorageType from .models import ( - Status, Session, Task, AppletHostDeployment, AppletHost + Status, Session, Task, AppletHostDeployment, + AppletHost, ReplayStorage, CommandStorage ) +from .notifications import StorageConnectivityMessage from .utils import find_session_replay_local CACHE_REFRESH_INTERVAL = 10 @@ -111,3 +116,36 @@ def applet_host_generate_accounts(host_id): with tmp_to_builtin_org(system=1): applet_host.generate_accounts() + + +@shared_task(verbose_name=_('Check command replay storage connectivity')) +@register_as_period_task(crontab='0 0 * * *') +@tmp_to_root_org() +def check_command_replay_storage_connectivity(): + errors = [] + replays = ReplayStorage.objects.exclude( + type__in=[ReplayStorageType.server, ReplayStorageType.null] + ) + commands = CommandStorage.objects.exclude( + type__in=[CommandStorageType.server, CommandStorageType.null] + ) + + for instance in chain(replays, commands): + msg = None + try: + is_valid = instance.is_valid() + except Exception as e: + is_valid = False + msg = _("Test failure: {}".format(str(e))) + if is_valid: + continue + errors.append({ + 'msg': msg or _("Test failure: Account invalid"), + 'type': instance.get_type_display(), + 'name': instance.name + }) + + if not errors: + return + + StorageConnectivityMessage(errors).publish_async() diff --git a/apps/terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html b/apps/terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html new file mode 100644 index 000000000..366be33cf --- /dev/null +++ b/apps/terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html @@ -0,0 +1,13 @@ +{% load i18n %} + +

+ {% blocktranslate %} + Invalid storage + {% endblocktranslate %} +

+ +
    + {% for item in items %} +
  • {{ item.name }}({{ item.type }}): {{ item.msg }}
  • + {% endfor %} +
From 51e5733f1c43afa2ac987afc16c92794943fad65 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Wed, 31 May 2023 10:20:37 +0800 Subject: [PATCH 062/153] =?UTF-8?q?fix:=20=E5=85=B7=E6=9C=89=E8=B6=85?= =?UTF-8?q?=E7=BA=A7=E5=B7=A5=E5=8D=95=E6=9D=83=E9=99=90=E7=9A=84=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=94=B3=E8=AF=B7=E5=B7=A5=E5=8D=95=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E7=BB=99=E6=9F=90=E4=BA=BA=20(#10596)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/tickets/api/ticket.py | 1 - apps/tickets/serializers/ticket/ticket.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tickets/api/ticket.py b/apps/tickets/api/ticket.py index 29163a342..2fa710ed6 100644 --- a/apps/tickets/api/ticket.py +++ b/apps/tickets/api/ticket.py @@ -64,7 +64,6 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet): def perform_create(self, serializer): instance = serializer.save() - instance.applicant = self.request.user instance.save(update_fields=['applicant']) instance.open() diff --git a/apps/tickets/serializers/ticket/ticket.py b/apps/tickets/serializers/ticket/ticket.py index 4a36ccf4f..ff76ee9eb 100644 --- a/apps/tickets/serializers/ticket/ticket.py +++ b/apps/tickets/serializers/ticket/ticket.py @@ -59,6 +59,7 @@ class TicketApplySerializer(TicketSerializer): org_id = serializers.CharField( required=True, max_length=36, allow_blank=True, label=_("Organization") ) + applicant = serializers.CharField(required=False, allow_blank=True) def get_applicant(self, applicant_id): current_user = self.context['request'].user From 0ba7ca6373700389d9c199f8c1b76c5d3680f7b0 Mon Sep 17 00:00:00 2001 From: Bai Date: Wed, 31 May 2023 14:02:05 +0800 Subject: [PATCH 063/153] =?UTF-8?q?perf:=20=E5=8D=87=E7=BA=A7=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=20certifi=3D=3D2022.12.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index cd57abbdd..74999c74e 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -6,7 +6,7 @@ ansible-runner==2.2.1 asn1crypto==0.24.0 bcrypt==3.1.4 billiard==3.6.4.0 -certifi==2018.1.18 +certifi==2022.12.7 cffi==1.15.1 chardet==3.0.4 configparser==3.5.0 From 7d111b6efb59a0b9efb7da3ed10f997f5d75d385 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 31 May 2023 16:21:24 +0800 Subject: [PATCH 064/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=B9=B3=E5=8F=B0=E5=92=8C=20applet=20?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/migrations/0028_protocol.py | 12 ++++++---- apps/assets/serializers/asset/common.py | 6 ++--- apps/assets/serializers/asset/custom.py | 16 ++++++++++--- apps/common/serializers/common.py | 2 +- apps/terminal/models/applet/applet.py | 32 ++++++++++++++++++------- 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/apps/assets/migrations/0028_protocol.py b/apps/assets/migrations/0028_protocol.py index 230c43773..82b311c11 100644 --- a/apps/assets/migrations/0028_protocol.py +++ b/apps/assets/migrations/0028_protocol.py @@ -1,12 +1,12 @@ # Generated by Django 2.1.7 on 2019-05-22 02:58 +import uuid + import django.core.validators from django.db import migrations, models -import uuid class Migration(migrations.Migration): - dependencies = [ ('assets', '0027_auto_20190521_1703'), ] @@ -16,8 +16,12 @@ class Migration(migrations.Migration): name='Protocol', fields=[ ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), - ('name', models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('telnet', 'telnet (beta)'), ('vnc', 'vnc')], default='ssh', max_length=16, verbose_name='Name')), - ('port', models.IntegerField(default=22, validators=[django.core.validators.MaxValueValidator(65535), django.core.validators.MinValueValidator(1)], verbose_name='Port')), + ('name', + models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('telnet', 'telnet (beta)'), ('vnc', 'vnc')], + default='ssh', max_length=16, verbose_name='Name')), + ('port', models.IntegerField(default=22, validators=[django.core.validators.MaxValueValidator(65535), + django.core.validators.MinValueValidator(0)], + verbose_name='Port')), ], ), migrations.AddField( diff --git a/apps/assets/serializers/asset/common.py b/apps/assets/serializers/asset/common.py index 88a6cfef2..ba642dd96 100644 --- a/apps/assets/serializers/asset/common.py +++ b/apps/assets/serializers/asset/common.py @@ -28,7 +28,7 @@ __all__ = [ class AssetProtocolsSerializer(serializers.ModelSerializer): - port = serializers.IntegerField(required=False, allow_null=True, max_value=65535, min_value=1) + port = serializers.IntegerField(required=False, allow_null=True, max_value=65535, min_value=0) def to_file_representation(self, data): return '{name}/{port}'.format(**data) @@ -259,8 +259,8 @@ class AssetSerializer(BulkOrgResourceModelSerializer, WritableNestedModelSeriali protocols_data_map = {p['name']: p for p in protocols_data} for p in protocols_data: port = p.get('port', 0) - if port < 1 or port > 65535: - error = p.get('name') + ': ' + _("port out of range (1-65535)") + if port < 0 or port > 65535: + error = p.get('name') + ': ' + _("port out of range (0-65535)") raise serializers.ValidationError(error) protocols_required, protocols_default = self._get_protocols_required_default() diff --git a/apps/assets/serializers/asset/custom.py b/apps/assets/serializers/asset/custom.py index d857aaa8b..6487517f6 100644 --- a/apps/assets/serializers/asset/custom.py +++ b/apps/assets/serializers/asset/custom.py @@ -1,22 +1,32 @@ from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ +from rest_framework import serializers from assets.models import Custom, Platform, Asset from common.const import UUID_PATTERN -from common.serializers import MethodSerializer, create_serializer_class -from common.serializers.common import DictSerializer +from common.serializers import create_serializer_class +from common.serializers.common import DictSerializer, MethodSerializer from .common import AssetSerializer __all__ = ['CustomSerializer'] +class CustomInfoSerializer(serializers.Serializer): + name = serializers.CharField(required=False) + + class CustomSerializer(AssetSerializer): - custom_info = MethodSerializer(label=_('Custom info')) + custom_info = MethodSerializer(label=_('Custom info'), required=False, allow_null=True) class Meta(AssetSerializer.Meta): model = Custom fields = AssetSerializer.Meta.fields + ['custom_info'] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if hasattr(self, 'initial_data') and not self.initial_data.get('custom_info'): + self.initial_data['custom_info'] = {} + def get_custom_info_serializer(self): request = self.context.get('request') default_field = DictSerializer() diff --git a/apps/common/serializers/common.py b/apps/common/serializers/common.py index cd91f269c..67233b174 100644 --- a/apps/common/serializers/common.py +++ b/apps/common/serializers/common.py @@ -14,7 +14,7 @@ __all__ = [ 'MethodSerializer', 'EmptySerializer', 'BulkModelSerializer', 'AdaptedBulkListSerializer', 'CeleryTaskExecutionSerializer', 'WritableNestedModelSerializer', 'GroupedChoiceSerializer', - 'FileSerializer' + 'FileSerializer', 'DictSerializer' ] diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index b420b3bf0..3101273a4 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -10,6 +10,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from rest_framework.serializers import ValidationError +from assets.models import Platform from common.db.models import JMSBaseModel from common.utils import lazyproperty, get_logger from common.utils.yml import yaml_load_with_i18n @@ -91,8 +92,7 @@ class Applet(JMSBaseModel): raise ValidationError({'error': 'Missing name in manifest.yml'}) return manifest - @classmethod - def load_platform_if_need(cls, d): + def load_platform_if_need(self, d): from assets.serializers import PlatformSerializer from assets.const import CustomTypes @@ -109,16 +109,21 @@ class Applet(JMSBaseModel): try: tp = data['type'] + platform_name = data['name'] except KeyError: raise ValidationError({'error': _('Missing type in platform.yml')}) if not data.get('automation'): data['automation'] = CustomTypes._get_automation_constrains()['*'] - s = PlatformSerializer(data=data) + created_by = 'Applet:{}'.format(self.name) + instance = Platform.objects.filter(name=platform_name, created_by=created_by).first() + s = PlatformSerializer(data=data, instance=instance) s.add_type_choices(tp, tp) s.is_valid(raise_exception=True) - s.save() + p = s.save() + p.created_by = created_by + p.save(update_fields=['created_by']) @classmethod def install_from_dir(cls, path, builtin=True): @@ -129,9 +134,8 @@ class Applet(JMSBaseModel): instance = cls.objects.filter(name=name).first() serializer = AppletSerializer(instance=instance, data=manifest) serializer.is_valid() - serializer.save(builtin=builtin) - - cls.load_platform_if_need(path) + instance = serializer.save(builtin=builtin) + instance.load_platform_if_need(path) pkg_path = default_storage.path('applets/{}'.format(name)) if os.path.exists(pkg_path): @@ -157,6 +161,11 @@ class Applet(JMSBaseModel): cache.set(prefer_key, host.id, timeout=None) return host + def get_related_platform(self): + created_by = 'Applet:{}'.format(self.name) + platform = Platform.objects.filter(created_by=created_by).first() + return platform + @staticmethod def random_select_prefer_account(user, host, accounts): msg = 'Applet host remain public accounts: {}: {}'.format(host.name, len(accounts)) @@ -197,7 +206,8 @@ class Applet(JMSBaseModel): if private_account and private_account.username not in accounts_username_used: account = private_account else: - accounts = accounts.exclude(username__in=accounts_username_used).filter(username__startswith='jms_') + accounts = accounts.exclude(username__in=accounts_username_used) \ + .filter(username__startswith='jms_') account = self.random_select_prefer_account(user, host, accounts) if not account: return @@ -212,6 +222,12 @@ class Applet(JMSBaseModel): 'ttl': ttl } + def delete(self, using=None, keep_parents=False): + platform = self.get_related_platform() + if platform and platform.assets.count() == 0: + platform.delete() + return super().delete(using, keep_parents) + class AppletPublication(JMSBaseModel): applet = models.ForeignKey('Applet', on_delete=models.CASCADE, related_name='publications', From 2a183e34ac8fe6a7ed393c007a0fc4615905ff7a Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 31 May 2023 16:33:25 +0800 Subject: [PATCH 065/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=20debug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/serializers/asset/custom.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/assets/serializers/asset/custom.py b/apps/assets/serializers/asset/custom.py index 6487517f6..151597b44 100644 --- a/apps/assets/serializers/asset/custom.py +++ b/apps/assets/serializers/asset/custom.py @@ -1,6 +1,5 @@ from django.db.models import QuerySet from django.utils.translation import gettext_lazy as _ -from rest_framework import serializers from assets.models import Custom, Platform, Asset from common.const import UUID_PATTERN @@ -11,10 +10,6 @@ from .common import AssetSerializer __all__ = ['CustomSerializer'] -class CustomInfoSerializer(serializers.Serializer): - name = serializers.CharField(required=False) - - class CustomSerializer(AssetSerializer): custom_info = MethodSerializer(label=_('Custom info'), required=False, allow_null=True) From d402de012bb8687c81f3e1e0cef18d9e9d346ff6 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 31 May 2023 16:35:42 +0800 Subject: [PATCH 066/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=86=99?= =?UTF-8?q?=E6=B3=95=EF=BC=8C=E9=81=BF=E5=85=8D=E9=87=8D=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/models/applet/applet.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index 3101273a4..bd9543f40 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -109,7 +109,6 @@ class Applet(JMSBaseModel): try: tp = data['type'] - platform_name = data['name'] except KeyError: raise ValidationError({'error': _('Missing type in platform.yml')}) @@ -117,7 +116,7 @@ class Applet(JMSBaseModel): data['automation'] = CustomTypes._get_automation_constrains()['*'] created_by = 'Applet:{}'.format(self.name) - instance = Platform.objects.filter(name=platform_name, created_by=created_by).first() + instance = self.get_related_platform() s = PlatformSerializer(data=data, instance=instance) s.add_type_choices(tp, tp) s.is_valid(raise_exception=True) From 51d6090fdcd60c719661c0337b99121cb625b10a Mon Sep 17 00:00:00 2001 From: Bai Date: Wed, 31 May 2023 16:37:55 +0800 Subject: [PATCH 067/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=B4=A6=E5=8F=B7=E5=88=97=E8=A1=A8=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E8=B5=84=E4=BA=A7=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/accounts/api/account/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/accounts/api/account/account.py b/apps/accounts/api/account/account.py index 6fb699721..ddf88e0c7 100644 --- a/apps/accounts/api/account/account.py +++ b/apps/accounts/api/account/account.py @@ -22,7 +22,7 @@ __all__ = [ class AccountViewSet(OrgBulkModelViewSet): model = Account - search_fields = ('username', 'asset__address', 'name') + search_fields = ('username', 'name', 'asset__name', 'asset__address') filterset_class = AccountFilterSet serializer_classes = { 'default': serializers.AccountSerializer, From a0bb25e55862663bdda604c7c691a8a927fc9da7 Mon Sep 17 00:00:00 2001 From: fangfangdong Date: Wed, 31 May 2023 17:16:48 +0800 Subject: [PATCH 068/153] =?UTF-8?q?feat:=20=E7=B3=BB=E7=BB=9F=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE-=E5=AE=89=E5=85=A8=E8=AE=BE=E7=BD=AE=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=85=8D=E7=BD=AE=20=E4=BD=9C=E4=B8=9A=E4=B8=AD?= =?UTF-8?q?=E5=BF=83=E5=91=BD=E4=BB=A4=E9=BB=91=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jumpserver/conf.py | 3 + apps/jumpserver/settings/custom.py | 1 + apps/locale/ja/LC_MESSAGES/django.po | 1217 +++++++++++-------------- apps/locale/zh/LC_MESSAGES/django.po | 1196 +++++++++++------------- apps/ops/ansible/runner.py | 5 +- apps/settings/serializers/public.py | 1 + apps/settings/serializers/security.py | 5 + 7 files changed, 1089 insertions(+), 1339 deletions(-) diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index d0a1470ff..5ae50a407 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -452,6 +452,9 @@ class Config(dict): 'SECURITY_MFA_AUTH': 0, # 0 不开启 1 全局开启 2 管理员开启 'SECURITY_MFA_AUTH_ENABLED_FOR_THIRD_PARTY': True, 'SECURITY_COMMAND_EXECUTION': True, + 'SECURITY_COMMAND_BLACKLIST': [ + 'reboot', 'shutdown', 'poweroff', 'halt', 'dd', 'half', 'top' + ], 'SECURITY_SERVICE_ACCOUNT_REGISTRATION': True, 'SECURITY_VIEW_AUTH_NEED_MFA': True, 'SECURITY_MAX_IDLE_TIME': 30, diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index 7312bd7eb..cf9880d45 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -35,6 +35,7 @@ SECURITY_MFA_AUTH = CONFIG.SECURITY_MFA_AUTH SECURITY_MFA_AUTH_ENABLED_FOR_THIRD_PARTY = CONFIG.SECURITY_MFA_AUTH_ENABLED_FOR_THIRD_PARTY SECURITY_MAX_IDLE_TIME = CONFIG.SECURITY_MAX_IDLE_TIME # Unit: minute SECURITY_COMMAND_EXECUTION = CONFIG.SECURITY_COMMAND_EXECUTION +SECURITY_COMMAND_BLACKLIST = CONFIG.SECURITY_COMMAND_BLACKLIST SECURITY_PASSWORD_EXPIRATION_TIME = CONFIG.SECURITY_PASSWORD_EXPIRATION_TIME # Unit: day SECURITY_PASSWORD_MIN_LENGTH = CONFIG.SECURITY_PASSWORD_MIN_LENGTH # Unit: bit SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH = CONFIG.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH # Unit: bit diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 2f7cb65b4..372314f42 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-29 18:19+0800\n" +"POT-Creation-Date: 2023-05-31 17:15+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -31,7 +31,6 @@ msgstr "パラメータ 'action' は [{}] でなければなりません。" #: users/forms/profile.py:22 users/serializers/user.py:105 #: users/templates/users/_msg_user_created.html:13 #: users/templates/users/user_password_verify.html:18 -#: xpack/plugins/cloud/serializers/account_attrs.py:28 msgid "Password" msgstr "パスワード" @@ -87,7 +86,7 @@ msgstr "更新" #: accounts/const/account.py:27 #: accounts/serializers/automations/change_secret.py:156 audits/const.py:53 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 -#: ops/const.py:58 terminal/const.py:61 xpack/plugins/cloud/const.py:41 +#: ops/const.py:58 terminal/const.py:61 msgid "Failed" msgstr "失敗しました" @@ -193,7 +192,7 @@ msgstr "作成のみ" #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 -#: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:212 +#: tickets/models/ticket/apply_asset.py:16 msgid "Asset" msgstr "資産" @@ -206,7 +205,7 @@ msgid "Su from" msgstr "から切り替え" #: accounts/models/account.py:55 settings/serializers/auth/cas.py:20 -#: settings/serializers/auth/feishu.py:20 terminal/models/applet/applet.py:29 +#: settings/serializers/auth/feishu.py:20 terminal/models/applet/applet.py:30 msgid "Version" msgstr "バージョン" @@ -226,7 +225,7 @@ msgstr "ソース ID" #: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: terminal/backends/command/models.py:21 terminal/models/session/session.py:34 -#: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 +#: tickets/models/ticket/command_confirm.py:13 msgid "Account" msgstr "アカウント" @@ -304,7 +303,7 @@ msgid "Trigger mode" msgstr "トリガーモード" #: accounts/models/automations/backup_account.py:97 audits/models.py:172 -#: terminal/models/session/sharing.py:111 xpack/plugins/cloud/models.py:168 +#: terminal/models/session/sharing.py:111 msgid "Reason" msgstr "理由" @@ -433,7 +432,6 @@ msgstr "最終ログイン日" #: authentication/templates/authentication/_msg_oauth_bind.html:9 #: users/forms/profile.py:32 users/forms/profile.py:115 #: users/models/user.py:751 users/templates/users/_msg_user_created.html:12 -#: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" msgstr "ユーザー名" @@ -458,7 +456,7 @@ msgstr "アカウントのコレクション" msgid "Triggers" msgstr "トリガー方式" -#: accounts/models/automations/push_account.py:16 acls/models/base.py:41 +#: accounts/models/automations/push_account.py:16 acls/models/base.py:43 #: acls/serializers/base.py:57 assets/models/cmd_filter.py:81 #: audits/models.py:65 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:116 @@ -474,7 +472,7 @@ msgstr "アカウントプッシュ" msgid "Verify asset account" msgstr "アカウントの確認" -#: accounts/models/base.py:33 acls/models/base.py:35 +#: accounts/models/base.py:33 acls/models/base.py:37 #: acls/models/command_acl.py:21 acls/serializers/base.py:35 #: applications/models.py:9 assets/models/_user.py:22 #: assets/models/asset/common.py:91 assets/models/asset/common.py:149 @@ -488,12 +486,11 @@ msgstr "アカウントの確認" #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 #: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29 #: settings/models.py:33 settings/serializers/sms.py:6 -#: terminal/models/applet/applet.py:27 terminal/models/component/endpoint.py:12 +#: terminal/models/applet/applet.py:28 terminal/models/component/endpoint.py:12 #: terminal/models/component/endpoint.py:90 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:15 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33 #: users/models/group.py:13 users/models/user.py:753 -#: xpack/plugins/cloud/models.py:28 msgid "Name" msgstr "名前" @@ -505,7 +502,7 @@ msgstr "特権アカウント" #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:114 -#: terminal/models/applet/applet.py:32 users/serializers/user.py:170 +#: terminal/models/applet/applet.py:33 users/serializers/user.py:170 msgid "Is active" msgstr "アクティブです。" @@ -575,7 +572,7 @@ msgstr "カテゴリ" #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 #: assets/serializers/platform.py:109 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 -#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:31 +#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:32 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/serializers/session.py:22 terminal/serializers/storage.py:224 @@ -607,7 +604,7 @@ msgid "Changed" msgstr "編集済み" #: accounts/serializers/account/account.py:249 -#: accounts/serializers/automations/base.py:22 acls/models/base.py:58 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:84 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -635,7 +632,7 @@ msgstr "アカウントはすでに存在しています" msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:424 acls/models/login_acl.py:13 +#: accounts/serializers/account/account.py:424 acls/models/login_acl.py:12 #: acls/serializers/base.py:75 acls/serializers/login_acl.py:21 #: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:44 #: audits/models.py:63 audits/models.py:141 @@ -779,36 +776,36 @@ msgstr "秘密鍵が無効またはpassphraseエラー" msgid "Acls" msgstr "Acls" -#: acls/models/base.py:15 tickets/const.py:45 +#: acls/models/base.py:17 tickets/const.py:45 #: tickets/templates/tickets/approve_check_password.html:49 msgid "Reject" msgstr "拒否" -#: acls/models/base.py:16 +#: acls/models/base.py:18 msgid "Accept" msgstr "受け入れられる" -#: acls/models/base.py:17 +#: acls/models/base.py:19 msgid "Review" msgstr "レビュー担当者" -#: acls/models/base.py:37 assets/models/_user.py:51 +#: acls/models/base.py:39 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:93 msgid "Priority" msgstr "優先順位" -#: acls/models/base.py:38 assets/models/_user.py:51 +#: acls/models/base.py:40 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:94 msgid "1-100, the lower the value will be match first" msgstr "1-100、低い値は最初に一致します" -#: acls/models/base.py:42 acls/serializers/base.py:79 +#: acls/models/base.py:44 acls/serializers/base.py:79 #: acls/serializers/login_acl.py:23 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "レビュー担当者" -#: acls/models/base.py:43 authentication/models/access_key.py:17 +#: acls/models/base.py:45 authentication/models/access_key.py:17 #: authentication/models/connection_token.py:50 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 @@ -816,11 +813,11 @@ msgstr "レビュー担当者" msgid "Active" msgstr "アクティブ" -#: acls/models/base.py:57 users/apps.py:9 +#: acls/models/base.py:83 users/apps.py:9 msgid "Users" msgstr "ユーザー" -#: acls/models/base.py:59 assets/models/automations/base.py:17 +#: acls/models/base.py:85 assets/models/automations/base.py:17 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 #: rbac/tree.py:35 msgid "Accounts" @@ -839,7 +836,7 @@ msgid "Regex" msgstr "正規情報" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 +#: settings/serializers/basic.py:10 msgid "Content" msgstr "コンテンツ" @@ -869,29 +866,24 @@ msgstr "コマンドフィルタリング" msgid "Command confirm" msgstr "コマンドの確認" -#: acls/models/login_acl.py:16 acls/serializers/login_acl.py:28 +#: acls/models/login_acl.py:15 acls/models/login_asset_acl.py:9 +#: acls/serializers/login_acl.py:28 acls/serializers/login_asset_acl.py:13 msgid "Rule" msgstr "ルール" -#: acls/models/login_acl.py:19 +#: acls/models/login_acl.py:18 msgid "Login acl" msgstr "ログインacl" -#: acls/models/login_acl.py:54 tickets/const.py:10 +#: acls/models/login_acl.py:39 tickets/const.py:10 msgid "Login confirm" msgstr "ログイン確認" -#: acls/models/login_asset_acl.py:8 -#, fuzzy -#| msgid "User ID" -msgid "User IP" -msgstr "ユーザーID" - -#: acls/models/login_asset_acl.py:11 +#: acls/models/login_asset_acl.py:12 msgid "Login asset acl" msgstr "ログインasset acl" -#: acls/models/login_asset_acl.py:21 tickets/const.py:12 +#: acls/models/login_asset_acl.py:22 tickets/const.py:12 msgid "Login asset confirm" msgstr "ログイン資産の確認" @@ -917,7 +909,7 @@ msgstr "IP/ホスト" msgid "Reviewers amount" msgstr "承認者数" -#: acls/serializers/base.py:108 tickets/serializers/ticket/ticket.py:76 +#: acls/serializers/base.py:108 tickets/serializers/ticket/ticket.py:77 msgid "The organization `{}` does not exist" msgstr "組織 '{}'は存在しません" @@ -929,13 +921,7 @@ msgstr "いずれのレビューアも組織 '{}' に属していません" msgid "Command group amount" msgstr "コマンドグループ数" -#: acls/serializers/login_asset_acl.py:12 audits/models.py:161 -#: tickets/models/ticket/login_confirm.py:10 -msgid "Login IP" -msgstr "ログインIP" - #: acls/serializers/rules/rules.py:20 -#: xpack/plugins/cloud/serializers/task.py:22 msgid "IP address invalid: `{}`" msgstr "IPアドレスが無効: '{}'" @@ -951,7 +937,7 @@ msgstr "" #: authentication/templates/authentication/_msg_oauth_bind.html:12 #: authentication/templates/authentication/_msg_rest_password_success.html:8 #: authentication/templates/authentication/_msg_rest_public_key_success.html:8 -#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:67 +#: settings/serializers/terminal.py:10 msgid "IP" msgstr "IP" @@ -963,8 +949,7 @@ msgstr "期間" msgid "Applications" msgstr "アプリケーション" -#: applications/models.py:16 xpack/plugins/cloud/models.py:33 -#: xpack/plugins/cloud/serializers/account.py:62 +#: applications/models.py:16 msgid "Attrs" msgstr "ツールバーの" @@ -976,7 +961,7 @@ msgstr "アプリケーション" msgid "Can match application" msgstr "アプリケーションを一致させることができます" -#: assets/api/asset/asset.py:143 +#: assets/api/asset/asset.py:149 msgid "Cannot create asset directly, you should create a host or other" msgstr "" "資産を直接作成することはできません。ホストまたはその他を作成する必要がありま" @@ -1021,7 +1006,7 @@ msgid "Unable to connect to port {port} on {address}" msgstr "{port} のポート {address} に接続できません" #: assets/automations/ping_gateway/manager.py:58 -#: authentication/middleware.py:92 xpack/plugins/cloud/providers/fc.py:48 +#: authentication/middleware.py:92 msgid "Authentication failed" msgstr "認証に失敗しました" @@ -1055,7 +1040,6 @@ msgstr "資産情報の収集" #: assets/const/category.py:10 assets/models/asset/host.py:8 #: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:68 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:72 msgid "Host" msgstr "ホスト" @@ -1073,7 +1057,7 @@ msgid "Cloud service" msgstr "クラウド サービス" #: assets/const/category.py:14 assets/models/asset/web.py:16 audits/const.py:33 -#: terminal/models/applet/applet.py:25 +#: terminal/models/applet/applet.py:26 msgid "Web" msgstr "Web" @@ -1093,7 +1077,7 @@ msgstr "私有雲" msgid "Kubernetes" msgstr "" -#: assets/const/device.py:7 terminal/models/applet/applet.py:24 +#: assets/const/device.py:7 terminal/models/applet/applet.py:25 #: tickets/const.py:8 msgid "General" msgstr "一般" @@ -1152,12 +1136,11 @@ msgstr "SSHパブリックキー" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:37 terminal/models/applet/applet.py:222 +#: terminal/models/applet/applet.py:38 terminal/models/applet/applet.py:237 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 #: tickets/models/ticket/general.py:297 users/models/user.py:792 -#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:111 msgid "Comment" msgstr "コメント" @@ -1202,7 +1185,7 @@ msgstr "ユーザーと同じユーザー名" #: assets/models/_user.py:52 authentication/models/connection_token.py:39 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:34 terminal/serializers/session.py:20 +#: terminal/models/applet/applet.py:35 terminal/serializers/session.py:20 #: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "プロトコル" @@ -1257,7 +1240,6 @@ msgstr "クラウド サービス" #: assets/models/asset/common.py:92 assets/models/platform.py:14 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:69 -#: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "ポート" @@ -1268,7 +1250,6 @@ msgstr "アドレス" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:187 msgid "Platform" msgstr "プラットフォーム" @@ -1363,12 +1344,11 @@ msgstr "アセットの自動化タスク" #: assets/models/automations/base.py:113 audits/models.py:177 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:221 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:236 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 -#: tickets/serializers/ticket/ticket.py:20 xpack/plugins/cloud/models.py:164 -#: xpack/plugins/cloud/models.py:216 +#: tickets/serializers/ticket/ticket.py:20 msgid "Status" msgstr "ステータス" @@ -1432,7 +1412,6 @@ msgstr "資産グループ" #: assets/models/group.py:34 assets/models/platform.py:17 #: assets/serializers/platform.py:95 -#: xpack/plugins/cloud/providers/nutanix.py:30 msgid "Default" msgstr "デフォルト" @@ -1482,7 +1461,7 @@ msgid "Parent key" msgstr "親キー" #: assets/models/node.py:571 perms/serializers/permission.py:35 -#: tickets/models/ticket/apply_asset.py:14 xpack/plugins/cloud/models.py:96 +#: tickets/models/ticket/apply_asset.py:14 msgid "Node" msgstr "ノード" @@ -1622,7 +1601,7 @@ msgstr "" #: assets/serializers/asset/common.py:124 assets/serializers/platform.py:111 #: authentication/serializers/connect_token_secret.py:29 #: authentication/serializers/connect_token_secret.py:72 -#: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 +#: perms/serializers/user_permission.py:25 msgid "Protocols" msgstr "プロトコル" @@ -1641,7 +1620,9 @@ msgid "Platform not exist" msgstr "プラットフォームが存在しません" #: assets/serializers/asset/common.py:263 -msgid "port out of range (1-65535)" +#, fuzzy +#| msgid "port out of range (1-65535)" +msgid "port out of range (0-65535)" msgstr "ポート番号が範囲外です (1-65535)" #: assets/serializers/asset/common.py:270 @@ -1656,9 +1637,6 @@ msgstr "デフォルトのストレージ" #: assets/serializers/asset/database.py:28 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 -#: xpack/plugins/cloud/serializers/account_attrs.py:56 -#: xpack/plugins/cloud/serializers/account_attrs.py:79 -#: xpack/plugins/cloud/serializers/account_attrs.py:143 msgid "This field is required." msgstr "このフィールドは必須です。" @@ -2016,6 +1994,10 @@ msgstr "パスワード変更ログ" msgid "Login type" msgstr "ログインタイプ" +#: audits/models.py:161 tickets/models/ticket/login_confirm.py:10 +msgid "Login IP" +msgstr "ログインIP" + #: audits/models.py:163 #: authentication/templates/authentication/_msg_different_city.html:11 #: tickets/models/ticket/login_confirm.py:11 @@ -2124,13 +2106,13 @@ msgstr "アカウントが見つかりません" msgid "Permission expired" msgstr "承認の有効期限が切れています" -#: authentication/api/connection_token.py:320 +#: authentication/api/connection_token.py:322 #, fuzzy #| msgid "ACL action is reject" msgid "ACL action is reject: {}({})" msgstr "ACL アクションは拒否です" -#: authentication/api/connection_token.py:324 +#: authentication/api/connection_token.py:326 msgid "ACL action is review" msgstr "ACL アクションはレビューです" @@ -2892,7 +2874,6 @@ msgid "Copy success" msgstr "コピー成功" #: authentication/utils.py:28 common/utils/ip/geoip/utils.py:24 -#: xpack/plugins/cloud/const.py:27 msgid "LAN" msgstr "ローカルエリアネットワーク" @@ -3234,7 +3215,7 @@ msgstr "アリ雲" msgid "Tencent cloud" msgstr "テンセント雲" -#: common/sdk/sms/endpoint.py:18 xpack/plugins/cloud/const.py:13 +#: common/sdk/sms/endpoint.py:18 msgid "Huawei Cloud" msgstr "華為雲" @@ -3568,7 +3549,6 @@ msgid "Date last run" msgstr "最終実行日" #: ops/models/base.py:51 ops/models/job.py:188 -#: xpack/plugins/cloud/models.py:162 msgid "Result" msgstr "結果" @@ -3795,7 +3775,7 @@ msgstr "組織" msgid "Org name" msgstr "組織名" -#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:33 +#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:34 msgid "Builtin" msgstr "ビルトイン" @@ -4040,7 +4020,7 @@ msgstr "パーマ" msgid "Users amount" msgstr "ユーザー数" -#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:28 +#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:29 msgid "Display name" msgstr "表示名" @@ -4104,8 +4084,8 @@ msgstr "タスクセンター" msgid "My assets" msgstr "私の資産" -#: rbac/tree.py:56 terminal/models/applet/applet.py:44 -#: terminal/models/applet/applet.py:218 terminal/models/applet/host.py:28 +#: rbac/tree.py:56 terminal/models/applet/applet.py:45 +#: terminal/models/applet/applet.py:233 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "リモートアプリケーション" @@ -4375,7 +4355,6 @@ msgid "Client Id" msgstr "クライアントID" #: settings/serializers/auth/oauth2.py:33 settings/serializers/auth/oidc.py:22 -#: xpack/plugins/cloud/serializers/account_attrs.py:38 msgid "Client Secret" msgstr "クライアント秘密" @@ -4618,7 +4597,6 @@ msgid "SSO auth key TTL" msgstr "Token有効期間" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Unit: second" msgstr "単位: 秒" @@ -4708,9 +4686,11 @@ msgstr "セッション維持期間(天)" #: settings/serializers/cleaning.py:32 msgid "" -"Session, record, command will be delete if more than duration, only in database, OSS will not be affected." +"Session, record, command will be delete if more than duration, only in " +"database, OSS will not be affected." msgstr "" -"この期間を超えるセッション、録音、およびコマンド レコードは削除されます (データベースのバックアップに影響し、OSS などには影響しません)" +"この期間を超えるセッション、録音、およびコマンド レコードは削除されます (デー" +"タベースのバックアップに影響し、OSS などには影響しません)" #: settings/serializers/cleaning.py:36 msgid "Activity log keep days (day)" @@ -4898,11 +4878,11 @@ msgstr "特別な" #: settings/serializers/security.py:31 msgid "" -"If the user has failed to log in for a limited number of " -"times, no login is allowed during this time interval." +"If the user has failed to log in for a limited number of times, no login is " +"allowed during this time interval." msgstr "" -"ユーザーが限られた回数だけログインできなかった場合、この時間間隔で" -"はログインはできません。" +"ユーザーが限られた回数だけログインできなかった場合、この時間間隔ではログイン" +"はできません。" #: settings/serializers/security.py:40 msgid "All users" @@ -4954,15 +4934,14 @@ msgstr "ユーザーパスワードの有効期限(天)" #: settings/serializers/security.py:82 msgid "" -"If the user does not update the password during the time, the " -"user password will expire failure;The password expiration reminder mail will " -"be automatic sent to the user by system within 5 days (daily) before the " -"password expires" +"If the user does not update the password during the time, the user password " +"will expire failure;The password expiration reminder mail will be automatic " +"sent to the user by system within 5 days (daily) before the password expires" msgstr "" -"ユーザーがその期間中にパスワードを更新しなかった場合、ユーザーパス" -"ワードの有効期限が切れます。パスワードの有効期限が切れる前の5日 (毎日) 以内" -"に、パスワードの有効期限が切れるリマインダーメールがシステムからユーザーに自" -"動的に送信されます。" +"ユーザーがその期間中にパスワードを更新しなかった場合、ユーザーパスワードの有" +"効期限が切れます。パスワードの有効期限が切れる前の5日 (毎日) 以内に、パスワー" +"ドの有効期限が切れるリマインダーメールがシステムからユーザーに自動的に送信さ" +"れます。" #: settings/serializers/security.py:89 msgid "Number of repeated historical passwords" @@ -5024,11 +5003,8 @@ msgstr "MFAはTTLを確認します(秒)" #: settings/serializers/security.py:111 msgid "" -"The verification MFA takes effect only when you view the " -"account password" -msgstr "" -"検証MFAはアカウントのパスワードを表示したときにのみ有効になり" -"ます。" +"The verification MFA takes effect only when you view the account password" +msgstr "検証MFAはアカウントのパスワードを表示したときにのみ有効になります。" #: settings/serializers/security.py:116 msgid "Verify code TTL" @@ -5123,20 +5099,28 @@ msgstr "職業センター" msgid "Allow user run batch command or not using ansible" msgstr "ユーザー実行バッチコマンドを許可するか、ansibleを使用しない" -#: settings/serializers/security.py:183 +#: settings/serializers/security.py:184 +msgid "Operation center command blacklist" +msgstr "オペレーション センター コマンド ブラックリスト" + +#: settings/serializers/security.py:185 +msgid "Commands that are not allowed execute." +msgstr "実行が許可されていないコマンド" + +#: settings/serializers/security.py:188 msgid "Session share" msgstr "セッション共有" -#: settings/serializers/security.py:184 +#: settings/serializers/security.py:189 msgid "Enabled, Allows user active session to be shared with other users" msgstr "" "ユーザーのアクティブなセッションを他のユーザーと共有できるようにします。" -#: settings/serializers/security.py:187 +#: settings/serializers/security.py:192 msgid "Remote Login Protection" msgstr "リモートログイン保護" -#: settings/serializers/security.py:189 +#: settings/serializers/security.py:194 msgid "" "The system determines whether the login IP address belongs to a common login " "city. If the account is logged in from a common login city, the system sends " @@ -5552,7 +5536,7 @@ msgstr "コマンドストア" msgid "Invalid" msgstr "無効" -#: terminal/api/component/storage.py:119 +#: terminal/api/component/storage.py:119 terminal/tasks.py:139 msgid "Test failure: {}" msgstr "テスト失敗: {}" @@ -5560,7 +5544,8 @@ msgstr "テスト失敗: {}" msgid "Test successful" msgstr "テスト成功" -#: terminal/api/component/storage.py:124 +#: terminal/api/component/storage.py:124 terminal/notifications.py:179 +#: terminal/tasks.py:143 msgid "Test failure: Account invalid" msgstr "テスト失敗: アカウントが無効" @@ -5662,25 +5647,25 @@ msgstr "一括作成非サポート" msgid "Storage is invalid" msgstr "ストレージが無効です" -#: terminal/models/applet/applet.py:30 +#: terminal/models/applet/applet.py:31 msgid "Author" msgstr "著者" -#: terminal/models/applet/applet.py:35 +#: terminal/models/applet/applet.py:36 #, fuzzy #| msgid "Can push account" msgid "Can concurrent" msgstr "アカウントをプッシュできます" -#: terminal/models/applet/applet.py:36 +#: terminal/models/applet/applet.py:37 msgid "Tags" msgstr "ラベル" -#: terminal/models/applet/applet.py:40 terminal/serializers/storage.py:157 +#: terminal/models/applet/applet.py:41 terminal/serializers/storage.py:157 msgid "Hosts" msgstr "ホスト" -#: terminal/models/applet/applet.py:85 +#: terminal/models/applet/applet.py:86 msgid "Applet pkg not valid, Missing file {}" msgstr "無効なアプレット パッケージ、ファイル {} がありません" @@ -5696,7 +5681,7 @@ msgstr "" msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:220 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:235 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "ホスト マシン" @@ -5754,7 +5739,7 @@ msgid "Redis port" msgstr "Redis ポート" #: terminal/models/component/endpoint.py:29 -#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:68 +#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:73 #: terminal/serializers/storage.py:38 terminal/serializers/storage.py:50 #: terminal/serializers/storage.py:80 terminal/serializers/storage.py:90 #: terminal/serializers/storage.py:98 @@ -5948,6 +5933,24 @@ msgstr "レベル" msgid "Batch danger command alert" msgstr "一括危険コマンド警告" +#: terminal/notifications.py:163 +#, fuzzy +#| msgid "Command storage" +msgid "Command and replay storage" +msgstr "コマンドストレージ" + +#: terminal/notifications.py:164 +#, fuzzy +#| msgid "Connectivity" +msgid "Connectivity alarm" +msgstr "接続性" + +#: terminal/notifications.py:189 +#, fuzzy +#| msgid "Invalid signature." +msgid "Invalid storage" +msgstr "署名が無効です。" + #: terminal/serializers/applet.py:28 msgid "Icon" msgstr "アイコン" @@ -6043,7 +6046,7 @@ msgstr "" "Oracle プロキシサーバーがリッスンするポートは動的です。追加の Oracle データ" "ベースインスタンスはポートリスナーを追加します" -#: terminal/serializers/endpoint.py:37 +#: terminal/serializers/endpoint.py:38 msgid "" "The host address accessed when connecting to assets, if it is empty, the " "access address of the current browser will be used (the default endpoint " @@ -6059,14 +6062,14 @@ msgid "" "connection" msgstr "このIP範囲内のアセットは、以下のエンドポイントを使用して接続されます" -#: terminal/serializers/endpoint.py:60 +#: terminal/serializers/endpoint.py:65 msgid "" "If asset IP addresses under different endpoints conflict, use asset labels" msgstr "" "異なるエンドポイントの下に競合するアセットIPがある場合は、アセットタグを使用" "して実装します" -#: terminal/serializers/endpoint.py:64 +#: terminal/serializers/endpoint.py:69 msgid "Asset IP" msgstr "資産 IP" @@ -6111,16 +6114,14 @@ msgid "Bucket" msgstr "バケット" #: terminal/serializers/storage.py:30 -#: xpack/plugins/cloud/serializers/account_attrs.py:17 msgid "Access key id" msgstr "アクセスキー" #: terminal/serializers/storage.py:34 -#: xpack/plugins/cloud/serializers/account_attrs.py:20 msgid "Access key secret" msgstr "アクセスキーシークレット" -#: terminal/serializers/storage.py:65 xpack/plugins/cloud/models.py:209 +#: terminal/serializers/storage.py:65 msgid "Region" msgstr "リージョン" @@ -6168,32 +6169,45 @@ msgstr "Docタイプ" msgid "Not found" msgstr "見つかりません" -#: terminal/tasks.py:28 +#: terminal/tasks.py:33 msgid "Periodic delete terminal status" msgstr "端末の状態を定期的にクリーンアップする" -#: terminal/tasks.py:37 +#: terminal/tasks.py:42 msgid "Clean orphan session" msgstr "オフライン セッションをクリアする" -#: terminal/tasks.py:56 +#: terminal/tasks.py:61 msgid "Upload session replay to external storage" msgstr "セッションの記録を外部ストレージにアップロードする" -#: terminal/tasks.py:84 +#: terminal/tasks.py:89 msgid "Run applet host deployment" msgstr "アプリケーション マシンの展開を実行する" -#: terminal/tasks.py:94 +#: terminal/tasks.py:99 msgid "Install applet" msgstr "アプリをインストールする" -#: terminal/tasks.py:104 +#: terminal/tasks.py:109 #, fuzzy #| msgid "Gather assets accounts" msgid "Generate applet host accounts" msgstr "資産の口座番号を収集する" +#: terminal/tasks.py:121 +#, fuzzy +#| msgid "Can test asset connectivity" +msgid "Check command replay storage connectivity" +msgstr "資産接続をテストできます" + +#: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 +msgid "" +"\n" +" Invalid storage\n" +" " +msgstr "" + #: terminal/templates/terminal/_msg_command_alert.html:10 msgid "view" msgstr "表示" @@ -6504,7 +6518,7 @@ msgstr "有効期限は開始日より大きくする必要があります" msgid "Permission named `{}` already exists" msgstr "'{}'という名前の権限は既に存在します" -#: tickets/serializers/ticket/ticket.py:88 +#: tickets/serializers/ticket/ticket.py:89 msgid "The ticket flow `{}` does not exist" msgstr "チケットフロー '{}'が存在しない" @@ -7122,585 +7136,442 @@ msgstr "* 新しいパスワードを最後の {} パスワードにすること msgid "Reset password success, return to login page" msgstr "パスワードの成功をリセットし、ログインページに戻る" -#: xpack/apps.py:8 -msgid "XPACK" -msgstr "XPack" - -#: xpack/plugins/cloud/api.py:40 -msgid "Test connection successful" -msgstr "テスト接続成功" - -#: xpack/plugins/cloud/api.py:42 -msgid "Test connection failed: {}" -msgstr "テスト接続に失敗しました: {}" - -#: xpack/plugins/cloud/const.py:8 -msgid "Alibaba Cloud" -msgstr "アリ雲" - -#: xpack/plugins/cloud/const.py:9 -msgid "AWS (International)" -msgstr "AWS (国際)" - -#: xpack/plugins/cloud/const.py:10 -msgid "AWS (China)" -msgstr "AWS (中国)" - -#: xpack/plugins/cloud/const.py:11 -msgid "Azure (China)" -msgstr "Azure (中国)" - -#: xpack/plugins/cloud/const.py:12 -msgid "Azure (International)" -msgstr "Azure (国際)" - -#: xpack/plugins/cloud/const.py:14 -msgid "Baidu Cloud" -msgstr "百度雲" - -#: xpack/plugins/cloud/const.py:15 -msgid "JD Cloud" -msgstr "京東雲" - -#: xpack/plugins/cloud/const.py:16 -msgid "KingSoft Cloud" -msgstr "金山雲" - -#: xpack/plugins/cloud/const.py:17 -msgid "Tencent Cloud" -msgstr "テンセント雲" - -#: xpack/plugins/cloud/const.py:18 -msgid "Tencent Cloud (Lighthouse)" -msgstr "テンセント雲(軽量アプリケーション)" - -#: xpack/plugins/cloud/const.py:19 -msgid "VMware" -msgstr "VMware" - -#: xpack/plugins/cloud/const.py:20 xpack/plugins/cloud/providers/nutanix.py:13 -msgid "Nutanix" -msgstr "Nutanix" - -#: xpack/plugins/cloud/const.py:21 -msgid "Huawei Private Cloud" -msgstr "華為私有雲" - -#: xpack/plugins/cloud/const.py:22 -msgid "Qingyun Private Cloud" -msgstr "青雲私有雲" - -#: xpack/plugins/cloud/const.py:23 -msgid "CTYun Private Cloud" -msgstr "スカイウィング私有雲" - -#: xpack/plugins/cloud/const.py:24 -msgid "OpenStack" -msgstr "OpenStack" - -#: xpack/plugins/cloud/const.py:25 -msgid "Google Cloud Platform" -msgstr "谷歌雲" - -#: xpack/plugins/cloud/const.py:26 -msgid "Fusion Compute" -msgstr "" - -#: xpack/plugins/cloud/const.py:31 -msgid "Private IP" -msgstr "プライベートIP" - -#: xpack/plugins/cloud/const.py:32 -msgid "Public IP" -msgstr "パブリックIP" - -#: xpack/plugins/cloud/const.py:36 -msgid "Instance name" -msgstr "インスタンス名" - -#: xpack/plugins/cloud/const.py:37 -msgid "Instance name and Partial IP" -msgstr "インスタンス名と部分IP" - -#: xpack/plugins/cloud/const.py:42 -msgid "Succeed" -msgstr "成功" - -#: xpack/plugins/cloud/const.py:46 -msgid "Unsync" -msgstr "同期していません" - -#: xpack/plugins/cloud/const.py:47 -msgid "New Sync" -msgstr "新しい同期" - -#: xpack/plugins/cloud/const.py:48 -msgid "Synced" -msgstr "同期済み" - -#: xpack/plugins/cloud/const.py:49 -msgid "Released" -msgstr "リリース済み" - -#: xpack/plugins/cloud/meta.py:9 -msgid "Cloud center" -msgstr "クラウドセンター" - -#: xpack/plugins/cloud/models.py:30 -msgid "Provider" -msgstr "プロバイダー" - -#: xpack/plugins/cloud/models.py:34 -msgid "Validity" -msgstr "有効性" - -#: xpack/plugins/cloud/models.py:39 -msgid "Cloud account" -msgstr "クラウドアカウント" - -#: xpack/plugins/cloud/models.py:41 -msgid "Test cloud account" -msgstr "クラウドアカウントのテスト" - -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 -msgid "Regions" -msgstr "リージョン" - -#: xpack/plugins/cloud/models.py:91 -msgid "Hostname strategy" -msgstr "ホスト名戦略" - -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 -msgid "IP network segment group" -msgstr "IPネットワークセグメントグループ" - -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 -msgid "Sync IP type" -msgstr "同期IPタイプ" - -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 -msgid "Always update" -msgstr "常に更新" - -#: xpack/plugins/cloud/models.py:114 -msgid "Date last sync" -msgstr "最終同期日" - -#: xpack/plugins/cloud/models.py:119 xpack/plugins/cloud/models.py:160 -msgid "Sync instance task" -msgstr "インスタンスの同期タスク" - -#: xpack/plugins/cloud/models.py:171 xpack/plugins/cloud/models.py:219 -msgid "Date sync" -msgstr "日付の同期" - -#: xpack/plugins/cloud/models.py:175 -msgid "Sync instance task execution" -msgstr "インスタンスタスクの同期実行" - -#: xpack/plugins/cloud/models.py:199 -msgid "Sync task" -msgstr "同期タスク" - -#: xpack/plugins/cloud/models.py:203 -msgid "Sync instance task history" -msgstr "インスタンスタスク履歴の同期" - -#: xpack/plugins/cloud/models.py:206 -msgid "Instance" -msgstr "インスタンス" - -#: xpack/plugins/cloud/models.py:223 -msgid "Sync instance detail" -msgstr "同期インスタンスの詳細" - -#: xpack/plugins/cloud/providers/aws_international.py:17 -msgid "China (Beijing)" -msgstr "中国 (北京)" - -#: xpack/plugins/cloud/providers/aws_international.py:18 -msgid "China (Ningxia)" -msgstr "中国 (寧夏)" - -#: xpack/plugins/cloud/providers/aws_international.py:21 -msgid "US East (Ohio)" -msgstr "米国東部 (オハイオ州)" - -#: xpack/plugins/cloud/providers/aws_international.py:22 -msgid "US East (N. Virginia)" -msgstr "米国東部 (N. バージニア州)" - -#: xpack/plugins/cloud/providers/aws_international.py:23 -msgid "US West (N. California)" -msgstr "米国西部 (N. カリフォルニア州)" - -#: xpack/plugins/cloud/providers/aws_international.py:24 -msgid "US West (Oregon)" -msgstr "米国西部 (オレゴン州)" - -#: xpack/plugins/cloud/providers/aws_international.py:25 -msgid "Africa (Cape Town)" -msgstr "アフリカ (ケープタウン)" - -#: xpack/plugins/cloud/providers/aws_international.py:26 -msgid "Asia Pacific (Hong Kong)" -msgstr "アジアパシフィック (香港)" - -#: xpack/plugins/cloud/providers/aws_international.py:27 -msgid "Asia Pacific (Mumbai)" -msgstr "アジア太平洋 (ムンバイ)" - -#: xpack/plugins/cloud/providers/aws_international.py:28 -msgid "Asia Pacific (Osaka-Local)" -msgstr "アジアパシフィック (大阪-ローカル)" - -#: xpack/plugins/cloud/providers/aws_international.py:29 -msgid "Asia Pacific (Seoul)" -msgstr "アジア太平洋地域 (ソウル)" - -#: xpack/plugins/cloud/providers/aws_international.py:30 -msgid "Asia Pacific (Singapore)" -msgstr "アジア太平洋 (シンガポール)" - -#: xpack/plugins/cloud/providers/aws_international.py:31 -msgid "Asia Pacific (Sydney)" -msgstr "アジア太平洋 (シドニー)" - -#: xpack/plugins/cloud/providers/aws_international.py:32 -msgid "Asia Pacific (Tokyo)" -msgstr "アジアパシフィック (東京)" - -#: xpack/plugins/cloud/providers/aws_international.py:33 -msgid "Canada (Central)" -msgstr "カナダ (中央)" - -#: xpack/plugins/cloud/providers/aws_international.py:34 -msgid "Europe (Frankfurt)" -msgstr "ヨーロッパ (フランクフルト)" - -#: xpack/plugins/cloud/providers/aws_international.py:35 -msgid "Europe (Ireland)" -msgstr "ヨーロッパ (アイルランド)" - -#: xpack/plugins/cloud/providers/aws_international.py:36 -msgid "Europe (London)" -msgstr "ヨーロッパ (ロンドン)" - -#: xpack/plugins/cloud/providers/aws_international.py:37 -msgid "Europe (Milan)" -msgstr "ヨーロッパ (ミラノ)" - -#: xpack/plugins/cloud/providers/aws_international.py:38 -msgid "Europe (Paris)" -msgstr "ヨーロッパ (パリ)" - -#: xpack/plugins/cloud/providers/aws_international.py:39 -msgid "Europe (Stockholm)" -msgstr "ヨーロッパ (ストックホルム)" - -#: xpack/plugins/cloud/providers/aws_international.py:40 -msgid "Middle East (Bahrain)" -msgstr "中东 (バーレーン)" - -#: xpack/plugins/cloud/providers/aws_international.py:41 -msgid "South America (São Paulo)" -msgstr "南米 (サンパウロ)" - -#: xpack/plugins/cloud/providers/baiducloud.py:54 -#: xpack/plugins/cloud/providers/jdcloud.py:127 -msgid "CN North-Beijing" -msgstr "華北-北京" - -#: xpack/plugins/cloud/providers/baiducloud.py:55 -#: xpack/plugins/cloud/providers/huaweicloud.py:40 -#: xpack/plugins/cloud/providers/jdcloud.py:130 -msgid "CN South-Guangzhou" -msgstr "華南-広州" - -#: xpack/plugins/cloud/providers/baiducloud.py:56 -msgid "CN East-Suzhou" -msgstr "華東-蘇州" - -#: xpack/plugins/cloud/providers/baiducloud.py:57 -#: xpack/plugins/cloud/providers/huaweicloud.py:48 -msgid "CN-Hong Kong" -msgstr "中国-香港" - -#: xpack/plugins/cloud/providers/baiducloud.py:58 -msgid "CN Center-Wuhan" -msgstr "華中-武漢" - -#: xpack/plugins/cloud/providers/baiducloud.py:59 -msgid "CN North-Baoding" -msgstr "華北-保定" - -#: xpack/plugins/cloud/providers/baiducloud.py:60 -#: xpack/plugins/cloud/providers/jdcloud.py:129 -msgid "CN East-Shanghai" -msgstr "華東-上海" - -#: xpack/plugins/cloud/providers/baiducloud.py:61 -#: xpack/plugins/cloud/providers/huaweicloud.py:47 -msgid "AP-Singapore" -msgstr "アジア太平洋-シンガポール" - -#: xpack/plugins/cloud/providers/huaweicloud.py:35 -msgid "AF-Johannesburg" -msgstr "アフリカ-ヨハネスブルク" - -#: xpack/plugins/cloud/providers/huaweicloud.py:36 -msgid "CN North-Beijing4" -msgstr "華北-北京4" - -#: xpack/plugins/cloud/providers/huaweicloud.py:37 -msgid "CN North-Beijing1" -msgstr "華北-北京1" - -#: xpack/plugins/cloud/providers/huaweicloud.py:38 -msgid "CN East-Shanghai2" -msgstr "華東-上海2" - -#: xpack/plugins/cloud/providers/huaweicloud.py:39 -msgid "CN East-Shanghai1" -msgstr "華東-上海1" - -#: xpack/plugins/cloud/providers/huaweicloud.py:41 -msgid "LA-Mexico City1" -msgstr "LA-メキシコCity1" - -#: xpack/plugins/cloud/providers/huaweicloud.py:42 -msgid "LA-Santiago" -msgstr "ラテンアメリカ-サンディエゴ" - -#: xpack/plugins/cloud/providers/huaweicloud.py:43 -msgid "LA-Sao Paulo1" -msgstr "ラミー・サンパウロ1" - -#: xpack/plugins/cloud/providers/huaweicloud.py:44 -msgid "EU-Paris" -msgstr "ヨーロッパ-パリ" - -#: xpack/plugins/cloud/providers/huaweicloud.py:45 -msgid "CN Southwest-Guiyang1" -msgstr "南西-貴陽1" - -#: xpack/plugins/cloud/providers/huaweicloud.py:46 -msgid "AP-Bangkok" -msgstr "アジア太平洋-バンコク" - -#: xpack/plugins/cloud/providers/huaweicloud.py:50 -msgid "CN Northeast-Dalian" -msgstr "华北-大连" - -#: xpack/plugins/cloud/providers/huaweicloud.py:51 -msgid "CN North-Ulanqab1" -msgstr "華北-ウランチャブ一" - -#: xpack/plugins/cloud/providers/huaweicloud.py:52 -msgid "CN South-Guangzhou-InvitationOnly" -msgstr "華南-広州-友好ユーザー環境" - -#: xpack/plugins/cloud/providers/jdcloud.py:128 -msgid "CN East-Suqian" -msgstr "華東-宿遷" - -#: xpack/plugins/cloud/serializers/account.py:63 -msgid "Validity display" -msgstr "有効表示" - -#: xpack/plugins/cloud/serializers/account.py:64 -msgid "Provider display" -msgstr "プロバイダ表示" - -#: xpack/plugins/cloud/serializers/account_attrs.py:35 -msgid "Client ID" -msgstr "クライアントID" - -#: xpack/plugins/cloud/serializers/account_attrs.py:41 -msgid "Tenant ID" -msgstr "テナントID" - -#: xpack/plugins/cloud/serializers/account_attrs.py:44 -msgid "Subscription ID" -msgstr "サブスクリプションID" - -#: xpack/plugins/cloud/serializers/account_attrs.py:98 -#: xpack/plugins/cloud/serializers/account_attrs.py:103 -#: xpack/plugins/cloud/serializers/account_attrs.py:119 -#: xpack/plugins/cloud/serializers/account_attrs.py:149 -msgid "API Endpoint" -msgstr "APIエンドポイント" - -#: xpack/plugins/cloud/serializers/account_attrs.py:109 -msgid "Auth url" -msgstr "認証アドレス" - -#: xpack/plugins/cloud/serializers/account_attrs.py:110 -msgid "eg: http://openstack.example.com:5000/v3" -msgstr "例えば: http://openstack.example.com:5000/v3" - -#: xpack/plugins/cloud/serializers/account_attrs.py:113 -msgid "User domain" -msgstr "ユーザードメイン" - -#: xpack/plugins/cloud/serializers/account_attrs.py:120 -msgid "Cert File" -msgstr "証明書ファイル" - -#: xpack/plugins/cloud/serializers/account_attrs.py:121 -msgid "Key File" -msgstr "キーファイル" - -#: xpack/plugins/cloud/serializers/account_attrs.py:137 -msgid "Service account key" -msgstr "サービスアカウントキー" - -#: xpack/plugins/cloud/serializers/account_attrs.py:138 -msgid "The file is in JSON format" -msgstr "ファイルはJSON形式です。" - -#: xpack/plugins/cloud/serializers/account_attrs.py:156 -msgid "IP address invalid `{}`, {}" -msgstr "IPアドレスが無効: '{}', {}" - -#: xpack/plugins/cloud/serializers/account_attrs.py:162 #, fuzzy -#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" -msgid "" -"Format for comma-delimited string,Such as: 192.168.1.0/24, " -"10.0.0.0-10.0.0.255" -msgstr "例:192.168.1.0/24,10.0.0.0-10.0.0.255" +#~| msgid "User ID" +#~ msgid "User IP" +#~ msgstr "ユーザーID" -#: xpack/plugins/cloud/serializers/account_attrs.py:166 -msgid "" -"The port is used to detect the validity of the IP address. When the " -"synchronization task is executed, only the valid IP address will be " -"synchronized.
If the port is 0, all IP addresses are valid." -msgstr "" -"このポートは、 IP アドレスの有効性を検出するために使用されます。同期タスクが" -"実行されると、有効な IP アドレスのみが同期されます。
ポートが0の場合、す" -"べてのIPアドレスが有効です。" +#~ msgid "XPACK" +#~ msgstr "XPack" -#: xpack/plugins/cloud/serializers/account_attrs.py:174 -msgid "Hostname prefix" -msgstr "ホスト名プレフィックス" +#~ msgid "Test connection successful" +#~ msgstr "テスト接続成功" -#: xpack/plugins/cloud/serializers/account_attrs.py:177 -msgid "IP segment" -msgstr "IP セグメント" +#~ msgid "Test connection failed: {}" +#~ msgstr "テスト接続に失敗しました: {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:181 -msgid "Test port" -msgstr "テストポート" +#~ msgid "Alibaba Cloud" +#~ msgstr "アリ雲" -#: xpack/plugins/cloud/serializers/account_attrs.py:184 -msgid "Test timeout" -msgstr "テストタイムアウト" +#~ msgid "AWS (International)" +#~ msgstr "AWS (国際)" + +#~ msgid "AWS (China)" +#~ msgstr "AWS (中国)" + +#~ msgid "Azure (China)" +#~ msgstr "Azure (中国)" + +#~ msgid "Azure (International)" +#~ msgstr "Azure (国際)" + +#~ msgid "Baidu Cloud" +#~ msgstr "百度雲" + +#~ msgid "JD Cloud" +#~ msgstr "京東雲" + +#~ msgid "KingSoft Cloud" +#~ msgstr "金山雲" + +#~ msgid "Tencent Cloud" +#~ msgstr "テンセント雲" + +#~ msgid "Tencent Cloud (Lighthouse)" +#~ msgstr "テンセント雲(軽量アプリケーション)" + +#~ msgid "VMware" +#~ msgstr "VMware" + +#~ msgid "Nutanix" +#~ msgstr "Nutanix" + +#~ msgid "Huawei Private Cloud" +#~ msgstr "華為私有雲" + +#~ msgid "Qingyun Private Cloud" +#~ msgstr "青雲私有雲" + +#~ msgid "CTYun Private Cloud" +#~ msgstr "スカイウィング私有雲" + +#~ msgid "OpenStack" +#~ msgstr "OpenStack" + +#~ msgid "Google Cloud Platform" +#~ msgstr "谷歌雲" + +#~ msgid "Private IP" +#~ msgstr "プライベートIP" + +#~ msgid "Public IP" +#~ msgstr "パブリックIP" + +#~ msgid "Instance name" +#~ msgstr "インスタンス名" + +#~ msgid "Instance name and Partial IP" +#~ msgstr "インスタンス名と部分IP" + +#~ msgid "Succeed" +#~ msgstr "成功" + +#~ msgid "Unsync" +#~ msgstr "同期していません" + +#~ msgid "New Sync" +#~ msgstr "新しい同期" + +#~ msgid "Synced" +#~ msgstr "同期済み" + +#~ msgid "Released" +#~ msgstr "リリース済み" + +#~ msgid "Cloud center" +#~ msgstr "クラウドセンター" + +#~ msgid "Provider" +#~ msgstr "プロバイダー" + +#~ msgid "Validity" +#~ msgstr "有効性" + +#~ msgid "Cloud account" +#~ msgstr "クラウドアカウント" + +#~ msgid "Test cloud account" +#~ msgstr "クラウドアカウントのテスト" + +#~ msgid "Regions" +#~ msgstr "リージョン" + +#~ msgid "Hostname strategy" +#~ msgstr "ホスト名戦略" + +#~ msgid "IP network segment group" +#~ msgstr "IPネットワークセグメントグループ" + +#~ msgid "Sync IP type" +#~ msgstr "同期IPタイプ" + +#~ msgid "Always update" +#~ msgstr "常に更新" + +#~ msgid "Date last sync" +#~ msgstr "最終同期日" + +#~ msgid "Sync instance task" +#~ msgstr "インスタンスの同期タスク" + +#~ msgid "Date sync" +#~ msgstr "日付の同期" + +#~ msgid "Sync instance task execution" +#~ msgstr "インスタンスタスクの同期実行" + +#~ msgid "Sync task" +#~ msgstr "同期タスク" + +#~ msgid "Sync instance task history" +#~ msgstr "インスタンスタスク履歴の同期" + +#~ msgid "Instance" +#~ msgstr "インスタンス" + +#~ msgid "Sync instance detail" +#~ msgstr "同期インスタンスの詳細" + +#~ msgid "China (Beijing)" +#~ msgstr "中国 (北京)" + +#~ msgid "China (Ningxia)" +#~ msgstr "中国 (寧夏)" + +#~ msgid "US East (Ohio)" +#~ msgstr "米国東部 (オハイオ州)" + +#~ msgid "US East (N. Virginia)" +#~ msgstr "米国東部 (N. バージニア州)" + +#~ msgid "US West (N. California)" +#~ msgstr "米国西部 (N. カリフォルニア州)" + +#~ msgid "US West (Oregon)" +#~ msgstr "米国西部 (オレゴン州)" + +#~ msgid "Africa (Cape Town)" +#~ msgstr "アフリカ (ケープタウン)" + +#~ msgid "Asia Pacific (Hong Kong)" +#~ msgstr "アジアパシフィック (香港)" + +#~ msgid "Asia Pacific (Mumbai)" +#~ msgstr "アジア太平洋 (ムンバイ)" + +#~ msgid "Asia Pacific (Osaka-Local)" +#~ msgstr "アジアパシフィック (大阪-ローカル)" + +#~ msgid "Asia Pacific (Seoul)" +#~ msgstr "アジア太平洋地域 (ソウル)" + +#~ msgid "Asia Pacific (Singapore)" +#~ msgstr "アジア太平洋 (シンガポール)" + +#~ msgid "Asia Pacific (Sydney)" +#~ msgstr "アジア太平洋 (シドニー)" + +#~ msgid "Asia Pacific (Tokyo)" +#~ msgstr "アジアパシフィック (東京)" + +#~ msgid "Canada (Central)" +#~ msgstr "カナダ (中央)" + +#~ msgid "Europe (Frankfurt)" +#~ msgstr "ヨーロッパ (フランクフルト)" + +#~ msgid "Europe (Ireland)" +#~ msgstr "ヨーロッパ (アイルランド)" + +#~ msgid "Europe (London)" +#~ msgstr "ヨーロッパ (ロンドン)" + +#~ msgid "Europe (Milan)" +#~ msgstr "ヨーロッパ (ミラノ)" + +#~ msgid "Europe (Paris)" +#~ msgstr "ヨーロッパ (パリ)" + +#~ msgid "Europe (Stockholm)" +#~ msgstr "ヨーロッパ (ストックホルム)" + +#~ msgid "Middle East (Bahrain)" +#~ msgstr "中东 (バーレーン)" + +#~ msgid "South America (São Paulo)" +#~ msgstr "南米 (サンパウロ)" + +#~ msgid "CN North-Beijing" +#~ msgstr "華北-北京" + +#~ msgid "CN South-Guangzhou" +#~ msgstr "華南-広州" + +#~ msgid "CN East-Suzhou" +#~ msgstr "華東-蘇州" + +#~ msgid "CN-Hong Kong" +#~ msgstr "中国-香港" + +#~ msgid "CN Center-Wuhan" +#~ msgstr "華中-武漢" + +#~ msgid "CN North-Baoding" +#~ msgstr "華北-保定" + +#~ msgid "CN East-Shanghai" +#~ msgstr "華東-上海" + +#~ msgid "AP-Singapore" +#~ msgstr "アジア太平洋-シンガポール" + +#~ msgid "AF-Johannesburg" +#~ msgstr "アフリカ-ヨハネスブルク" + +#~ msgid "CN North-Beijing4" +#~ msgstr "華北-北京4" + +#~ msgid "CN North-Beijing1" +#~ msgstr "華北-北京1" + +#~ msgid "CN East-Shanghai2" +#~ msgstr "華東-上海2" + +#~ msgid "CN East-Shanghai1" +#~ msgstr "華東-上海1" + +#~ msgid "LA-Mexico City1" +#~ msgstr "LA-メキシコCity1" + +#~ msgid "LA-Santiago" +#~ msgstr "ラテンアメリカ-サンディエゴ" + +#~ msgid "LA-Sao Paulo1" +#~ msgstr "ラミー・サンパウロ1" + +#~ msgid "EU-Paris" +#~ msgstr "ヨーロッパ-パリ" + +#~ msgid "CN Southwest-Guiyang1" +#~ msgstr "南西-貴陽1" + +#~ msgid "AP-Bangkok" +#~ msgstr "アジア太平洋-バンコク" + +#~ msgid "CN Northeast-Dalian" +#~ msgstr "华北-大连" + +#~ msgid "CN North-Ulanqab1" +#~ msgstr "華北-ウランチャブ一" + +#~ msgid "CN South-Guangzhou-InvitationOnly" +#~ msgstr "華南-広州-友好ユーザー環境" + +#~ msgid "CN East-Suqian" +#~ msgstr "華東-宿遷" + +#~ msgid "Validity display" +#~ msgstr "有効表示" + +#~ msgid "Provider display" +#~ msgstr "プロバイダ表示" + +#~ msgid "Client ID" +#~ msgstr "クライアントID" + +#~ msgid "Tenant ID" +#~ msgstr "テナントID" + +#~ msgid "Subscription ID" +#~ msgstr "サブスクリプションID" + +#~ msgid "API Endpoint" +#~ msgstr "APIエンドポイント" + +#~ msgid "Auth url" +#~ msgstr "認証アドレス" + +#~ msgid "eg: http://openstack.example.com:5000/v3" +#~ msgstr "例えば: http://openstack.example.com:5000/v3" + +#~ msgid "User domain" +#~ msgstr "ユーザードメイン" + +#~ msgid "Cert File" +#~ msgstr "証明書ファイル" + +#~ msgid "Key File" +#~ msgstr "キーファイル" + +#~ msgid "Service account key" +#~ msgstr "サービスアカウントキー" + +#~ msgid "The file is in JSON format" +#~ msgstr "ファイルはJSON形式です。" + +#~ msgid "IP address invalid `{}`, {}" +#~ msgstr "IPアドレスが無効: '{}', {}" -#: xpack/plugins/cloud/serializers/task.py:28 #, fuzzy -#| msgid "" -#| "Only instances matching the IP range will be synced.
If the instance " -#| "contains multiple IP addresses, the first IP address that matches will be " -#| "used as the IP for the created asset.
The default value of * means " -#| "sync all instances and randomly match IP addresses.
Such as: " -#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" -msgid "" -"Only instances matching the IP range will be synced.
If the instance " -"contains multiple IP addresses, the first IP address that matches will be " -"used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Format for comma-" -"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" -msgstr "" -"IP範囲に一致するインスタンスのみが同期されます。
インスタンスに複数のIPア" -"ドレスが含まれている場合、一致する最初のIPアドレスが作成されたアセットのIPと" -"して使用されます。
デフォルト値の*は、すべてのインスタンスを同期し、IPア" -"ドレスをランダムに一致させることを意味します。
例:" -"192.168.1.0/24,10.1.1.1-10.1.1.20" +#~| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +#~ msgid "" +#~ "Format for comma-delimited string,Such as: 192.168.1.0/24, " +#~ "10.0.0.0-10.0.0.255" +#~ msgstr "例:192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/task.py:35 -msgid "History count" -msgstr "実行回数" +#~ msgid "" +#~ "The port is used to detect the validity of the IP address. When the " +#~ "synchronization task is executed, only the valid IP address will be " +#~ "synchronized.
If the port is 0, all IP addresses are valid." +#~ msgstr "" +#~ "このポートは、 IP アドレスの有効性を検出するために使用されます。同期タスク" +#~ "が実行されると、有効な IP アドレスのみが同期されます。
ポートが0の場" +#~ "合、すべてのIPアドレスが有効です。" -#: xpack/plugins/cloud/serializers/task.py:36 -msgid "Instance count" -msgstr "インスタンス数" +#~ msgid "Hostname prefix" +#~ msgstr "ホスト名プレフィックス" -#: xpack/plugins/cloud/tasks.py:27 -msgid "Run sync instance task" -msgstr "同期インスタンス タスクを実行する" +#~ msgid "IP segment" +#~ msgstr "IP セグメント" -#: xpack/plugins/cloud/tasks.py:41 -msgid "Period clean sync instance task execution" -msgstr "同期インスタンス タスクの実行記録を定期的にクリアする" +#~ msgid "Test port" +#~ msgstr "テストポート" -#: xpack/plugins/cloud/utils.py:69 -msgid "Account unavailable" -msgstr "利用できないアカウント" +#~ msgid "Test timeout" +#~ msgstr "テストタイムアウト" -#: xpack/plugins/interface/api.py:52 -msgid "Restore default successfully." -msgstr "デフォルトの復元に成功しました。" +#, fuzzy +#~| msgid "" +#~| "Only instances matching the IP range will be synced.
If the instance " +#~| "contains multiple IP addresses, the first IP address that matches will " +#~| "be used as the IP for the created asset.
The default value of * " +#~| "means sync all instances and randomly match IP addresses.
Such as: " +#~| "192.168.1.0/24, 10.1.1.1-10.1.1.20" +#~ msgid "" +#~ "Only instances matching the IP range will be synced.
If the instance " +#~ "contains multiple IP addresses, the first IP address that matches will be " +#~ "used as the IP for the created asset.
The default value of * means " +#~ "sync all instances and randomly match IP addresses.
Format for comma-" +#~ "delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" +#~ msgstr "" +#~ "IP範囲に一致するインスタンスのみが同期されます。
インスタンスに複数のIP" +#~ "アドレスが含まれている場合、一致する最初のIPアドレスが作成されたアセットの" +#~ "IPとして使用されます。
デフォルト値の*は、すべてのインスタンスを同期" +#~ "し、IPアドレスをランダムに一致させることを意味します。
例:" +#~ "192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/interface/meta.py:10 -msgid "Interface settings" -msgstr "インターフェイスの設定" +#~ msgid "History count" +#~ msgstr "実行回数" -#: xpack/plugins/interface/models.py:23 -msgid "Title of login page" -msgstr "ログインページのタイトル" +#~ msgid "Instance count" +#~ msgstr "インスタンス数" -#: xpack/plugins/interface/models.py:27 -msgid "Image of login page" -msgstr "ログインページのイメージ" +#~ msgid "Run sync instance task" +#~ msgstr "同期インスタンス タスクを実行する" -#: xpack/plugins/interface/models.py:31 -msgid "Website icon" -msgstr "ウェブサイトのアイコン" +#~ msgid "Period clean sync instance task execution" +#~ msgstr "同期インスタンス タスクの実行記録を定期的にクリアする" -#: xpack/plugins/interface/models.py:35 -msgid "Logo of management page" -msgstr "管理ページのロゴ" +#~ msgid "Account unavailable" +#~ msgstr "利用できないアカウント" -#: xpack/plugins/interface/models.py:39 -msgid "Logo of logout page" -msgstr "ログアウトページのロゴ" +#~ msgid "Restore default successfully." +#~ msgstr "デフォルトの復元に成功しました。" -#: xpack/plugins/interface/models.py:41 -msgid "Theme" -msgstr "テーマ" +#~ msgid "Interface settings" +#~ msgstr "インターフェイスの設定" -#: xpack/plugins/interface/models.py:44 xpack/plugins/interface/models.py:85 -msgid "Interface setting" -msgstr "インターフェイスの設定" +#~ msgid "Title of login page" +#~ msgstr "ログインページのタイトル" -#: xpack/plugins/license/api.py:50 -msgid "License import successfully" -msgstr "ライセンスのインポートに成功" +#~ msgid "Image of login page" +#~ msgstr "ログインページのイメージ" -#: xpack/plugins/license/api.py:51 -msgid "License is invalid" -msgstr "ライセンスが無効です" +#~ msgid "Website icon" +#~ msgstr "ウェブサイトのアイコン" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 -msgid "License" -msgstr "ライセンス" +#~ msgid "Logo of management page" +#~ msgstr "管理ページのロゴ" -#: xpack/plugins/license/models.py:79 -msgid "Standard edition" -msgstr "標準版" +#~ msgid "Logo of logout page" +#~ msgstr "ログアウトページのロゴ" -#: xpack/plugins/license/models.py:81 -msgid "Enterprise edition" -msgstr "エンタープライズ版" +#~ msgid "Theme" +#~ msgstr "テーマ" -#: xpack/plugins/license/models.py:83 -msgid "Ultimate edition" -msgstr "究極のエディション" +#~ msgid "Interface setting" +#~ msgstr "インターフェイスの設定" -#: xpack/plugins/license/models.py:85 -msgid "Community edition" -msgstr "コミュニティ版" +#~ msgid "License import successfully" +#~ msgstr "ライセンスのインポートに成功" + +#~ msgid "License is invalid" +#~ msgstr "ライセンスが無効です" + +#~ msgid "License" +#~ msgstr "ライセンス" + +#~ msgid "Standard edition" +#~ msgstr "標準版" + +#~ msgid "Enterprise edition" +#~ msgstr "エンタープライズ版" + +#~ msgid "Ultimate edition" +#~ msgstr "究極のエディション" + +#~ msgid "Community edition" +#~ msgstr "コミュニティ版" #, fuzzy #~| msgid "Delete" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 7b429aa50..68e8287d1 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-29 18:19+0800\n" +"POT-Creation-Date: 2023-05-31 17:15+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -30,7 +30,6 @@ msgstr "参数 'action' 必须是 [{}]" #: users/forms/profile.py:22 users/serializers/user.py:105 #: users/templates/users/_msg_user_created.html:13 #: users/templates/users/user_password_verify.html:18 -#: xpack/plugins/cloud/serializers/account_attrs.py:28 msgid "Password" msgstr "密码" @@ -86,7 +85,7 @@ msgstr "更新" #: accounts/const/account.py:27 #: accounts/serializers/automations/change_secret.py:156 audits/const.py:53 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 -#: ops/const.py:58 terminal/const.py:61 xpack/plugins/cloud/const.py:41 +#: ops/const.py:58 terminal/const.py:61 msgid "Failed" msgstr "失败" @@ -192,7 +191,7 @@ msgstr "仅创建" #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 -#: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:212 +#: tickets/models/ticket/apply_asset.py:16 msgid "Asset" msgstr "资产" @@ -205,7 +204,7 @@ msgid "Su from" msgstr "切换自" #: accounts/models/account.py:55 settings/serializers/auth/cas.py:20 -#: settings/serializers/auth/feishu.py:20 terminal/models/applet/applet.py:29 +#: settings/serializers/auth/feishu.py:20 terminal/models/applet/applet.py:30 msgid "Version" msgstr "版本" @@ -225,7 +224,7 @@ msgstr "来源 ID" #: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: terminal/backends/command/models.py:21 terminal/models/session/session.py:34 -#: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 +#: tickets/models/ticket/command_confirm.py:13 msgid "Account" msgstr "账号" @@ -303,7 +302,7 @@ msgid "Trigger mode" msgstr "触发模式" #: accounts/models/automations/backup_account.py:97 audits/models.py:172 -#: terminal/models/session/sharing.py:111 xpack/plugins/cloud/models.py:168 +#: terminal/models/session/sharing.py:111 msgid "Reason" msgstr "原因" @@ -432,7 +431,6 @@ msgstr "最后登录日期" #: authentication/templates/authentication/_msg_oauth_bind.html:9 #: users/forms/profile.py:32 users/forms/profile.py:115 #: users/models/user.py:751 users/templates/users/_msg_user_created.html:12 -#: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" msgstr "用户名" @@ -457,7 +455,7 @@ msgstr "收集账号" msgid "Triggers" msgstr "触发方式" -#: accounts/models/automations/push_account.py:16 acls/models/base.py:41 +#: accounts/models/automations/push_account.py:16 acls/models/base.py:43 #: acls/serializers/base.py:57 assets/models/cmd_filter.py:81 #: audits/models.py:65 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:116 @@ -473,7 +471,7 @@ msgstr "账号推送" msgid "Verify asset account" msgstr "账号验证" -#: accounts/models/base.py:33 acls/models/base.py:35 +#: accounts/models/base.py:33 acls/models/base.py:37 #: acls/models/command_acl.py:21 acls/serializers/base.py:35 #: applications/models.py:9 assets/models/_user.py:22 #: assets/models/asset/common.py:91 assets/models/asset/common.py:149 @@ -487,12 +485,11 @@ msgstr "账号验证" #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 #: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29 #: settings/models.py:33 settings/serializers/sms.py:6 -#: terminal/models/applet/applet.py:27 terminal/models/component/endpoint.py:12 +#: terminal/models/applet/applet.py:28 terminal/models/component/endpoint.py:12 #: terminal/models/component/endpoint.py:90 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:15 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33 #: users/models/group.py:13 users/models/user.py:753 -#: xpack/plugins/cloud/models.py:28 msgid "Name" msgstr "名称" @@ -504,7 +501,7 @@ msgstr "特权账号" #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:114 -#: terminal/models/applet/applet.py:32 users/serializers/user.py:170 +#: terminal/models/applet/applet.py:33 users/serializers/user.py:170 msgid "Is active" msgstr "激活" @@ -571,7 +568,7 @@ msgstr "类别" #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 #: assets/serializers/platform.py:109 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 -#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:31 +#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:32 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/serializers/session.py:22 terminal/serializers/storage.py:224 @@ -603,7 +600,7 @@ msgid "Changed" msgstr "已修改" #: accounts/serializers/account/account.py:249 -#: accounts/serializers/automations/base.py:22 acls/models/base.py:58 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:84 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -631,7 +628,7 @@ msgstr "账号已存在" msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:424 acls/models/login_acl.py:13 +#: accounts/serializers/account/account.py:424 acls/models/login_acl.py:12 #: acls/serializers/base.py:75 acls/serializers/login_acl.py:21 #: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:44 #: audits/models.py:63 audits/models.py:141 @@ -775,36 +772,36 @@ msgstr "密钥不合法或密钥密码错误" msgid "Acls" msgstr "访问控制" -#: acls/models/base.py:15 tickets/const.py:45 +#: acls/models/base.py:17 tickets/const.py:45 #: tickets/templates/tickets/approve_check_password.html:49 msgid "Reject" msgstr "拒绝" -#: acls/models/base.py:16 +#: acls/models/base.py:18 msgid "Accept" msgstr "接受" -#: acls/models/base.py:17 +#: acls/models/base.py:19 msgid "Review" msgstr "审批" -#: acls/models/base.py:37 assets/models/_user.py:51 +#: acls/models/base.py:39 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:93 msgid "Priority" msgstr "优先级" -#: acls/models/base.py:38 assets/models/_user.py:51 +#: acls/models/base.py:40 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:94 msgid "1-100, the lower the value will be match first" msgstr "优先级可选范围为 1-100 (数值越小越优先)" -#: acls/models/base.py:42 acls/serializers/base.py:79 +#: acls/models/base.py:44 acls/serializers/base.py:79 #: acls/serializers/login_acl.py:23 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "审批人" -#: acls/models/base.py:43 authentication/models/access_key.py:17 +#: acls/models/base.py:45 authentication/models/access_key.py:17 #: authentication/models/connection_token.py:50 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 @@ -812,11 +809,11 @@ msgstr "审批人" msgid "Active" msgstr "激活中" -#: acls/models/base.py:57 users/apps.py:9 +#: acls/models/base.py:83 users/apps.py:9 msgid "Users" msgstr "用户管理" -#: acls/models/base.py:59 assets/models/automations/base.py:17 +#: acls/models/base.py:85 assets/models/automations/base.py:17 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 #: rbac/tree.py:35 msgid "Accounts" @@ -835,7 +832,7 @@ msgid "Regex" msgstr "正则表达式" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 +#: settings/serializers/basic.py:10 msgid "Content" msgstr "内容" @@ -865,29 +862,24 @@ msgstr "命令过滤" msgid "Command confirm" msgstr "命令复核" -#: acls/models/login_acl.py:16 acls/serializers/login_acl.py:28 +#: acls/models/login_acl.py:15 acls/models/login_asset_acl.py:9 +#: acls/serializers/login_acl.py:28 acls/serializers/login_asset_acl.py:13 msgid "Rule" msgstr "规则" -#: acls/models/login_acl.py:19 +#: acls/models/login_acl.py:18 msgid "Login acl" msgstr "登录访问控制" -#: acls/models/login_acl.py:54 tickets/const.py:10 +#: acls/models/login_acl.py:39 tickets/const.py:10 msgid "Login confirm" msgstr "登录复核" -#: acls/models/login_asset_acl.py:8 -#, fuzzy -#| msgid "User ID" -msgid "User IP" -msgstr "用户 ID" - -#: acls/models/login_asset_acl.py:11 +#: acls/models/login_asset_acl.py:12 msgid "Login asset acl" msgstr "登录资产访问控制" -#: acls/models/login_asset_acl.py:21 tickets/const.py:12 +#: acls/models/login_asset_acl.py:22 tickets/const.py:12 msgid "Login asset confirm" msgstr "登录资产复核" @@ -912,7 +904,7 @@ msgstr "IP/主机" msgid "Reviewers amount" msgstr "审批人数量" -#: acls/serializers/base.py:108 tickets/serializers/ticket/ticket.py:76 +#: acls/serializers/base.py:108 tickets/serializers/ticket/ticket.py:77 msgid "The organization `{}` does not exist" msgstr "组织 `{}` 不存在" @@ -924,13 +916,7 @@ msgstr "所有复核人都不属于组织 `{}`" msgid "Command group amount" msgstr "命令组数量" -#: acls/serializers/login_asset_acl.py:12 audits/models.py:161 -#: tickets/models/ticket/login_confirm.py:10 -msgid "Login IP" -msgstr "登录 IP" - #: acls/serializers/rules/rules.py:20 -#: xpack/plugins/cloud/serializers/task.py:22 msgid "IP address invalid: `{}`" msgstr "IP 地址无效: `{}`" @@ -958,8 +944,7 @@ msgstr "时段" msgid "Applications" msgstr "应用管理" -#: applications/models.py:16 xpack/plugins/cloud/models.py:33 -#: xpack/plugins/cloud/serializers/account.py:62 +#: applications/models.py:16 msgid "Attrs" msgstr "属性" @@ -971,7 +956,7 @@ msgstr "应用程序" msgid "Can match application" msgstr "匹配应用" -#: assets/api/asset/asset.py:143 +#: assets/api/asset/asset.py:149 msgid "Cannot create asset directly, you should create a host or other" msgstr "不能直接创建资产, 你应该创建主机或其他资产" @@ -1014,7 +999,7 @@ msgid "Unable to connect to port {port} on {address}" msgstr "无法连接到 {port} 上的端口 {address}" #: assets/automations/ping_gateway/manager.py:58 -#: authentication/middleware.py:92 xpack/plugins/cloud/providers/fc.py:48 +#: authentication/middleware.py:92 msgid "Authentication failed" msgstr "认证失败" @@ -1048,7 +1033,6 @@ msgstr "收集资产信息" #: assets/const/category.py:10 assets/models/asset/host.py:8 #: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:68 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:72 msgid "Host" msgstr "主机" @@ -1066,7 +1050,7 @@ msgid "Cloud service" msgstr "云服务" #: assets/const/category.py:14 assets/models/asset/web.py:16 audits/const.py:33 -#: terminal/models/applet/applet.py:25 +#: terminal/models/applet/applet.py:26 msgid "Web" msgstr "Web" @@ -1086,7 +1070,7 @@ msgstr "私有云" msgid "Kubernetes" msgstr "" -#: assets/const/device.py:7 terminal/models/applet/applet.py:24 +#: assets/const/device.py:7 terminal/models/applet/applet.py:25 #: tickets/const.py:8 msgid "General" msgstr "一般" @@ -1145,12 +1129,11 @@ msgstr "SSH公钥" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:37 terminal/models/applet/applet.py:222 +#: terminal/models/applet/applet.py:38 terminal/models/applet/applet.py:237 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 #: tickets/models/ticket/general.py:297 users/models/user.py:792 -#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:111 msgid "Comment" msgstr "备注" @@ -1195,7 +1178,7 @@ msgstr "用户名与用户相同" #: assets/models/_user.py:52 authentication/models/connection_token.py:39 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:34 terminal/serializers/session.py:20 +#: terminal/models/applet/applet.py:35 terminal/serializers/session.py:20 #: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "协议" @@ -1250,7 +1233,6 @@ msgstr "云服务" #: assets/models/asset/common.py:92 assets/models/platform.py:14 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:69 -#: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "端口" @@ -1261,7 +1243,6 @@ msgstr "地址" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:187 msgid "Platform" msgstr "系统平台" @@ -1356,12 +1337,11 @@ msgstr "资产自动化任务" #: assets/models/automations/base.py:113 audits/models.py:177 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:221 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:236 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 -#: tickets/serializers/ticket/ticket.py:20 xpack/plugins/cloud/models.py:164 -#: xpack/plugins/cloud/models.py:216 +#: tickets/serializers/ticket/ticket.py:20 msgid "Status" msgstr "状态" @@ -1425,7 +1405,6 @@ msgstr "资产组" #: assets/models/group.py:34 assets/models/platform.py:17 #: assets/serializers/platform.py:95 -#: xpack/plugins/cloud/providers/nutanix.py:30 msgid "Default" msgstr "默认" @@ -1475,7 +1454,7 @@ msgid "Parent key" msgstr "ssh私钥" #: assets/models/node.py:571 perms/serializers/permission.py:35 -#: tickets/models/ticket/apply_asset.py:14 xpack/plugins/cloud/models.py:96 +#: tickets/models/ticket/apply_asset.py:14 msgid "Node" msgstr "节点" @@ -1613,7 +1592,7 @@ msgstr "资产中批量更新平台,不符合平台类型跳过的资产" #: assets/serializers/asset/common.py:124 assets/serializers/platform.py:111 #: authentication/serializers/connect_token_secret.py:29 #: authentication/serializers/connect_token_secret.py:72 -#: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 +#: perms/serializers/user_permission.py:25 msgid "Protocols" msgstr "协议组" @@ -1632,7 +1611,9 @@ msgid "Platform not exist" msgstr "平台不存在" #: assets/serializers/asset/common.py:263 -msgid "port out of range (1-65535)" +#, fuzzy +#| msgid "port out of range (1-65535)" +msgid "port out of range (0-65535)" msgstr "端口超出范围 (1-65535)" #: assets/serializers/asset/common.py:270 @@ -1647,9 +1628,6 @@ msgstr "默认存储" #: assets/serializers/asset/database.py:28 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 -#: xpack/plugins/cloud/serializers/account_attrs.py:56 -#: xpack/plugins/cloud/serializers/account_attrs.py:79 -#: xpack/plugins/cloud/serializers/account_attrs.py:143 msgid "This field is required." msgstr "该字段是必填项。" @@ -2005,6 +1983,10 @@ msgstr "改密日志" msgid "Login type" msgstr "登录方式" +#: audits/models.py:161 tickets/models/ticket/login_confirm.py:10 +msgid "Login IP" +msgstr "登录 IP" + #: audits/models.py:163 #: authentication/templates/authentication/_msg_different_city.html:11 #: tickets/models/ticket/login_confirm.py:11 @@ -2113,13 +2095,13 @@ msgstr "账号未找到" msgid "Permission expired" msgstr "授权已过期" -#: authentication/api/connection_token.py:320 +#: authentication/api/connection_token.py:322 #, fuzzy #| msgid "ACL action is reject" msgid "ACL action is reject: {}({})" msgstr "ACL 动作是拒绝" -#: authentication/api/connection_token.py:324 +#: authentication/api/connection_token.py:326 msgid "ACL action is review" msgstr "ACL 动作是复核" @@ -2859,7 +2841,6 @@ msgid "Copy success" msgstr "复制成功" #: authentication/utils.py:28 common/utils/ip/geoip/utils.py:24 -#: xpack/plugins/cloud/const.py:27 msgid "LAN" msgstr "局域网" @@ -3199,7 +3180,7 @@ msgstr "阿里云" msgid "Tencent cloud" msgstr "腾讯云" -#: common/sdk/sms/endpoint.py:18 xpack/plugins/cloud/const.py:13 +#: common/sdk/sms/endpoint.py:18 msgid "Huawei Cloud" msgstr "华为云" @@ -3528,7 +3509,6 @@ msgid "Date last run" msgstr "最后运行日期" #: ops/models/base.py:51 ops/models/job.py:188 -#: xpack/plugins/cloud/models.py:162 msgid "Result" msgstr "结果" @@ -3754,7 +3734,7 @@ msgstr "组织" msgid "Org name" msgstr "组织名称" -#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:33 +#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:34 msgid "Builtin" msgstr "内置的" @@ -3998,7 +3978,7 @@ msgstr "权限" msgid "Users amount" msgstr "用户数量" -#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:28 +#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:29 msgid "Display name" msgstr "显示名称" @@ -4062,8 +4042,8 @@ msgstr "任务中心" msgid "My assets" msgstr "我的资产" -#: rbac/tree.py:56 terminal/models/applet/applet.py:44 -#: terminal/models/applet/applet.py:218 terminal/models/applet/host.py:28 +#: rbac/tree.py:56 terminal/models/applet/applet.py:45 +#: terminal/models/applet/applet.py:233 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "远程应用" @@ -4333,7 +4313,6 @@ msgid "Client Id" msgstr "客户端 ID" #: settings/serializers/auth/oauth2.py:33 settings/serializers/auth/oidc.py:22 -#: xpack/plugins/cloud/serializers/account_attrs.py:38 msgid "Client Secret" msgstr "客户端密钥" @@ -4574,7 +4553,6 @@ msgid "SSO auth key TTL" msgstr "令牌有效期" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Unit: second" msgstr "单位: 秒" @@ -4664,7 +4642,8 @@ msgstr "会话日志(天)" #: settings/serializers/cleaning.py:32 msgid "" -"Session, record, command will be delete if more than duration, only in database, OSS will not be affected." +"Session, record, command will be delete if more than duration, only in " +"database, OSS will not be affected." msgstr "" "会话、录像,命令记录超过该时长将会被洲除(影响数据库存備,OSS 等不受影响)" @@ -4847,8 +4826,8 @@ msgstr "必须包含特殊字符" #: settings/serializers/security.py:31 msgid "" -"If the user has failed to log in for a limited number of " -"times, no login is allowed during this time interval." +"If the user has failed to log in for a limited number of times, no login is " +"allowed during this time interval." msgstr "当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录" #: settings/serializers/security.py:40 @@ -4901,13 +4880,12 @@ msgstr "用户密码过期时间(天)" #: settings/serializers/security.py:82 msgid "" -"If the user does not update the password during the time, the " -"user password will expire failure;The password expiration reminder mail will " -"be automatic sent to the user by system within 5 days (daily) before the " -"password expires" +"If the user does not update the password during the time, the user password " +"will expire failure;The password expiration reminder mail will be automatic " +"sent to the user by system within 5 days (daily) before the password expires" msgstr "" -"如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期提醒邮件" -"将在密码过期前5天内由系统(每天)自动发送给用户" +"如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期提醒邮件将在密码过" +"期前5天内由系统(每天)自动发送给用户" #: settings/serializers/security.py:89 msgid "Number of repeated historical passwords" @@ -4963,8 +4941,7 @@ msgstr "MFA 校验有效期(秒)" #: settings/serializers/security.py:111 msgid "" -"The verification MFA takes effect only when you view the " -"account password" +"The verification MFA takes effect only when you view the account password" msgstr "目前仅在查看账号密码校验 MFA 时生效" #: settings/serializers/security.py:116 @@ -5031,7 +5008,7 @@ msgstr "连接最大空闲时间(分)" #: settings/serializers/security.py:166 msgid "If idle time more than it, disconnect connection." -msgstr "提示:如果超过该配置没有操作,连接会被断开)" +msgstr "提示:如果超过该配置没有操作,连接会被断开" #: settings/serializers/security.py:169 msgid "Remember manual auth" @@ -5057,19 +5034,27 @@ msgstr "作业中心" msgid "Allow user run batch command or not using ansible" msgstr "是否允许用户使用 ansible 执行批量命令" -#: settings/serializers/security.py:183 +#: settings/serializers/security.py:184 +msgid "Operation center command blacklist" +msgstr "作业中心命令黑名单" + +#: settings/serializers/security.py:185 +msgid "Commands that are not allowed execute." +msgstr "不允许执行的命令" + +#: settings/serializers/security.py:188 msgid "Session share" msgstr "会话分享" -#: settings/serializers/security.py:184 +#: settings/serializers/security.py:189 msgid "Enabled, Allows user active session to be shared with other users" msgstr "开启后允许用户分享已连接的资产会话给他人,协同工作" -#: settings/serializers/security.py:187 +#: settings/serializers/security.py:192 msgid "Remote Login Protection" msgstr "异地登录保护" -#: settings/serializers/security.py:189 +#: settings/serializers/security.py:194 msgid "" "The system determines whether the login IP address belongs to a common login " "city. If the account is logged in from a common login city, the system sends " @@ -5471,7 +5456,7 @@ msgstr "命令存储" msgid "Invalid" msgstr "无效" -#: terminal/api/component/storage.py:119 +#: terminal/api/component/storage.py:119 terminal/tasks.py:139 msgid "Test failure: {}" msgstr "测试失败: {}" @@ -5479,7 +5464,8 @@ msgstr "测试失败: {}" msgid "Test successful" msgstr "测试成功" -#: terminal/api/component/storage.py:124 +#: terminal/api/component/storage.py:124 terminal/notifications.py:179 +#: terminal/tasks.py:143 msgid "Test failure: Account invalid" msgstr "测试失败: 账号无效" @@ -5581,25 +5567,25 @@ msgstr "不支持批量创建" msgid "Storage is invalid" msgstr "存储无效" -#: terminal/models/applet/applet.py:30 +#: terminal/models/applet/applet.py:31 msgid "Author" msgstr "作者" -#: terminal/models/applet/applet.py:35 +#: terminal/models/applet/applet.py:36 #, fuzzy #| msgid "Can push account" msgid "Can concurrent" msgstr "可以推送账号" -#: terminal/models/applet/applet.py:36 +#: terminal/models/applet/applet.py:37 msgid "Tags" msgstr "标签" -#: terminal/models/applet/applet.py:40 terminal/serializers/storage.py:157 +#: terminal/models/applet/applet.py:41 terminal/serializers/storage.py:157 msgid "Hosts" msgstr "主机" -#: terminal/models/applet/applet.py:85 +#: terminal/models/applet/applet.py:86 msgid "Applet pkg not valid, Missing file {}" msgstr "Applet pkg 无效,缺少文件 {}" @@ -5615,7 +5601,7 @@ msgstr "" msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:220 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:235 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "宿主机" @@ -5673,7 +5659,7 @@ msgid "Redis port" msgstr "Redis 端口" #: terminal/models/component/endpoint.py:29 -#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:68 +#: terminal/models/component/endpoint.py:98 terminal/serializers/endpoint.py:73 #: terminal/serializers/storage.py:38 terminal/serializers/storage.py:50 #: terminal/serializers/storage.py:80 terminal/serializers/storage.py:90 #: terminal/serializers/storage.py:98 @@ -5867,6 +5853,24 @@ msgstr "级别" msgid "Batch danger command alert" msgstr "批量危险命令告警" +#: terminal/notifications.py:163 +#, fuzzy +#| msgid "Command storage" +msgid "Command and replay storage" +msgstr "命令存储" + +#: terminal/notifications.py:164 +#, fuzzy +#| msgid "Connectivity" +msgid "Connectivity alarm" +msgstr "可连接性" + +#: terminal/notifications.py:189 +#, fuzzy +#| msgid "Invalid signature." +msgid "Invalid storage" +msgstr "签名无效" + #: terminal/serializers/applet.py:28 msgid "Icon" msgstr "图标" @@ -5960,7 +5964,7 @@ msgstr "" "Oracle 代理服务器监听端口是动态的,每增加一个 Oracle 数据库实例,就会增加一个" "端口监听" -#: terminal/serializers/endpoint.py:37 +#: terminal/serializers/endpoint.py:38 msgid "" "The host address accessed when connecting to assets, if it is empty, the " "access address of the current browser will be used (the default endpoint " @@ -5975,12 +5979,12 @@ msgid "" "connection" msgstr "该 IP 范围内的资产,将使用下面的端点进行连接" -#: terminal/serializers/endpoint.py:60 +#: terminal/serializers/endpoint.py:65 msgid "" "If asset IP addresses under different endpoints conflict, use asset labels" msgstr "如果不同端点下的资产 IP 有冲突,使用资产标签实现" -#: terminal/serializers/endpoint.py:64 +#: terminal/serializers/endpoint.py:69 msgid "Asset IP" msgstr "资产 IP" @@ -6025,16 +6029,14 @@ msgid "Bucket" msgstr "桶名称" #: terminal/serializers/storage.py:30 -#: xpack/plugins/cloud/serializers/account_attrs.py:17 msgid "Access key id" msgstr "Access key ID(AK)" #: terminal/serializers/storage.py:34 -#: xpack/plugins/cloud/serializers/account_attrs.py:20 msgid "Access key secret" msgstr "Access key secret(SK)" -#: terminal/serializers/storage.py:65 xpack/plugins/cloud/models.py:209 +#: terminal/serializers/storage.py:65 msgid "Region" msgstr "地域" @@ -6082,32 +6084,45 @@ msgstr "文档类型" msgid "Not found" msgstr "没有发现" -#: terminal/tasks.py:28 +#: terminal/tasks.py:33 msgid "Periodic delete terminal status" msgstr "周期清理终端状态" -#: terminal/tasks.py:37 +#: terminal/tasks.py:42 msgid "Clean orphan session" msgstr "清除离线会话" -#: terminal/tasks.py:56 +#: terminal/tasks.py:61 msgid "Upload session replay to external storage" msgstr "上传会话录像到外部存储" -#: terminal/tasks.py:84 +#: terminal/tasks.py:89 msgid "Run applet host deployment" msgstr "运行应用机部署" -#: terminal/tasks.py:94 +#: terminal/tasks.py:99 msgid "Install applet" msgstr "安装应用" -#: terminal/tasks.py:104 +#: terminal/tasks.py:109 #, fuzzy #| msgid "Gather assets accounts" msgid "Generate applet host accounts" msgstr "收集资产上的账号" +#: terminal/tasks.py:121 +#, fuzzy +#| msgid "Can test asset connectivity" +msgid "Check command replay storage connectivity" +msgstr "可以测试资产连接性" + +#: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 +msgid "" +"\n" +" Invalid storage\n" +" " +msgstr "" + #: terminal/templates/terminal/_msg_command_alert.html:10 msgid "view" msgstr "查看" @@ -6414,7 +6429,7 @@ msgstr "过期时间要大于开始时间" msgid "Permission named `{}` already exists" msgstr "授权名称 `{}` 已存在" -#: tickets/serializers/ticket/ticket.py:88 +#: tickets/serializers/ticket/ticket.py:89 msgid "The ticket flow `{}` does not exist" msgstr "工单流程 `{}` 不存在" @@ -7017,582 +7032,439 @@ msgstr "* 新密码不能是最近 {} 次的密码" msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" -#: xpack/apps.py:8 -msgid "XPACK" -msgstr "XPack" - -#: xpack/plugins/cloud/api.py:40 -msgid "Test connection successful" -msgstr "测试成功" - -#: xpack/plugins/cloud/api.py:42 -msgid "Test connection failed: {}" -msgstr "测试连接失败:{}" - -#: xpack/plugins/cloud/const.py:8 -msgid "Alibaba Cloud" -msgstr "阿里云" - -#: xpack/plugins/cloud/const.py:9 -msgid "AWS (International)" -msgstr "AWS (国际)" - -#: xpack/plugins/cloud/const.py:10 -msgid "AWS (China)" -msgstr "AWS (中国)" - -#: xpack/plugins/cloud/const.py:11 -msgid "Azure (China)" -msgstr "Azure (中国)" - -#: xpack/plugins/cloud/const.py:12 -msgid "Azure (International)" -msgstr "Azure (国际)" - -#: xpack/plugins/cloud/const.py:14 -msgid "Baidu Cloud" -msgstr "百度云" - -#: xpack/plugins/cloud/const.py:15 -msgid "JD Cloud" -msgstr "京东云" - -#: xpack/plugins/cloud/const.py:16 -msgid "KingSoft Cloud" -msgstr "金山云" - -#: xpack/plugins/cloud/const.py:17 -msgid "Tencent Cloud" -msgstr "腾讯云" - -#: xpack/plugins/cloud/const.py:18 -msgid "Tencent Cloud (Lighthouse)" -msgstr "腾讯云(轻量服务器应用)" - -#: xpack/plugins/cloud/const.py:19 -msgid "VMware" -msgstr "VMware" - -#: xpack/plugins/cloud/const.py:20 xpack/plugins/cloud/providers/nutanix.py:13 -msgid "Nutanix" -msgstr "Nutanix" - -#: xpack/plugins/cloud/const.py:21 -msgid "Huawei Private Cloud" -msgstr "华为私有云" - -#: xpack/plugins/cloud/const.py:22 -msgid "Qingyun Private Cloud" -msgstr "青云私有云" - -#: xpack/plugins/cloud/const.py:23 -msgid "CTYun Private Cloud" -msgstr "天翼私有云" - -#: xpack/plugins/cloud/const.py:24 -msgid "OpenStack" -msgstr "OpenStack" - -#: xpack/plugins/cloud/const.py:25 -msgid "Google Cloud Platform" -msgstr "谷歌云" - -#: xpack/plugins/cloud/const.py:26 -msgid "Fusion Compute" -msgstr "" - -#: xpack/plugins/cloud/const.py:31 -msgid "Private IP" -msgstr "私有IP" - -#: xpack/plugins/cloud/const.py:32 -msgid "Public IP" -msgstr "公网IP" - -#: xpack/plugins/cloud/const.py:36 -msgid "Instance name" -msgstr "实例名称" - -#: xpack/plugins/cloud/const.py:37 -msgid "Instance name and Partial IP" -msgstr "实例名称和部分IP" - -#: xpack/plugins/cloud/const.py:42 -msgid "Succeed" -msgstr "成功" - -#: xpack/plugins/cloud/const.py:46 -msgid "Unsync" -msgstr "未同步" - -#: xpack/plugins/cloud/const.py:47 -msgid "New Sync" -msgstr "新同步" - -#: xpack/plugins/cloud/const.py:48 -msgid "Synced" -msgstr "已同步" - -#: xpack/plugins/cloud/const.py:49 -msgid "Released" -msgstr "已释放" - -#: xpack/plugins/cloud/meta.py:9 -msgid "Cloud center" -msgstr "云管中心" - -#: xpack/plugins/cloud/models.py:30 -msgid "Provider" -msgstr "云服务商" - -#: xpack/plugins/cloud/models.py:34 -msgid "Validity" -msgstr "有效" - -#: xpack/plugins/cloud/models.py:39 -msgid "Cloud account" -msgstr "云账号" - -#: xpack/plugins/cloud/models.py:41 -msgid "Test cloud account" -msgstr "测试云账号" - -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 -msgid "Regions" -msgstr "地域" - -#: xpack/plugins/cloud/models.py:91 -msgid "Hostname strategy" -msgstr "主机名策略" - -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 -msgid "IP network segment group" -msgstr "IP网段组" - -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 -msgid "Sync IP type" -msgstr "同步IP类型" - -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 -msgid "Always update" -msgstr "总是更新" - -#: xpack/plugins/cloud/models.py:114 -msgid "Date last sync" -msgstr "最后同步日期" - -#: xpack/plugins/cloud/models.py:119 xpack/plugins/cloud/models.py:160 -msgid "Sync instance task" -msgstr "同步实例任务" - -#: xpack/plugins/cloud/models.py:171 xpack/plugins/cloud/models.py:219 -msgid "Date sync" -msgstr "同步日期" - -#: xpack/plugins/cloud/models.py:175 -msgid "Sync instance task execution" -msgstr "同步实例任务执行" - -#: xpack/plugins/cloud/models.py:199 -msgid "Sync task" -msgstr "同步任务" - -#: xpack/plugins/cloud/models.py:203 -msgid "Sync instance task history" -msgstr "同步实例任务历史" - -#: xpack/plugins/cloud/models.py:206 -msgid "Instance" -msgstr "实例" - -#: xpack/plugins/cloud/models.py:223 -msgid "Sync instance detail" -msgstr "同步实例详情" - -#: xpack/plugins/cloud/providers/aws_international.py:17 -msgid "China (Beijing)" -msgstr "中国(北京)" - -#: xpack/plugins/cloud/providers/aws_international.py:18 -msgid "China (Ningxia)" -msgstr "中国(宁夏)" - -#: xpack/plugins/cloud/providers/aws_international.py:21 -msgid "US East (Ohio)" -msgstr "美国东部(俄亥俄州)" - -#: xpack/plugins/cloud/providers/aws_international.py:22 -msgid "US East (N. Virginia)" -msgstr "美国东部(弗吉尼亚北部)" - -#: xpack/plugins/cloud/providers/aws_international.py:23 -msgid "US West (N. California)" -msgstr "美国西部(加利福尼亚北部)" - -#: xpack/plugins/cloud/providers/aws_international.py:24 -msgid "US West (Oregon)" -msgstr "美国西部(俄勒冈)" - -#: xpack/plugins/cloud/providers/aws_international.py:25 -msgid "Africa (Cape Town)" -msgstr "非洲(开普敦)" - -#: xpack/plugins/cloud/providers/aws_international.py:26 -msgid "Asia Pacific (Hong Kong)" -msgstr "亚太地区(香港)" - -#: xpack/plugins/cloud/providers/aws_international.py:27 -msgid "Asia Pacific (Mumbai)" -msgstr "亚太地区(孟买)" - -#: xpack/plugins/cloud/providers/aws_international.py:28 -msgid "Asia Pacific (Osaka-Local)" -msgstr "亚太区域(大阪当地)" - -#: xpack/plugins/cloud/providers/aws_international.py:29 -msgid "Asia Pacific (Seoul)" -msgstr "亚太区域(首尔)" - -#: xpack/plugins/cloud/providers/aws_international.py:30 -msgid "Asia Pacific (Singapore)" -msgstr "亚太区域(新加坡)" - -#: xpack/plugins/cloud/providers/aws_international.py:31 -msgid "Asia Pacific (Sydney)" -msgstr "亚太区域(悉尼)" - -#: xpack/plugins/cloud/providers/aws_international.py:32 -msgid "Asia Pacific (Tokyo)" -msgstr "亚太区域(东京)" - -#: xpack/plugins/cloud/providers/aws_international.py:33 -msgid "Canada (Central)" -msgstr "加拿大(中部)" - -#: xpack/plugins/cloud/providers/aws_international.py:34 -msgid "Europe (Frankfurt)" -msgstr "欧洲(法兰克福)" - -#: xpack/plugins/cloud/providers/aws_international.py:35 -msgid "Europe (Ireland)" -msgstr "欧洲(爱尔兰)" - -#: xpack/plugins/cloud/providers/aws_international.py:36 -msgid "Europe (London)" -msgstr "欧洲(伦敦)" - -#: xpack/plugins/cloud/providers/aws_international.py:37 -msgid "Europe (Milan)" -msgstr "欧洲(米兰)" - -#: xpack/plugins/cloud/providers/aws_international.py:38 -msgid "Europe (Paris)" -msgstr "欧洲(巴黎)" - -#: xpack/plugins/cloud/providers/aws_international.py:39 -msgid "Europe (Stockholm)" -msgstr "欧洲(斯德哥尔摩)" - -#: xpack/plugins/cloud/providers/aws_international.py:40 -msgid "Middle East (Bahrain)" -msgstr "中东(巴林)" - -#: xpack/plugins/cloud/providers/aws_international.py:41 -msgid "South America (São Paulo)" -msgstr "南美洲(圣保罗)" - -#: xpack/plugins/cloud/providers/baiducloud.py:54 -#: xpack/plugins/cloud/providers/jdcloud.py:127 -msgid "CN North-Beijing" -msgstr "华北-北京" - -#: xpack/plugins/cloud/providers/baiducloud.py:55 -#: xpack/plugins/cloud/providers/huaweicloud.py:40 -#: xpack/plugins/cloud/providers/jdcloud.py:130 -msgid "CN South-Guangzhou" -msgstr "华南-广州" - -#: xpack/plugins/cloud/providers/baiducloud.py:56 -msgid "CN East-Suzhou" -msgstr "华东-苏州" - -#: xpack/plugins/cloud/providers/baiducloud.py:57 -#: xpack/plugins/cloud/providers/huaweicloud.py:48 -msgid "CN-Hong Kong" -msgstr "中国-香港" - -#: xpack/plugins/cloud/providers/baiducloud.py:58 -msgid "CN Center-Wuhan" -msgstr "华中-武汉" - -#: xpack/plugins/cloud/providers/baiducloud.py:59 -msgid "CN North-Baoding" -msgstr "华北-保定" - -#: xpack/plugins/cloud/providers/baiducloud.py:60 -#: xpack/plugins/cloud/providers/jdcloud.py:129 -msgid "CN East-Shanghai" -msgstr "华东-上海" - -#: xpack/plugins/cloud/providers/baiducloud.py:61 -#: xpack/plugins/cloud/providers/huaweicloud.py:47 -msgid "AP-Singapore" -msgstr "亚太-新加坡" - -#: xpack/plugins/cloud/providers/huaweicloud.py:35 -msgid "AF-Johannesburg" -msgstr "非洲-约翰内斯堡" - -#: xpack/plugins/cloud/providers/huaweicloud.py:36 -msgid "CN North-Beijing4" -msgstr "华北-北京4" - -#: xpack/plugins/cloud/providers/huaweicloud.py:37 -msgid "CN North-Beijing1" -msgstr "华北-北京1" - -#: xpack/plugins/cloud/providers/huaweicloud.py:38 -msgid "CN East-Shanghai2" -msgstr "华东-上海2" - -#: xpack/plugins/cloud/providers/huaweicloud.py:39 -msgid "CN East-Shanghai1" -msgstr "华东-上海1" - -#: xpack/plugins/cloud/providers/huaweicloud.py:41 -msgid "LA-Mexico City1" -msgstr "拉美-墨西哥城一" - -#: xpack/plugins/cloud/providers/huaweicloud.py:42 -msgid "LA-Santiago" -msgstr "拉美-圣地亚哥" - -#: xpack/plugins/cloud/providers/huaweicloud.py:43 -msgid "LA-Sao Paulo1" -msgstr "拉美-圣保罗一" - -#: xpack/plugins/cloud/providers/huaweicloud.py:44 -msgid "EU-Paris" -msgstr "欧洲-巴黎" - -#: xpack/plugins/cloud/providers/huaweicloud.py:45 -msgid "CN Southwest-Guiyang1" -msgstr "西南-贵阳1" - -#: xpack/plugins/cloud/providers/huaweicloud.py:46 -msgid "AP-Bangkok" -msgstr "亚太-曼谷" - -#: xpack/plugins/cloud/providers/huaweicloud.py:50 -msgid "CN Northeast-Dalian" -msgstr "华北-大连" - -#: xpack/plugins/cloud/providers/huaweicloud.py:51 -msgid "CN North-Ulanqab1" -msgstr "华北-乌兰察布一" - -#: xpack/plugins/cloud/providers/huaweicloud.py:52 -msgid "CN South-Guangzhou-InvitationOnly" -msgstr "华南-广州-友好用户环境" - -#: xpack/plugins/cloud/providers/jdcloud.py:128 -msgid "CN East-Suqian" -msgstr "华东-宿迁" - -#: xpack/plugins/cloud/serializers/account.py:63 -msgid "Validity display" -msgstr "有效性显示" - -#: xpack/plugins/cloud/serializers/account.py:64 -msgid "Provider display" -msgstr "服务商显示" - -#: xpack/plugins/cloud/serializers/account_attrs.py:35 -msgid "Client ID" -msgstr "客户端 ID" - -#: xpack/plugins/cloud/serializers/account_attrs.py:41 -msgid "Tenant ID" -msgstr "租户 ID" - -#: xpack/plugins/cloud/serializers/account_attrs.py:44 -msgid "Subscription ID" -msgstr "订阅 ID" - -#: xpack/plugins/cloud/serializers/account_attrs.py:98 -#: xpack/plugins/cloud/serializers/account_attrs.py:103 -#: xpack/plugins/cloud/serializers/account_attrs.py:119 -#: xpack/plugins/cloud/serializers/account_attrs.py:149 -msgid "API Endpoint" -msgstr "API 端点" - -#: xpack/plugins/cloud/serializers/account_attrs.py:109 -msgid "Auth url" -msgstr "认证地址" - -#: xpack/plugins/cloud/serializers/account_attrs.py:110 -msgid "eg: http://openstack.example.com:5000/v3" -msgstr "如: http://openstack.example.com:5000/v3" - -#: xpack/plugins/cloud/serializers/account_attrs.py:113 -msgid "User domain" -msgstr "用户域" - -#: xpack/plugins/cloud/serializers/account_attrs.py:120 -msgid "Cert File" -msgstr "证书文件" - -#: xpack/plugins/cloud/serializers/account_attrs.py:121 -msgid "Key File" -msgstr "密钥文件" - -#: xpack/plugins/cloud/serializers/account_attrs.py:137 -msgid "Service account key" -msgstr "服务账号密钥" - -#: xpack/plugins/cloud/serializers/account_attrs.py:138 -msgid "The file is in JSON format" -msgstr "JSON 格式的文件" - -#: xpack/plugins/cloud/serializers/account_attrs.py:156 -msgid "IP address invalid `{}`, {}" -msgstr "IP 地址无效: `{}`, {}" - -#: xpack/plugins/cloud/serializers/account_attrs.py:162 #, fuzzy -#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" -msgid "" -"Format for comma-delimited string,Such as: 192.168.1.0/24, " -"10.0.0.0-10.0.0.255" -msgstr "如:192.168.1.0/24,10.0.0.0-10.0.0.255" +#~| msgid "User ID" +#~ msgid "User IP" +#~ msgstr "用户 ID" -#: xpack/plugins/cloud/serializers/account_attrs.py:166 -msgid "" -"The port is used to detect the validity of the IP address. When the " -"synchronization task is executed, only the valid IP address will be " -"synchronized.
If the port is 0, all IP addresses are valid." -msgstr "" -"端口用来检测 IP 地址的有效性,在同步任务执行时,只会同步有效的 IP 地址。
" -"如果端口为 0,则表示所有 IP 地址均有效。" +#~ msgid "XPACK" +#~ msgstr "XPack" -#: xpack/plugins/cloud/serializers/account_attrs.py:174 -msgid "Hostname prefix" -msgstr "主机名前缀" +#~ msgid "Test connection successful" +#~ msgstr "测试成功" -#: xpack/plugins/cloud/serializers/account_attrs.py:177 -msgid "IP segment" -msgstr "IP 网段" +#~ msgid "Test connection failed: {}" +#~ msgstr "测试连接失败:{}" -#: xpack/plugins/cloud/serializers/account_attrs.py:181 -msgid "Test port" -msgstr "测试端口" +#~ msgid "Alibaba Cloud" +#~ msgstr "阿里云" -#: xpack/plugins/cloud/serializers/account_attrs.py:184 -msgid "Test timeout" -msgstr "测试超时时间" +#~ msgid "AWS (International)" +#~ msgstr "AWS (国际)" + +#~ msgid "AWS (China)" +#~ msgstr "AWS (中国)" + +#~ msgid "Azure (China)" +#~ msgstr "Azure (中国)" + +#~ msgid "Azure (International)" +#~ msgstr "Azure (国际)" + +#~ msgid "Baidu Cloud" +#~ msgstr "百度云" + +#~ msgid "JD Cloud" +#~ msgstr "京东云" + +#~ msgid "KingSoft Cloud" +#~ msgstr "金山云" + +#~ msgid "Tencent Cloud" +#~ msgstr "腾讯云" + +#~ msgid "Tencent Cloud (Lighthouse)" +#~ msgstr "腾讯云(轻量服务器应用)" + +#~ msgid "VMware" +#~ msgstr "VMware" + +#~ msgid "Nutanix" +#~ msgstr "Nutanix" + +#~ msgid "Huawei Private Cloud" +#~ msgstr "华为私有云" + +#~ msgid "Qingyun Private Cloud" +#~ msgstr "青云私有云" + +#~ msgid "CTYun Private Cloud" +#~ msgstr "天翼私有云" + +#~ msgid "OpenStack" +#~ msgstr "OpenStack" + +#~ msgid "Google Cloud Platform" +#~ msgstr "谷歌云" + +#~ msgid "Private IP" +#~ msgstr "私有IP" + +#~ msgid "Public IP" +#~ msgstr "公网IP" + +#~ msgid "Instance name" +#~ msgstr "实例名称" + +#~ msgid "Instance name and Partial IP" +#~ msgstr "实例名称和部分IP" + +#~ msgid "Succeed" +#~ msgstr "成功" + +#~ msgid "Unsync" +#~ msgstr "未同步" + +#~ msgid "New Sync" +#~ msgstr "新同步" + +#~ msgid "Synced" +#~ msgstr "已同步" + +#~ msgid "Released" +#~ msgstr "已释放" + +#~ msgid "Cloud center" +#~ msgstr "云管中心" + +#~ msgid "Provider" +#~ msgstr "云服务商" + +#~ msgid "Validity" +#~ msgstr "有效" + +#~ msgid "Cloud account" +#~ msgstr "云账号" + +#~ msgid "Test cloud account" +#~ msgstr "测试云账号" + +#~ msgid "Regions" +#~ msgstr "地域" + +#~ msgid "Hostname strategy" +#~ msgstr "主机名策略" + +#~ msgid "IP network segment group" +#~ msgstr "IP网段组" + +#~ msgid "Sync IP type" +#~ msgstr "同步IP类型" + +#~ msgid "Always update" +#~ msgstr "总是更新" + +#~ msgid "Date last sync" +#~ msgstr "最后同步日期" + +#~ msgid "Sync instance task" +#~ msgstr "同步实例任务" + +#~ msgid "Date sync" +#~ msgstr "同步日期" + +#~ msgid "Sync instance task execution" +#~ msgstr "同步实例任务执行" + +#~ msgid "Sync task" +#~ msgstr "同步任务" + +#~ msgid "Sync instance task history" +#~ msgstr "同步实例任务历史" + +#~ msgid "Instance" +#~ msgstr "实例" + +#~ msgid "Sync instance detail" +#~ msgstr "同步实例详情" + +#~ msgid "China (Beijing)" +#~ msgstr "中国(北京)" + +#~ msgid "China (Ningxia)" +#~ msgstr "中国(宁夏)" + +#~ msgid "US East (Ohio)" +#~ msgstr "美国东部(俄亥俄州)" + +#~ msgid "US East (N. Virginia)" +#~ msgstr "美国东部(弗吉尼亚北部)" + +#~ msgid "US West (N. California)" +#~ msgstr "美国西部(加利福尼亚北部)" + +#~ msgid "US West (Oregon)" +#~ msgstr "美国西部(俄勒冈)" + +#~ msgid "Africa (Cape Town)" +#~ msgstr "非洲(开普敦)" + +#~ msgid "Asia Pacific (Hong Kong)" +#~ msgstr "亚太地区(香港)" + +#~ msgid "Asia Pacific (Mumbai)" +#~ msgstr "亚太地区(孟买)" + +#~ msgid "Asia Pacific (Osaka-Local)" +#~ msgstr "亚太区域(大阪当地)" + +#~ msgid "Asia Pacific (Seoul)" +#~ msgstr "亚太区域(首尔)" + +#~ msgid "Asia Pacific (Singapore)" +#~ msgstr "亚太区域(新加坡)" + +#~ msgid "Asia Pacific (Sydney)" +#~ msgstr "亚太区域(悉尼)" + +#~ msgid "Asia Pacific (Tokyo)" +#~ msgstr "亚太区域(东京)" + +#~ msgid "Canada (Central)" +#~ msgstr "加拿大(中部)" + +#~ msgid "Europe (Frankfurt)" +#~ msgstr "欧洲(法兰克福)" + +#~ msgid "Europe (Ireland)" +#~ msgstr "欧洲(爱尔兰)" + +#~ msgid "Europe (London)" +#~ msgstr "欧洲(伦敦)" + +#~ msgid "Europe (Milan)" +#~ msgstr "欧洲(米兰)" + +#~ msgid "Europe (Paris)" +#~ msgstr "欧洲(巴黎)" + +#~ msgid "Europe (Stockholm)" +#~ msgstr "欧洲(斯德哥尔摩)" + +#~ msgid "Middle East (Bahrain)" +#~ msgstr "中东(巴林)" + +#~ msgid "South America (São Paulo)" +#~ msgstr "南美洲(圣保罗)" + +#~ msgid "CN North-Beijing" +#~ msgstr "华北-北京" + +#~ msgid "CN South-Guangzhou" +#~ msgstr "华南-广州" + +#~ msgid "CN East-Suzhou" +#~ msgstr "华东-苏州" + +#~ msgid "CN-Hong Kong" +#~ msgstr "中国-香港" + +#~ msgid "CN Center-Wuhan" +#~ msgstr "华中-武汉" + +#~ msgid "CN North-Baoding" +#~ msgstr "华北-保定" + +#~ msgid "CN East-Shanghai" +#~ msgstr "华东-上海" + +#~ msgid "AP-Singapore" +#~ msgstr "亚太-新加坡" + +#~ msgid "AF-Johannesburg" +#~ msgstr "非洲-约翰内斯堡" + +#~ msgid "CN North-Beijing4" +#~ msgstr "华北-北京4" + +#~ msgid "CN North-Beijing1" +#~ msgstr "华北-北京1" + +#~ msgid "CN East-Shanghai2" +#~ msgstr "华东-上海2" + +#~ msgid "CN East-Shanghai1" +#~ msgstr "华东-上海1" + +#~ msgid "LA-Mexico City1" +#~ msgstr "拉美-墨西哥城一" + +#~ msgid "LA-Santiago" +#~ msgstr "拉美-圣地亚哥" + +#~ msgid "LA-Sao Paulo1" +#~ msgstr "拉美-圣保罗一" + +#~ msgid "EU-Paris" +#~ msgstr "欧洲-巴黎" + +#~ msgid "CN Southwest-Guiyang1" +#~ msgstr "西南-贵阳1" + +#~ msgid "AP-Bangkok" +#~ msgstr "亚太-曼谷" + +#~ msgid "CN Northeast-Dalian" +#~ msgstr "华北-大连" + +#~ msgid "CN North-Ulanqab1" +#~ msgstr "华北-乌兰察布一" + +#~ msgid "CN South-Guangzhou-InvitationOnly" +#~ msgstr "华南-广州-友好用户环境" + +#~ msgid "CN East-Suqian" +#~ msgstr "华东-宿迁" + +#~ msgid "Validity display" +#~ msgstr "有效性显示" + +#~ msgid "Provider display" +#~ msgstr "服务商显示" + +#~ msgid "Client ID" +#~ msgstr "客户端 ID" + +#~ msgid "Tenant ID" +#~ msgstr "租户 ID" + +#~ msgid "Subscription ID" +#~ msgstr "订阅 ID" + +#~ msgid "API Endpoint" +#~ msgstr "API 端点" + +#~ msgid "Auth url" +#~ msgstr "认证地址" + +#~ msgid "eg: http://openstack.example.com:5000/v3" +#~ msgstr "如: http://openstack.example.com:5000/v3" + +#~ msgid "User domain" +#~ msgstr "用户域" + +#~ msgid "Cert File" +#~ msgstr "证书文件" + +#~ msgid "Key File" +#~ msgstr "密钥文件" + +#~ msgid "Service account key" +#~ msgstr "服务账号密钥" + +#~ msgid "The file is in JSON format" +#~ msgstr "JSON 格式的文件" + +#~ msgid "IP address invalid `{}`, {}" +#~ msgstr "IP 地址无效: `{}`, {}" -#: xpack/plugins/cloud/serializers/task.py:28 #, fuzzy -#| msgid "" -#| "Only instances matching the IP range will be synced.
If the instance " -#| "contains multiple IP addresses, the first IP address that matches will be " -#| "used as the IP for the created asset.
The default value of * means " -#| "sync all instances and randomly match IP addresses.
Such as: " -#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" -msgid "" -"Only instances matching the IP range will be synced.
If the instance " -"contains multiple IP addresses, the first IP address that matches will be " -"used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Format for comma-" -"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" -msgstr "" -"只有匹配到 IP 段的实例会被同步。
如果实例包含多个 IP 地址,那么第一个匹配" -"到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示同步所有实例和随机匹配 " -"IP 地址。
例如:192.168.1.0/24,10.1.1.1-10.1.1.20" +#~| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +#~ msgid "" +#~ "Format for comma-delimited string,Such as: 192.168.1.0/24, " +#~ "10.0.0.0-10.0.0.255" +#~ msgstr "如:192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/task.py:35 -msgid "History count" -msgstr "执行次数" +#~ msgid "" +#~ "The port is used to detect the validity of the IP address. When the " +#~ "synchronization task is executed, only the valid IP address will be " +#~ "synchronized.
If the port is 0, all IP addresses are valid." +#~ msgstr "" +#~ "端口用来检测 IP 地址的有效性,在同步任务执行时,只会同步有效的 IP 地址。 " +#~ "
如果端口为 0,则表示所有 IP 地址均有效。" -#: xpack/plugins/cloud/serializers/task.py:36 -msgid "Instance count" -msgstr "实例个数" +#~ msgid "Hostname prefix" +#~ msgstr "主机名前缀" -#: xpack/plugins/cloud/tasks.py:27 -msgid "Run sync instance task" -msgstr "执行同步实例任务" +#~ msgid "IP segment" +#~ msgstr "IP 网段" -#: xpack/plugins/cloud/tasks.py:41 -msgid "Period clean sync instance task execution" -msgstr "定期清除同步实例任务执行记录" +#~ msgid "Test port" +#~ msgstr "测试端口" -#: xpack/plugins/cloud/utils.py:69 -msgid "Account unavailable" -msgstr "账号无效" +#~ msgid "Test timeout" +#~ msgstr "测试超时时间" -#: xpack/plugins/interface/api.py:52 -msgid "Restore default successfully." -msgstr "恢复默认成功!" +#, fuzzy +#~| msgid "" +#~| "Only instances matching the IP range will be synced.
If the instance " +#~| "contains multiple IP addresses, the first IP address that matches will " +#~| "be used as the IP for the created asset.
The default value of * " +#~| "means sync all instances and randomly match IP addresses.
Such as: " +#~| "192.168.1.0/24, 10.1.1.1-10.1.1.20" +#~ msgid "" +#~ "Only instances matching the IP range will be synced.
If the instance " +#~ "contains multiple IP addresses, the first IP address that matches will be " +#~ "used as the IP for the created asset.
The default value of * means " +#~ "sync all instances and randomly match IP addresses.
Format for comma-" +#~ "delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" +#~ msgstr "" +#~ "只有匹配到 IP 段的实例会被同步。
如果实例包含多个 IP 地址,那么第一个匹" +#~ "配到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示同步所有实例和随机" +#~ "匹配 IP 地址。
例如:192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/interface/meta.py:10 -msgid "Interface settings" -msgstr "界面设置" +#~ msgid "History count" +#~ msgstr "执行次数" -#: xpack/plugins/interface/models.py:23 -msgid "Title of login page" -msgstr "登录页面标题" +#~ msgid "Instance count" +#~ msgstr "实例个数" -#: xpack/plugins/interface/models.py:27 -msgid "Image of login page" -msgstr "登录页面图片" +#~ msgid "Run sync instance task" +#~ msgstr "执行同步实例任务" -#: xpack/plugins/interface/models.py:31 -msgid "Website icon" -msgstr "网站图标" +#~ msgid "Period clean sync instance task execution" +#~ msgstr "定期清除同步实例任务执行记录" -#: xpack/plugins/interface/models.py:35 -msgid "Logo of management page" -msgstr "管理页面logo" +#~ msgid "Account unavailable" +#~ msgstr "账号无效" -#: xpack/plugins/interface/models.py:39 -msgid "Logo of logout page" -msgstr "退出页面logo" +#~ msgid "Restore default successfully." +#~ msgstr "恢复默认成功!" -#: xpack/plugins/interface/models.py:41 -msgid "Theme" -msgstr "主题" +#~ msgid "Interface settings" +#~ msgstr "界面设置" -#: xpack/plugins/interface/models.py:44 xpack/plugins/interface/models.py:85 -msgid "Interface setting" -msgstr "界面设置" +#~ msgid "Title of login page" +#~ msgstr "登录页面标题" -#: xpack/plugins/license/api.py:50 -msgid "License import successfully" -msgstr "许可证导入成功" +#~ msgid "Image of login page" +#~ msgstr "登录页面图片" -#: xpack/plugins/license/api.py:51 -msgid "License is invalid" -msgstr "无效的许可证" +#~ msgid "Website icon" +#~ msgstr "网站图标" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 -msgid "License" -msgstr "许可证" +#~ msgid "Logo of management page" +#~ msgstr "管理页面logo" -#: xpack/plugins/license/models.py:79 -msgid "Standard edition" -msgstr "标准版" +#~ msgid "Logo of logout page" +#~ msgstr "退出页面logo" -#: xpack/plugins/license/models.py:81 -msgid "Enterprise edition" -msgstr "企业版" +#~ msgid "Theme" +#~ msgstr "主题" -#: xpack/plugins/license/models.py:83 -msgid "Ultimate edition" -msgstr "旗舰版" +#~ msgid "Interface setting" +#~ msgstr "界面设置" -#: xpack/plugins/license/models.py:85 -msgid "Community edition" -msgstr "社区版" +#~ msgid "License import successfully" +#~ msgstr "许可证导入成功" + +#~ msgid "License is invalid" +#~ msgstr "无效的许可证" + +#~ msgid "License" +#~ msgstr "许可证" + +#~ msgid "Standard edition" +#~ msgstr "标准版" + +#~ msgid "Enterprise edition" +#~ msgstr "企业版" + +#~ msgid "Ultimate edition" +#~ msgstr "旗舰版" + +#~ msgid "Community edition" +#~ msgstr "社区版" #~ msgid "Connect (All Protocols)" #~ msgstr "连接 (所以协议)" diff --git a/apps/ops/ansible/runner.py b/apps/ops/ansible/runner.py index 18df1a702..3bce64b2a 100644 --- a/apps/ops/ansible/runner.py +++ b/apps/ops/ansible/runner.py @@ -9,9 +9,6 @@ from .callback import DefaultCallback class AdHocRunner: cmd_modules_choices = ('shell', 'raw', 'command', 'script', 'win_shell') - cmd_blacklist = [ - "reboot", 'shutdown', 'poweroff', 'halt', 'dd', 'half', 'top' - ] def __init__(self, inventory, module, module_args='', pattern='*', project_dir='/tmp/', extra_vars={}, dry_run=False, timeout=-1): @@ -30,7 +27,7 @@ class AdHocRunner: def check_module(self): if self.module not in self.cmd_modules_choices: return - if self.module_args and self.module_args.split()[0] in self.cmd_blacklist: + if self.module_args and self.module_args.split()[0] in settings.SECURITY_COMMAND_BLACKLIST: raise Exception("command not allowed: {}".format(self.module_args[0])) def run(self, verbosity=0, **kwargs): diff --git a/apps/settings/serializers/public.py b/apps/settings/serializers/public.py index 82f73bc03..8429ccd48 100644 --- a/apps/settings/serializers/public.py +++ b/apps/settings/serializers/public.py @@ -21,6 +21,7 @@ class PrivateSettingSerializer(PublicSettingSerializer): SECURITY_VIEW_AUTH_NEED_MFA = serializers.BooleanField() SECURITY_MFA_VERIFY_TTL = serializers.IntegerField() SECURITY_COMMAND_EXECUTION = serializers.BooleanField() + SECURITY_COMMAND_BLACKLIST = serializers.ListField() SECURITY_PASSWORD_EXPIRATION_TIME = serializers.IntegerField() SECURITY_LUNA_REMEMBER_AUTH = serializers.BooleanField() SECURITY_WATERMARK_ENABLED = serializers.BooleanField() diff --git a/apps/settings/serializers/security.py b/apps/settings/serializers/security.py index 7a84c9a00..c9f02d591 100644 --- a/apps/settings/serializers/security.py +++ b/apps/settings/serializers/security.py @@ -179,6 +179,11 @@ class SecuritySettingSerializer(SecurityPasswordRuleSerializer, SecurityAuthSeri required=False, label=_('Operation center'), help_text=_('Allow user run batch command or not using ansible') ) + SECURITY_COMMAND_BLACKLIST = serializers.ListField( + child=serializers.CharField(max_length=1024, ), + label=_('Operation center command blacklist'), + help_text=_("Commands that are not allowed execute.") + ) SECURITY_SESSION_SHARE = serializers.BooleanField( required=True, label=_('Session share'), help_text=_("Enabled, Allows user active session to be shared with other users") From 1ac9d727efd54c0291aa3fdf12c73497a48e1799 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 31 May 2023 18:19:11 +0800 Subject: [PATCH 069/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=20(#10604)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 1012 +++++++++++++------------ apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 1019 ++++++++++++++------------ 4 files changed, 1117 insertions(+), 922 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 40198acca..7e5717517 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:40f43cc773ecf5da0637ba302144e1b81ee837a835bda4a6c2cb1eedf5ccc5f1 -size 141722 +oid sha256:a93b6a850b251ea2ee17b6b9dbdee93130f745ce8278faaecbf60d74f934f1b5 +size 143780 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 372314f42..d8bb27c88 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 17:15+0800\n" +"POT-Creation-Date: 2023-05-31 18:12+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -31,6 +31,7 @@ msgstr "パラメータ 'action' は [{}] でなければなりません。" #: users/forms/profile.py:22 users/serializers/user.py:105 #: users/templates/users/_msg_user_created.html:13 #: users/templates/users/user_password_verify.html:18 +#: xpack/plugins/cloud/serializers/account_attrs.py:28 msgid "Password" msgstr "パスワード" @@ -86,7 +87,7 @@ msgstr "更新" #: accounts/const/account.py:27 #: accounts/serializers/automations/change_secret.py:156 audits/const.py:53 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 -#: ops/const.py:58 terminal/const.py:61 +#: ops/const.py:58 terminal/const.py:61 xpack/plugins/cloud/const.py:41 msgid "Failed" msgstr "失敗しました" @@ -192,7 +193,7 @@ msgstr "作成のみ" #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 -#: tickets/models/ticket/apply_asset.py:16 +#: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:212 msgid "Asset" msgstr "資産" @@ -225,7 +226,7 @@ msgstr "ソース ID" #: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: terminal/backends/command/models.py:21 terminal/models/session/session.py:34 -#: tickets/models/ticket/command_confirm.py:13 +#: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 msgid "Account" msgstr "アカウント" @@ -303,7 +304,7 @@ msgid "Trigger mode" msgstr "トリガーモード" #: accounts/models/automations/backup_account.py:97 audits/models.py:172 -#: terminal/models/session/sharing.py:111 +#: terminal/models/session/sharing.py:111 xpack/plugins/cloud/models.py:168 msgid "Reason" msgstr "理由" @@ -432,6 +433,7 @@ msgstr "最終ログイン日" #: authentication/templates/authentication/_msg_oauth_bind.html:9 #: users/forms/profile.py:32 users/forms/profile.py:115 #: users/models/user.py:751 users/templates/users/_msg_user_created.html:12 +#: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" msgstr "ユーザー名" @@ -491,6 +493,7 @@ msgstr "アカウントの確認" #: terminal/models/component/storage.py:26 terminal/models/component/task.py:15 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33 #: users/models/group.py:13 users/models/user.py:753 +#: xpack/plugins/cloud/models.py:28 msgid "Name" msgstr "名前" @@ -836,7 +839,7 @@ msgid "Regex" msgstr "正規情報" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 msgid "Content" msgstr "コンテンツ" @@ -922,6 +925,7 @@ msgid "Command group amount" msgstr "コマンドグループ数" #: acls/serializers/rules/rules.py:20 +#: xpack/plugins/cloud/serializers/task.py:22 msgid "IP address invalid: `{}`" msgstr "IPアドレスが無効: '{}'" @@ -949,7 +953,8 @@ msgstr "期間" msgid "Applications" msgstr "アプリケーション" -#: applications/models.py:16 +#: applications/models.py:16 xpack/plugins/cloud/models.py:33 +#: xpack/plugins/cloud/serializers/account.py:62 msgid "Attrs" msgstr "ツールバーの" @@ -1006,7 +1011,7 @@ msgid "Unable to connect to port {port} on {address}" msgstr "{port} のポート {address} に接続できません" #: assets/automations/ping_gateway/manager.py:58 -#: authentication/middleware.py:92 +#: authentication/middleware.py:92 xpack/plugins/cloud/providers/fc.py:48 msgid "Authentication failed" msgstr "認証に失敗しました" @@ -1040,6 +1045,7 @@ msgstr "資産情報の収集" #: assets/const/category.py:10 assets/models/asset/host.py:8 #: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:68 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 +#: xpack/plugins/cloud/serializers/account_attrs.py:72 msgid "Host" msgstr "ホスト" @@ -1141,6 +1147,7 @@ msgstr "SSHパブリックキー" #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 #: tickets/models/ticket/general.py:297 users/models/user.py:792 +#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:111 msgid "Comment" msgstr "コメント" @@ -1240,6 +1247,7 @@ msgstr "クラウド サービス" #: assets/models/asset/common.py:92 assets/models/platform.py:14 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:69 +#: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "ポート" @@ -1250,6 +1258,7 @@ msgstr "アドレス" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 +#: xpack/plugins/cloud/serializers/account_attrs.py:196 msgid "Platform" msgstr "プラットフォーム" @@ -1348,7 +1357,8 @@ msgstr "アセットの自動化タスク" #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 -#: tickets/serializers/ticket/ticket.py:20 +#: tickets/serializers/ticket/ticket.py:20 xpack/plugins/cloud/models.py:164 +#: xpack/plugins/cloud/models.py:216 msgid "Status" msgstr "ステータス" @@ -1412,6 +1422,7 @@ msgstr "資産グループ" #: assets/models/group.py:34 assets/models/platform.py:17 #: assets/serializers/platform.py:95 +#: xpack/plugins/cloud/providers/nutanix.py:30 msgid "Default" msgstr "デフォルト" @@ -1461,7 +1472,7 @@ msgid "Parent key" msgstr "親キー" #: assets/models/node.py:571 perms/serializers/permission.py:35 -#: tickets/models/ticket/apply_asset.py:14 +#: tickets/models/ticket/apply_asset.py:14 xpack/plugins/cloud/models.py:96 msgid "Node" msgstr "ノード" @@ -1601,7 +1612,7 @@ msgstr "" #: assets/serializers/asset/common.py:124 assets/serializers/platform.py:111 #: authentication/serializers/connect_token_secret.py:29 #: authentication/serializers/connect_token_secret.py:72 -#: perms/serializers/user_permission.py:25 +#: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 msgid "Protocols" msgstr "プロトコル" @@ -1620,23 +1631,22 @@ msgid "Platform not exist" msgstr "プラットフォームが存在しません" #: assets/serializers/asset/common.py:263 -#, fuzzy -#| msgid "port out of range (1-65535)" msgid "port out of range (0-65535)" -msgstr "ポート番号が範囲外です (1-65535)" +msgstr "ポート番号が範囲外です (0-65535)" #: assets/serializers/asset/common.py:270 msgid "Protocol is required: {}" msgstr "プロトコルが必要です: {}" #: assets/serializers/asset/database.py:13 -#, fuzzy -#| msgid "Default storage" msgid "Default database" -msgstr "デフォルトのストレージ" +msgstr "デフォルト・データベース" #: assets/serializers/asset/database.py:28 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 +#: xpack/plugins/cloud/serializers/account_attrs.py:56 +#: xpack/plugins/cloud/serializers/account_attrs.py:79 +#: xpack/plugins/cloud/serializers/account_attrs.py:143 msgid "This field is required." msgstr "このフィールドは必須です。" @@ -2107,10 +2117,8 @@ msgid "Permission expired" msgstr "承認の有効期限が切れています" #: authentication/api/connection_token.py:322 -#, fuzzy -#| msgid "ACL action is reject" msgid "ACL action is reject: {}({})" -msgstr "ACL アクションは拒否です" +msgstr "ACL アクションは拒否です: {}({})" #: authentication/api/connection_token.py:326 msgid "ACL action is review" @@ -2521,10 +2529,8 @@ msgid "Asset display" msgstr "アセット名" #: authentication/models/connection_token.py:43 -#, fuzzy -#| msgid "Disable" msgid "Reusable" -msgstr "無効化" +msgstr "再利用可能" #: authentication/models/connection_token.py:44 #: authentication/models/temp_token.py:13 perms/models/asset_permission.py:74 @@ -2874,6 +2880,7 @@ msgid "Copy success" msgstr "コピー成功" #: authentication/utils.py:28 common/utils/ip/geoip/utils.py:24 +#: xpack/plugins/cloud/const.py:27 msgid "LAN" msgstr "ローカルエリアネットワーク" @@ -3215,7 +3222,7 @@ msgstr "アリ雲" msgid "Tencent cloud" msgstr "テンセント雲" -#: common/sdk/sms/endpoint.py:18 +#: common/sdk/sms/endpoint.py:18 xpack/plugins/cloud/const.py:13 msgid "Huawei Cloud" msgstr "華為雲" @@ -3549,6 +3556,7 @@ msgid "Date last run" msgstr "最終実行日" #: ops/models/base.py:51 ops/models/job.py:188 +#: xpack/plugins/cloud/models.py:162 msgid "Result" msgstr "結果" @@ -4355,6 +4363,7 @@ msgid "Client Id" msgstr "クライアントID" #: settings/serializers/auth/oauth2.py:33 settings/serializers/auth/oidc.py:22 +#: xpack/plugins/cloud/serializers/account_attrs.py:38 msgid "Client Secret" msgstr "クライアント秘密" @@ -4597,6 +4606,7 @@ msgid "SSO auth key TTL" msgstr "Token有効期間" #: settings/serializers/auth/sso.py:17 +#: xpack/plugins/cloud/serializers/account_attrs.py:193 msgid "Unit: second" msgstr "単位: 秒" @@ -5652,10 +5662,8 @@ msgid "Author" msgstr "著者" #: terminal/models/applet/applet.py:36 -#, fuzzy -#| msgid "Can push account" msgid "Can concurrent" -msgstr "アカウントをプッシュできます" +msgstr "同時実行可能" #: terminal/models/applet/applet.py:37 msgid "Tags" @@ -5934,22 +5942,16 @@ msgid "Batch danger command alert" msgstr "一括危険コマンド警告" #: terminal/notifications.py:163 -#, fuzzy -#| msgid "Command storage" msgid "Command and replay storage" -msgstr "コマンドストレージ" +msgstr "コマンド及び録画記憶" #: terminal/notifications.py:164 -#, fuzzy -#| msgid "Connectivity" msgid "Connectivity alarm" -msgstr "接続性" +msgstr "接続性アラーム" #: terminal/notifications.py:189 -#, fuzzy -#| msgid "Invalid signature." msgid "Invalid storage" -msgstr "署名が無効です。" +msgstr "無効なストレージ" #: terminal/serializers/applet.py:28 msgid "Icon" @@ -6114,14 +6116,16 @@ msgid "Bucket" msgstr "バケット" #: terminal/serializers/storage.py:30 +#: xpack/plugins/cloud/serializers/account_attrs.py:17 msgid "Access key id" msgstr "アクセスキー" #: terminal/serializers/storage.py:34 +#: xpack/plugins/cloud/serializers/account_attrs.py:20 msgid "Access key secret" msgstr "アクセスキーシークレット" -#: terminal/serializers/storage.py:65 +#: terminal/serializers/storage.py:65 xpack/plugins/cloud/models.py:209 msgid "Region" msgstr "リージョン" @@ -6190,16 +6194,12 @@ msgid "Install applet" msgstr "アプリをインストールする" #: terminal/tasks.py:109 -#, fuzzy -#| msgid "Gather assets accounts" msgid "Generate applet host accounts" -msgstr "資産の口座番号を収集する" +msgstr "リモートアプリケーション上のアカウントを収集する" #: terminal/tasks.py:121 -#, fuzzy -#| msgid "Can test asset connectivity" msgid "Check command replay storage connectivity" -msgstr "資産接続をテストできます" +msgstr "チェックコマンドと録画ストレージの接続性" #: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 msgid "" @@ -7136,467 +7136,571 @@ msgstr "* 新しいパスワードを最後の {} パスワードにすること msgid "Reset password success, return to login page" msgstr "パスワードの成功をリセットし、ログインページに戻る" -#, fuzzy -#~| msgid "User ID" -#~ msgid "User IP" -#~ msgstr "ユーザーID" +#: xpack/apps.py:8 +msgid "XPACK" +msgstr "XPack" -#~ msgid "XPACK" -#~ msgstr "XPack" +#: xpack/plugins/cloud/api.py:40 +msgid "Test connection successful" +msgstr "テスト接続成功" -#~ msgid "Test connection successful" -#~ msgstr "テスト接続成功" +#: xpack/plugins/cloud/api.py:42 +msgid "Test connection failed: {}" +msgstr "テスト接続に失敗しました: {}" -#~ msgid "Test connection failed: {}" -#~ msgstr "テスト接続に失敗しました: {}" +#: xpack/plugins/cloud/const.py:8 +msgid "Alibaba Cloud" +msgstr "アリ雲" -#~ msgid "Alibaba Cloud" -#~ msgstr "アリ雲" +#: xpack/plugins/cloud/const.py:9 +msgid "AWS (International)" +msgstr "AWS (国際)" -#~ msgid "AWS (International)" -#~ msgstr "AWS (国際)" +#: xpack/plugins/cloud/const.py:10 +msgid "AWS (China)" +msgstr "AWS (中国)" -#~ msgid "AWS (China)" -#~ msgstr "AWS (中国)" +#: xpack/plugins/cloud/const.py:11 +msgid "Azure (China)" +msgstr "Azure (中国)" -#~ msgid "Azure (China)" -#~ msgstr "Azure (中国)" +#: xpack/plugins/cloud/const.py:12 +msgid "Azure (International)" +msgstr "Azure (国際)" -#~ msgid "Azure (International)" -#~ msgstr "Azure (国際)" +#: xpack/plugins/cloud/const.py:14 +msgid "Baidu Cloud" +msgstr "百度雲" -#~ msgid "Baidu Cloud" -#~ msgstr "百度雲" +#: xpack/plugins/cloud/const.py:15 +msgid "JD Cloud" +msgstr "京東雲" -#~ msgid "JD Cloud" -#~ msgstr "京東雲" +#: xpack/plugins/cloud/const.py:16 +msgid "KingSoft Cloud" +msgstr "金山雲" -#~ msgid "KingSoft Cloud" -#~ msgstr "金山雲" +#: xpack/plugins/cloud/const.py:17 +msgid "Tencent Cloud" +msgstr "テンセント雲" -#~ msgid "Tencent Cloud" -#~ msgstr "テンセント雲" +#: xpack/plugins/cloud/const.py:18 +msgid "Tencent Cloud (Lighthouse)" +msgstr "テンセント雲(軽量アプリケーション)" -#~ msgid "Tencent Cloud (Lighthouse)" -#~ msgstr "テンセント雲(軽量アプリケーション)" +#: xpack/plugins/cloud/const.py:19 +msgid "VMware" +msgstr "VMware" -#~ msgid "VMware" -#~ msgstr "VMware" +#: xpack/plugins/cloud/const.py:20 xpack/plugins/cloud/providers/nutanix.py:13 +msgid "Nutanix" +msgstr "Nutanix" -#~ msgid "Nutanix" -#~ msgstr "Nutanix" +#: xpack/plugins/cloud/const.py:21 +msgid "Huawei Private Cloud" +msgstr "華為私有雲" -#~ msgid "Huawei Private Cloud" -#~ msgstr "華為私有雲" +#: xpack/plugins/cloud/const.py:22 +msgid "Qingyun Private Cloud" +msgstr "青雲私有雲" -#~ msgid "Qingyun Private Cloud" -#~ msgstr "青雲私有雲" +#: xpack/plugins/cloud/const.py:23 +msgid "CTYun Private Cloud" +msgstr "スカイウィング私有雲" -#~ msgid "CTYun Private Cloud" -#~ msgstr "スカイウィング私有雲" +#: xpack/plugins/cloud/const.py:24 +msgid "OpenStack" +msgstr "OpenStack" -#~ msgid "OpenStack" -#~ msgstr "OpenStack" +#: xpack/plugins/cloud/const.py:25 +msgid "Google Cloud Platform" +msgstr "谷歌雲" -#~ msgid "Google Cloud Platform" -#~ msgstr "谷歌雲" +#: xpack/plugins/cloud/const.py:26 +msgid "Fusion Compute" +msgstr "" -#~ msgid "Private IP" -#~ msgstr "プライベートIP" +#: xpack/plugins/cloud/const.py:31 +msgid "Private IP" +msgstr "プライベートIP" -#~ msgid "Public IP" -#~ msgstr "パブリックIP" +#: xpack/plugins/cloud/const.py:32 +msgid "Public IP" +msgstr "パブリックIP" -#~ msgid "Instance name" -#~ msgstr "インスタンス名" +#: xpack/plugins/cloud/const.py:36 +msgid "Instance name" +msgstr "インスタンス名" -#~ msgid "Instance name and Partial IP" -#~ msgstr "インスタンス名と部分IP" +#: xpack/plugins/cloud/const.py:37 +msgid "Instance name and Partial IP" +msgstr "インスタンス名と部分IP" -#~ msgid "Succeed" -#~ msgstr "成功" +#: xpack/plugins/cloud/const.py:42 +msgid "Succeed" +msgstr "成功" -#~ msgid "Unsync" -#~ msgstr "同期していません" +#: xpack/plugins/cloud/const.py:46 +msgid "Unsync" +msgstr "同期していません" -#~ msgid "New Sync" -#~ msgstr "新しい同期" +#: xpack/plugins/cloud/const.py:47 +msgid "New Sync" +msgstr "新しい同期" -#~ msgid "Synced" -#~ msgstr "同期済み" +#: xpack/plugins/cloud/const.py:48 +msgid "Synced" +msgstr "同期済み" -#~ msgid "Released" -#~ msgstr "リリース済み" +#: xpack/plugins/cloud/const.py:49 +msgid "Released" +msgstr "リリース済み" -#~ msgid "Cloud center" -#~ msgstr "クラウドセンター" +#: xpack/plugins/cloud/meta.py:9 +msgid "Cloud center" +msgstr "クラウドセンター" -#~ msgid "Provider" -#~ msgstr "プロバイダー" +#: xpack/plugins/cloud/models.py:30 +msgid "Provider" +msgstr "プロバイダー" -#~ msgid "Validity" -#~ msgstr "有効性" +#: xpack/plugins/cloud/models.py:34 +msgid "Validity" +msgstr "有効性" -#~ msgid "Cloud account" -#~ msgstr "クラウドアカウント" +#: xpack/plugins/cloud/models.py:39 +msgid "Cloud account" +msgstr "クラウドアカウント" -#~ msgid "Test cloud account" -#~ msgstr "クラウドアカウントのテスト" +#: xpack/plugins/cloud/models.py:41 +msgid "Test cloud account" +msgstr "クラウドアカウントのテスト" -#~ msgid "Regions" -#~ msgstr "リージョン" +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 +msgid "Regions" +msgstr "リージョン" -#~ msgid "Hostname strategy" -#~ msgstr "ホスト名戦略" +#: xpack/plugins/cloud/models.py:91 +msgid "Hostname strategy" +msgstr "ホスト名戦略" -#~ msgid "IP network segment group" -#~ msgstr "IPネットワークセグメントグループ" +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 +msgid "IP network segment group" +msgstr "IPネットワークセグメントグループ" -#~ msgid "Sync IP type" -#~ msgstr "同期IPタイプ" +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 +msgid "Sync IP type" +msgstr "同期IPタイプ" -#~ msgid "Always update" -#~ msgstr "常に更新" +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 +msgid "Always update" +msgstr "常に更新" -#~ msgid "Date last sync" -#~ msgstr "最終同期日" +#: xpack/plugins/cloud/models.py:114 +msgid "Date last sync" +msgstr "最終同期日" -#~ msgid "Sync instance task" -#~ msgstr "インスタンスの同期タスク" +#: xpack/plugins/cloud/models.py:119 xpack/plugins/cloud/models.py:160 +msgid "Sync instance task" +msgstr "インスタンスの同期タスク" -#~ msgid "Date sync" -#~ msgstr "日付の同期" +#: xpack/plugins/cloud/models.py:171 xpack/plugins/cloud/models.py:219 +msgid "Date sync" +msgstr "日付の同期" -#~ msgid "Sync instance task execution" -#~ msgstr "インスタンスタスクの同期実行" +#: xpack/plugins/cloud/models.py:175 +msgid "Sync instance task execution" +msgstr "インスタンスタスクの同期実行" -#~ msgid "Sync task" -#~ msgstr "同期タスク" +#: xpack/plugins/cloud/models.py:199 +msgid "Sync task" +msgstr "同期タスク" -#~ msgid "Sync instance task history" -#~ msgstr "インスタンスタスク履歴の同期" +#: xpack/plugins/cloud/models.py:203 +msgid "Sync instance task history" +msgstr "インスタンスタスク履歴の同期" -#~ msgid "Instance" -#~ msgstr "インスタンス" +#: xpack/plugins/cloud/models.py:206 +msgid "Instance" +msgstr "インスタンス" -#~ msgid "Sync instance detail" -#~ msgstr "同期インスタンスの詳細" +#: xpack/plugins/cloud/models.py:223 +msgid "Sync instance detail" +msgstr "同期インスタンスの詳細" -#~ msgid "China (Beijing)" -#~ msgstr "中国 (北京)" +#: xpack/plugins/cloud/providers/aws_international.py:17 +msgid "China (Beijing)" +msgstr "中国 (北京)" -#~ msgid "China (Ningxia)" -#~ msgstr "中国 (寧夏)" +#: xpack/plugins/cloud/providers/aws_international.py:18 +msgid "China (Ningxia)" +msgstr "中国 (寧夏)" -#~ msgid "US East (Ohio)" -#~ msgstr "米国東部 (オハイオ州)" +#: xpack/plugins/cloud/providers/aws_international.py:21 +msgid "US East (Ohio)" +msgstr "米国東部 (オハイオ州)" -#~ msgid "US East (N. Virginia)" -#~ msgstr "米国東部 (N. バージニア州)" +#: xpack/plugins/cloud/providers/aws_international.py:22 +msgid "US East (N. Virginia)" +msgstr "米国東部 (N. バージニア州)" -#~ msgid "US West (N. California)" -#~ msgstr "米国西部 (N. カリフォルニア州)" +#: xpack/plugins/cloud/providers/aws_international.py:23 +msgid "US West (N. California)" +msgstr "米国西部 (N. カリフォルニア州)" -#~ msgid "US West (Oregon)" -#~ msgstr "米国西部 (オレゴン州)" - -#~ msgid "Africa (Cape Town)" -#~ msgstr "アフリカ (ケープタウン)" - -#~ msgid "Asia Pacific (Hong Kong)" -#~ msgstr "アジアパシフィック (香港)" - -#~ msgid "Asia Pacific (Mumbai)" -#~ msgstr "アジア太平洋 (ムンバイ)" - -#~ msgid "Asia Pacific (Osaka-Local)" -#~ msgstr "アジアパシフィック (大阪-ローカル)" - -#~ msgid "Asia Pacific (Seoul)" -#~ msgstr "アジア太平洋地域 (ソウル)" - -#~ msgid "Asia Pacific (Singapore)" -#~ msgstr "アジア太平洋 (シンガポール)" - -#~ msgid "Asia Pacific (Sydney)" -#~ msgstr "アジア太平洋 (シドニー)" - -#~ msgid "Asia Pacific (Tokyo)" -#~ msgstr "アジアパシフィック (東京)" - -#~ msgid "Canada (Central)" -#~ msgstr "カナダ (中央)" - -#~ msgid "Europe (Frankfurt)" -#~ msgstr "ヨーロッパ (フランクフルト)" - -#~ msgid "Europe (Ireland)" -#~ msgstr "ヨーロッパ (アイルランド)" - -#~ msgid "Europe (London)" -#~ msgstr "ヨーロッパ (ロンドン)" - -#~ msgid "Europe (Milan)" -#~ msgstr "ヨーロッパ (ミラノ)" - -#~ msgid "Europe (Paris)" -#~ msgstr "ヨーロッパ (パリ)" - -#~ msgid "Europe (Stockholm)" -#~ msgstr "ヨーロッパ (ストックホルム)" - -#~ msgid "Middle East (Bahrain)" -#~ msgstr "中东 (バーレーン)" - -#~ msgid "South America (São Paulo)" -#~ msgstr "南米 (サンパウロ)" - -#~ msgid "CN North-Beijing" -#~ msgstr "華北-北京" - -#~ msgid "CN South-Guangzhou" -#~ msgstr "華南-広州" - -#~ msgid "CN East-Suzhou" -#~ msgstr "華東-蘇州" - -#~ msgid "CN-Hong Kong" -#~ msgstr "中国-香港" - -#~ msgid "CN Center-Wuhan" -#~ msgstr "華中-武漢" - -#~ msgid "CN North-Baoding" -#~ msgstr "華北-保定" - -#~ msgid "CN East-Shanghai" -#~ msgstr "華東-上海" - -#~ msgid "AP-Singapore" -#~ msgstr "アジア太平洋-シンガポール" - -#~ msgid "AF-Johannesburg" -#~ msgstr "アフリカ-ヨハネスブルク" - -#~ msgid "CN North-Beijing4" -#~ msgstr "華北-北京4" - -#~ msgid "CN North-Beijing1" -#~ msgstr "華北-北京1" - -#~ msgid "CN East-Shanghai2" -#~ msgstr "華東-上海2" - -#~ msgid "CN East-Shanghai1" -#~ msgstr "華東-上海1" - -#~ msgid "LA-Mexico City1" -#~ msgstr "LA-メキシコCity1" - -#~ msgid "LA-Santiago" -#~ msgstr "ラテンアメリカ-サンディエゴ" - -#~ msgid "LA-Sao Paulo1" -#~ msgstr "ラミー・サンパウロ1" - -#~ msgid "EU-Paris" -#~ msgstr "ヨーロッパ-パリ" - -#~ msgid "CN Southwest-Guiyang1" -#~ msgstr "南西-貴陽1" - -#~ msgid "AP-Bangkok" -#~ msgstr "アジア太平洋-バンコク" - -#~ msgid "CN Northeast-Dalian" -#~ msgstr "华北-大连" - -#~ msgid "CN North-Ulanqab1" -#~ msgstr "華北-ウランチャブ一" - -#~ msgid "CN South-Guangzhou-InvitationOnly" -#~ msgstr "華南-広州-友好ユーザー環境" - -#~ msgid "CN East-Suqian" -#~ msgstr "華東-宿遷" - -#~ msgid "Validity display" -#~ msgstr "有効表示" - -#~ msgid "Provider display" -#~ msgstr "プロバイダ表示" - -#~ msgid "Client ID" -#~ msgstr "クライアントID" - -#~ msgid "Tenant ID" -#~ msgstr "テナントID" - -#~ msgid "Subscription ID" -#~ msgstr "サブスクリプションID" - -#~ msgid "API Endpoint" -#~ msgstr "APIエンドポイント" - -#~ msgid "Auth url" -#~ msgstr "認証アドレス" - -#~ msgid "eg: http://openstack.example.com:5000/v3" -#~ msgstr "例えば: http://openstack.example.com:5000/v3" - -#~ msgid "User domain" -#~ msgstr "ユーザードメイン" - -#~ msgid "Cert File" -#~ msgstr "証明書ファイル" - -#~ msgid "Key File" -#~ msgstr "キーファイル" - -#~ msgid "Service account key" -#~ msgstr "サービスアカウントキー" - -#~ msgid "The file is in JSON format" -#~ msgstr "ファイルはJSON形式です。" - -#~ msgid "IP address invalid `{}`, {}" -#~ msgstr "IPアドレスが無効: '{}', {}" - -#, fuzzy -#~| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" -#~ msgid "" -#~ "Format for comma-delimited string,Such as: 192.168.1.0/24, " -#~ "10.0.0.0-10.0.0.255" -#~ msgstr "例:192.168.1.0/24,10.0.0.0-10.0.0.255" - -#~ msgid "" -#~ "The port is used to detect the validity of the IP address. When the " -#~ "synchronization task is executed, only the valid IP address will be " -#~ "synchronized.
If the port is 0, all IP addresses are valid." -#~ msgstr "" -#~ "このポートは、 IP アドレスの有効性を検出するために使用されます。同期タスク" -#~ "が実行されると、有効な IP アドレスのみが同期されます。
ポートが0の場" -#~ "合、すべてのIPアドレスが有効です。" - -#~ msgid "Hostname prefix" -#~ msgstr "ホスト名プレフィックス" - -#~ msgid "IP segment" -#~ msgstr "IP セグメント" - -#~ msgid "Test port" -#~ msgstr "テストポート" - -#~ msgid "Test timeout" -#~ msgstr "テストタイムアウト" - -#, fuzzy -#~| msgid "" -#~| "Only instances matching the IP range will be synced.
If the instance " -#~| "contains multiple IP addresses, the first IP address that matches will " -#~| "be used as the IP for the created asset.
The default value of * " -#~| "means sync all instances and randomly match IP addresses.
Such as: " -#~| "192.168.1.0/24, 10.1.1.1-10.1.1.20" -#~ msgid "" -#~ "Only instances matching the IP range will be synced.
If the instance " -#~ "contains multiple IP addresses, the first IP address that matches will be " -#~ "used as the IP for the created asset.
The default value of * means " -#~ "sync all instances and randomly match IP addresses.
Format for comma-" -#~ "delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" -#~ msgstr "" -#~ "IP範囲に一致するインスタンスのみが同期されます。
インスタンスに複数のIP" -#~ "アドレスが含まれている場合、一致する最初のIPアドレスが作成されたアセットの" -#~ "IPとして使用されます。
デフォルト値の*は、すべてのインスタンスを同期" -#~ "し、IPアドレスをランダムに一致させることを意味します。
例:" -#~ "192.168.1.0/24,10.1.1.1-10.1.1.20" - -#~ msgid "History count" -#~ msgstr "実行回数" - -#~ msgid "Instance count" -#~ msgstr "インスタンス数" - -#~ msgid "Run sync instance task" -#~ msgstr "同期インスタンス タスクを実行する" - -#~ msgid "Period clean sync instance task execution" -#~ msgstr "同期インスタンス タスクの実行記録を定期的にクリアする" - -#~ msgid "Account unavailable" -#~ msgstr "利用できないアカウント" - -#~ msgid "Restore default successfully." -#~ msgstr "デフォルトの復元に成功しました。" - -#~ msgid "Interface settings" -#~ msgstr "インターフェイスの設定" - -#~ msgid "Title of login page" -#~ msgstr "ログインページのタイトル" - -#~ msgid "Image of login page" -#~ msgstr "ログインページのイメージ" - -#~ msgid "Website icon" -#~ msgstr "ウェブサイトのアイコン" - -#~ msgid "Logo of management page" -#~ msgstr "管理ページのロゴ" - -#~ msgid "Logo of logout page" -#~ msgstr "ログアウトページのロゴ" - -#~ msgid "Theme" -#~ msgstr "テーマ" - -#~ msgid "Interface setting" -#~ msgstr "インターフェイスの設定" - -#~ msgid "License import successfully" -#~ msgstr "ライセンスのインポートに成功" - -#~ msgid "License is invalid" -#~ msgstr "ライセンスが無効です" - -#~ msgid "License" -#~ msgstr "ライセンス" - -#~ msgid "Standard edition" -#~ msgstr "標準版" - -#~ msgid "Enterprise edition" -#~ msgstr "エンタープライズ版" - -#~ msgid "Ultimate edition" -#~ msgstr "究極のエディション" - -#~ msgid "Community edition" -#~ msgstr "コミュニティ版" - -#, fuzzy -#~| msgid "Delete" -#~ msgid "Delete (SFTP)" -#~ msgstr "削除" - -#~ msgid "User (username)" -#~ msgstr "ユーザー (ユーザー名)" - -#~ msgid "Asset (name)" -#~ msgstr "資産(名前)" - -#~ msgid "Asset (address)" -#~ msgstr "資産(住所)" - -#~ msgid "Account (username)" -#~ msgstr "アカウント (ユーザー名)" - -#~ msgid "MFA method not support" -#~ msgstr "MFAメソッドはサポートしていません" - -#, fuzzy -#~| msgid "Trigger mode" -#~ msgid "Trigger type" -#~ msgstr "トリガーモード" - -#~ msgid "Please login with a password and then bind the FeiShu" -#~ msgstr "パスワードでログインしてから本を飛ばすをバインドしてください" +#: xpack/plugins/cloud/providers/aws_international.py:24 +msgid "US West (Oregon)" +msgstr "米国西部 (オレゴン州)" + +#: xpack/plugins/cloud/providers/aws_international.py:25 +msgid "Africa (Cape Town)" +msgstr "アフリカ (ケープタウン)" + +#: xpack/plugins/cloud/providers/aws_international.py:26 +msgid "Asia Pacific (Hong Kong)" +msgstr "アジアパシフィック (香港)" + +#: xpack/plugins/cloud/providers/aws_international.py:27 +msgid "Asia Pacific (Mumbai)" +msgstr "アジア太平洋 (ムンバイ)" + +#: xpack/plugins/cloud/providers/aws_international.py:28 +msgid "Asia Pacific (Osaka-Local)" +msgstr "アジアパシフィック (大阪-ローカル)" + +#: xpack/plugins/cloud/providers/aws_international.py:29 +msgid "Asia Pacific (Seoul)" +msgstr "アジア太平洋地域 (ソウル)" + +#: xpack/plugins/cloud/providers/aws_international.py:30 +msgid "Asia Pacific (Singapore)" +msgstr "アジア太平洋 (シンガポール)" + +#: xpack/plugins/cloud/providers/aws_international.py:31 +msgid "Asia Pacific (Sydney)" +msgstr "アジア太平洋 (シドニー)" + +#: xpack/plugins/cloud/providers/aws_international.py:32 +msgid "Asia Pacific (Tokyo)" +msgstr "アジアパシフィック (東京)" + +#: xpack/plugins/cloud/providers/aws_international.py:33 +msgid "Canada (Central)" +msgstr "カナダ (中央)" + +#: xpack/plugins/cloud/providers/aws_international.py:34 +msgid "Europe (Frankfurt)" +msgstr "ヨーロッパ (フランクフルト)" + +#: xpack/plugins/cloud/providers/aws_international.py:35 +msgid "Europe (Ireland)" +msgstr "ヨーロッパ (アイルランド)" + +#: xpack/plugins/cloud/providers/aws_international.py:36 +msgid "Europe (London)" +msgstr "ヨーロッパ (ロンドン)" + +#: xpack/plugins/cloud/providers/aws_international.py:37 +msgid "Europe (Milan)" +msgstr "ヨーロッパ (ミラノ)" + +#: xpack/plugins/cloud/providers/aws_international.py:38 +msgid "Europe (Paris)" +msgstr "ヨーロッパ (パリ)" + +#: xpack/plugins/cloud/providers/aws_international.py:39 +msgid "Europe (Stockholm)" +msgstr "ヨーロッパ (ストックホルム)" + +#: xpack/plugins/cloud/providers/aws_international.py:40 +msgid "Middle East (Bahrain)" +msgstr "中东 (バーレーン)" + +#: xpack/plugins/cloud/providers/aws_international.py:41 +msgid "South America (São Paulo)" +msgstr "南米 (サンパウロ)" + +#: xpack/plugins/cloud/providers/baiducloud.py:54 +#: xpack/plugins/cloud/providers/jdcloud.py:127 +msgid "CN North-Beijing" +msgstr "華北-北京" + +#: xpack/plugins/cloud/providers/baiducloud.py:55 +#: xpack/plugins/cloud/providers/huaweicloud.py:40 +#: xpack/plugins/cloud/providers/jdcloud.py:130 +msgid "CN South-Guangzhou" +msgstr "華南-広州" + +#: xpack/plugins/cloud/providers/baiducloud.py:56 +msgid "CN East-Suzhou" +msgstr "華東-蘇州" + +#: xpack/plugins/cloud/providers/baiducloud.py:57 +#: xpack/plugins/cloud/providers/huaweicloud.py:48 +msgid "CN-Hong Kong" +msgstr "中国-香港" + +#: xpack/plugins/cloud/providers/baiducloud.py:58 +msgid "CN Center-Wuhan" +msgstr "華中-武漢" + +#: xpack/plugins/cloud/providers/baiducloud.py:59 +msgid "CN North-Baoding" +msgstr "華北-保定" + +#: xpack/plugins/cloud/providers/baiducloud.py:60 +#: xpack/plugins/cloud/providers/jdcloud.py:129 +msgid "CN East-Shanghai" +msgstr "華東-上海" + +#: xpack/plugins/cloud/providers/baiducloud.py:61 +#: xpack/plugins/cloud/providers/huaweicloud.py:47 +msgid "AP-Singapore" +msgstr "アジア太平洋-シンガポール" + +#: xpack/plugins/cloud/providers/huaweicloud.py:35 +msgid "AF-Johannesburg" +msgstr "アフリカ-ヨハネスブルク" + +#: xpack/plugins/cloud/providers/huaweicloud.py:36 +msgid "CN North-Beijing4" +msgstr "華北-北京4" + +#: xpack/plugins/cloud/providers/huaweicloud.py:37 +msgid "CN North-Beijing1" +msgstr "華北-北京1" + +#: xpack/plugins/cloud/providers/huaweicloud.py:38 +msgid "CN East-Shanghai2" +msgstr "華東-上海2" + +#: xpack/plugins/cloud/providers/huaweicloud.py:39 +msgid "CN East-Shanghai1" +msgstr "華東-上海1" + +#: xpack/plugins/cloud/providers/huaweicloud.py:41 +msgid "LA-Mexico City1" +msgstr "LA-メキシコCity1" + +#: xpack/plugins/cloud/providers/huaweicloud.py:42 +msgid "LA-Santiago" +msgstr "ラテンアメリカ-サンディエゴ" + +#: xpack/plugins/cloud/providers/huaweicloud.py:43 +msgid "LA-Sao Paulo1" +msgstr "ラミー・サンパウロ1" + +#: xpack/plugins/cloud/providers/huaweicloud.py:44 +msgid "EU-Paris" +msgstr "ヨーロッパ-パリ" + +#: xpack/plugins/cloud/providers/huaweicloud.py:45 +msgid "CN Southwest-Guiyang1" +msgstr "南西-貴陽1" + +#: xpack/plugins/cloud/providers/huaweicloud.py:46 +msgid "AP-Bangkok" +msgstr "アジア太平洋-バンコク" + +#: xpack/plugins/cloud/providers/huaweicloud.py:50 +msgid "CN Northeast-Dalian" +msgstr "华北-大连" + +#: xpack/plugins/cloud/providers/huaweicloud.py:51 +msgid "CN North-Ulanqab1" +msgstr "華北-ウランチャブ一" + +#: xpack/plugins/cloud/providers/huaweicloud.py:52 +msgid "CN South-Guangzhou-InvitationOnly" +msgstr "華南-広州-友好ユーザー環境" + +#: xpack/plugins/cloud/providers/jdcloud.py:128 +msgid "CN East-Suqian" +msgstr "華東-宿遷" + +#: xpack/plugins/cloud/serializers/account.py:63 +msgid "Validity display" +msgstr "有効表示" + +#: xpack/plugins/cloud/serializers/account.py:64 +msgid "Provider display" +msgstr "プロバイダ表示" + +#: xpack/plugins/cloud/serializers/account_attrs.py:35 +msgid "Client ID" +msgstr "クライアントID" + +#: xpack/plugins/cloud/serializers/account_attrs.py:41 +msgid "Tenant ID" +msgstr "テナントID" + +#: xpack/plugins/cloud/serializers/account_attrs.py:44 +msgid "Subscription ID" +msgstr "サブスクリプションID" + +#: xpack/plugins/cloud/serializers/account_attrs.py:98 +#: xpack/plugins/cloud/serializers/account_attrs.py:103 +#: xpack/plugins/cloud/serializers/account_attrs.py:119 +#: xpack/plugins/cloud/serializers/account_attrs.py:149 +msgid "API Endpoint" +msgstr "APIエンドポイント" + +#: xpack/plugins/cloud/serializers/account_attrs.py:109 +msgid "Auth url" +msgstr "認証アドレス" + +#: xpack/plugins/cloud/serializers/account_attrs.py:110 +msgid "eg: http://openstack.example.com:5000/v3" +msgstr "例えば: http://openstack.example.com:5000/v3" + +#: xpack/plugins/cloud/serializers/account_attrs.py:113 +msgid "User domain" +msgstr "ユーザードメイン" + +#: xpack/plugins/cloud/serializers/account_attrs.py:120 +msgid "Cert File" +msgstr "証明書ファイル" + +#: xpack/plugins/cloud/serializers/account_attrs.py:121 +msgid "Key File" +msgstr "キーファイル" + +#: xpack/plugins/cloud/serializers/account_attrs.py:137 +msgid "Service account key" +msgstr "サービスアカウントキー" + +#: xpack/plugins/cloud/serializers/account_attrs.py:138 +msgid "The file is in JSON format" +msgstr "ファイルはJSON形式です。" + +#: xpack/plugins/cloud/serializers/account_attrs.py:156 +msgid "IP address invalid `{}`, {}" +msgstr "IPアドレスが無効: '{}', {}" + +#: xpack/plugins/cloud/serializers/account_attrs.py:172 +msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgstr "例: 192.168.1.0/24,10.0.0.0-10.0.0.255" + +#: xpack/plugins/cloud/serializers/account_attrs.py:175 +msgid "" +"The port is used to detect the validity of the IP address. When the " +"synchronization task is executed, only the valid IP address will be " +"synchronized.
If the port is 0, all IP addresses are valid." +msgstr "" +"このポートは、 IP アドレスの有効性を検出するために使用されます。同期タスクが" +"実行されると、有効な IP アドレスのみが同期されます。
ポートが0の場合、す" +"べてのIPアドレスが有効です。" + +#: xpack/plugins/cloud/serializers/account_attrs.py:183 +msgid "Hostname prefix" +msgstr "ホスト名プレフィックス" + +#: xpack/plugins/cloud/serializers/account_attrs.py:186 +msgid "IP segment" +msgstr "IP セグメント" + +#: xpack/plugins/cloud/serializers/account_attrs.py:190 +msgid "Test port" +msgstr "テストポート" + +#: xpack/plugins/cloud/serializers/account_attrs.py:193 +msgid "Test timeout" +msgstr "テストタイムアウト" + +#: xpack/plugins/cloud/serializers/task.py:28 +msgid "" +"Only instances matching the IP range will be synced.
If the instance " +"contains multiple IP addresses, the first IP address that matches will be " +"used as the IP for the created asset.
The default value of * means sync " +"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " +"10.1.1.1-10.1.1.20" +msgstr "" +"IP範囲に一致するインスタンスのみが同期されます。
インスタンスに複数のIPア" +"ドレスが含まれている場合、一致する最初のIPアドレスが作成されたアセットのIPと" +"して使用されます。
デフォルト値の*は、すべてのインスタンスを同期し、IPア" +"ドレスをランダムに一致させることを意味します。
例: " +"192.168.1.0/24,10.1.1.1-10.1.1.20" + +#: xpack/plugins/cloud/serializers/task.py:34 +msgid "History count" +msgstr "実行回数" + +#: xpack/plugins/cloud/serializers/task.py:35 +msgid "Instance count" +msgstr "インスタンス数" + +#: xpack/plugins/cloud/tasks.py:27 +msgid "Run sync instance task" +msgstr "同期インスタンス タスクを実行する" + +#: xpack/plugins/cloud/tasks.py:41 +msgid "Period clean sync instance task execution" +msgstr "同期インスタンス タスクの実行記録を定期的にクリアする" + +#: xpack/plugins/cloud/utils.py:69 +msgid "Account unavailable" +msgstr "利用できないアカウント" + +#: xpack/plugins/interface/api.py:52 +msgid "Restore default successfully." +msgstr "デフォルトの復元に成功しました。" + +#: xpack/plugins/interface/meta.py:10 +msgid "Interface settings" +msgstr "インターフェイスの設定" + +#: xpack/plugins/interface/models.py:23 +msgid "Title of login page" +msgstr "ログインページのタイトル" + +#: xpack/plugins/interface/models.py:27 +msgid "Image of login page" +msgstr "ログインページのイメージ" + +#: xpack/plugins/interface/models.py:31 +msgid "Website icon" +msgstr "ウェブサイトのアイコン" + +#: xpack/plugins/interface/models.py:35 +msgid "Logo of management page" +msgstr "管理ページのロゴ" + +#: xpack/plugins/interface/models.py:39 +msgid "Logo of logout page" +msgstr "ログアウトページのロゴ" + +#: xpack/plugins/interface/models.py:41 +msgid "Theme" +msgstr "テーマ" + +#: xpack/plugins/interface/models.py:44 xpack/plugins/interface/models.py:85 +msgid "Interface setting" +msgstr "インターフェイスの設定" + +#: xpack/plugins/license/api.py:50 +msgid "License import successfully" +msgstr "ライセンスのインポートに成功" + +#: xpack/plugins/license/api.py:51 +msgid "License is invalid" +msgstr "ライセンスが無効です" + +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 +msgid "License" +msgstr "ライセンス" + +#: xpack/plugins/license/models.py:80 +msgid "Standard edition" +msgstr "標準版" + +#: xpack/plugins/license/models.py:82 +msgid "Enterprise edition" +msgstr "エンタープライズ版" + +#: xpack/plugins/license/models.py:84 +msgid "Ultimate edition" +msgstr "究極のエディション" + +#: xpack/plugins/license/models.py:86 +msgid "Community edition" +msgstr "コミュニティ版" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 256aed8c9..6a20beeda 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4cf57efef290fb80f5159a628b8cde7861cb2bd3fcc247fcf7255fbd2757fb9 -size 115892 +oid sha256:f236155485cdb4b453ff317d3c932ef4455d29e856ef3c2902a349d430992404 +size 117637 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 68e8287d1..4ec8237a3 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 17:15+0800\n" +"POT-Creation-Date: 2023-05-31 18:12+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -30,6 +30,7 @@ msgstr "参数 'action' 必须是 [{}]" #: users/forms/profile.py:22 users/serializers/user.py:105 #: users/templates/users/_msg_user_created.html:13 #: users/templates/users/user_password_verify.html:18 +#: xpack/plugins/cloud/serializers/account_attrs.py:28 msgid "Password" msgstr "密码" @@ -85,7 +86,7 @@ msgstr "更新" #: accounts/const/account.py:27 #: accounts/serializers/automations/change_secret.py:156 audits/const.py:53 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 -#: ops/const.py:58 terminal/const.py:61 +#: ops/const.py:58 terminal/const.py:61 xpack/plugins/cloud/const.py:41 msgid "Failed" msgstr "失败" @@ -191,7 +192,7 @@ msgstr "仅创建" #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 -#: tickets/models/ticket/apply_asset.py:16 +#: tickets/models/ticket/apply_asset.py:16 xpack/plugins/cloud/models.py:212 msgid "Asset" msgstr "资产" @@ -224,7 +225,7 @@ msgstr "来源 ID" #: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: terminal/backends/command/models.py:21 terminal/models/session/session.py:34 -#: tickets/models/ticket/command_confirm.py:13 +#: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 msgid "Account" msgstr "账号" @@ -302,7 +303,7 @@ msgid "Trigger mode" msgstr "触发模式" #: accounts/models/automations/backup_account.py:97 audits/models.py:172 -#: terminal/models/session/sharing.py:111 +#: terminal/models/session/sharing.py:111 xpack/plugins/cloud/models.py:168 msgid "Reason" msgstr "原因" @@ -431,6 +432,7 @@ msgstr "最后登录日期" #: authentication/templates/authentication/_msg_oauth_bind.html:9 #: users/forms/profile.py:32 users/forms/profile.py:115 #: users/models/user.py:751 users/templates/users/_msg_user_created.html:12 +#: xpack/plugins/cloud/serializers/account_attrs.py:26 msgid "Username" msgstr "用户名" @@ -490,6 +492,7 @@ msgstr "账号验证" #: terminal/models/component/storage.py:26 terminal/models/component/task.py:15 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33 #: users/models/group.py:13 users/models/user.py:753 +#: xpack/plugins/cloud/models.py:28 msgid "Name" msgstr "名称" @@ -832,7 +835,7 @@ msgid "Regex" msgstr "正则表达式" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 msgid "Content" msgstr "内容" @@ -917,6 +920,7 @@ msgid "Command group amount" msgstr "命令组数量" #: acls/serializers/rules/rules.py:20 +#: xpack/plugins/cloud/serializers/task.py:22 msgid "IP address invalid: `{}`" msgstr "IP 地址无效: `{}`" @@ -944,7 +948,8 @@ msgstr "时段" msgid "Applications" msgstr "应用管理" -#: applications/models.py:16 +#: applications/models.py:16 xpack/plugins/cloud/models.py:33 +#: xpack/plugins/cloud/serializers/account.py:62 msgid "Attrs" msgstr "属性" @@ -999,7 +1004,7 @@ msgid "Unable to connect to port {port} on {address}" msgstr "无法连接到 {port} 上的端口 {address}" #: assets/automations/ping_gateway/manager.py:58 -#: authentication/middleware.py:92 +#: authentication/middleware.py:92 xpack/plugins/cloud/providers/fc.py:48 msgid "Authentication failed" msgstr "认证失败" @@ -1033,6 +1038,7 @@ msgstr "收集资产信息" #: assets/const/category.py:10 assets/models/asset/host.py:8 #: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:68 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 +#: xpack/plugins/cloud/serializers/account_attrs.py:72 msgid "Host" msgstr "主机" @@ -1134,6 +1140,7 @@ msgstr "SSH公钥" #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 #: tickets/models/ticket/general.py:297 users/models/user.py:792 +#: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:111 msgid "Comment" msgstr "备注" @@ -1233,6 +1240,7 @@ msgstr "云服务" #: assets/models/asset/common.py:92 assets/models/platform.py:14 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:69 +#: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "端口" @@ -1243,6 +1251,7 @@ msgstr "地址" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 +#: xpack/plugins/cloud/serializers/account_attrs.py:196 msgid "Platform" msgstr "系统平台" @@ -1341,7 +1350,8 @@ msgstr "资产自动化任务" #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 -#: tickets/serializers/ticket/ticket.py:20 +#: tickets/serializers/ticket/ticket.py:20 xpack/plugins/cloud/models.py:164 +#: xpack/plugins/cloud/models.py:216 msgid "Status" msgstr "状态" @@ -1405,6 +1415,7 @@ msgstr "资产组" #: assets/models/group.py:34 assets/models/platform.py:17 #: assets/serializers/platform.py:95 +#: xpack/plugins/cloud/providers/nutanix.py:30 msgid "Default" msgstr "默认" @@ -1454,7 +1465,7 @@ msgid "Parent key" msgstr "ssh私钥" #: assets/models/node.py:571 perms/serializers/permission.py:35 -#: tickets/models/ticket/apply_asset.py:14 +#: tickets/models/ticket/apply_asset.py:14 xpack/plugins/cloud/models.py:96 msgid "Node" msgstr "节点" @@ -1592,7 +1603,7 @@ msgstr "资产中批量更新平台,不符合平台类型跳过的资产" #: assets/serializers/asset/common.py:124 assets/serializers/platform.py:111 #: authentication/serializers/connect_token_secret.py:29 #: authentication/serializers/connect_token_secret.py:72 -#: perms/serializers/user_permission.py:25 +#: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 msgid "Protocols" msgstr "协议组" @@ -1611,23 +1622,22 @@ msgid "Platform not exist" msgstr "平台不存在" #: assets/serializers/asset/common.py:263 -#, fuzzy -#| msgid "port out of range (1-65535)" msgid "port out of range (0-65535)" -msgstr "端口超出范围 (1-65535)" +msgstr "端口超出范围 (0-65535)" #: assets/serializers/asset/common.py:270 msgid "Protocol is required: {}" msgstr "协议是必填的: {}" #: assets/serializers/asset/database.py:13 -#, fuzzy -#| msgid "Default storage" msgid "Default database" -msgstr "默认存储" +msgstr "默认数据库" #: assets/serializers/asset/database.py:28 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 +#: xpack/plugins/cloud/serializers/account_attrs.py:56 +#: xpack/plugins/cloud/serializers/account_attrs.py:79 +#: xpack/plugins/cloud/serializers/account_attrs.py:143 msgid "This field is required." msgstr "该字段是必填项。" @@ -2096,10 +2106,8 @@ msgid "Permission expired" msgstr "授权已过期" #: authentication/api/connection_token.py:322 -#, fuzzy -#| msgid "ACL action is reject" msgid "ACL action is reject: {}({})" -msgstr "ACL 动作是拒绝" +msgstr "ACL 动作是拒绝: {}({})" #: authentication/api/connection_token.py:326 msgid "ACL action is review" @@ -2496,10 +2504,8 @@ msgid "Asset display" msgstr "资产名称" #: authentication/models/connection_token.py:43 -#, fuzzy -#| msgid "Disable" msgid "Reusable" -msgstr "禁用" +msgstr "可以重复使用" #: authentication/models/connection_token.py:44 #: authentication/models/temp_token.py:13 perms/models/asset_permission.py:74 @@ -2841,6 +2847,7 @@ msgid "Copy success" msgstr "复制成功" #: authentication/utils.py:28 common/utils/ip/geoip/utils.py:24 +#: xpack/plugins/cloud/const.py:27 msgid "LAN" msgstr "局域网" @@ -3180,7 +3187,7 @@ msgstr "阿里云" msgid "Tencent cloud" msgstr "腾讯云" -#: common/sdk/sms/endpoint.py:18 +#: common/sdk/sms/endpoint.py:18 xpack/plugins/cloud/const.py:13 msgid "Huawei Cloud" msgstr "华为云" @@ -3509,6 +3516,7 @@ msgid "Date last run" msgstr "最后运行日期" #: ops/models/base.py:51 ops/models/job.py:188 +#: xpack/plugins/cloud/models.py:162 msgid "Result" msgstr "结果" @@ -4313,6 +4321,7 @@ msgid "Client Id" msgstr "客户端 ID" #: settings/serializers/auth/oauth2.py:33 settings/serializers/auth/oidc.py:22 +#: xpack/plugins/cloud/serializers/account_attrs.py:38 msgid "Client Secret" msgstr "客户端密钥" @@ -4553,6 +4562,7 @@ msgid "SSO auth key TTL" msgstr "令牌有效期" #: settings/serializers/auth/sso.py:17 +#: xpack/plugins/cloud/serializers/account_attrs.py:193 msgid "Unit: second" msgstr "单位: 秒" @@ -5572,10 +5582,8 @@ msgid "Author" msgstr "作者" #: terminal/models/applet/applet.py:36 -#, fuzzy -#| msgid "Can push account" msgid "Can concurrent" -msgstr "可以推送账号" +msgstr "可以并发" #: terminal/models/applet/applet.py:37 msgid "Tags" @@ -5854,22 +5862,16 @@ msgid "Batch danger command alert" msgstr "批量危险命令告警" #: terminal/notifications.py:163 -#, fuzzy -#| msgid "Command storage" msgid "Command and replay storage" -msgstr "命令存储" +msgstr "命令及录像存储" #: terminal/notifications.py:164 -#, fuzzy -#| msgid "Connectivity" msgid "Connectivity alarm" -msgstr "可连接性" +msgstr "可连接性告警" #: terminal/notifications.py:189 -#, fuzzy -#| msgid "Invalid signature." msgid "Invalid storage" -msgstr "签名无效" +msgstr "无效的存储" #: terminal/serializers/applet.py:28 msgid "Icon" @@ -6029,14 +6031,16 @@ msgid "Bucket" msgstr "桶名称" #: terminal/serializers/storage.py:30 +#: xpack/plugins/cloud/serializers/account_attrs.py:17 msgid "Access key id" msgstr "Access key ID(AK)" #: terminal/serializers/storage.py:34 +#: xpack/plugins/cloud/serializers/account_attrs.py:20 msgid "Access key secret" msgstr "Access key secret(SK)" -#: terminal/serializers/storage.py:65 +#: terminal/serializers/storage.py:65 xpack/plugins/cloud/models.py:209 msgid "Region" msgstr "地域" @@ -6105,16 +6109,12 @@ msgid "Install applet" msgstr "安装应用" #: terminal/tasks.py:109 -#, fuzzy -#| msgid "Gather assets accounts" msgid "Generate applet host accounts" -msgstr "收集资产上的账号" +msgstr "收集远程应用上的账号" #: terminal/tasks.py:121 -#, fuzzy -#| msgid "Can test asset connectivity" msgid "Check command replay storage connectivity" -msgstr "可以测试资产连接性" +msgstr "检查命令及录像存储可连接性 " #: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 msgid "" @@ -7032,477 +7032,568 @@ msgstr "* 新密码不能是最近 {} 次的密码" msgid "Reset password success, return to login page" msgstr "重置密码成功,返回到登录页面" -#, fuzzy -#~| msgid "User ID" -#~ msgid "User IP" -#~ msgstr "用户 ID" +#: xpack/apps.py:8 +msgid "XPACK" +msgstr "XPack" -#~ msgid "XPACK" -#~ msgstr "XPack" +#: xpack/plugins/cloud/api.py:40 +msgid "Test connection successful" +msgstr "测试成功" -#~ msgid "Test connection successful" -#~ msgstr "测试成功" +#: xpack/plugins/cloud/api.py:42 +msgid "Test connection failed: {}" +msgstr "测试连接失败:{}" -#~ msgid "Test connection failed: {}" -#~ msgstr "测试连接失败:{}" +#: xpack/plugins/cloud/const.py:8 +msgid "Alibaba Cloud" +msgstr "阿里云" -#~ msgid "Alibaba Cloud" -#~ msgstr "阿里云" +#: xpack/plugins/cloud/const.py:9 +msgid "AWS (International)" +msgstr "AWS (国际)" -#~ msgid "AWS (International)" -#~ msgstr "AWS (国际)" +#: xpack/plugins/cloud/const.py:10 +msgid "AWS (China)" +msgstr "AWS (中国)" -#~ msgid "AWS (China)" -#~ msgstr "AWS (中国)" +#: xpack/plugins/cloud/const.py:11 +msgid "Azure (China)" +msgstr "Azure (中国)" -#~ msgid "Azure (China)" -#~ msgstr "Azure (中国)" +#: xpack/plugins/cloud/const.py:12 +msgid "Azure (International)" +msgstr "Azure (国际)" -#~ msgid "Azure (International)" -#~ msgstr "Azure (国际)" +#: xpack/plugins/cloud/const.py:14 +msgid "Baidu Cloud" +msgstr "百度云" -#~ msgid "Baidu Cloud" -#~ msgstr "百度云" +#: xpack/plugins/cloud/const.py:15 +msgid "JD Cloud" +msgstr "京东云" -#~ msgid "JD Cloud" -#~ msgstr "京东云" +#: xpack/plugins/cloud/const.py:16 +msgid "KingSoft Cloud" +msgstr "金山云" -#~ msgid "KingSoft Cloud" -#~ msgstr "金山云" +#: xpack/plugins/cloud/const.py:17 +msgid "Tencent Cloud" +msgstr "腾讯云" -#~ msgid "Tencent Cloud" -#~ msgstr "腾讯云" +#: xpack/plugins/cloud/const.py:18 +msgid "Tencent Cloud (Lighthouse)" +msgstr "腾讯云(轻量服务器应用)" -#~ msgid "Tencent Cloud (Lighthouse)" -#~ msgstr "腾讯云(轻量服务器应用)" +#: xpack/plugins/cloud/const.py:19 +msgid "VMware" +msgstr "VMware" -#~ msgid "VMware" -#~ msgstr "VMware" +#: xpack/plugins/cloud/const.py:20 xpack/plugins/cloud/providers/nutanix.py:13 +msgid "Nutanix" +msgstr "Nutanix" -#~ msgid "Nutanix" -#~ msgstr "Nutanix" +#: xpack/plugins/cloud/const.py:21 +msgid "Huawei Private Cloud" +msgstr "华为私有云" -#~ msgid "Huawei Private Cloud" -#~ msgstr "华为私有云" +#: xpack/plugins/cloud/const.py:22 +msgid "Qingyun Private Cloud" +msgstr "青云私有云" -#~ msgid "Qingyun Private Cloud" -#~ msgstr "青云私有云" +#: xpack/plugins/cloud/const.py:23 +msgid "CTYun Private Cloud" +msgstr "天翼私有云" -#~ msgid "CTYun Private Cloud" -#~ msgstr "天翼私有云" +#: xpack/plugins/cloud/const.py:24 +msgid "OpenStack" +msgstr "OpenStack" -#~ msgid "OpenStack" -#~ msgstr "OpenStack" +#: xpack/plugins/cloud/const.py:25 +msgid "Google Cloud Platform" +msgstr "谷歌云" -#~ msgid "Google Cloud Platform" -#~ msgstr "谷歌云" +#: xpack/plugins/cloud/const.py:26 +msgid "Fusion Compute" +msgstr "" -#~ msgid "Private IP" -#~ msgstr "私有IP" +#: xpack/plugins/cloud/const.py:31 +msgid "Private IP" +msgstr "私有IP" -#~ msgid "Public IP" -#~ msgstr "公网IP" +#: xpack/plugins/cloud/const.py:32 +msgid "Public IP" +msgstr "公网IP" -#~ msgid "Instance name" -#~ msgstr "实例名称" +#: xpack/plugins/cloud/const.py:36 +msgid "Instance name" +msgstr "实例名称" -#~ msgid "Instance name and Partial IP" -#~ msgstr "实例名称和部分IP" +#: xpack/plugins/cloud/const.py:37 +msgid "Instance name and Partial IP" +msgstr "实例名称和部分IP" -#~ msgid "Succeed" -#~ msgstr "成功" +#: xpack/plugins/cloud/const.py:42 +msgid "Succeed" +msgstr "成功" -#~ msgid "Unsync" -#~ msgstr "未同步" +#: xpack/plugins/cloud/const.py:46 +msgid "Unsync" +msgstr "未同步" -#~ msgid "New Sync" -#~ msgstr "新同步" +#: xpack/plugins/cloud/const.py:47 +msgid "New Sync" +msgstr "新同步" -#~ msgid "Synced" -#~ msgstr "已同步" +#: xpack/plugins/cloud/const.py:48 +msgid "Synced" +msgstr "已同步" -#~ msgid "Released" -#~ msgstr "已释放" +#: xpack/plugins/cloud/const.py:49 +msgid "Released" +msgstr "已释放" -#~ msgid "Cloud center" -#~ msgstr "云管中心" +#: xpack/plugins/cloud/meta.py:9 +msgid "Cloud center" +msgstr "云管中心" -#~ msgid "Provider" -#~ msgstr "云服务商" +#: xpack/plugins/cloud/models.py:30 +msgid "Provider" +msgstr "云服务商" -#~ msgid "Validity" -#~ msgstr "有效" +#: xpack/plugins/cloud/models.py:34 +msgid "Validity" +msgstr "有效" -#~ msgid "Cloud account" -#~ msgstr "云账号" +#: xpack/plugins/cloud/models.py:39 +msgid "Cloud account" +msgstr "云账号" -#~ msgid "Test cloud account" -#~ msgstr "测试云账号" +#: xpack/plugins/cloud/models.py:41 +msgid "Test cloud account" +msgstr "测试云账号" -#~ msgid "Regions" -#~ msgstr "地域" +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 +msgid "Regions" +msgstr "地域" -#~ msgid "Hostname strategy" -#~ msgstr "主机名策略" +#: xpack/plugins/cloud/models.py:91 +msgid "Hostname strategy" +msgstr "主机名策略" -#~ msgid "IP network segment group" -#~ msgstr "IP网段组" +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 +msgid "IP network segment group" +msgstr "IP网段组" -#~ msgid "Sync IP type" -#~ msgstr "同步IP类型" +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 +msgid "Sync IP type" +msgstr "同步IP类型" -#~ msgid "Always update" -#~ msgstr "总是更新" +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 +msgid "Always update" +msgstr "总是更新" -#~ msgid "Date last sync" -#~ msgstr "最后同步日期" +#: xpack/plugins/cloud/models.py:114 +msgid "Date last sync" +msgstr "最后同步日期" -#~ msgid "Sync instance task" -#~ msgstr "同步实例任务" +#: xpack/plugins/cloud/models.py:119 xpack/plugins/cloud/models.py:160 +msgid "Sync instance task" +msgstr "同步实例任务" -#~ msgid "Date sync" -#~ msgstr "同步日期" +#: xpack/plugins/cloud/models.py:171 xpack/plugins/cloud/models.py:219 +msgid "Date sync" +msgstr "同步日期" -#~ msgid "Sync instance task execution" -#~ msgstr "同步实例任务执行" +#: xpack/plugins/cloud/models.py:175 +msgid "Sync instance task execution" +msgstr "同步实例任务执行" -#~ msgid "Sync task" -#~ msgstr "同步任务" +#: xpack/plugins/cloud/models.py:199 +msgid "Sync task" +msgstr "同步任务" -#~ msgid "Sync instance task history" -#~ msgstr "同步实例任务历史" +#: xpack/plugins/cloud/models.py:203 +msgid "Sync instance task history" +msgstr "同步实例任务历史" -#~ msgid "Instance" -#~ msgstr "实例" +#: xpack/plugins/cloud/models.py:206 +msgid "Instance" +msgstr "实例" -#~ msgid "Sync instance detail" -#~ msgstr "同步实例详情" +#: xpack/plugins/cloud/models.py:223 +msgid "Sync instance detail" +msgstr "同步实例详情" -#~ msgid "China (Beijing)" -#~ msgstr "中国(北京)" +#: xpack/plugins/cloud/providers/aws_international.py:17 +msgid "China (Beijing)" +msgstr "中国(北京)" -#~ msgid "China (Ningxia)" -#~ msgstr "中国(宁夏)" +#: xpack/plugins/cloud/providers/aws_international.py:18 +msgid "China (Ningxia)" +msgstr "中国(宁夏)" -#~ msgid "US East (Ohio)" -#~ msgstr "美国东部(俄亥俄州)" +#: xpack/plugins/cloud/providers/aws_international.py:21 +msgid "US East (Ohio)" +msgstr "美国东部(俄亥俄州)" -#~ msgid "US East (N. Virginia)" -#~ msgstr "美国东部(弗吉尼亚北部)" +#: xpack/plugins/cloud/providers/aws_international.py:22 +msgid "US East (N. Virginia)" +msgstr "美国东部(弗吉尼亚北部)" -#~ msgid "US West (N. California)" -#~ msgstr "美国西部(加利福尼亚北部)" +#: xpack/plugins/cloud/providers/aws_international.py:23 +msgid "US West (N. California)" +msgstr "美国西部(加利福尼亚北部)" -#~ msgid "US West (Oregon)" -#~ msgstr "美国西部(俄勒冈)" - -#~ msgid "Africa (Cape Town)" -#~ msgstr "非洲(开普敦)" - -#~ msgid "Asia Pacific (Hong Kong)" -#~ msgstr "亚太地区(香港)" - -#~ msgid "Asia Pacific (Mumbai)" -#~ msgstr "亚太地区(孟买)" - -#~ msgid "Asia Pacific (Osaka-Local)" -#~ msgstr "亚太区域(大阪当地)" - -#~ msgid "Asia Pacific (Seoul)" -#~ msgstr "亚太区域(首尔)" - -#~ msgid "Asia Pacific (Singapore)" -#~ msgstr "亚太区域(新加坡)" - -#~ msgid "Asia Pacific (Sydney)" -#~ msgstr "亚太区域(悉尼)" - -#~ msgid "Asia Pacific (Tokyo)" -#~ msgstr "亚太区域(东京)" - -#~ msgid "Canada (Central)" -#~ msgstr "加拿大(中部)" - -#~ msgid "Europe (Frankfurt)" -#~ msgstr "欧洲(法兰克福)" - -#~ msgid "Europe (Ireland)" -#~ msgstr "欧洲(爱尔兰)" - -#~ msgid "Europe (London)" -#~ msgstr "欧洲(伦敦)" - -#~ msgid "Europe (Milan)" -#~ msgstr "欧洲(米兰)" - -#~ msgid "Europe (Paris)" -#~ msgstr "欧洲(巴黎)" - -#~ msgid "Europe (Stockholm)" -#~ msgstr "欧洲(斯德哥尔摩)" - -#~ msgid "Middle East (Bahrain)" -#~ msgstr "中东(巴林)" - -#~ msgid "South America (São Paulo)" -#~ msgstr "南美洲(圣保罗)" - -#~ msgid "CN North-Beijing" -#~ msgstr "华北-北京" - -#~ msgid "CN South-Guangzhou" -#~ msgstr "华南-广州" - -#~ msgid "CN East-Suzhou" -#~ msgstr "华东-苏州" - -#~ msgid "CN-Hong Kong" -#~ msgstr "中国-香港" - -#~ msgid "CN Center-Wuhan" -#~ msgstr "华中-武汉" - -#~ msgid "CN North-Baoding" -#~ msgstr "华北-保定" - -#~ msgid "CN East-Shanghai" -#~ msgstr "华东-上海" - -#~ msgid "AP-Singapore" -#~ msgstr "亚太-新加坡" - -#~ msgid "AF-Johannesburg" -#~ msgstr "非洲-约翰内斯堡" - -#~ msgid "CN North-Beijing4" -#~ msgstr "华北-北京4" - -#~ msgid "CN North-Beijing1" -#~ msgstr "华北-北京1" - -#~ msgid "CN East-Shanghai2" -#~ msgstr "华东-上海2" - -#~ msgid "CN East-Shanghai1" -#~ msgstr "华东-上海1" - -#~ msgid "LA-Mexico City1" -#~ msgstr "拉美-墨西哥城一" - -#~ msgid "LA-Santiago" -#~ msgstr "拉美-圣地亚哥" - -#~ msgid "LA-Sao Paulo1" -#~ msgstr "拉美-圣保罗一" - -#~ msgid "EU-Paris" -#~ msgstr "欧洲-巴黎" - -#~ msgid "CN Southwest-Guiyang1" -#~ msgstr "西南-贵阳1" - -#~ msgid "AP-Bangkok" -#~ msgstr "亚太-曼谷" - -#~ msgid "CN Northeast-Dalian" -#~ msgstr "华北-大连" - -#~ msgid "CN North-Ulanqab1" -#~ msgstr "华北-乌兰察布一" - -#~ msgid "CN South-Guangzhou-InvitationOnly" -#~ msgstr "华南-广州-友好用户环境" - -#~ msgid "CN East-Suqian" -#~ msgstr "华东-宿迁" - -#~ msgid "Validity display" -#~ msgstr "有效性显示" - -#~ msgid "Provider display" -#~ msgstr "服务商显示" - -#~ msgid "Client ID" -#~ msgstr "客户端 ID" - -#~ msgid "Tenant ID" -#~ msgstr "租户 ID" - -#~ msgid "Subscription ID" -#~ msgstr "订阅 ID" - -#~ msgid "API Endpoint" -#~ msgstr "API 端点" - -#~ msgid "Auth url" -#~ msgstr "认证地址" - -#~ msgid "eg: http://openstack.example.com:5000/v3" -#~ msgstr "如: http://openstack.example.com:5000/v3" - -#~ msgid "User domain" -#~ msgstr "用户域" - -#~ msgid "Cert File" -#~ msgstr "证书文件" - -#~ msgid "Key File" -#~ msgstr "密钥文件" - -#~ msgid "Service account key" -#~ msgstr "服务账号密钥" - -#~ msgid "The file is in JSON format" -#~ msgstr "JSON 格式的文件" - -#~ msgid "IP address invalid `{}`, {}" -#~ msgstr "IP 地址无效: `{}`, {}" - -#, fuzzy -#~| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" -#~ msgid "" -#~ "Format for comma-delimited string,Such as: 192.168.1.0/24, " -#~ "10.0.0.0-10.0.0.255" -#~ msgstr "如:192.168.1.0/24,10.0.0.0-10.0.0.255" - -#~ msgid "" -#~ "The port is used to detect the validity of the IP address. When the " -#~ "synchronization task is executed, only the valid IP address will be " -#~ "synchronized.
If the port is 0, all IP addresses are valid." -#~ msgstr "" -#~ "端口用来检测 IP 地址的有效性,在同步任务执行时,只会同步有效的 IP 地址。 " -#~ "
如果端口为 0,则表示所有 IP 地址均有效。" - -#~ msgid "Hostname prefix" -#~ msgstr "主机名前缀" - -#~ msgid "IP segment" -#~ msgstr "IP 网段" - -#~ msgid "Test port" -#~ msgstr "测试端口" - -#~ msgid "Test timeout" -#~ msgstr "测试超时时间" - -#, fuzzy -#~| msgid "" -#~| "Only instances matching the IP range will be synced.
If the instance " -#~| "contains multiple IP addresses, the first IP address that matches will " -#~| "be used as the IP for the created asset.
The default value of * " -#~| "means sync all instances and randomly match IP addresses.
Such as: " -#~| "192.168.1.0/24, 10.1.1.1-10.1.1.20" -#~ msgid "" -#~ "Only instances matching the IP range will be synced.
If the instance " -#~ "contains multiple IP addresses, the first IP address that matches will be " -#~ "used as the IP for the created asset.
The default value of * means " -#~ "sync all instances and randomly match IP addresses.
Format for comma-" -#~ "delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" -#~ msgstr "" -#~ "只有匹配到 IP 段的实例会被同步。
如果实例包含多个 IP 地址,那么第一个匹" -#~ "配到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示同步所有实例和随机" -#~ "匹配 IP 地址。
例如:192.168.1.0/24,10.1.1.1-10.1.1.20" - -#~ msgid "History count" -#~ msgstr "执行次数" - -#~ msgid "Instance count" -#~ msgstr "实例个数" - -#~ msgid "Run sync instance task" -#~ msgstr "执行同步实例任务" - -#~ msgid "Period clean sync instance task execution" -#~ msgstr "定期清除同步实例任务执行记录" - -#~ msgid "Account unavailable" -#~ msgstr "账号无效" - -#~ msgid "Restore default successfully." -#~ msgstr "恢复默认成功!" - -#~ msgid "Interface settings" -#~ msgstr "界面设置" - -#~ msgid "Title of login page" -#~ msgstr "登录页面标题" - -#~ msgid "Image of login page" -#~ msgstr "登录页面图片" - -#~ msgid "Website icon" -#~ msgstr "网站图标" - -#~ msgid "Logo of management page" -#~ msgstr "管理页面logo" - -#~ msgid "Logo of logout page" -#~ msgstr "退出页面logo" - -#~ msgid "Theme" -#~ msgstr "主题" - -#~ msgid "Interface setting" -#~ msgstr "界面设置" - -#~ msgid "License import successfully" -#~ msgstr "许可证导入成功" - -#~ msgid "License is invalid" -#~ msgstr "无效的许可证" - -#~ msgid "License" -#~ msgstr "许可证" - -#~ msgid "Standard edition" -#~ msgstr "标准版" - -#~ msgid "Enterprise edition" -#~ msgstr "企业版" - -#~ msgid "Ultimate edition" -#~ msgstr "旗舰版" - -#~ msgid "Community edition" -#~ msgstr "社区版" - -#~ msgid "Connect (All Protocols)" -#~ msgstr "连接 (所以协议)" - -#~ msgid "Upload (RDP, SFTP)" -#~ msgstr "上传 (RDP, SFTP)" - -#~ msgid "Download (RDP, SFTP)" -#~ msgstr "下载 (RDP, SFTP)" - -#~ msgid "Copy (RDP, VNC)" -#~ msgstr "复制 (RDP, VNC)" - -#~ msgid "Paste (RDP, VNC)" -#~ msgstr "粘贴 (RDP, VNC)" - -#~ msgid "Delete (SFTP)" -#~ msgstr "删除 (SFTP)" - -#~ msgid "User (username)" -#~ msgstr "用户(用户名)" - -#~ msgid "Asset (name)" -#~ msgstr "资产(名称)" - -#~ msgid "Asset (address)" -#~ msgstr "资产(地址)" - -#~ msgid "Account (username)" -#~ msgstr "账号(用户名)" - -#~ msgid "MFA method not support" -#~ msgstr "不支持该 MFA 方式" - -#, fuzzy -#~| msgid "Trigger mode" -#~ msgid "Trigger type" -#~ msgstr "触发模式" - -#~ msgid "Please login with a password and then bind the FeiShu" -#~ msgstr "请使用密码登录,然后绑定飞书" +#: xpack/plugins/cloud/providers/aws_international.py:24 +msgid "US West (Oregon)" +msgstr "美国西部(俄勒冈)" + +#: xpack/plugins/cloud/providers/aws_international.py:25 +msgid "Africa (Cape Town)" +msgstr "非洲(开普敦)" + +#: xpack/plugins/cloud/providers/aws_international.py:26 +msgid "Asia Pacific (Hong Kong)" +msgstr "亚太地区(香港)" + +#: xpack/plugins/cloud/providers/aws_international.py:27 +msgid "Asia Pacific (Mumbai)" +msgstr "亚太地区(孟买)" + +#: xpack/plugins/cloud/providers/aws_international.py:28 +msgid "Asia Pacific (Osaka-Local)" +msgstr "亚太区域(大阪当地)" + +#: xpack/plugins/cloud/providers/aws_international.py:29 +msgid "Asia Pacific (Seoul)" +msgstr "亚太区域(首尔)" + +#: xpack/plugins/cloud/providers/aws_international.py:30 +msgid "Asia Pacific (Singapore)" +msgstr "亚太区域(新加坡)" + +#: xpack/plugins/cloud/providers/aws_international.py:31 +msgid "Asia Pacific (Sydney)" +msgstr "亚太区域(悉尼)" + +#: xpack/plugins/cloud/providers/aws_international.py:32 +msgid "Asia Pacific (Tokyo)" +msgstr "亚太区域(东京)" + +#: xpack/plugins/cloud/providers/aws_international.py:33 +msgid "Canada (Central)" +msgstr "加拿大(中部)" + +#: xpack/plugins/cloud/providers/aws_international.py:34 +msgid "Europe (Frankfurt)" +msgstr "欧洲(法兰克福)" + +#: xpack/plugins/cloud/providers/aws_international.py:35 +msgid "Europe (Ireland)" +msgstr "欧洲(爱尔兰)" + +#: xpack/plugins/cloud/providers/aws_international.py:36 +msgid "Europe (London)" +msgstr "欧洲(伦敦)" + +#: xpack/plugins/cloud/providers/aws_international.py:37 +msgid "Europe (Milan)" +msgstr "欧洲(米兰)" + +#: xpack/plugins/cloud/providers/aws_international.py:38 +msgid "Europe (Paris)" +msgstr "欧洲(巴黎)" + +#: xpack/plugins/cloud/providers/aws_international.py:39 +msgid "Europe (Stockholm)" +msgstr "欧洲(斯德哥尔摩)" + +#: xpack/plugins/cloud/providers/aws_international.py:40 +msgid "Middle East (Bahrain)" +msgstr "中东(巴林)" + +#: xpack/plugins/cloud/providers/aws_international.py:41 +msgid "South America (São Paulo)" +msgstr "南美洲(圣保罗)" + +#: xpack/plugins/cloud/providers/baiducloud.py:54 +#: xpack/plugins/cloud/providers/jdcloud.py:127 +msgid "CN North-Beijing" +msgstr "华北-北京" + +#: xpack/plugins/cloud/providers/baiducloud.py:55 +#: xpack/plugins/cloud/providers/huaweicloud.py:40 +#: xpack/plugins/cloud/providers/jdcloud.py:130 +msgid "CN South-Guangzhou" +msgstr "华南-广州" + +#: xpack/plugins/cloud/providers/baiducloud.py:56 +msgid "CN East-Suzhou" +msgstr "华东-苏州" + +#: xpack/plugins/cloud/providers/baiducloud.py:57 +#: xpack/plugins/cloud/providers/huaweicloud.py:48 +msgid "CN-Hong Kong" +msgstr "中国-香港" + +#: xpack/plugins/cloud/providers/baiducloud.py:58 +msgid "CN Center-Wuhan" +msgstr "华中-武汉" + +#: xpack/plugins/cloud/providers/baiducloud.py:59 +msgid "CN North-Baoding" +msgstr "华北-保定" + +#: xpack/plugins/cloud/providers/baiducloud.py:60 +#: xpack/plugins/cloud/providers/jdcloud.py:129 +msgid "CN East-Shanghai" +msgstr "华东-上海" + +#: xpack/plugins/cloud/providers/baiducloud.py:61 +#: xpack/plugins/cloud/providers/huaweicloud.py:47 +msgid "AP-Singapore" +msgstr "亚太-新加坡" + +#: xpack/plugins/cloud/providers/huaweicloud.py:35 +msgid "AF-Johannesburg" +msgstr "非洲-约翰内斯堡" + +#: xpack/plugins/cloud/providers/huaweicloud.py:36 +msgid "CN North-Beijing4" +msgstr "华北-北京4" + +#: xpack/plugins/cloud/providers/huaweicloud.py:37 +msgid "CN North-Beijing1" +msgstr "华北-北京1" + +#: xpack/plugins/cloud/providers/huaweicloud.py:38 +msgid "CN East-Shanghai2" +msgstr "华东-上海2" + +#: xpack/plugins/cloud/providers/huaweicloud.py:39 +msgid "CN East-Shanghai1" +msgstr "华东-上海1" + +#: xpack/plugins/cloud/providers/huaweicloud.py:41 +msgid "LA-Mexico City1" +msgstr "拉美-墨西哥城一" + +#: xpack/plugins/cloud/providers/huaweicloud.py:42 +msgid "LA-Santiago" +msgstr "拉美-圣地亚哥" + +#: xpack/plugins/cloud/providers/huaweicloud.py:43 +msgid "LA-Sao Paulo1" +msgstr "拉美-圣保罗一" + +#: xpack/plugins/cloud/providers/huaweicloud.py:44 +msgid "EU-Paris" +msgstr "欧洲-巴黎" + +#: xpack/plugins/cloud/providers/huaweicloud.py:45 +msgid "CN Southwest-Guiyang1" +msgstr "西南-贵阳1" + +#: xpack/plugins/cloud/providers/huaweicloud.py:46 +msgid "AP-Bangkok" +msgstr "亚太-曼谷" + +#: xpack/plugins/cloud/providers/huaweicloud.py:50 +msgid "CN Northeast-Dalian" +msgstr "华北-大连" + +#: xpack/plugins/cloud/providers/huaweicloud.py:51 +msgid "CN North-Ulanqab1" +msgstr "华北-乌兰察布一" + +#: xpack/plugins/cloud/providers/huaweicloud.py:52 +msgid "CN South-Guangzhou-InvitationOnly" +msgstr "华南-广州-友好用户环境" + +#: xpack/plugins/cloud/providers/jdcloud.py:128 +msgid "CN East-Suqian" +msgstr "华东-宿迁" + +#: xpack/plugins/cloud/serializers/account.py:63 +msgid "Validity display" +msgstr "有效性显示" + +#: xpack/plugins/cloud/serializers/account.py:64 +msgid "Provider display" +msgstr "服务商显示" + +#: xpack/plugins/cloud/serializers/account_attrs.py:35 +msgid "Client ID" +msgstr "客户端 ID" + +#: xpack/plugins/cloud/serializers/account_attrs.py:41 +msgid "Tenant ID" +msgstr "租户 ID" + +#: xpack/plugins/cloud/serializers/account_attrs.py:44 +msgid "Subscription ID" +msgstr "订阅 ID" + +#: xpack/plugins/cloud/serializers/account_attrs.py:98 +#: xpack/plugins/cloud/serializers/account_attrs.py:103 +#: xpack/plugins/cloud/serializers/account_attrs.py:119 +#: xpack/plugins/cloud/serializers/account_attrs.py:149 +msgid "API Endpoint" +msgstr "API 端点" + +#: xpack/plugins/cloud/serializers/account_attrs.py:109 +msgid "Auth url" +msgstr "认证地址" + +#: xpack/plugins/cloud/serializers/account_attrs.py:110 +msgid "eg: http://openstack.example.com:5000/v3" +msgstr "如: http://openstack.example.com:5000/v3" + +#: xpack/plugins/cloud/serializers/account_attrs.py:113 +msgid "User domain" +msgstr "用户域" + +#: xpack/plugins/cloud/serializers/account_attrs.py:120 +msgid "Cert File" +msgstr "证书文件" + +#: xpack/plugins/cloud/serializers/account_attrs.py:121 +msgid "Key File" +msgstr "密钥文件" + +#: xpack/plugins/cloud/serializers/account_attrs.py:137 +msgid "Service account key" +msgstr "服务账号密钥" + +#: xpack/plugins/cloud/serializers/account_attrs.py:138 +msgid "The file is in JSON format" +msgstr "JSON 格式的文件" + +#: xpack/plugins/cloud/serializers/account_attrs.py:156 +msgid "IP address invalid `{}`, {}" +msgstr "IP 地址无效: `{}`, {}" + +#: xpack/plugins/cloud/serializers/account_attrs.py:172 +msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgstr "如: 192.168.1.0/24,10.0.0.0-10.0.0.255" + +#: xpack/plugins/cloud/serializers/account_attrs.py:175 +msgid "" +"The port is used to detect the validity of the IP address. When the " +"synchronization task is executed, only the valid IP address will be " +"synchronized.
If the port is 0, all IP addresses are valid." +msgstr "" +"端口用来检测 IP 地址的有效性,在同步任务执行时,只会同步有效的 IP 地址。
" +"如果端口为 0,则表示所有 IP 地址均有效。" + +#: xpack/plugins/cloud/serializers/account_attrs.py:183 +msgid "Hostname prefix" +msgstr "主机名前缀" + +#: xpack/plugins/cloud/serializers/account_attrs.py:186 +msgid "IP segment" +msgstr "IP 网段" + +#: xpack/plugins/cloud/serializers/account_attrs.py:190 +msgid "Test port" +msgstr "测试端口" + +#: xpack/plugins/cloud/serializers/account_attrs.py:193 +msgid "Test timeout" +msgstr "测试超时时间" + +#: xpack/plugins/cloud/serializers/task.py:28 +msgid "" +"Only instances matching the IP range will be synced.
If the instance " +"contains multiple IP addresses, the first IP address that matches will be " +"used as the IP for the created asset.
The default value of * means sync " +"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " +"10.1.1.1-10.1.1.20" +msgstr "" +"只有匹配到 IP 段的实例会被同步。
如果实例包含多个 IP 地址,那么第一个匹配" +"到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示同步所有实例和随机匹配 " +"IP 地址。
例如: 192.168.1.0/24,10.1.1.1-10.1.1.20" + +#: xpack/plugins/cloud/serializers/task.py:34 +msgid "History count" +msgstr "执行次数" + +#: xpack/plugins/cloud/serializers/task.py:35 +msgid "Instance count" +msgstr "实例个数" + +#: xpack/plugins/cloud/tasks.py:27 +msgid "Run sync instance task" +msgstr "执行同步实例任务" + +#: xpack/plugins/cloud/tasks.py:41 +msgid "Period clean sync instance task execution" +msgstr "定期清除同步实例任务执行记录" + +#: xpack/plugins/cloud/utils.py:69 +msgid "Account unavailable" +msgstr "账号无效" + +#: xpack/plugins/interface/api.py:52 +msgid "Restore default successfully." +msgstr "恢复默认成功!" + +#: xpack/plugins/interface/meta.py:10 +msgid "Interface settings" +msgstr "界面设置" + +#: xpack/plugins/interface/models.py:23 +msgid "Title of login page" +msgstr "登录页面标题" + +#: xpack/plugins/interface/models.py:27 +msgid "Image of login page" +msgstr "登录页面图片" + +#: xpack/plugins/interface/models.py:31 +msgid "Website icon" +msgstr "网站图标" + +#: xpack/plugins/interface/models.py:35 +msgid "Logo of management page" +msgstr "管理页面logo" + +#: xpack/plugins/interface/models.py:39 +msgid "Logo of logout page" +msgstr "退出页面logo" + +#: xpack/plugins/interface/models.py:41 +msgid "Theme" +msgstr "主题" + +#: xpack/plugins/interface/models.py:44 xpack/plugins/interface/models.py:85 +msgid "Interface setting" +msgstr "界面设置" + +#: xpack/plugins/license/api.py:50 +msgid "License import successfully" +msgstr "许可证导入成功" + +#: xpack/plugins/license/api.py:51 +msgid "License is invalid" +msgstr "无效的许可证" + +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 +msgid "License" +msgstr "许可证" + +#: xpack/plugins/license/models.py:80 +msgid "Standard edition" +msgstr "标准版" + +#: xpack/plugins/license/models.py:82 +msgid "Enterprise edition" +msgstr "企业版" + +#: xpack/plugins/license/models.py:84 +msgid "Ultimate edition" +msgstr "旗舰版" + +#: xpack/plugins/license/models.py:86 +msgid "Community edition" +msgstr "社区版" From ed117ceac3b4ba18d3093c4dd219135568bd53e1 Mon Sep 17 00:00:00 2001 From: Bai Date: Thu, 1 Jun 2023 16:22:17 +0800 Subject: [PATCH 070/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E8=8A=82=E7=82=B9=E6=97=B6=E6=A0=A1=E9=AA=8C=E5=90=8C?= =?UTF-8?q?=E7=BA=A7=E8=8A=82=E7=82=B9=E5=90=8D=E7=A7=B0=E4=B8=8D=E5=85=81?= =?UTF-8?q?=E8=AE=B8=E9=87=8D=E5=A4=8D(API=E6=96=B9=E5=BC=8F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/tree.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/assets/api/tree.py b/apps/assets/api/tree.py index f27afd019..794e093b7 100644 --- a/apps/assets/api/tree.py +++ b/apps/assets/api/tree.py @@ -3,10 +3,12 @@ from django.db.models import Q from rest_framework.generics import get_object_or_404 from rest_framework.response import Response +from django.utils.translation import gettext_lazy as _ from assets.locks import NodeAddChildrenLock from common.tree import TreeNodeSerializer from common.utils import get_logger +from common.exceptions import JMSException from orgs.mixins import generics from orgs.utils import current_org from .mixin import SerializeToTreeNodeMixin @@ -41,7 +43,11 @@ class NodeChildrenApi(generics.ListCreateAPIView): data = serializer.validated_data _id = data.get("id") value = data.get("value") - if not value: + if value: + children = self.instance.get_children() + if children.filter(value=value).exists(): + raise JMSException(_('The same level node name cannot be the same')) + else: value = self.instance.get_next_child_preset_name() node = self.instance.create_child(value=value, _id=_id) # 避免查询 full value From 9d8c1bb317ee6d7f54e96ad9cdeafdac10d569ac Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Fri, 2 Jun 2023 10:56:00 +0800 Subject: [PATCH 071/153] =?UTF-8?q?perf:=20=E8=B4=A6=E5=8F=B7=E6=A8=A1?= =?UTF-8?q?=E7=89=88=E6=9B=B4=E6=96=B0=E6=97=B6,=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=9B=B4=E6=96=B0=E8=B4=A6=E5=8F=B7=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20(#10611)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/accounts/serializers/account/template.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/accounts/serializers/account/template.py b/apps/accounts/serializers/account/template.py index d2d992ea6..ffe8c7564 100644 --- a/apps/accounts/serializers/account/template.py +++ b/apps/accounts/serializers/account/template.py @@ -23,8 +23,12 @@ class AccountTemplateSerializer(BaseAccountSerializer): def sync_accounts_secret(self, instance, diff): if not self._is_sync_account or 'secret' not in diff: return - - accounts = Account.objects.filter(source_id=instance.id) + query_data = { + 'source_id': instance.id, + 'username': instance.username, + 'secret_type': instance.secret_type + } + accounts = Account.objects.filter(**query_data) instance.bulk_sync_account_secret(accounts, self.context['request'].user.id) def validate(self, attrs): @@ -38,7 +42,10 @@ class AccountTemplateSerializer(BaseAccountSerializer): if getattr(instance, k, None) != v } instance = super().update(instance, validated_data) - self.sync_accounts_secret(instance, diff) + if {'username', 'secret_type'} & set(diff.keys()): + Account.objects.filter(source_id=instance.id).update(source_id=None) + else: + self.sync_accounts_secret(instance, diff) return instance From 8d8f479da6d78fd9f2260b814dadb509d0f13e3e Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 2 Jun 2023 15:37:33 +0800 Subject: [PATCH 072/153] =?UTF-8?q?perf:=20dbeaver=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=BD=91=E5=85=B3=E8=BF=9E=E6=8E=A5=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/applets/dbeaver/app.py | 11 +++++++---- apps/terminal/applets/dbeaver/common.py | 22 ++++++++++++++++++++++ apps/terminal/applets/dbeaver/manifest.yml | 2 +- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/apps/terminal/applets/dbeaver/app.py b/apps/terminal/applets/dbeaver/app.py index 39d953926..ff2d4fd4c 100644 --- a/apps/terminal/applets/dbeaver/app.py +++ b/apps/terminal/applets/dbeaver/app.py @@ -1,14 +1,13 @@ import os -import time -import win32api import shutil import subprocess - +import time from xml.etree import ElementTree from xml.sax import SAXException -from common import wait_pid, BaseApplication +import win32api +from common import wait_pid, BaseApplication _default_path = r'C:\Program Files\DBeaver\dbeaver-cli.exe' @@ -22,6 +21,10 @@ class AppletApplication(BaseApplication): self.privileged = self.account.privileged self.host = self.asset.address self.port = self.asset.get_protocol_port(self.protocol) + if self.tinker_forward: + self.host = self.tinker_forward.host + self.port = self.tinker_forward.port + self.db = self.asset.spec_info.db_name self.name = '%s-%s-%s' % (self.host, self.db, int(time.time())) self.app_work_path = self.get_app_work_path() diff --git a/apps/terminal/applets/dbeaver/common.py b/apps/terminal/applets/dbeaver/common.py index 010347fe0..53d46f06a 100644 --- a/apps/terminal/applets/dbeaver/common.py +++ b/apps/terminal/applets/dbeaver/common.py @@ -152,6 +152,20 @@ class Platform(DictObj): type: LabelValue +class Gateway(DictObj): + id: str + name: str + address: str + port: int + protocols: list[Protocol] + account: Account + + +class TinkerForward(DictObj): + host: str + port: int + + class Manifest(DictObj): name: str version: str @@ -199,6 +213,14 @@ class BaseApplication(abc.ABC): self.asset = Asset(kwargs.get('asset', {})) self.account = Account(kwargs.get('account', {})) self.platform = Platform(kwargs.get('platform', {})) + self.gateway = None + self.tinker_forward = None + gateway = kwargs.get('gateway') + tinker_forward = kwargs.get('tinker_forward') + if gateway: + self.gateway = Gateway(gateway) + if tinker_forward: + self.tinker_forward = TinkerForward(tinker_forward) @abc.abstractmethod def run(self): diff --git a/apps/terminal/applets/dbeaver/manifest.yml b/apps/terminal/applets/dbeaver/manifest.yml index 5b834cf99..8b2713ee6 100644 --- a/apps/terminal/applets/dbeaver/manifest.yml +++ b/apps/terminal/applets/dbeaver/manifest.yml @@ -1,7 +1,7 @@ name: dbeaver display_name: "{{ 'DBeaver Community' | trans }}" comment: "{{ 'Free multi-platform database tool for developers, database administrators, analysts and all people who need to work with databases.' | trans }}" -version: 0.1 +version: 0.2 exec_type: python author: JumpServer Team type: general From 42c35b027107a733e44f6b3c66e95a378e00a279 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 2 Jun 2023 16:12:16 +0800 Subject: [PATCH 073/153] =?UTF-8?q?perf:=20chrome=20=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20sleep=20=E7=AD=89=E5=BE=85=E6=8C=87?= =?UTF-8?q?=E4=BB=A4=EF=BC=8C=E5=8D=95=E4=BD=8D=E7=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/applets/chrome/app.py | 12 ++++++++++++ apps/terminal/applets/chrome/manifest.yml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/terminal/applets/chrome/app.py b/apps/terminal/applets/chrome/app.py index c6a8a25c8..9cc452590 100644 --- a/apps/terminal/applets/chrome/app.py +++ b/apps/terminal/applets/chrome/app.py @@ -21,6 +21,7 @@ class Command(Enum): OPEN = 'open' CODE = 'code' SELECT_FRAME = 'select_frame' + SLEEP = 'sleep' def _execute_type(ele: WebElement, value: str): @@ -59,6 +60,9 @@ class StepAction: if self.command == 'select_frame': self._switch_iframe(driver, self.target) return True + elif self.command == 'sleep': + self._sleep(driver, self.target) + return True target_name, target_value = self.target.split("=", 1) by_name = self.methods_map.get(target_name.upper(), By.NAME) ele = driver.find_element(by=by_name, value=target_value) @@ -103,6 +107,14 @@ class StepAction: else: driver.switch_to.frame(target) + def _sleep(self, driver: webdriver.Chrome, target: str): + try: + sleep_time = int(target) + except Exception as e: + # at least sleep 1 second + sleep_time = 1 + time.sleep(sleep_time) + def execute_action(driver: webdriver.Chrome, step: StepAction) -> bool: try: diff --git a/apps/terminal/applets/chrome/manifest.yml b/apps/terminal/applets/chrome/manifest.yml index 523f9f3a1..4c66515b6 100644 --- a/apps/terminal/applets/chrome/manifest.yml +++ b/apps/terminal/applets/chrome/manifest.yml @@ -1,6 +1,6 @@ name: chrome display_name: "{{ 'Chrome Browser' | trans }}" -version: 0.3 +version: 0.4 comment: "{{ 'Chrome Browser Open URL Page Address' | trans }}" author: JumpServer Team exec_type: python From 3c68b880a781db9048ac9df90a936997c3752d8e Mon Sep 17 00:00:00 2001 From: fangfangdong Date: Mon, 5 Jun 2023 15:00:25 +0800 Subject: [PATCH 074/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20jumpserver.?= =?UTF-8?q?js=20=E6=96=87=E4=BB=B6=E4=B8=AD=20rules=5Fid=5Fmap=5Flabel=20?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E7=BC=BA=E5=A4=B1=E5=BC=95=E8=B5=B7=E7=9A=84?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=88=9D=E6=AC=A1=E7=99=BB=E5=BD=95=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=AF=86=E7=A0=81=E8=A1=A8=E5=8D=95=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E6=8F=90=E7=A4=BA=E7=9A=84=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/static/js/jumpserver.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index d78cccb74..e4aa52033 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -895,6 +895,14 @@ var rules_short_map_id = { 'special': 'id_security_password_special_char' }; +var rules_id_map_label = { + 'id_security_password_min_length': gettext('Password minimum length {N} bits'), + 'id_security_password_upper_case': gettext('Must contain capital letters'), + 'id_security_password_lower_case': gettext('Must contain lowercase letters'), + 'id_security_password_number': gettext('Must contain numeric characters'), + 'id_security_password_special_char': gettext('Must contain special characters') +}; + function getRuleLabel(rule) { var label = ''; if (rule.key === rules_short_map_id['min']) { From a341b55f435089a386c8c75b6f58cc307667e668 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:10:33 +0800 Subject: [PATCH 075/153] =?UTF-8?q?perf:=20=E4=B8=80=E4=BA=9B=E8=B5=84?= =?UTF-8?q?=E4=BA=A7=E6=B2=A1=E6=9C=89=E9=BB=98=E8=AE=A4=E8=8A=82=E7=82=B9?= =?UTF-8?q?+=20(#10622)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- .../0119_assets_add_default_node.py | 43 +++++++++++++++++++ apps/assets/utils/node.py | 3 +- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 apps/assets/migrations/0119_assets_add_default_node.py diff --git a/apps/assets/migrations/0119_assets_add_default_node.py b/apps/assets/migrations/0119_assets_add_default_node.py new file mode 100644 index 000000000..a281196f2 --- /dev/null +++ b/apps/assets/migrations/0119_assets_add_default_node.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.19 on 2023-06-05 06:28 + +from django.db import migrations + + +# 历史问题一些资产没有关联到节点,这里将这些资产关联到默认节点 +def migrate_asset_add_default_node(apps, *args): + node_model = apps.get_model('assets', 'Node') + asset_model = apps.get_model('assets', 'Asset') + m2m_model = asset_model.nodes.through + assets = asset_model.objects.filter(nodes__isnull=True).only('id', 'org_id') + org_assets_map = {} + for asset in assets: + org_assets_map.setdefault(str(asset.org_id), []).append(str(asset.id)) + + if not org_assets_map: + return + + m2m_objs = [] + for org_id, asset_ids in org_assets_map.items(): + default_node = node_model.objects.filter(parent_key='', org_id=org_id).first() + if not default_node: + continue + m2m_objs.extend( + [ + m2m_model(node=default_node, asset_id=asset_id) + for asset_id in asset_ids + ] + ) + if not m2m_objs: + return + + m2m_model.objects.bulk_create(m2m_objs) + + +class Migration(migrations.Migration): + dependencies = [ + ('assets', '0118_auto_20230524_1647'), + ] + + operations = [ + migrations.RunPython(migrate_asset_add_default_node), + ] diff --git a/apps/assets/utils/node.py b/apps/assets/utils/node.py index b21508b64..c0a28713d 100644 --- a/apps/assets/utils/node.py +++ b/apps/assets/utils/node.py @@ -17,8 +17,9 @@ logger = get_logger(__file__) @ensure_in_real_or_default_org def check_node_assets_amount(): logger.info(f'Check node assets amount {current_org}') + m2m_model = Asset.nodes.through nodes = list(Node.objects.all().only('id', 'key', 'assets_amount')) - nodeid_assetid_pairs = list(Asset.nodes.through.objects.all().values_list('node_id', 'asset_id')) + nodeid_assetid_pairs = list(m2m_model.objects.all().values_list('node_id', 'asset_id')) nodekey_assetids_mapper = defaultdict(set) nodeid_nodekey_mapper = {} From c6f92a462fd153f1502739c1fde217a0e98c72d3 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 5 Jun 2023 17:27:44 +0800 Subject: [PATCH 076/153] =?UTF-8?q?perf:=20=E8=BF=9E=E6=8E=A5=E6=97=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=BF=9E=E6=8E=A5=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0020_connectiontoken_connect_options.py | 18 ++++++++++++++++++ apps/authentication/models/connection_token.py | 1 + .../serializers/connect_token_secret.py | 2 ++ .../serializers/connection_token.py | 4 ++-- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 apps/authentication/migrations/0020_connectiontoken_connect_options.py diff --git a/apps/authentication/migrations/0020_connectiontoken_connect_options.py b/apps/authentication/migrations/0020_connectiontoken_connect_options.py new file mode 100644 index 000000000..15447c9b6 --- /dev/null +++ b/apps/authentication/migrations/0020_connectiontoken_connect_options.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.17 on 2023-06-05 07:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0019_connectiontoken_is_reusable'), + ] + + operations = [ + migrations.AddField( + model_name='connectiontoken', + name='connect_options', + field=models.JSONField(default=dict, verbose_name='Connect options'), + ), + ] diff --git a/apps/authentication/models/connection_token.py b/apps/authentication/models/connection_token.py index 6b8cd4d8e..e0793c7dc 100644 --- a/apps/authentication/models/connection_token.py +++ b/apps/authentication/models/connection_token.py @@ -38,6 +38,7 @@ class ConnectionToken(JMSOrgBaseModel): input_secret = EncryptTextField(max_length=64, default='', blank=True, verbose_name=_("Input secret")) protocol = models.CharField(max_length=16, default=Protocol.ssh, verbose_name=_("Protocol")) connect_method = models.CharField(max_length=32, verbose_name=_("Connect method")) + connect_options = models.JSONField(default=dict, verbose_name=_("Connect options")) user_display = models.CharField(max_length=128, default='', verbose_name=_("User display")) asset_display = models.CharField(max_length=128, default='', verbose_name=_("Asset display")) is_reusable = models.BooleanField(default=False, verbose_name=_("Reusable")) diff --git a/apps/authentication/serializers/connect_token_secret.py b/apps/authentication/serializers/connect_token_secret.py index feb032665..a3d56b90c 100644 --- a/apps/authentication/serializers/connect_token_secret.py +++ b/apps/authentication/serializers/connect_token_secret.py @@ -134,6 +134,7 @@ class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin): command_filter_acls = _ConnectionTokenCommandFilterACLSerializer(read_only=True, many=True) expire_now = serializers.BooleanField(label=_('Expired now'), write_only=True, default=True) connect_method = _ConnectTokenConnectMethodSerializer(read_only=True, source='connect_method_object') + connect_options = serializers.JSONField(read_only=True) actions = ActionChoicesField() expire_at = serializers.IntegerField() @@ -144,6 +145,7 @@ class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin): 'platform', 'command_filter_acls', 'protocol', 'domain', 'gateway', 'actions', 'expire_at', 'from_ticket', 'expire_now', 'connect_method', + 'connect_options', ] extra_kwargs = { 'value': {'read_only': True}, diff --git a/apps/authentication/serializers/connection_token.py b/apps/authentication/serializers/connection_token.py index 7d3de1bb7..74b645aec 100644 --- a/apps/authentication/serializers/connection_token.py +++ b/apps/authentication/serializers/connection_token.py @@ -26,8 +26,8 @@ class ConnectionTokenSerializer(OrgResourceModelSerializerMixin): model = ConnectionToken fields_mini = ['id', 'value'] fields_small = fields_mini + [ - 'user', 'asset', 'account', 'input_username', - 'input_secret', 'connect_method', 'protocol', 'actions', + 'user', 'asset', 'account', 'input_username', 'input_secret', + 'connect_method', 'connect_options', 'protocol', 'actions', 'is_active', 'is_reusable', 'from_ticket', 'from_ticket_info', 'date_expired', 'date_created', 'date_updated', 'created_by', 'updated_by', 'org_id', 'org_name', From 10996f573a658af9c419b0983d621e1f7b9cf05a Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 6 Jun 2023 19:05:31 +0800 Subject: [PATCH 077/153] =?UTF-8?q?perf:=20=E7=BF=BB=E8=AF=91=20i18n=20?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.po | 2 +- apps/locale/zh/LC_MESSAGES/django.po | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index d8bb27c88..1e83ad711 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -5923,7 +5923,7 @@ msgstr "検証コードが無効" #: terminal/models/session/sharing.py:142 msgid "You have already joined this session" -msgstr "" +msgstr "すでにこのセッションに参加しています" #: terminal/notifications.py:21 msgid "Sessions" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 4ec8237a3..00ca7b26b 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -5843,7 +5843,7 @@ msgstr "验证码不正确" #: terminal/models/session/sharing.py:142 msgid "You have already joined this session" -msgstr "" +msgstr "您已经加入了这个会话" #: terminal/notifications.py:21 msgid "Sessions" From 7d3b60232cb7c55b7ca17e36151471046b3deca9 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 6 Jun 2023 19:08:52 +0800 Subject: [PATCH 078/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=BF=BB?= =?UTF-8?q?=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/zh/LC_MESSAGES/django.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 00ca7b26b..04c98066b 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -5843,7 +5843,7 @@ msgstr "验证码不正确" #: terminal/models/session/sharing.py:142 msgid "You have already joined this session" -msgstr "您已经加入了这个会话" +msgstr "您已经加入过此会话" #: terminal/notifications.py:21 msgid "Sessions" From bfd77aa1b04ec4a70651c01d9929381a582d1a40 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 7 Jun 2023 17:28:35 +0800 Subject: [PATCH 079/153] feat: automation windows pyrdp ping (#10602) * feat: automation windows pyrdp ping * perf: add pyfreerdp deps --------- Co-authored-by: feng <1304903146@qq.com> Co-authored-by: Eric --- .../verify_account/custom/{ => rdp}/main.yml | 0 .../verify_account/custom/rdp/manifest.yml | 13 +++ .../verify_account/custom/ssh/main.yml | 14 +++ .../custom/{ => ssh}/manifest.yml | 0 apps/ops/ansible/modules/custom_command.py | 4 +- apps/ops/ansible/modules/rdp_ping.py | 86 +++++++++++++++++++ apps/ops/ansible/modules/ssh_ping.py | 4 +- .../ansible/modules_utils/custom_common.py | 3 +- requirements/apk_pkg.sh | 2 +- requirements/deb_pkg.sh | 2 +- requirements/mac_pkg.sh | 2 +- requirements/requirements.txt | 1 + requirements/rpm_pkg.sh | 2 +- 13 files changed, 123 insertions(+), 10 deletions(-) rename apps/accounts/automations/verify_account/custom/{ => rdp}/main.yml (100%) create mode 100644 apps/accounts/automations/verify_account/custom/rdp/manifest.yml create mode 100644 apps/accounts/automations/verify_account/custom/ssh/main.yml rename apps/accounts/automations/verify_account/custom/{ => ssh}/manifest.yml (100%) create mode 100644 apps/ops/ansible/modules/rdp_ping.py diff --git a/apps/accounts/automations/verify_account/custom/main.yml b/apps/accounts/automations/verify_account/custom/rdp/main.yml similarity index 100% rename from apps/accounts/automations/verify_account/custom/main.yml rename to apps/accounts/automations/verify_account/custom/rdp/main.yml diff --git a/apps/accounts/automations/verify_account/custom/rdp/manifest.yml b/apps/accounts/automations/verify_account/custom/rdp/manifest.yml new file mode 100644 index 000000000..79fcce96b --- /dev/null +++ b/apps/accounts/automations/verify_account/custom/rdp/manifest.yml @@ -0,0 +1,13 @@ +id: verify_account_by_rdp +name: "{{ 'Windows rdp account verify' | trans }}" +category: + - host +type: + - windows +method: verify_account + +i18n: + Windows rdp account verify: + zh: 使用 Python 模块 pyfreerdp 验证账号 + ja: Python モジュール pyfreerdp を使用してアカウントを検証する + en: Using Python module pyfreerdp to verify account diff --git a/apps/accounts/automations/verify_account/custom/ssh/main.yml b/apps/accounts/automations/verify_account/custom/ssh/main.yml new file mode 100644 index 000000000..cf4a937a7 --- /dev/null +++ b/apps/accounts/automations/verify_account/custom/ssh/main.yml @@ -0,0 +1,14 @@ +- hosts: custom + gather_facts: no + vars: + ansible_connection: local + + tasks: + - name: Verify account + ssh_ping: + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + login_user: "{{ account.username }}" + login_password: "{{ account.secret }}" + login_secret_type: "{{ account.secret_type }}" + login_private_key_path: "{{ account.private_key_path }}" diff --git a/apps/accounts/automations/verify_account/custom/manifest.yml b/apps/accounts/automations/verify_account/custom/ssh/manifest.yml similarity index 100% rename from apps/accounts/automations/verify_account/custom/manifest.yml rename to apps/accounts/automations/verify_account/custom/ssh/manifest.yml diff --git a/apps/ops/ansible/modules/custom_command.py b/apps/ops/ansible/modules/custom_command.py index 4edff4324..e4f7cf11d 100644 --- a/apps/ops/ansible/modules/custom_command.py +++ b/apps/ops/ansible/modules/custom_command.py @@ -64,7 +64,7 @@ name: from ansible.module_utils.basic import AnsibleModule from ops.ansible.modules_utils.custom_common import ( - SSHClient, ssh_common_argument_spec + SSHClient, common_argument_spec ) @@ -85,7 +85,7 @@ def get_commands(module): def main(): - argument_spec = ssh_common_argument_spec() + argument_spec = common_argument_spec() argument_spec.update( name=dict(required=True, aliases=['user']), password=dict(aliases=['pass'], no_log=True), diff --git a/apps/ops/ansible/modules/rdp_ping.py b/apps/ops/ansible/modules/rdp_ping.py new file mode 100644 index 000000000..f069b5bf7 --- /dev/null +++ b/apps/ops/ansible/modules/rdp_ping.py @@ -0,0 +1,86 @@ +#!/usr/bin/python + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: custom_rdp_ping +short_description: Use rdp to probe whether an asset is connectable +description: + - Use rdp to probe whether an asset is connectable +''' + +EXAMPLES = ''' +- name: > + Ping asset server. + custom_rdp_ping: + login_host: 127.0.0.1 + login_port: 3389 + login_user: jms + login_password: password +''' + +RETURN = ''' +is_available: + description: Windows server availability. + returned: always + type: bool + sample: true +conn_err_msg: + description: Connection error message. + returned: always + type: str + sample: '' +''' + +import pyfreerdp +from typing import NamedTuple +from ansible.module_utils.basic import AnsibleModule + +from ops.ansible.modules_utils.custom_common import ( + common_argument_spec +) + + +# ========================================= +# Module execution. +# + +class Param(NamedTuple): + hostname: str + port: int + username: str + password: str + + +def main(): + options = common_argument_spec() + module = AnsibleModule(argument_spec=options, supports_check_mode=True) + result = {'changed': False, 'is_available': False} + + secret_type = module.params['login_secret_type'] + if secret_type != 'password': + module.fail_json( + msg=f'The current ansible does not support \ + the verification method for {secret_type} types.' + ) + return module.exit_json(**result) + + params = Param( + hostname=module.params['login_host'], + port=module.params['login_port'], + username=module.params['login_user'], + password=module.params['login_password'] + ) + + is_available = pyfreerdp.check_connectivity(*params, '', 0) + result['is_available'] = is_available + if not is_available: + module.fail_json(msg='Unable to connect to asset.') + return module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/apps/ops/ansible/modules/ssh_ping.py b/apps/ops/ansible/modules/ssh_ping.py index 15a30eb0e..700291e24 100644 --- a/apps/ops/ansible/modules/ssh_ping.py +++ b/apps/ops/ansible/modules/ssh_ping.py @@ -40,7 +40,7 @@ conn_err_msg: from ansible.module_utils.basic import AnsibleModule from ops.ansible.modules_utils.custom_common import ( - SSHClient, ssh_common_argument_spec + SSHClient, common_argument_spec ) @@ -50,7 +50,7 @@ from ops.ansible.modules_utils.custom_common import ( def main(): - options = ssh_common_argument_spec() + options = common_argument_spec() module = AnsibleModule(argument_spec=options, supports_check_mode=True,) result = { diff --git a/apps/ops/ansible/modules_utils/custom_common.py b/apps/ops/ansible/modules_utils/custom_common.py index 07c2b6648..5da1a725e 100644 --- a/apps/ops/ansible/modules_utils/custom_common.py +++ b/apps/ops/ansible/modules_utils/custom_common.py @@ -1,11 +1,10 @@ import time import paramiko - from paramiko.ssh_exception import SSHException, NoValidConnectionsError -def ssh_common_argument_spec(): +def common_argument_spec(): options = dict( login_host=dict(type='str', required=False, default='localhost'), login_port=dict(type='int', required=False, default=22), diff --git a/requirements/apk_pkg.sh b/requirements/apk_pkg.sh index b85baf5e6..c188c2d32 100644 --- a/requirements/apk_pkg.sh +++ b/requirements/apk_pkg.sh @@ -3,4 +3,4 @@ apk add \ gcc make python3-dev python3 libffi-dev mariadb-dev \ libc-dev krb5-dev openldap-dev jpeg-dev linux-headers sshpass \ openssh-client build-base libressl libffi-dev libressl-dev \ - libxslt-dev libxml2-dev xmlsec-dev xmlsec + libxslt-dev libxml2-dev xmlsec-dev xmlsec freerdp-dev diff --git a/requirements/deb_pkg.sh b/requirements/deb_pkg.sh index 18d0b8f06..31c6eedf9 100644 --- a/requirements/deb_pkg.sh +++ b/requirements/deb_pkg.sh @@ -2,4 +2,4 @@ apt install \ g++ make iputils-ping default-libmysqlclient-dev libpq-dev \ libffi-dev libldap2-dev libsasl2-dev openssh-client sshpass pkg-config libxml2-dev \ - libxmlsec1-dev libxmlsec1-openssl libaio-dev freetds-dev + libxmlsec1-dev libxmlsec1-openssl libaio-dev freetds-dev freerdp2-dev diff --git a/requirements/mac_pkg.sh b/requirements/mac_pkg.sh index 45049eb0a..909282cf0 100644 --- a/requirements/mac_pkg.sh +++ b/requirements/mac_pkg.sh @@ -5,7 +5,7 @@ PROJECT_DIR=$(dirname "$BASE_DIR") echo "1. 安装依赖" brew install libtiff libjpeg webp little-cms2 openssl gettext git \ git-lfs mysql libxml2 libxmlsec1 pkg-config postgresql freetds openssl \ - libffi + libffi freerdp echo "2. 下载 IP 数据库" ip_db_path="${PROJECT_DIR}/apps/common/utils/geoip/GeoLite2-City.mmdb" diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 74999c74e..33bc01dbe 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -126,6 +126,7 @@ pyOpenSSL==22.0.0 redis==4.5.4 pyOpenSSL==22.0.0 pymongo==4.2.0 +pyfreerdp==0.0.1 # Debug ipython==8.10.0 ForgeryPy3==0.3.1 diff --git a/requirements/rpm_pkg.sh b/requirements/rpm_pkg.sh index 53df8bf0d..b1f7126a1 100644 --- a/requirements/rpm_pkg.sh +++ b/requirements/rpm_pkg.sh @@ -2,4 +2,4 @@ yum -y install \ gcc-c++ sshpass mariadb-devel openldap-devel openssh-clients libxml2-devel \ xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel \ - postgresql-devel + postgresql-devel freerdp-devel From d6eb4bcbd2dd17f4a5dcf375855c4d948dcd6e51 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 7 Jun 2023 17:39:56 +0800 Subject: [PATCH 080/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20connect=20?= =?UTF-8?q?method=20acls=20=E5=92=8C=E7=99=BB=E5=BD=95=20acls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/api/__init__.py | 1 + apps/acls/api/command_acl.py | 7 +-- apps/acls/api/common.py | 14 +++-- apps/acls/api/connect_method.py | 23 ++++++++ apps/acls/api/login_acl.py | 10 +++- apps/acls/api/login_asset_acl.py | 9 ++- apps/acls/filters.py | 15 ----- apps/acls/migrations/0015_connectmethodacl.py | 46 ++++++++++++++++ .../migrations/0016_auto_20230606_1857.py | 37 +++++++++++++ apps/acls/models/__init__.py | 3 +- apps/acls/models/base.py | 24 ++++++-- apps/acls/models/connect_method.py | 10 ++++ apps/acls/models/login_acl.py | 14 +---- apps/acls/serializers/__init__.py | 3 +- apps/acls/serializers/base.py | 41 ++++++++------ apps/acls/serializers/command_acl.py | 8 +-- apps/acls/serializers/connect_method.py | 23 ++++++++ apps/acls/serializers/login_acl.py | 41 +++----------- apps/acls/serializers/login_asset_acl.py | 2 +- apps/acls/urls/api_urls.py | 1 + apps/common/utils/common.py | 55 ++++++++++++------- apps/rbac/const.py | 2 + .../terminal/api/component/connect_methods.py | 27 ++++++++- apps/terminal/connect_methods.py | 36 ++++++------ 24 files changed, 309 insertions(+), 143 deletions(-) create mode 100644 apps/acls/api/connect_method.py delete mode 100644 apps/acls/filters.py create mode 100644 apps/acls/migrations/0015_connectmethodacl.py create mode 100644 apps/acls/migrations/0016_auto_20230606_1857.py create mode 100644 apps/acls/models/connect_method.py create mode 100644 apps/acls/serializers/connect_method.py diff --git a/apps/acls/api/__init__.py b/apps/acls/api/__init__.py index 2f720effe..d3fa9cdc6 100644 --- a/apps/acls/api/__init__.py +++ b/apps/acls/api/__init__.py @@ -1,4 +1,5 @@ from .command_acl import * +from .connect_method import * from .login_acl import * from .login_asset_acl import * from .login_asset_check import * diff --git a/apps/acls/api/command_acl.py b/apps/acls/api/command_acl.py index 349190d00..182b881eb 100644 --- a/apps/acls/api/command_acl.py +++ b/apps/acls/api/command_acl.py @@ -1,9 +1,8 @@ from rest_framework.decorators import action from rest_framework.response import Response -from common.drf.filters import BaseFilterSet from orgs.mixins.api import OrgBulkModelViewSet -from .common import ACLFiltersetMixin +from .common import ACLUserAssetFilterMixin from .. import models, serializers __all__ = ['CommandFilterACLViewSet', 'CommandGroupViewSet'] @@ -16,10 +15,10 @@ class CommandGroupViewSet(OrgBulkModelViewSet): serializer_class = serializers.CommandGroupSerializer -class CommandACLFilter(ACLFiltersetMixin, BaseFilterSet): +class CommandACLFilter(ACLUserAssetFilterMixin): class Meta: model = models.CommandFilterACL - fields = ['name', 'users', 'assets'] + fields = ['name', ] class CommandFilterACLViewSet(OrgBulkModelViewSet): diff --git a/apps/acls/api/common.py b/apps/acls/api/common.py index 621901471..55f2ad94a 100644 --- a/apps/acls/api/common.py +++ b/apps/acls/api/common.py @@ -1,12 +1,12 @@ +from django.db.models import Q from django_filters import rest_framework as drf_filters from common.drf.filters import BaseFilterSet from common.utils import is_uuid -class ACLFiltersetMixin(BaseFilterSet): +class ACLUserFilterMixin(BaseFilterSet): users = drf_filters.CharFilter(method='filter_user') - assets = drf_filters.CharFilter(method='filter_asset') @staticmethod def filter_user(queryset, name, value): @@ -16,12 +16,17 @@ class ACLFiltersetMixin(BaseFilterSet): if is_uuid(value): user = User.objects.filter(id=value).first() else: - user = User.objects.filter(name=value).first() + q = Q(name=value) | Q(username=value) + user = User.objects.filter(q).first() if not user: return queryset.none() q = queryset.model.users.get_filter_q(user) return queryset.filter(q).distinct() + +class ACLUserAssetFilterMixin(ACLUserFilterMixin): + assets = drf_filters.CharFilter(method='filter_asset') + @staticmethod def filter_asset(queryset, name, value): from assets.models import Asset @@ -31,7 +36,8 @@ class ACLFiltersetMixin(BaseFilterSet): if is_uuid(value): asset = Asset.objects.filter(id=value).first() else: - asset = Asset.objects.filter(name=value).first() + q = Q(name=value) | Q(address=value) + asset = Asset.objects.filter(q).first() if not asset: return queryset.none() diff --git a/apps/acls/api/connect_method.py b/apps/acls/api/connect_method.py new file mode 100644 index 000000000..ce65dcc34 --- /dev/null +++ b/apps/acls/api/connect_method.py @@ -0,0 +1,23 @@ +from django_filters import rest_framework as drf_filters + +from common.api import JMSBulkModelViewSet +from .common import ACLUserFilterMixin +from .. import serializers +from ..models import ConnectMethodACL + +__all__ = ['ConnectMethodACLViewSet'] + + +class ConnectMethodFilter(ACLUserFilterMixin): + methods = drf_filters.CharFilter(field_name="methods__contains", lookup_expr='exact') + + class Meta: + model = ConnectMethodACL + fields = ['name', ] + + +class ConnectMethodACLViewSet(JMSBulkModelViewSet): + queryset = ConnectMethodACL.objects.all() + filterset_class = ConnectMethodFilter + search_fields = ('name',) + serializer_class = serializers.ConnectMethodACLSerializer diff --git a/apps/acls/api/login_acl.py b/apps/acls/api/login_acl.py index 07aa7f46e..fc7693bd6 100644 --- a/apps/acls/api/login_acl.py +++ b/apps/acls/api/login_acl.py @@ -1,13 +1,19 @@ from common.api import JMSBulkModelViewSet +from .common import ACLUserFilterMixin from .. import serializers -from ..filters import LoginAclFilter from ..models import LoginACL __all__ = ['LoginACLViewSet'] +class LoginACLFilter(ACLUserFilterMixin): + class Meta: + model = LoginACL + fields = ('name', 'action') + + class LoginACLViewSet(JMSBulkModelViewSet): queryset = LoginACL.objects.all() - filterset_class = LoginAclFilter + filterset_class = LoginACLFilter search_fields = ('name',) serializer_class = serializers.LoginACLSerializer diff --git a/apps/acls/api/login_asset_acl.py b/apps/acls/api/login_asset_acl.py index a2a662bfa..5d282854e 100644 --- a/apps/acls/api/login_asset_acl.py +++ b/apps/acls/api/login_asset_acl.py @@ -1,19 +1,18 @@ -from common.drf.filters import BaseFilterSet from orgs.mixins.api import OrgBulkModelViewSet -from .common import ACLFiltersetMixin +from .common import ACLUserAssetFilterMixin from .. import models, serializers __all__ = ['LoginAssetACLViewSet'] -class CommandACLFilter(ACLFiltersetMixin, BaseFilterSet): +class LoginAssetACLFilter(ACLUserAssetFilterMixin): class Meta: model = models.LoginAssetACL - fields = ['name', 'users', 'assets'] + fields = ['name', ] class LoginAssetACLViewSet(OrgBulkModelViewSet): model = models.LoginAssetACL - filterset_class = CommandACLFilter + filterset_class = LoginAssetACLFilter search_fields = ['name'] serializer_class = serializers.LoginAssetACLSerializer diff --git a/apps/acls/filters.py b/apps/acls/filters.py deleted file mode 100644 index f5d1c73b3..000000000 --- a/apps/acls/filters.py +++ /dev/null @@ -1,15 +0,0 @@ -from django_filters import rest_framework as filters -from common.drf.filters import BaseFilterSet - -from acls.models import LoginACL - - -class LoginAclFilter(BaseFilterSet): - user = filters.UUIDFilter(field_name='user_id') - user_display = filters.CharFilter(field_name='user__name') - - class Meta: - model = LoginACL - fields = ( - 'name', 'user', 'user_display', 'action' - ) diff --git a/apps/acls/migrations/0015_connectmethodacl.py b/apps/acls/migrations/0015_connectmethodacl.py new file mode 100644 index 000000000..66beca0cc --- /dev/null +++ b/apps/acls/migrations/0015_connectmethodacl.py @@ -0,0 +1,46 @@ +# Generated by Django 3.2.17 on 2023-06-06 06:23 + +import uuid + +import django.core.validators +from django.conf import settings +from django.db import migrations, models + +import common.db.fields + + +class Migration(migrations.Migration): + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('acls', '0014_loginassetacl_rules'), + ] + + operations = [ + migrations.CreateModel( + name='ConnectMethodACL', + fields=[ + ('created_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Created by')), + ('updated_by', models.CharField(blank=True, max_length=128, null=True, verbose_name='Updated by')), + ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), + ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=128, unique=True, verbose_name='Name')), + ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', + validators=[django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100)], + verbose_name='Priority')), + ('action', models.CharField(default='reject', max_length=64, verbose_name='Action')), + ('is_active', models.BooleanField(default=True, verbose_name='Active')), + ('users', common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users')), + ('connect_methods', models.JSONField(default=list, verbose_name='Connect methods')), + ( + 'reviewers', + models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')), + ], + options={ + 'ordering': ('priority', 'date_updated', 'name'), + 'abstract': False, + }, + ), + ] diff --git a/apps/acls/migrations/0016_auto_20230606_1857.py b/apps/acls/migrations/0016_auto_20230606_1857.py new file mode 100644 index 000000000..305f0e49b --- /dev/null +++ b/apps/acls/migrations/0016_auto_20230606_1857.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.17 on 2023-06-06 10:57 + +from django.db import migrations, models + +import common.db.fields + + +def migrate_users_login_acls(apps, schema_editor): + login_acl_model = apps.get_model('acls', 'LoginACL') + for login_acl in login_acl_model.objects.all(): + login_acl.users = { + "type": "ids", "ids": [str(login_acl.user_id)] + } + login_acl.save() + + +class Migration(migrations.Migration): + dependencies = [ + ('acls', '0015_connectmethodacl'), + ] + + operations = [ + migrations.AddField( + model_name='loginacl', + name='users', + field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'), + ), + migrations.RemoveField( + model_name='loginacl', + name='user', + ), + migrations.AlterField( + model_name='loginacl', + name='name', + field=models.CharField(max_length=128, unique=True, verbose_name='Name'), + ), + ] diff --git a/apps/acls/models/__init__.py b/apps/acls/models/__init__.py index 3c5416992..28fe366b3 100644 --- a/apps/acls/models/__init__.py +++ b/apps/acls/models/__init__.py @@ -1,3 +1,4 @@ +from .command_acl import * +from .connect_method import * from .login_acl import * from .login_asset_acl import * -from .command_acl import * diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 12c66167c..0fe16d7d1 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -9,7 +9,7 @@ from common.utils.time_period import contains_time_period from orgs.mixins.models import OrgModelMixin __all__ = [ - 'BaseACL', 'UserAssetAccountBaseACL', + 'BaseACL', 'UserBaseACL', 'UserAssetAccountBaseACL', ] @@ -34,7 +34,7 @@ class BaseACLQuerySet(models.QuerySet): class BaseACL(JMSBaseModel): - name = models.CharField(max_length=128, verbose_name=_('Name')) + name = models.CharField(max_length=128, verbose_name=_('Name'), unique=True) priority = models.IntegerField( default=50, verbose_name=_("Priority"), help_text=_("1-100, the lower the value will be match first"), @@ -79,13 +79,27 @@ class BaseACL(JMSBaseModel): return None -class UserAssetAccountBaseACL(BaseACL, OrgModelMixin): +class UserBaseACL(BaseACL): users = JSONManyToManyField('users.User', default=dict, verbose_name=_('Users')) + + class Meta: + abstract = True + + @classmethod + def get_user_acls(cls, user): + queryset = cls.objects.all() + q = cls.users.get_filter_q(user) + queryset = queryset.filter(q) + return queryset.valid().distinct() + + +class UserAssetAccountBaseACL(UserBaseACL, OrgModelMixin): + name = models.CharField(max_length=128, verbose_name=_('Name')) assets = JSONManyToManyField('assets.Asset', default=dict, verbose_name=_('Assets')) accounts = models.JSONField(default=list, verbose_name=_("Accounts")) - class Meta(BaseACL.Meta): - unique_together = ('name', 'org_id') + class Meta(UserBaseACL.Meta): + unique_together = [('name', 'org_id')] abstract = True @classmethod diff --git a/apps/acls/models/connect_method.py b/apps/acls/models/connect_method.py new file mode 100644 index 000000000..2ae61a13c --- /dev/null +++ b/apps/acls/models/connect_method.py @@ -0,0 +1,10 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from .base import UserBaseACL + +__all__ = ['ConnectMethodACL'] + + +class ConnectMethodACL(UserBaseACL): + connect_methods = models.JSONField(default=list, verbose_name=_('Connect methods')) diff --git a/apps/acls/models/login_acl.py b/apps/acls/models/login_acl.py index 143196d78..68e6aa22a 100644 --- a/apps/acls/models/login_acl.py +++ b/apps/acls/models/login_acl.py @@ -3,18 +3,14 @@ from django.utils.translation import ugettext_lazy as _ from common.utils import get_request_ip, get_ip_city from common.utils.timezone import local_now_display -from .base import BaseACL +from .base import UserBaseACL -class LoginACL(BaseACL): - user = models.ForeignKey( - 'users.User', on_delete=models.CASCADE, - related_name='login_acls', verbose_name=_('User') - ) +class LoginACL(UserBaseACL): # 规则, ip_group, time_period rules = models.JSONField(default=dict, verbose_name=_('Rule')) - class Meta(BaseACL.Meta): + class Meta(UserBaseACL.Meta): verbose_name = _('Login acl') abstract = False @@ -28,10 +24,6 @@ class LoginACL(BaseACL): def filter_acl(cls, user): return user.login_acls.all().valid().distinct() - @classmethod - def get_user_acls(cls, user): - return cls.filter_acl(user) - def create_confirm_ticket(self, request): from tickets import const from tickets.models import ApplyLoginTicket diff --git a/apps/acls/serializers/__init__.py b/apps/acls/serializers/__init__.py index 88814b6c4..d3fa9cdc6 100644 --- a/apps/acls/serializers/__init__.py +++ b/apps/acls/serializers/__init__.py @@ -1,4 +1,5 @@ +from .command_acl import * +from .connect_method import * from .login_acl import * from .login_asset_acl import * from .login_asset_check import * -from .command_acl import * diff --git a/apps/acls/serializers/base.py b/apps/acls/serializers/base.py index c1a2f0a1f..d8a172c93 100644 --- a/apps/acls/serializers/base.py +++ b/apps/acls/serializers/base.py @@ -1,11 +1,10 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers -from acls.models.base import ActionChoices +from acls.models.base import ActionChoices, BaseACL +from common.serializers.fields import JSONManyToManyField, LabeledChoiceField from jumpserver.utils import has_valid_xpack_license -from common.serializers.fields import JSONManyToManyField, ObjectRelatedField, LabeledChoiceField from orgs.models import Organization -from users.models import User common_help_text = _( "With * indicating a match all. " @@ -71,25 +70,16 @@ class ActionAclSerializer(serializers.Serializer): action._choices = choices -class BaseUserAssetAccountACLSerializerMixin(ActionAclSerializer, serializers.Serializer): - users = JSONManyToManyField(label=_('User')) - assets = JSONManyToManyField(label=_('Asset')) - accounts = serializers.ListField(label=_('Account')) - reviewers = ObjectRelatedField( - queryset=User.objects, many=True, required=False, label=_('Reviewers') - ) - reviewers_amount = serializers.IntegerField( - read_only=True, source="reviewers.count", label=_('Reviewers amount') - ) - +class BaserACLSerializer(ActionAclSerializer, serializers.Serializer): class Meta: + model = BaseACL fields_mini = ["id", "name"] fields_small = fields_mini + [ - "users", "accounts", "assets", "is_active", - "date_created", "date_updated", "priority", - "action", "comment", "created_by", "org_id", + "is_active", "priority", "action", + "date_created", "date_updated", + "comment", "created_by", "org_id", ] - fields_m2m = ["reviewers", "reviewers_amount"] + fields_m2m = ["reviewers", ] fields = fields_small + fields_m2m extra_kwargs = { "priority": {"default": 50}, @@ -115,3 +105,18 @@ class BaseUserAssetAccountACLSerializerMixin(ActionAclSerializer, serializers.Se ) raise serializers.ValidationError(error) return valid_reviewers + + +class BaserUserACLSerializer(BaserACLSerializer): + users = JSONManyToManyField(label=_('User')) + + class Meta(BaserACLSerializer.Meta): + fields = BaserACLSerializer.Meta.fields + ['users'] + + +class BaseUserAssetAccountACLSerializer(BaserUserACLSerializer): + assets = JSONManyToManyField(label=_('Asset')) + accounts = serializers.ListField(label=_('Account')) + + class Meta(BaserUserACLSerializer.Meta): + fields = BaserUserACLSerializer.Meta.fields + ['assets', 'accounts'] diff --git a/apps/acls/serializers/command_acl.py b/apps/acls/serializers/command_acl.py index f4729ffd5..16cb615a8 100644 --- a/apps/acls/serializers/command_acl.py +++ b/apps/acls/serializers/command_acl.py @@ -1,13 +1,13 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers -from terminal.models import Session from acls.models import CommandGroup, CommandFilterACL -from common.utils import lazyproperty, get_object_or_none from common.serializers.fields import ObjectRelatedField, LabeledChoiceField -from orgs.utils import tmp_to_root_org +from common.utils import lazyproperty, get_object_or_none from orgs.mixins.serializers import BulkOrgResourceModelSerializer -from .base import BaseUserAssetAccountACLSerializerMixin as BaseSerializer +from orgs.utils import tmp_to_root_org +from terminal.models import Session +from .base import BaseUserAssetAccountACLSerializer as BaseSerializer __all__ = ["CommandFilterACLSerializer", "CommandGroupSerializer", "CommandReviewSerializer"] diff --git a/apps/acls/serializers/connect_method.py b/apps/acls/serializers/connect_method.py new file mode 100644 index 000000000..b36fde06d --- /dev/null +++ b/apps/acls/serializers/connect_method.py @@ -0,0 +1,23 @@ +from orgs.mixins.serializers import BulkOrgResourceModelSerializer +from .base import BaseUserAssetAccountACLSerializer as BaseSerializer +from ..models import ConnectMethodACL + +__all__ = ["ConnectMethodACLSerializer"] + + +class ConnectMethodACLSerializer(BaseSerializer, BulkOrgResourceModelSerializer): + class Meta(BaseSerializer.Meta): + model = ConnectMethodACL + fields = [ + i for i in BaseSerializer.Meta.fields + ['connect_methods'] + if i not in ['assets', 'accounts'] + ] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + field_action = self.fields.get('action') + if not field_action: + return + # 仅支持拒绝 + for k in ['review', 'accept']: + field_action._choices.pop(k, None) diff --git a/apps/acls/serializers/login_acl.py b/apps/acls/serializers/login_acl.py index 07e499ed6..1371bc091 100644 --- a/apps/acls/serializers/login_acl.py +++ b/apps/acls/serializers/login_acl.py @@ -1,47 +1,22 @@ from django.utils.translation import ugettext as _ -from rest_framework import serializers -from common.serializers import BulkModelSerializer, MethodSerializer -from common.serializers.fields import ObjectRelatedField -from users.models import User -from .base import ActionAclSerializer +from common.serializers import MethodSerializer +from orgs.mixins.serializers import BulkOrgResourceModelSerializer +from .base import BaserUserACLSerializer from .rules import RuleSerializer from ..models import LoginACL -__all__ = [ - "LoginACLSerializer", -] +__all__ = ["LoginACLSerializer"] -common_help_text = _( - "With * indicating a match all. " -) +common_help_text = _("With * indicating a match all. ") -class LoginACLSerializer(ActionAclSerializer, BulkModelSerializer): - user = ObjectRelatedField(queryset=User.objects, label=_("User")) - reviewers = ObjectRelatedField( - queryset=User.objects, label=_("Reviewers"), many=True, required=False - ) - reviewers_amount = serializers.IntegerField( - read_only=True, source="reviewers.count", label=_("Reviewers amount") - ) +class LoginACLSerializer(BaserUserACLSerializer, BulkOrgResourceModelSerializer): rules = MethodSerializer(label=_('Rule')) - class Meta: + class Meta(BaserUserACLSerializer.Meta): model = LoginACL - fields_mini = ["id", "name"] - fields_small = fields_mini + [ - "priority", "user", "rules", "action", - "is_active", "date_created", "date_updated", - "comment", "created_by", - ] - fields_fk = ["user"] - fields_m2m = ["reviewers", "reviewers_amount"] - fields = fields_small + fields_fk + fields_m2m - extra_kwargs = { - "priority": {"default": 50}, - "is_active": {"default": True}, - } + fields = BaserUserACLSerializer.Meta.fields + ['rules', ] def get_rules_serializer(self): return RuleSerializer() diff --git a/apps/acls/serializers/login_asset_acl.py b/apps/acls/serializers/login_asset_acl.py index 7480100f8..1b3bb2769 100644 --- a/apps/acls/serializers/login_asset_acl.py +++ b/apps/acls/serializers/login_asset_acl.py @@ -2,7 +2,7 @@ from django.utils.translation import gettext_lazy as _ from common.serializers import MethodSerializer from orgs.mixins.serializers import BulkOrgResourceModelSerializer -from .base import BaseUserAssetAccountACLSerializerMixin as BaseSerializer +from .base import BaseUserAssetAccountACLSerializer as BaseSerializer from .rules import RuleSerializer from ..models import LoginAssetACL diff --git a/apps/acls/urls/api_urls.py b/apps/acls/urls/api_urls.py index b0f5cdf22..8c91698d8 100644 --- a/apps/acls/urls/api_urls.py +++ b/apps/acls/urls/api_urls.py @@ -10,6 +10,7 @@ router.register(r'login-acls', api.LoginACLViewSet, 'login-acl') router.register(r'login-asset-acls', api.LoginAssetACLViewSet, 'login-asset-acl') router.register(r'command-filter-acls', api.CommandFilterACLViewSet, 'command-filter-acl') router.register(r'command-groups', api.CommandGroupViewSet, 'command-group') +router.register(r'connect-method-acls', api.ConnectMethodACLViewSet, 'connect-method-acl') urlpatterns = [ path('login-asset/check/', api.LoginAssetCheckAPI.as_view(), name='login-asset-check'), diff --git a/apps/common/utils/common.py b/apps/common/utils/common.py index 181b43cfb..56f1dbd09 100644 --- a/apps/common/utils/common.py +++ b/apps/common/utils/common.py @@ -1,21 +1,21 @@ # -*- coding: utf-8 -*- # -import re -from django.templatetags.static import static -from collections import OrderedDict -from itertools import chain -import logging import datetime -import uuid -from functools import wraps -import time import ipaddress -import psutil -import platform +import logging import os +import platform +import re import socket +import time +import uuid +from collections import OrderedDict +from functools import wraps +from itertools import chain +import psutil from django.conf import settings +from django.templatetags.static import static UUID_PATTERN = re.compile(r'\w{8}(-\w{4}){3}-\w{12}') ipip_db = None @@ -76,6 +76,7 @@ def setattr_bulk(seq, key, value): def set_attr(obj): setattr(obj, key, value) return obj + return map(set_attr, seq) @@ -97,12 +98,12 @@ def capacity_convert(size, expect='auto', rate=1000): rate_mapping = ( ('K', rate), ('KB', rate), - ('M', rate**2), - ('MB', rate**2), - ('G', rate**3), - ('GB', rate**3), - ('T', rate**4), - ('TB', rate**4), + ('M', rate ** 2), + ('MB', rate ** 2), + ('G', rate ** 3), + ('GB', rate ** 3), + ('T', rate ** 4), + ('TB', rate ** 4), ) rate_mapping = OrderedDict(rate_mapping) @@ -117,7 +118,7 @@ def capacity_convert(size, expect='auto', rate=1000): if expect == 'auto': for unit, rate_ in rate_mapping.items(): - if rate > std_size/rate_ >= 1 or unit == "T": + if rate > std_size / rate_ >= 1 or unit == "T": expect = unit break @@ -195,6 +196,7 @@ def with_cache(func): res = func(*args, **kwargs) cache[key] = res return res + return wrapper @@ -216,6 +218,7 @@ def timeit(func): msg = "End call {}, using: {:.1f}ms".format(name, using) logger.debug(msg) return result + return wrapper @@ -310,7 +313,7 @@ class Time: def print(self): last, *timestamps = self._timestamps for timestamp, msg in zip(timestamps, self._msgs): - logger.debug(f'TIME_IT: {msg} {timestamp-last}') + logger.debug(f'TIME_IT: {msg} {timestamp - last}') last = timestamp @@ -367,7 +370,7 @@ def pretty_string(data, max_length=128, ellipsis_str='...'): def group_by_count(it, count): - return [it[i:i+count] for i in range(0, len(it), count)] + return [it[i:i + count] for i in range(0, len(it), count)] def test_ip_connectivity(host, port, timeout=0.5): @@ -395,3 +398,17 @@ def static_or_direct(logo_path): def make_dirs(name, mode=0o755, exist_ok=False): """ 默认权限设置为 0o755 """ return os.makedirs(name, mode=mode, exist_ok=exist_ok) + + +def distinct(seq, key=None): + if key is None: + # 如果未提供关键字参数,则默认使用元素本身作为比较键 + key = lambda x: x + seen = set() + result = [] + for item in seq: + k = key(item) + if k not in seen: + seen.add(k) + result.append(item) + return result diff --git a/apps/rbac/const.py b/apps/rbac/const.py index 786cb74cc..cfc3c1863 100644 --- a/apps/rbac/const.py +++ b/apps/rbac/const.py @@ -148,6 +148,8 @@ only_system_permissions = ( ('orgs', 'organization', 'view', 'rootorg'), ('terminal', 'applet', '*', '*'), ('terminal', 'applethost', '*', '*'), + ('acls', 'loginacl', '*', '*'), + ('acls', 'connectmethodacl', '*', '*') ) only_org_permissions = ( diff --git a/apps/terminal/api/component/connect_methods.py b/apps/terminal/api/component/connect_methods.py index 0c397558b..d928c7329 100644 --- a/apps/terminal/api/component/connect_methods.py +++ b/apps/terminal/api/component/connect_methods.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- # +import itertools from rest_framework import generics from rest_framework.views import Response from common.permissions import IsValidUser -from common.utils import get_request_os +from common.utils import get_request_os, is_true, distinct from terminal import serializers from terminal.connect_methods import ConnectMethodUtil @@ -16,9 +17,29 @@ class ConnectMethodListApi(generics.ListAPIView): serializer_class = serializers.ConnectMethodSerializer permission_classes = [IsValidUser] + def filter_user_connect_methods(self, d): + from acls.models import ConnectMethodACL + # 这里要根据用户来了,受 acl 影响 + acls = ConnectMethodACL.get_user_acls(self.request.user) + disabled_connect_methods = acls.values_list('connect_methods', flat=True) + disabled_connect_methods = set(itertools.chain.from_iterable(disabled_connect_methods)) + new_queryset = {} + for protocol, methods in d.items(): + new_queryset[protocol] = [x for x in methods if x['value'] not in disabled_connect_methods] + return new_queryset + def get_queryset(self): - os = get_request_os(self.request) - return ConnectMethodUtil.get_filtered_protocols_connect_methods(os) + os = self.request.query_params.get('os') or get_request_os(self.request) + queryset = ConnectMethodUtil.get_filtered_protocols_connect_methods(os) + flat = self.request.query_params.get('flat') + + # 先这么处理, 这里不用过滤包含的事所有 + if is_true(flat): + queryset = itertools.chain.from_iterable(queryset.values()) + queryset = distinct(queryset, key=lambda x: x['value']) + else: + queryset = self.filter_queryset(queryset) + return queryset def list(self, request, *args, **kwargs): queryset = self.get_queryset() diff --git a/apps/terminal/connect_methods.py b/apps/terminal/connect_methods.py index a418c1460..aefdc7675 100644 --- a/apps/terminal/connect_methods.py +++ b/apps/terminal/connect_methods.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # +import itertools from collections import defaultdict from django.conf import settings @@ -51,11 +52,7 @@ class NativeClient(TextChoices): xshell = 'xshell', 'Xshell' # Magnus - mysql = 'db_client_mysql', _('DB Client') - psql = 'db_client_psql', _('DB Client') - sqlplus = 'db_client_sqlplus', _('DB Client') - redis = 'db_client_redis', _('DB Client') - mongodb = 'db_client_mongodb', _('DB Client') + db_client = 'db_client', _('DB Client') # Razor mstsc = 'mstsc', 'Remote Desktop' @@ -70,12 +67,12 @@ class NativeClient(TextChoices): 'windows': [cls.putty], }, Protocol.rdp: [cls.mstsc], - Protocol.mysql: [cls.mysql], - Protocol.mariadb: [cls.mysql], - Protocol.oracle: [cls.sqlplus], - Protocol.postgresql: [cls.psql], - Protocol.redis: [cls.redis], - Protocol.mongodb: [cls.mongodb], + Protocol.mysql: [cls.db_client], + Protocol.mariadb: [cls.db_client], + Protocol.oracle: [cls.db_client], + Protocol.postgresql: [cls.db_client], + Protocol.redis: [cls.db_client], + Protocol.mongodb: [cls.db_client], } return clients @@ -83,7 +80,10 @@ class NativeClient(TextChoices): def get_target_protocol(cls, name, os): for protocol, clients in cls.get_native_clients().items(): if isinstance(clients, dict): - clients = clients.get(os) or clients.get('default') + if os == 'all': + clients = list(itertools.chain(*clients.values())) + else: + clients = clients.get(os) or clients.get('default') if name in clients: return protocol return None @@ -99,7 +99,10 @@ class NativeClient(TextChoices): for protocol, _clients in clients_map.items(): if isinstance(_clients, dict): - _clients = _clients.get(os, _clients['default']) + if os == 'all': + _clients = list(itertools.chain(*_clients.values())) + else: + _clients = _clients.get(os, _clients['default']) for client in _clients: if not settings.XPACK_ENABLED and client in cls.xpack_methods(): continue @@ -245,11 +248,10 @@ class ConnectMethodUtil: if not getattr(settings, 'TERMINAL_KOKO_SSH_ENABLED'): protocol = Protocol.ssh methods[protocol] = [m for m in methods[protocol] if m['type'] != 'native'] - return methods @classmethod - def get_protocols_connect_methods(cls, os): + def get_protocols_connect_methods(cls, os='windows'): if cls._all_methods.get('os'): return cls._all_methods['os'] @@ -264,7 +266,7 @@ class ConnectMethodUtil: for protocol in support: # Web 方式 - methods[protocol.value].extend([ + methods[str(protocol)].extend([ { 'component': component.value, 'type': 'web', @@ -286,7 +288,7 @@ class ConnectMethodUtil: if component == TerminalType.koko and protocol.value != Protocol.ssh: # koko 仅支持 ssh 的 native 方式,其他数据库的 native 方式不提供 continue - methods[protocol.value].extend([ + methods[str(protocol)].extend([ { 'component': component.value, 'type': 'native', From f0c0ba3653f7135e826f11e3d33bfe1a9e5ebc12 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Thu, 8 Jun 2023 10:06:14 +0800 Subject: [PATCH 081/153] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3lina=E4=B8=8D?= =?UTF-8?q?=E6=98=BE=E7=A4=BAjson=E6=A0=BC=E5=BC=8F=E5=8F=82=E6=95=B0?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96DictSerializer=E6=94=B9=E4=B8=BAJSON?= =?UTF-8?q?Serialzer=EF=BC=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/settings/serializers/auth/cas.py | 2 +- apps/settings/serializers/auth/ldap.py | 2 +- apps/settings/serializers/auth/oauth2.py | 2 +- apps/settings/serializers/auth/oidc.py | 2 +- apps/settings/serializers/auth/saml2.py | 2 +- apps/settings/serializers/auth/sms.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/settings/serializers/auth/cas.py b/apps/settings/serializers/auth/cas.py index 4cfa07d1b..4fc964529 100644 --- a/apps/settings/serializers/auth/cas.py +++ b/apps/settings/serializers/auth/cas.py @@ -25,5 +25,5 @@ class CASSettingSerializer(serializers.Serializer): CAS_APPLY_ATTRIBUTES_TO_USER = serializers.BooleanField( required=False, label=_('Enable attributes map') ) - CAS_RENAME_ATTRIBUTES = serializers.DictField(required=False, label=_('Rename attr')) + CAS_RENAME_ATTRIBUTES = serializers.JSONField(required=False, label=_('Rename attr')) CAS_CREATE_USER = serializers.BooleanField(required=False, label=_('Create user if not')) diff --git a/apps/settings/serializers/auth/ldap.py b/apps/settings/serializers/auth/ldap.py index 016301558..cc1976884 100644 --- a/apps/settings/serializers/auth/ldap.py +++ b/apps/settings/serializers/auth/ldap.py @@ -54,7 +54,7 @@ class LDAPSettingSerializer(serializers.Serializer): max_length=1024, required=True, label=_('User search filter'), help_text=_('Choice may be (cn|uid|sAMAccountName)=%(user)s)') ) - AUTH_LDAP_USER_ATTR_MAP = serializers.DictField( + AUTH_LDAP_USER_ATTR_MAP = serializers.JSONField( required=True, label=_('User attr map'), help_text=_('User attr map present how to map LDAP user attr to ' 'jumpserver, username,name,email is jumpserver attr') diff --git a/apps/settings/serializers/auth/oauth2.py b/apps/settings/serializers/auth/oauth2.py index 6aaacaa5b..d7f1f4407 100644 --- a/apps/settings/serializers/auth/oauth2.py +++ b/apps/settings/serializers/auth/oauth2.py @@ -52,7 +52,7 @@ class OAuth2SettingSerializer(serializers.Serializer): required=False, allow_blank=True, max_length=1024, label=_('Provider end session endpoint') ) AUTH_OAUTH2_LOGOUT_COMPLETELY = serializers.BooleanField(required=False, label=_('Logout completely')) - AUTH_OAUTH2_USER_ATTR_MAP = serializers.DictField( + AUTH_OAUTH2_USER_ATTR_MAP = serializers.JSONField( required=True, label=_('User attr map') ) AUTH_OAUTH2_ALWAYS_UPDATE_USER = serializers.BooleanField( diff --git a/apps/settings/serializers/auth/oidc.py b/apps/settings/serializers/auth/oidc.py index 2c1aa8411..2daf02ff5 100644 --- a/apps/settings/serializers/auth/oidc.py +++ b/apps/settings/serializers/auth/oidc.py @@ -33,7 +33,7 @@ class CommonSettingSerializer(serializers.Serializer): AUTH_OPENID_IGNORE_SSL_VERIFICATION = serializers.BooleanField( required=False, label=_('Ignore ssl verification') ) - AUTH_OPENID_USER_ATTR_MAP = serializers.DictField( + AUTH_OPENID_USER_ATTR_MAP = serializers.JSONField( required=True, label=_('User attr map'), help_text=_('User attr map present how to map OpenID user attr to ' 'jumpserver, username,name,email is jumpserver attr') diff --git a/apps/settings/serializers/auth/saml2.py b/apps/settings/serializers/auth/saml2.py index d89f30577..9e0001218 100644 --- a/apps/settings/serializers/auth/saml2.py +++ b/apps/settings/serializers/auth/saml2.py @@ -30,6 +30,6 @@ class SAML2SettingSerializer(serializers.Serializer): allow_blank=True, required=False, write_only=True, label=_('SP cert') ) - SAML2_RENAME_ATTRIBUTES = serializers.DictField(required=False, label=_('Rename attr')) + SAML2_RENAME_ATTRIBUTES = serializers.JSONField(required=False, label=_('Rename attr')) SAML2_LOGOUT_COMPLETELY = serializers.BooleanField(required=False, label=_('Logout completely')) AUTH_SAML2_ALWAYS_UPDATE_USER = serializers.BooleanField(required=False, label=_('Always update user')) diff --git a/apps/settings/serializers/auth/sms.py b/apps/settings/serializers/auth/sms.py index 60033c476..2a3e60530 100644 --- a/apps/settings/serializers/auth/sms.py +++ b/apps/settings/serializers/auth/sms.py @@ -96,7 +96,7 @@ class CustomSMSSettingSerializer(BaseSMSSettingSerializer): post = 'post', 'Post' CUSTOM_SMS_URL = serializers.URLField(required=True, label=_("URL")) - CUSTOM_SMS_API_PARAMS = serializers.DictField( + CUSTOM_SMS_API_PARAMS = serializers.JSONField( label=_('Parameters'), default={'phone_number': '{phone_number}', 'code': '{code}'} ) CUSTOM_SMS_REQUEST_METHOD = serializers.ChoiceField( From a6d586efb4fdfd325997c6024ab99170d3673b7c Mon Sep 17 00:00:00 2001 From: "fangfang.dong" Date: Mon, 5 Jun 2023 18:57:34 +0800 Subject: [PATCH 082/153] =?UTF-8?q?feat:=20=E7=B3=BB=E7=BB=9F=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=20-=20=E7=9F=AD=E4=BF=A1=E6=9C=8D=E5=8A=A1=20-=20?= =?UTF-8?q?=E5=A4=9A=E5=B9=B3=E5=8F=B0=E9=85=8D=E7=BD=AE=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=89=8B=E6=9C=BA=E5=8F=B7:=20=E5=A2=9E=E5=8A=A0=E5=8C=BA?= =?UTF-8?q?=E5=8F=B7=E6=98=BE=E7=A4=BA=E4=B8=8E=E4=BF=AE=E6=94=B9=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/settings/serializers/auth/sms.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/settings/serializers/auth/sms.py b/apps/settings/serializers/auth/sms.py index 2a3e60530..0b8138137 100644 --- a/apps/settings/serializers/auth/sms.py +++ b/apps/settings/serializers/auth/sms.py @@ -2,7 +2,7 @@ from django.utils.translation import ugettext_lazy as _ from django.db import models from rest_framework import serializers -from common.serializers.fields import EncryptedField +from common.serializers.fields import EncryptedField, PhoneField from common.validators import PhoneValidator from common.sdk.sms import BACKENDS @@ -26,10 +26,9 @@ class SignTmplPairSerializer(serializers.Serializer): class BaseSMSSettingSerializer(serializers.Serializer): PREFIX_TITLE = _('SMS') - - SMS_TEST_PHONE = serializers.CharField( - max_length=256, required=False, validators=[PhoneValidator(), ], - allow_blank=True, label=_('Test phone') + + SMS_TEST_PHONE = PhoneField( + validators=[PhoneValidator()], required=False, allow_blank=True, allow_null=True, label=_('Test phone') ) def to_representation(self, instance): From 0025b2483e41c0bca54ff5cf0afe80a77838ffc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 19:59:23 +0000 Subject: [PATCH 083/153] chore(deps): bump cryptography from 38.0.4 to 41.0.0 in /requirements Bumps [cryptography](https://github.com/pyca/cryptography) from 38.0.4 to 41.0.0. - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/38.0.4...41.0.0) --- updated-dependencies: - dependency-name: cryptography dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 33bc01dbe..9b46ad897 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -26,7 +26,7 @@ paramiko==2.11.0 passlib==1.7.4 pyasn1==0.4.8 pycparser==2.21 -cryptography==38.0.4 +cryptography==41.0.0 pycryptodome==3.15.0 pycryptodomex==3.15.0 phonenumbers==8.13.8 From 41e147d4b202cb3c1d0b6abf7a101be38ea3fdad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E5=B9=BF?= Date: Thu, 8 Jun 2023 14:52:39 +0800 Subject: [PATCH 084/153] Revert "chore(deps): bump cryptography from 38.0.4 to 41.0.0 in /requirements" This reverts commit 0025b2483e41c0bca54ff5cf0afe80a77838ffc0. --- requirements/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 9b46ad897..33bc01dbe 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -26,7 +26,7 @@ paramiko==2.11.0 passlib==1.7.4 pyasn1==0.4.8 pycparser==2.21 -cryptography==41.0.0 +cryptography==38.0.4 pycryptodome==3.15.0 pycryptodomex==3.15.0 phonenumbers==8.13.8 From 271ec1bfe08351016d0c96fcf8efbb10b33994e7 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 8 Jun 2023 16:25:31 +0800 Subject: [PATCH 085/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=88=9A?= =?UTF-8?q?=E6=89=8D=E4=BF=AE=E6=94=B9=E5=AF=BC=E8=87=B4=E7=9A=84=20acls?= =?UTF-8?q?=20=E8=BF=87=E6=BB=A4=E6=B2=A1=E6=9C=89=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E7=BB=84=E7=BB=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/models/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 0fe16d7d1..d80baeb7e 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -82,7 +82,7 @@ class BaseACL(JMSBaseModel): class UserBaseACL(BaseACL): users = JSONManyToManyField('users.User', default=dict, verbose_name=_('Users')) - class Meta: + class Meta(BaseACL.Meta): abstract = True @classmethod @@ -93,7 +93,7 @@ class UserBaseACL(BaseACL): return queryset.valid().distinct() -class UserAssetAccountBaseACL(UserBaseACL, OrgModelMixin): +class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL): name = models.CharField(max_length=128, verbose_name=_('Name')) assets = JSONManyToManyField('assets.Asset', default=dict, verbose_name=_('Assets')) accounts = models.JSONField(default=list, verbose_name=_("Accounts")) From 2837dcf40e1d9c321c443c7cda5e36d388302f80 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Thu, 8 Jun 2023 18:04:07 +0800 Subject: [PATCH 086/153] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=B8=8A=E4=BC=A0=E4=B8=8B=E8=BD=BD=E5=A4=87=E4=BB=BD?= =?UTF-8?q?=20(#10438)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 支持文件上传下载备份 * perf: 抽离replay和ftpfile存储代码 * perf: FTPLog增加session字段 * fix: 修改变量名 --- apps/audits/api.py | 67 ++++++++++++++++- apps/audits/const.py | 1 + .../migrations/0022_auto_20230605_1555.py | 29 +++++++ apps/audits/models.py | 22 ++++++ apps/audits/serializers.py | 8 +- apps/audits/tasks.py | 35 +++++++++ apps/audits/utils.py | 2 - apps/common/storage/__init__.py | 0 apps/common/storage/base.py | 65 ++++++++++++++++ apps/common/storage/ftp_file.py | 17 +++++ apps/common/storage/replay.py | 31 ++++++++ apps/jumpserver/conf.py | 3 + apps/jumpserver/settings/custom.py | 1 + apps/rbac/const.py | 2 +- apps/terminal/api/session/session.py | 30 ++++---- apps/terminal/models/component/terminal.py | 3 +- apps/terminal/tasks.py | 5 +- apps/terminal/utils/__init__.py | 1 - apps/terminal/utils/session_replay.py | 75 ------------------- 19 files changed, 294 insertions(+), 103 deletions(-) create mode 100644 apps/audits/migrations/0022_auto_20230605_1555.py create mode 100644 apps/common/storage/__init__.py create mode 100644 apps/common/storage/base.py create mode 100644 apps/common/storage/ftp_file.py create mode 100644 apps/common/storage/replay.py delete mode 100644 apps/terminal/utils/session_replay.py diff --git a/apps/audits/api.py b/apps/audits/api.py index b672d8bad..e88afe7ed 100644 --- a/apps/audits/api.py +++ b/apps/audits/api.py @@ -1,30 +1,47 @@ # -*- coding: utf-8 -*- # +import os + from importlib import import_module from django.conf import settings +from django.shortcuts import get_object_or_404 from django.db.models import F, Value, CharField, Q +from django.http import HttpResponse, FileResponse +from django.utils.encoding import escape_uri_path from rest_framework import generics from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView +from rest_framework.decorators import action +from common.api import AsyncApiMixin from common.drf.filters import DatetimeRangeFilter +from common.permissions import IsServiceAccount from common.plugins.es import QuerySet as ESQuerySet -from common.utils import is_uuid -from common.utils import lazyproperty +from common.utils import is_uuid, get_logger, lazyproperty +from common.const.http import GET, POST +from common.storage.ftp_file import FTPFileStorageHandler from orgs.mixins.api import OrgReadonlyModelViewSet, OrgModelViewSet from orgs.utils import current_org, tmp_to_root_org from orgs.models import Organization +from rbac.permissions import RBACPermission +from terminal.models import default_storage from users.models import User from .backends import TYPE_ENGINE_MAPPING from .const import ActivityChoices from .models import FTPLog, UserLoginLog, OperateLog, PasswordChangeLog, ActivityLog, JobLog -from .serializers import FTPLogSerializer, UserLoginLogSerializer, JobLogSerializer from .serializers import ( + FTPLogSerializer, UserLoginLogSerializer, JobLogSerializer, OperateLogSerializer, OperateLogActionDetailSerializer, PasswordChangeLogSerializer, ActivityUnionLogSerializer, + FileSerializer ) +logger = get_logger(__name__) + + class JobAuditViewSet(OrgReadonlyModelViewSet): model = JobLog extra_filter_backends = [DatetimeRangeFilter] @@ -47,7 +64,49 @@ class FTPLogViewSet(OrgModelViewSet): filterset_fields = ['user', 'asset', 'account', 'filename'] search_fields = filterset_fields ordering = ['-date_start'] - http_method_names = ['post', 'get', 'head', 'options'] + http_method_names = ['post', 'get', 'head', 'options', 'patch'] + rbac_perms = { + 'download': 'audits.view_ftplog', + } + + def get_storage(self): + return FTPFileStorageHandler(self.get_object()) + + @action( + methods=[GET], detail=True, permission_classes=[RBACPermission, ], + url_path='file/download' + ) + def download(self, request, *args, **kwargs): + ftp_log = self.get_object() + ftp_storage = self.get_storage() + local_path, url_or_err = ftp_storage.get_file_path_url() + if local_path is None: + return HttpResponse(url_or_err) + + file = open(default_storage.path(local_path), 'rb') + response = FileResponse(file) + response['Content-Type'] = 'application/octet-stream' + filename = escape_uri_path(ftp_log.filename) + response["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(filename) + return response + + @action(methods=[POST], detail=True, permission_classes=[IsServiceAccount, ], serializer_class=FileSerializer) + def upload(self, request, *args, **kwargs): + ftp_log = self.get_object() + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(): + file = serializer.validated_data['file'] + name, err = ftp_log.save_file_to_storage(file) + if not name: + msg = "Failed save file `{}`: {}".format(ftp_log.id, err) + logger.error(msg) + return Response({'msg': str(err)}, status=400) + url = default_storage.url(name) + return Response({'url': url}, status=201) + else: + msg = 'Upload data invalid: {}'.format(serializer.errors) + logger.error(msg) + return Response({'msg': serializer.errors}, status=401) class UserLoginCommonMixin: diff --git a/apps/audits/const.py b/apps/audits/const.py index 90df97a6c..ae8679f01 100644 --- a/apps/audits/const.py +++ b/apps/audits/const.py @@ -16,6 +16,7 @@ class OperateChoices(TextChoices): rename = "rename", _("Rename") symlink = "symlink", _("Symlink") download = "download", _("Download") + rename_dir = "rename_dir", _("Rename dir") class ActionChoices(TextChoices): diff --git a/apps/audits/migrations/0022_auto_20230605_1555.py b/apps/audits/migrations/0022_auto_20230605_1555.py new file mode 100644 index 000000000..97db7b341 --- /dev/null +++ b/apps/audits/migrations/0022_auto_20230605_1555.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.17 on 2023-06-05 07:55 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('audits', '0021_auto_20230207_0857'), + ] + + operations = [ + migrations.AddField( + model_name='ftplog', + name='has_file', + field=models.BooleanField(default=False, verbose_name='File Record'), + ), + migrations.AddField( + model_name='ftplog', + name='session', + field=models.CharField(default=uuid.uuid4, max_length=36, verbose_name='Session'), + ), + migrations.AlterField( + model_name='ftplog', + name='operate', + field=models.CharField(choices=[('mkdir', 'Mkdir'), ('rmdir', 'Rmdir'), ('delete', 'Delete'), ('upload', 'Upload'), ('rename', 'Rename'), ('symlink', 'Symlink'), ('download', 'Download'), ('rename_dir', 'Rename dir')], max_length=16, verbose_name='Operate'), + ), + ] diff --git a/apps/audits/models.py b/apps/audits/models.py index 099bde56e..1b93c5715 100644 --- a/apps/audits/models.py +++ b/apps/audits/models.py @@ -1,7 +1,9 @@ +import os import uuid from django.db import models from django.db.models import Q +from django.conf import settings from django.utils import timezone from django.utils.translation import gettext, ugettext_lazy as _ @@ -10,6 +12,7 @@ from common.utils import lazyproperty from ops.models import JobExecution from orgs.mixins.models import OrgModelMixin, Organization from orgs.utils import current_org +from terminal.models import default_storage from .const import ( OperateChoices, ActionChoices, @@ -40,6 +43,8 @@ class JobLog(JobExecution): class FTPLog(OrgModelMixin): + upload_to = 'FTP_FILES' + id = models.UUIDField(default=uuid.uuid4, primary_key=True) user = models.CharField(max_length=128, verbose_name=_("User")) remote_addr = models.CharField( @@ -53,10 +58,27 @@ class FTPLog(OrgModelMixin): filename = models.CharField(max_length=1024, verbose_name=_("Filename")) is_success = models.BooleanField(default=True, verbose_name=_("Success")) date_start = models.DateTimeField(auto_now_add=True, verbose_name=_("Date start")) + has_file = models.BooleanField(default=False, verbose_name=_("File Record")) + session = models.CharField(max_length=36, verbose_name=_("Session"), default=uuid.uuid4) class Meta: verbose_name = _("File transfer log") + @property + def filepath(self): + return os.path.join(self.upload_to, self.date_start.strftime('%Y-%m-%d'), str(self.id)) + + def save_file_to_storage(self, file): + try: + name = default_storage.save(self.filepath, file) + except OSError as e: + return None, e + + if settings.SERVER_REPLAY_STORAGE: + from .tasks import upload_ftp_file_to_external_storage + upload_ftp_file_to_external_storage.delay(str(self.id), file.name) + return name, None + class OperateLog(OrgModelMixin): id = models.UUIDField(default=uuid.uuid4, primary_key=True) diff --git a/apps/audits/serializers.py b/apps/audits/serializers.py index 204d901e2..7b7573232 100644 --- a/apps/audits/serializers.py +++ b/apps/audits/serializers.py @@ -37,8 +37,8 @@ class FTPLogSerializer(serializers.ModelSerializer): fields_mini = ["id"] fields_small = fields_mini + [ "user", "remote_addr", "asset", "account", - "org_id", "operate", "filename", "is_success", - "date_start", + "org_id", "operate", "filename", "date_start", + "is_success", "has_file", ] fields = fields_small @@ -158,3 +158,7 @@ class ActivityUnionLogSerializer(serializers.Serializer): api_to_ui=True, is_audit=True ) return detail_url + + +class FileSerializer(serializers.Serializer): + file = serializers.FileField(allow_empty_file=True) diff --git a/apps/audits/tasks.py b/apps/audits/tasks.py index 7cd172bdd..a0da3f782 100644 --- a/apps/audits/tasks.py +++ b/apps/audits/tasks.py @@ -11,13 +11,16 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from common.utils import get_log_keep_day, get_logger +from common.storage.ftp_file import FTPFileStorageHandler from ops.celery.decorator import ( register_as_period_task, after_app_shutdown_clean_periodic ) from ops.models import CeleryTaskExecution from terminal.models import Session, Command +from terminal.backends import server_replay_storage from .models import UserLoginLog, OperateLog, FTPLog, ActivityLog + logger = get_logger(__name__) @@ -46,7 +49,15 @@ def clean_ftp_log_period(): now = timezone.now() days = get_log_keep_day('FTP_LOG_KEEP_DAYS') expired_day = now - datetime.timedelta(days=days) + file_store_dir = os.path.join(default_storage.base_location, 'ftp_file') FTPLog.objects.filter(date_start__lt=expired_day).delete() + command = "find %s -mtime +%s -exec rm -f {} \\;" % ( + file_store_dir, days + ) + subprocess.call(command, shell=True) + command = "find %s -type d -empty -delete;" % file_store_dir + subprocess.call(command, shell=True) + logger.info("Clean FTP file done") def clean_celery_tasks_period(): @@ -98,3 +109,27 @@ def clean_audits_log_period(): clean_activity_log_period() clean_celery_tasks_period() clean_expired_session_period() + + +@shared_task(verbose_name=_('Upload FTP file to external storage')) +def upload_ftp_file_to_external_storage(ftp_log_id, file_name): + logger.info(f'Start upload FTP file record to external storage: {ftp_log_id} - {file_name}') + ftp_log = FTPLog.objects.filter(id=ftp_log_id).first() + if not ftp_log: + logger.error(f'FTP db item not found: {ftp_log_id}') + return + ftp_storage = FTPFileStorageHandler(ftp_log) + local_path, url_or_err = ftp_storage.find_local() + if not local_path: + logger.error(f'FTP file record not found, may be upload error. file name: {file_name}') + return + abs_path = default_storage.path(local_path) + ok, err = server_replay_storage.upload(abs_path, ftp_log.filepath) + if not ok: + logger.error(f'Session file record upload to external error: {err}') + return + try: + default_storage.delete(local_path) + except: + pass + return diff --git a/apps/audits/utils.py b/apps/audits/utils.py index 3865e9326..d2f6b61cd 100644 --- a/apps/audits/utils.py +++ b/apps/audits/utils.py @@ -1,7 +1,5 @@ import codecs import copy -import csv - from itertools import chain from datetime import datetime diff --git a/apps/common/storage/__init__.py b/apps/common/storage/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/common/storage/base.py b/apps/common/storage/base.py new file mode 100644 index 000000000..66b4a7096 --- /dev/null +++ b/apps/common/storage/base.py @@ -0,0 +1,65 @@ +import os + +import jms_storage + +from django.conf import settings + +from terminal.models import default_storage, ReplayStorage +from common.utils import get_logger, make_dirs + + +logger = get_logger(__name__) + + +class BaseStorageHandler(object): + NAME = '' + + def __init__(self, obj): + self.obj = obj + + def get_file_path(self, **kwargs): + # return remote_path, local_path + raise NotImplementedError + + def find_local(self): + raise NotImplementedError + + def download(self): + replay_storages = ReplayStorage.objects.all() + configs = { + storage.name: storage.config + for storage in replay_storages + if not storage.type_null_or_server + } + if settings.SERVER_REPLAY_STORAGE: + configs['SERVER_REPLAY_STORAGE'] = settings.SERVER_REPLAY_STORAGE + if not configs: + msg = f"Not found {self.NAME} file, and not remote storage set" + return None, msg + storage = jms_storage.get_multi_object_storage(configs) + + remote_path, local_path = self.get_file_path(storage=storage) + if not remote_path: + msg = f'Not found {self.NAME} file' + logger.error(msg) + return None, msg + + # 保存到storage的路径 + target_path = os.path.join(default_storage.base_location, local_path) + target_dir = os.path.dirname(target_path) + if not os.path.isdir(target_dir): + make_dirs(target_dir, exist_ok=True) + + ok, err = storage.download(remote_path, target_path) + if not ok: + msg = f'Failed download {self.NAME} file: {err}' + logger.error(msg) + return None, msg + url = default_storage.url(local_path) + return local_path, url + + def get_file_path_url(self): + local_path, url = self.find_local() + if local_path is None: + local_path, url = self.download() + return local_path, url diff --git a/apps/common/storage/ftp_file.py b/apps/common/storage/ftp_file.py new file mode 100644 index 000000000..8cfd52e2c --- /dev/null +++ b/apps/common/storage/ftp_file.py @@ -0,0 +1,17 @@ +from terminal.models import default_storage +from .base import BaseStorageHandler + + +class FTPFileStorageHandler(BaseStorageHandler): + NAME = 'FTP' + + def get_file_path(self, **kwargs): + return self.obj.filepath, self.obj.filepath + + def find_local(self): + local_path = self.obj.filepath + # 去default storage中查找 + if default_storage.exists(local_path): + url = default_storage.url(local_path) + return local_path, url + return None, None diff --git a/apps/common/storage/replay.py b/apps/common/storage/replay.py new file mode 100644 index 000000000..3d84a234b --- /dev/null +++ b/apps/common/storage/replay.py @@ -0,0 +1,31 @@ +from itertools import chain + +from terminal.models import default_storage +from .base import BaseStorageHandler + + +class ReplayStorageHandler(BaseStorageHandler): + NAME = 'REPLAY' + + def get_file_path(self, **kwargs): + storage = kwargs['storage'] + # 获取外部存储路径名 + session_path = self.obj.find_ok_relative_path_in_storage(storage) + if not session_path: + return None + + # 通过外部存储路径名后缀,构造真实的本地存储路径 + return session_path, self.obj.get_local_path_by_relative_path(session_path) + + def find_local(self): + # 存在外部存储上,所有可能的路径名 + session_paths = self.obj.get_all_possible_relative_path() + + # 存在本地存储上,所有可能的路径名 + local_paths = self.obj.get_all_possible_local_path() + + for _local_path in chain(session_paths, local_paths): + if default_storage.exists(_local_path): + url = default_storage.url(_local_path) + return _local_path, url + return None, f'{self.NAME} not found.' diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 5ae50a407..1cb70f97a 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -548,6 +548,9 @@ class Config(dict): # Applet 等软件的下载地址 'APPLET_DOWNLOAD_HOST': '', + + # FTP 文件上传下载备份阈值,单位(M),当值小于等于0时,不备份 + 'FTP_FILE_MAX_STORE': 100, } def __init__(self, *args): diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index cf9880d45..78298db25 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -29,6 +29,7 @@ DEFAULT_TERMINAL_REPLAY_STORAGE = { }, } TERMINAL_REPLAY_STORAGE = CONFIG.TERMINAL_REPLAY_STORAGE +FTP_FILE_MAX_STORE = CONFIG.FTP_FILE_MAX_STORE # Security settings SECURITY_MFA_AUTH = CONFIG.SECURITY_MFA_AUTH diff --git a/apps/rbac/const.py b/apps/rbac/const.py index cfc3c1863..91ca727eb 100644 --- a/apps/rbac/const.py +++ b/apps/rbac/const.py @@ -91,7 +91,7 @@ exclude_permissions = ( ('audits', 'activitylog', 'add,delete,change', 'activitylog'), ('audits', 'passwordchangelog', 'add,change,delete', 'passwordchangelog'), ('audits', 'userloginlog', 'add,change,delete,change', 'userloginlog'), - ('audits', 'ftplog', 'change,delete', 'ftplog'), + ('audits', 'ftplog', 'delete', 'ftplog'), ('tickets', 'ticketassignee', '*', 'ticketassignee'), ('tickets', 'ticketflow', 'add,delete', 'ticketflow'), ('tickets', 'comment', '*', '*'), diff --git a/apps/terminal/api/session/session.py b/apps/terminal/api/session/session.py index 0661536f7..ab80293b1 100644 --- a/apps/terminal/api/session/session.py +++ b/apps/terminal/api/session/session.py @@ -22,15 +22,13 @@ from common.drf.renders import PassthroughRenderer from common.api import AsyncApiMixin from common.utils import data_to_json, is_uuid from common.utils import get_logger, get_object_or_none +from common.storage.replay import ReplayStorageHandler from rbac.permissions import RBACPermission from orgs.mixins.api import OrgBulkModelViewSet from orgs.utils import tmp_to_root_org, tmp_to_org from terminal import serializers from terminal.models import Session -from terminal.utils import ( - find_session_replay_local, download_session_replay, - is_session_approver, get_session_replay_url -) +from terminal.utils import is_session_approver from terminal.permissions import IsSessionAssignee from users.models import User @@ -112,20 +110,23 @@ class SessionViewSet(OrgBulkModelViewSet): os.chdir(current_dir) return file + def get_storage(self): + return ReplayStorageHandler(self.get_object()) + @action(methods=[GET], detail=True, renderer_classes=(PassthroughRenderer,), url_path='replay/download', url_name='replay-download') def download(self, request, *args, **kwargs): - session = self.get_object() - local_path, url = get_session_replay_url(session) + storage = self.get_storage() + local_path, url_or_err = storage.get_file_path_url() if local_path is None: - return Response({"error": url}, status=404) - file = self.prepare_offline_file(session, local_path) + return Response({'error': url_or_err}, status=404) + file = self.prepare_offline_file(storage.obj, local_path) response = FileResponse(file) response['Content-Type'] = 'application/octet-stream' # 这里要注意哦,网上查到的方法都是response['Content-Disposition']='attachment;filename="filename.py"', # 但是如果文件名是英文名没问题,如果文件名包含中文,下载下来的文件名会被改为url中的path。 - filename = escape_uri_path('{}.tar'.format(session.id)) + filename = escape_uri_path('{}.tar'.format(storage.obj.id)) disposition = "attachment; filename*=UTF-8''{}".format(filename) response["Content-Disposition"] = disposition return response @@ -208,13 +209,12 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet): def retrieve(self, request, *args, **kwargs): session_id = kwargs.get('pk') session = get_object_or_404(Session, id=session_id) - local_path, url = find_session_replay_local(session) - if not local_path: - local_path, url = download_session_replay(session) - if not local_path: - return Response({"error": url}, status=404) - data = self.get_replay_data(session, url) + storage = ReplayStorageHandler(session) + local_path, url_or_err = storage.get_file_path_url() + if url_or_err: + return Response({"error": url_or_err}, status=404) + data = self.get_replay_data(session, url_or_err) return Response(data) diff --git a/apps/terminal/models/component/terminal.py b/apps/terminal/models/component/terminal.py index 74364e06a..cc79212db 100644 --- a/apps/terminal/models/component/terminal.py +++ b/apps/terminal/models/component/terminal.py @@ -129,7 +129,8 @@ class Terminal(StorageMixin, TerminalStatusMixin, JMSBaseModel): configs.update(self.get_login_title_setting()) configs.update({ 'SECURITY_MAX_IDLE_TIME': settings.SECURITY_MAX_IDLE_TIME, - 'SECURITY_SESSION_SHARE': settings.SECURITY_SESSION_SHARE + 'SECURITY_SESSION_SHARE': settings.SECURITY_SESSION_SHARE, + 'FTP_FILE_MAX_STORE': settings.FTP_FILE_MAX_STORE, }) return configs diff --git a/apps/terminal/tasks.py b/apps/terminal/tasks.py index d53380923..e6f8a9140 100644 --- a/apps/terminal/tasks.py +++ b/apps/terminal/tasks.py @@ -10,6 +10,7 @@ from django.core.files.storage import default_storage from django.utils import timezone from django.utils.translation import gettext_lazy as _ +from common.storage.replay import ReplayStorageHandler from ops.celery.decorator import ( register_as_period_task, after_app_ready_start, after_app_shutdown_clean_periodic @@ -23,7 +24,6 @@ from .models import ( AppletHost, ReplayStorage, CommandStorage ) from .notifications import StorageConnectivityMessage -from .utils import find_session_replay_local CACHE_REFRESH_INTERVAL = 10 RUNNING = False @@ -66,7 +66,8 @@ def upload_session_replay_to_external_storage(session_id): logger.error(f'Session db item not found: {session_id}') return - local_path, foobar = find_session_replay_local(session) + replay_storage = ReplayStorageHandler(session) + local_path, url_or_err = replay_storage.find_local() if not local_path: logger.error(f'Session replay not found, may be upload error: {local_path}') return diff --git a/apps/terminal/utils/__init__.py b/apps/terminal/utils/__init__.py index b55827a8d..0110ad579 100644 --- a/apps/terminal/utils/__init__.py +++ b/apps/terminal/utils/__init__.py @@ -1,4 +1,3 @@ from .components import * from .common import * -from .session_replay import * from .db_port_mapper import * diff --git a/apps/terminal/utils/session_replay.py b/apps/terminal/utils/session_replay.py deleted file mode 100644 index 1e2bbad53..000000000 --- a/apps/terminal/utils/session_replay.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -# -import os -from itertools import groupby, chain - -from django.conf import settings -from django.core.files.storage import default_storage - -import jms_storage - -from common.utils import get_logger, make_dirs -from ..models import ReplayStorage - - -logger = get_logger(__name__) - - -def find_session_replay_local(session): - # 存在外部存储上,所有可能的路径名 - session_paths = session.get_all_possible_relative_path() - - # 存在本地存储上,所有可能的路径名 - local_paths = session.get_all_possible_local_path() - - for _local_path in chain(session_paths, local_paths): - if default_storage.exists(_local_path): - url = default_storage.url(_local_path) - return _local_path, url - return None, None - - -def download_session_replay(session): - replay_storages = ReplayStorage.objects.all() - configs = { - storage.name: storage.config - for storage in replay_storages - if not storage.type_null_or_server - } - if settings.SERVER_REPLAY_STORAGE: - configs['SERVER_REPLAY_STORAGE'] = settings.SERVER_REPLAY_STORAGE - if not configs: - msg = "Not found replay file, and not remote storage set" - return None, msg - storage = jms_storage.get_multi_object_storage(configs) - - # 获取外部存储路径名 - session_path = session.find_ok_relative_path_in_storage(storage) - if not session_path: - msg = "Not found session replay file" - return None, msg - - # 通过外部存储路径名后缀,构造真实的本地存储路径 - local_path = session.get_local_path_by_relative_path(session_path) - - # 保存到storage的路径 - target_path = os.path.join(default_storage.base_location, local_path) - target_dir = os.path.dirname(target_path) - if not os.path.isdir(target_dir): - make_dirs(target_dir, exist_ok=True) - - ok, err = storage.download(session_path, target_path) - if not ok: - msg = "Failed download replay file: {}".format(err) - logger.error(msg) - return None, msg - url = default_storage.url(local_path) - return local_path, url - - -def get_session_replay_url(session): - local_path, url = find_session_replay_local(session) - if local_path is None: - local_path, url = download_session_replay(session) - return local_path, url - From 1c95b6715412789dc1970c198af1f56e64bdadd2 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 8 Jun 2023 18:19:32 +0800 Subject: [PATCH 087/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20LoginACL?= =?UTF-8?q?=20=E8=BF=81=E7=A7=BB=EF=BC=8C=E9=81=BF=E5=85=8D=20uniq=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/migrations/0016_auto_20230606_1857.py | 8 ++++++++ apps/acls/models/login_acl.py | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/acls/migrations/0016_auto_20230606_1857.py b/apps/acls/migrations/0016_auto_20230606_1857.py index 305f0e49b..2838b5d1f 100644 --- a/apps/acls/migrations/0016_auto_20230606_1857.py +++ b/apps/acls/migrations/0016_auto_20230606_1857.py @@ -1,4 +1,5 @@ # Generated by Django 3.2.17 on 2023-06-06 10:57 +from collections import defaultdict from django.db import migrations, models @@ -7,7 +8,13 @@ import common.db.fields def migrate_users_login_acls(apps, schema_editor): login_acl_model = apps.get_model('acls', 'LoginACL') + name_used = defaultdict(int) + for login_acl in login_acl_model.objects.all(): + name = login_acl.name + if name_used[name] > 0: + login_acl.name += "_{}".format(name_used[name]) + name_used[name] += 1 login_acl.users = { "type": "ids", "ids": [str(login_acl.user_id)] } @@ -25,6 +32,7 @@ class Migration(migrations.Migration): name='users', field=common.db.fields.JSONManyToManyField(default=dict, to='users.User', verbose_name='Users'), ), + migrations.RunPython(migrate_users_login_acls), migrations.RemoveField( model_name='loginacl', name='user', diff --git a/apps/acls/models/login_acl.py b/apps/acls/models/login_acl.py index 68e6aa22a..80f5357ea 100644 --- a/apps/acls/models/login_acl.py +++ b/apps/acls/models/login_acl.py @@ -28,14 +28,14 @@ class LoginACL(UserBaseACL): from tickets import const from tickets.models import ApplyLoginTicket from orgs.models import Organization - title = _('Login confirm') + ' {}'.format(self.user) + title = _('Login confirm') + ' {}'.format(request.user) login_ip = get_request_ip(request) if request else '' login_ip = login_ip or '0.0.0.0' login_city = get_ip_city(login_ip) login_datetime = local_now_display() data = { 'title': title, - 'applicant': self.user, + 'applicant': request.user, 'apply_login_ip': login_ip, 'org_id': Organization.ROOT_ID, 'apply_login_city': login_city, From 998505e99985f696ce341da3c79e28e20b6ac66f Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 8 Jun 2023 18:33:43 +0800 Subject: [PATCH 088/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20acl=20?= =?UTF-8?q?=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/models/base.py | 4 ++-- apps/acls/models/login_acl.py | 4 ---- apps/authentication/mixins.py | 2 +- apps/common/db/fields.py | 6 +++++- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 0fe16d7d1..05994e4d2 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -90,7 +90,7 @@ class UserBaseACL(BaseACL): queryset = cls.objects.all() q = cls.users.get_filter_q(user) queryset = queryset.filter(q) - return queryset.valid().distinct() + return queryset.filter(is_active=True).distinct() class UserAssetAccountBaseACL(UserBaseACL, OrgModelMixin): @@ -125,4 +125,4 @@ class UserAssetAccountBaseACL(UserBaseACL, OrgModelMixin): kwargs['org_id'] = org_id if kwargs: queryset = queryset.filter(**kwargs) - return queryset.valid().distinct().order_by('priority', 'date_created') + return queryset.filter(is_active=True).distinct().order_by('priority', 'date_created') diff --git a/apps/acls/models/login_acl.py b/apps/acls/models/login_acl.py index 80f5357ea..ce678e236 100644 --- a/apps/acls/models/login_acl.py +++ b/apps/acls/models/login_acl.py @@ -20,10 +20,6 @@ class LoginACL(UserBaseACL): def is_action(self, action): return self.action == action - @classmethod - def filter_acl(cls, user): - return user.login_acls.all().valid().distinct() - def create_confirm_ticket(self, request): from tickets import const from tickets.models import ApplyLoginTicket diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index c1fb2720d..d3d84f560 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -369,7 +369,7 @@ class AuthACLMixin: logger.debug('Login confirm acl id: {}'.format(acl_id)) if not acl_id: return - acl = LoginACL.filter_acl(user).filter(id=acl_id).first() + acl = LoginACL.get_user_acls(user).filter(id=acl_id).first() if not acl: return if not acl.is_action(acl.ActionChoices.review): diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index bc0795eab..adc3a3b89 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -10,7 +10,7 @@ from django.apps import apps from django.core.exceptions import ValidationError from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models -from django.db.models import Q, Manager +from django.db.models import Q, Manager, QuerySet from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ from rest_framework.utils.encoders import JSONEncoder @@ -486,6 +486,10 @@ class JSONManyToManyDescriptor: elif rule['match'] == 'm2m': if isinstance(value, Manager): value = value.values_list('id', flat=True) + elif isinstance(value, QuerySet): + value = value.values_list('id', flat=True) + elif isinstance(value, models.Model): + value = [value.id] value = set(map(str, value)) rule_value = set(map(str, rule_value)) res &= rule_value.issubset(value) From 3022ca983c6ce70bc645047f59488fb80074841d Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 8 Jun 2023 22:03:45 +0800 Subject: [PATCH 089/153] =?UTF-8?q?perf:=20Dockerfile=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 1 + Dockerfile.loong64 | 1 + 2 files changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 4cad1e0bd..a501e06c6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,6 +27,7 @@ ARG DEPENDENCIES=" \ libxml2-dev \ libxmlsec1-dev \ libxmlsec1-openssl \ + freerdp2-dev \ libaio-dev" ARG TOOLS=" \ diff --git a/Dockerfile.loong64 b/Dockerfile.loong64 index 2de68d742..7e3f4bda2 100644 --- a/Dockerfile.loong64 +++ b/Dockerfile.loong64 @@ -28,6 +28,7 @@ ARG DEPENDENCIES=" \ libxml2-dev \ libxmlsec1-dev \ libxmlsec1-openssl \ + freerdp2-dev \ libaio-dev" ARG TOOLS=" \ From 6a73cd6b77c8d45b4ac686ec3240ce893f3ec3ba Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 9 Jun 2023 15:40:41 +0800 Subject: [PATCH 090/153] =?UTF-8?q?perf:=20=E6=B7=BB=E5=8A=A0=20edition=20?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 419 ++++++++++-------- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 413 +++++++++-------- .../migrations/0062_applet_edition.py | 18 + apps/terminal/models/applet/applet.py | 6 + apps/terminal/serializers/applet.py | 5 +- 7 files changed, 497 insertions(+), 372 deletions(-) create mode 100644 apps/terminal/migrations/0062_applet_edition.py diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 7e5717517..30c105fcf 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a93b6a850b251ea2ee17b6b9dbdee93130f745ce8278faaecbf60d74f934f1b5 -size 143780 +oid sha256:7db1805061d28a0ba931846140e9f106b71ed5ebeb414f741b68d6c3d93130be +size 142961 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 1e83ad711..9688219e7 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 18:12+0800\n" +"POT-Creation-Date: 2023-06-09 10:59+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -71,7 +71,7 @@ msgid "Collected" msgstr "集めました" #: accounts/const/account.py:21 accounts/serializers/account/account.py:26 -#: settings/serializers/auth/sms.py:76 +#: settings/serializers/auth/sms.py:75 msgid "Template" msgstr "テンプレート" @@ -79,13 +79,13 @@ msgstr "テンプレート" msgid "Skip" msgstr "スキップ" -#: accounts/const/account.py:26 audits/const.py:23 rbac/tree.py:229 +#: accounts/const/account.py:26 audits/const.py:24 rbac/tree.py:229 #: templates/_csv_import_export.html:18 templates/_csv_update_modal.html:6 msgid "Update" msgstr "更新" #: accounts/const/account.py:27 -#: accounts/serializers/automations/change_secret.py:156 audits/const.py:53 +#: accounts/serializers/automations/change_secret.py:156 audits/const.py:54 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 #: ops/const.py:58 terminal/const.py:61 xpack/plugins/cloud/const.py:41 msgid "Failed" @@ -186,10 +186,10 @@ msgstr "作成のみ" #: accounts/serializers/account/gathered_account.py:10 #: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:132 -#: acls/serializers/base.py:76 assets/models/asset/common.py:93 +#: acls/serializers/base.py:118 assets/models/asset/common.py:93 #: assets/models/asset/common.py:332 assets/models/cmd_filter.py:36 #: assets/serializers/domain.py:19 assets/serializers/label.py:27 -#: audits/models.py:48 authentication/models/connection_token.py:34 +#: audits/models.py:53 authentication/models/connection_token.py:34 #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 @@ -206,7 +206,7 @@ msgid "Su from" msgstr "から切り替え" #: accounts/models/account.py:55 settings/serializers/auth/cas.py:20 -#: settings/serializers/auth/feishu.py:20 terminal/models/applet/applet.py:30 +#: settings/serializers/auth/feishu.py:20 terminal/models/applet/applet.py:34 msgid "Version" msgstr "バージョン" @@ -222,8 +222,8 @@ msgstr "ソース ID" #: accounts/models/account.py:61 #: accounts/serializers/automations/change_secret.py:113 #: accounts/serializers/automations/change_secret.py:133 -#: acls/serializers/base.py:77 assets/serializers/asset/common.py:125 -#: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 +#: acls/serializers/base.py:119 assets/serializers/asset/common.py:125 +#: assets/serializers/gateway.py:28 audits/models.py:54 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: terminal/backends/command/models.py:21 terminal/models/session/session.py:34 #: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 @@ -275,7 +275,7 @@ msgid "Account backup plan" msgstr "アカウントバックアップ計画" #: accounts/models/automations/backup_account.py:83 -#: assets/models/automations/base.py:115 audits/models.py:55 +#: assets/models/automations/base.py:115 audits/models.py:60 #: ops/models/base.py:55 ops/models/celery.py:63 ops/models/job.py:192 #: ops/templates/ops/celery_task_log.html:75 #: perms/models/asset_permission.py:72 terminal/models/applet/host.py:137 @@ -303,7 +303,7 @@ msgstr "アカウントのバックアップスナップショット" msgid "Trigger mode" msgstr "トリガーモード" -#: accounts/models/automations/backup_account.py:97 audits/models.py:172 +#: accounts/models/automations/backup_account.py:97 audits/models.py:194 #: terminal/models/session/sharing.py:111 xpack/plugins/cloud/models.py:168 msgid "Reason" msgstr "理由" @@ -426,8 +426,8 @@ msgstr "最終ログイン日" #: accounts/models/automations/gather_account.py:17 #: accounts/models/automations/push_account.py:15 accounts/models/base.py:34 -#: acls/serializers/base.py:19 acls/serializers/base.py:50 -#: assets/models/_user.py:23 audits/models.py:157 authentication/forms.py:25 +#: acls/serializers/base.py:18 acls/serializers/base.py:49 +#: assets/models/_user.py:23 audits/models.py:179 authentication/forms.py:25 #: authentication/forms.py:27 authentication/models/temp_token.py:9 #: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_oauth_bind.html:9 @@ -459,8 +459,8 @@ msgid "Triggers" msgstr "トリガー方式" #: accounts/models/automations/push_account.py:16 acls/models/base.py:43 -#: acls/serializers/base.py:57 assets/models/cmd_filter.py:81 -#: audits/models.py:65 audits/serializers.py:82 +#: acls/serializers/base.py:56 assets/models/cmd_filter.py:81 +#: audits/models.py:87 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:116 #: authentication/templates/authentication/_access_key_modal.html:34 msgid "Action" @@ -474,8 +474,8 @@ msgstr "アカウントプッシュ" msgid "Verify asset account" msgstr "アカウントの確認" -#: accounts/models/base.py:33 acls/models/base.py:37 -#: acls/models/command_acl.py:21 acls/serializers/base.py:35 +#: accounts/models/base.py:33 acls/models/base.py:37 acls/models/base.py:97 +#: acls/models/command_acl.py:21 acls/serializers/base.py:34 #: applications/models.py:9 assets/models/_user.py:22 #: assets/models/asset/common.py:91 assets/models/asset/common.py:149 #: assets/models/cmd_filter.py:21 assets/models/domain.py:18 @@ -488,7 +488,7 @@ msgstr "アカウントの確認" #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 #: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29 #: settings/models.py:33 settings/serializers/sms.py:6 -#: terminal/models/applet/applet.py:28 terminal/models/component/endpoint.py:12 +#: terminal/models/applet/applet.py:32 terminal/models/component/endpoint.py:12 #: terminal/models/component/endpoint.py:90 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:15 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33 @@ -505,7 +505,7 @@ msgstr "特権アカウント" #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:114 -#: terminal/models/applet/applet.py:33 users/serializers/user.py:170 +#: terminal/models/applet/applet.py:38 users/serializers/user.py:170 msgid "Is active" msgstr "アクティブです。" @@ -575,7 +575,7 @@ msgstr "カテゴリ" #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 #: assets/serializers/platform.py:109 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 -#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:32 +#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:37 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/serializers/session.py:22 terminal/serializers/storage.py:224 @@ -607,7 +607,7 @@ msgid "Changed" msgstr "編集済み" #: accounts/serializers/account/account.py:249 -#: accounts/serializers/automations/base.py:22 acls/models/base.py:84 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:98 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -629,16 +629,15 @@ msgid "Account has exist" msgstr "アカウントはすでに存在しています" #: accounts/serializers/account/account.py:417 -#: authentication/serializers/connect_token_secret.py:154 +#: authentication/serializers/connect_token_secret.py:156 #: authentication/templates/authentication/_access_key_modal.html:30 #: perms/models/perm_node.py:21 users/serializers/group.py:33 msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:424 acls/models/login_acl.py:12 -#: acls/serializers/base.py:75 acls/serializers/login_acl.py:21 -#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:44 -#: audits/models.py:63 audits/models.py:141 +#: accounts/serializers/account/account.py:424 acls/serializers/base.py:111 +#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:49 +#: audits/models.py:85 audits/models.py:163 #: authentication/models/connection_token.py:30 #: authentication/models/sso_token.py:16 #: notifications/models/notification.py:12 @@ -727,8 +726,8 @@ msgstr "* パスワードの長さの範囲6-30ビット" msgid "Automation task execution" msgstr "自動タスク実行履歴" -#: accounts/serializers/automations/change_secret.py:155 audits/const.py:52 -#: audits/models.py:54 audits/signal_handlers/activity_log.py:33 +#: accounts/serializers/automations/change_secret.py:155 audits/const.py:53 +#: audits/models.py:59 audits/signal_handlers/activity_log.py:33 #: common/const/choices.py:18 ops/const.py:56 ops/serializers/celery.py:40 #: terminal/const.py:60 terminal/models/session/sharing.py:107 #: tickets/views/approve.py:114 @@ -802,14 +801,13 @@ msgstr "優先順位" msgid "1-100, the lower the value will be match first" msgstr "1-100、低い値は最初に一致します" -#: acls/models/base.py:44 acls/serializers/base.py:79 -#: acls/serializers/login_acl.py:23 assets/models/cmd_filter.py:86 +#: acls/models/base.py:44 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "レビュー担当者" #: acls/models/base.py:45 authentication/models/access_key.py:17 -#: authentication/models/connection_token.py:50 +#: authentication/models/connection_token.py:51 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 #: tickets/const.py:37 @@ -820,7 +818,7 @@ msgstr "アクティブ" msgid "Users" msgstr "ユーザー" -#: acls/models/base.py:85 assets/models/automations/base.py:17 +#: acls/models/base.py:99 assets/models/automations/base.py:17 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 #: rbac/tree.py:35 msgid "Accounts" @@ -839,7 +837,7 @@ msgid "Regex" msgstr "正規情報" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 msgid "Content" msgstr "コンテンツ" @@ -869,16 +867,22 @@ msgstr "コマンドフィルタリング" msgid "Command confirm" msgstr "コマンドの確認" -#: acls/models/login_acl.py:15 acls/models/login_asset_acl.py:9 -#: acls/serializers/login_acl.py:28 acls/serializers/login_asset_acl.py:13 +#: acls/models/connect_method.py:10 +#, fuzzy +#| msgid "Connect method" +msgid "Connect methods" +msgstr "接続方法" + +#: acls/models/login_acl.py:11 acls/models/login_asset_acl.py:9 +#: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:13 msgid "Rule" msgstr "ルール" -#: acls/models/login_acl.py:18 +#: acls/models/login_acl.py:14 msgid "Login acl" msgstr "ログインacl" -#: acls/models/login_acl.py:39 tickets/const.py:10 +#: acls/models/login_acl.py:27 tickets/const.py:10 msgid "Login confirm" msgstr "ログイン確認" @@ -890,11 +894,11 @@ msgstr "ログインasset acl" msgid "Login asset confirm" msgstr "ログイン資産の確認" -#: acls/serializers/base.py:11 acls/serializers/login_acl.py:16 +#: acls/serializers/base.py:10 acls/serializers/login_acl.py:11 msgid "With * indicating a match all. " msgstr "* はすべて一致することを示します。" -#: acls/serializers/base.py:26 +#: acls/serializers/base.py:25 msgid "" "With * indicating a match all. Such as: 192.168.10.1, 192.168.1.0/24, " "10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64 (Domain name " @@ -904,19 +908,15 @@ msgstr "" "10.1.1.1-10.1.1.20、2001:db8:2de::e13、2001:db8:1a:1110:::/64 (ドメイン名サ" "ポート)" -#: acls/serializers/base.py:41 assets/serializers/asset/host.py:19 +#: acls/serializers/base.py:40 assets/serializers/asset/host.py:19 msgid "IP/Host" msgstr "IP/ホスト" -#: acls/serializers/base.py:82 acls/serializers/login_acl.py:26 -msgid "Reviewers amount" -msgstr "承認者数" - -#: acls/serializers/base.py:108 tickets/serializers/ticket/ticket.py:77 +#: acls/serializers/base.py:98 tickets/serializers/ticket/ticket.py:77 msgid "The organization `{}` does not exist" msgstr "組織 '{}'は存在しません" -#: acls/serializers/base.py:114 +#: acls/serializers/base.py:104 msgid "None of the reviewers belong to Organization `{}`" msgstr "いずれのレビューアも組織 '{}' に属していません" @@ -988,6 +988,10 @@ msgstr "ルートノード ({}) を削除できません。" msgid "Deletion failed and the node contains assets" msgstr "削除に失敗し、ノードにアセットが含まれています。" +#: assets/api/tree.py:49 assets/serializers/node.py:41 +msgid "The same level node name cannot be the same" +msgstr "同じレベルのノード名を同じにすることはできません。" + #: assets/apps.py:9 msgid "App assets" msgstr "アプリ資産" @@ -997,7 +1001,7 @@ msgid "{} disabled" msgstr "{} 無効" #: assets/automations/ping_gateway/manager.py:33 -#: authentication/models/connection_token.py:115 +#: authentication/models/connection_token.py:116 msgid "No account" msgstr "アカウントなし" @@ -1020,7 +1024,7 @@ msgstr "認証に失敗しました" msgid "Connect failed" msgstr "接続に失敗しました" -#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:35 +#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:36 #: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31 #: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104 msgid "Unknown" @@ -1043,7 +1047,7 @@ msgid "Gather facts" msgstr "資産情報の収集" #: assets/const/category.py:10 assets/models/asset/host.py:8 -#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:68 +#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 #: xpack/plugins/cloud/serializers/account_attrs.py:72 msgid "Host" @@ -1062,7 +1066,7 @@ msgstr "データベース" msgid "Cloud service" msgstr "クラウド サービス" -#: assets/const/category.py:14 assets/models/asset/web.py:16 audits/const.py:33 +#: assets/const/category.py:14 assets/models/asset/web.py:16 audits/const.py:34 #: terminal/models/applet/applet.py:26 msgid "Web" msgstr "Web" @@ -1112,7 +1116,7 @@ msgstr "いろんなタイプ" msgid "Website" msgstr "Webサイト" -#: assets/const/web.py:59 audits/const.py:46 +#: assets/const/web.py:59 audits/const.py:47 #: terminal/serializers/applet_host.py:28 msgid "Disabled" msgstr "無効" @@ -1142,7 +1146,7 @@ msgstr "SSHパブリックキー" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:38 terminal/models/applet/applet.py:237 +#: terminal/models/applet/applet.py:43 terminal/models/applet/applet.py:242 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 @@ -1192,7 +1196,7 @@ msgstr "ユーザーと同じユーザー名" #: assets/models/_user.py:52 authentication/models/connection_token.py:39 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:35 terminal/serializers/session.py:20 +#: terminal/models/applet/applet.py:40 terminal/serializers/session.py:20 #: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "プロトコル" @@ -1246,7 +1250,7 @@ msgid "Cloud" msgstr "クラウド サービス" #: assets/models/asset/common.py:92 assets/models/platform.py:14 -#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:69 +#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "ポート" @@ -1258,7 +1262,7 @@ msgstr "アドレス" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:196 +#: xpack/plugins/cloud/serializers/account_attrs.py:187 msgid "Platform" msgstr "プラットフォーム" @@ -1339,7 +1343,7 @@ msgid "Submit selector" msgstr "ボタンセレクターを確認する" #: assets/models/automations/base.py:22 ops/models/job.py:187 -#: settings/serializers/auth/sms.py:100 +#: settings/serializers/auth/sms.py:99 msgid "Parameters" msgstr "パラメータ" @@ -1351,9 +1355,9 @@ msgstr "自動化されたタスク" msgid "Asset automation task" msgstr "アセットの自動化タスク" -#: assets/models/automations/base.py:113 audits/models.py:177 +#: assets/models/automations/base.py:113 audits/models.py:199 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:236 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:241 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 @@ -1497,7 +1501,7 @@ msgstr "開ける" msgid "Setting" msgstr "設定" -#: assets/models/platform.py:31 audits/const.py:47 settings/models.py:37 +#: assets/models/platform.py:31 audits/const.py:48 settings/models.py:37 #: terminal/serializers/applet_host.py:29 msgid "Enabled" msgstr "有効化" @@ -1724,10 +1728,6 @@ msgstr "値" msgid "Can't contains: /" msgstr "含まれない:/" -#: assets/serializers/node.py:41 -msgid "The same level node name cannot be the same" -msgstr "同じレベルのノード名を同じにすることはできません。" - #: assets/serializers/platform.py:26 msgid "SFTP enabled" msgstr "SFTP が有効" @@ -1860,7 +1860,7 @@ msgstr "Mkdir" msgid "Rmdir" msgstr "Rmdir" -#: audits/const.py:14 audits/const.py:24 +#: audits/const.py:14 audits/const.py:25 #: authentication/templates/authentication/_access_key_modal.html:65 #: perms/const.py:17 rbac/tree.py:230 msgid "Delete" @@ -1882,54 +1882,60 @@ msgstr "Symlink" msgid "Download" msgstr "ダウンロード" -#: audits/const.py:22 rbac/tree.py:228 +#: audits/const.py:19 +#, fuzzy +#| msgid "Rename attr" +msgid "Rename dir" +msgstr "マッピングのプロパティ" + +#: audits/const.py:23 rbac/tree.py:228 msgid "View" msgstr "表示" -#: audits/const.py:25 +#: audits/const.py:26 #: authentication/templates/authentication/_access_key_modal.html:22 #: rbac/tree.py:227 msgid "Create" msgstr "作成" -#: audits/const.py:27 perms/const.py:12 +#: audits/const.py:28 perms/const.py:12 msgid "Connect" msgstr "接続" -#: audits/const.py:28 authentication/templates/authentication/login.html:240 +#: audits/const.py:29 authentication/templates/authentication/login.html:240 #: authentication/templates/authentication/login.html:313 #: templates/_header_bar.html:89 msgid "Login" msgstr "ログイン" -#: audits/const.py:29 ops/const.py:9 +#: audits/const.py:30 ops/const.py:9 msgid "Change password" msgstr "パスワードを変更する" -#: audits/const.py:34 settings/serializers/terminal.py:6 -#: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:162 +#: audits/const.py:35 settings/serializers/terminal.py:6 +#: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:163 #: terminal/serializers/session.py:48 msgid "Terminal" msgstr "ターミナル" -#: audits/const.py:39 audits/models.py:105 +#: audits/const.py:40 audits/models.py:127 msgid "Operate log" msgstr "ログの操作" -#: audits/const.py:40 +#: audits/const.py:41 msgid "Session log" msgstr "セッションログ" -#: audits/const.py:41 +#: audits/const.py:42 msgid "Login log" msgstr "ログインログ" -#: audits/const.py:42 terminal/models/applet/host.py:140 +#: audits/const.py:43 terminal/models/applet/host.py:140 #: terminal/models/component/task.py:24 msgid "Task" msgstr "タスク" -#: audits/const.py:48 +#: audits/const.py:49 msgid "-" msgstr "-" @@ -1941,99 +1947,111 @@ msgstr "是" msgid "No" msgstr "否" -#: audits/models.py:39 +#: audits/models.py:42 msgid "Job audit log" msgstr "ジョブ監査ログ" -#: audits/models.py:46 audits/models.py:73 audits/models.py:144 +#: audits/models.py:51 audits/models.py:95 audits/models.py:166 #: terminal/models/session/session.py:39 terminal/models/session/sharing.py:99 msgid "Remote addr" msgstr "リモートaddr" -#: audits/models.py:51 audits/serializers.py:33 +#: audits/models.py:56 audits/serializers.py:33 msgid "Operate" msgstr "操作" -#: audits/models.py:53 +#: audits/models.py:58 msgid "Filename" msgstr "ファイル名" -#: audits/models.py:58 +#: audits/models.py:61 +msgid "File Record" +msgstr "" + +#: audits/models.py:62 terminal/backends/command/models.py:24 +#: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18 +#: terminal/models/session/sharing.py:81 +#: terminal/templates/terminal/_msg_command_alert.html:10 +#: tickets/models/ticket/command_confirm.py:15 +msgid "Session" +msgstr "セッション" + +#: audits/models.py:65 msgid "File transfer log" msgstr "ファイル転送ログ" -#: audits/models.py:67 audits/serializers.py:84 +#: audits/models.py:89 audits/serializers.py:84 msgid "Resource Type" msgstr "リソースタイプ" -#: audits/models.py:68 audits/models.py:71 audits/models.py:117 +#: audits/models.py:90 audits/models.py:93 audits/models.py:139 #: audits/serializers.py:83 msgid "Resource" msgstr "リソース" -#: audits/models.py:74 audits/models.py:120 audits/models.py:146 +#: audits/models.py:96 audits/models.py:142 audits/models.py:168 #: terminal/serializers/command.py:50 msgid "Datetime" msgstr "時間" -#: audits/models.py:113 +#: audits/models.py:135 msgid "Activity type" msgstr "活動の種類" -#: audits/models.py:123 +#: audits/models.py:145 msgid "Detail" msgstr "詳細" -#: audits/models.py:126 +#: audits/models.py:148 msgid "Detail ID" msgstr "詳細 ID" -#: audits/models.py:130 +#: audits/models.py:152 msgid "Activity log" msgstr "活動記録" -#: audits/models.py:142 +#: audits/models.py:164 msgid "Change by" msgstr "による変更" -#: audits/models.py:152 +#: audits/models.py:174 msgid "Password change log" msgstr "パスワード変更ログ" -#: audits/models.py:159 +#: audits/models.py:181 msgid "Login type" msgstr "ログインタイプ" -#: audits/models.py:161 tickets/models/ticket/login_confirm.py:10 +#: audits/models.py:183 tickets/models/ticket/login_confirm.py:10 msgid "Login IP" msgstr "ログインIP" -#: audits/models.py:163 +#: audits/models.py:185 #: authentication/templates/authentication/_msg_different_city.html:11 #: tickets/models/ticket/login_confirm.py:11 msgid "Login city" msgstr "ログイン都市" -#: audits/models.py:166 audits/serializers.py:63 +#: audits/models.py:188 audits/serializers.py:63 msgid "User agent" msgstr "ユーザーエージェント" -#: audits/models.py:169 audits/serializers.py:47 +#: audits/models.py:191 audits/serializers.py:47 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 #: users/forms/profile.py:65 users/models/user.py:776 #: users/serializers/profile.py:126 msgid "MFA" msgstr "MFA" -#: audits/models.py:179 +#: audits/models.py:201 msgid "Date login" msgstr "日付ログイン" -#: audits/models.py:181 audits/serializers.py:65 +#: audits/models.py:203 audits/serializers.py:65 msgid "Authentication backend" msgstr "認証バックエンド" -#: audits/models.py:225 +#: audits/models.py:247 msgid "User login log" msgstr "ユーザーログインログ" @@ -2100,10 +2118,16 @@ msgstr "DingTalk" msgid "Temporary token" msgstr "仮パスワード" -#: audits/tasks.py:90 +#: audits/tasks.py:101 msgid "Clean audits session task log" msgstr "監査セッション タスク ログのクリーンアップ" +#: audits/tasks.py:114 +#, fuzzy +#| msgid "Upload session replay to external storage" +msgid "Upload FTP file to external storage" +msgstr "セッションの記録を外部ストレージにアップロードする" + #: authentication/api/confirm.py:40 msgid "This action require verify your MFA" msgstr "この操作には、MFAを検証する必要があります" @@ -2520,55 +2544,61 @@ msgid "Connect method" msgstr "接続方法" #: authentication/models/connection_token.py:41 +#, fuzzy +#| msgid "Connections" +msgid "Connect options" +msgstr "接続" + +#: authentication/models/connection_token.py:42 #: rbac/serializers/rolebinding.py:21 msgid "User display" msgstr "ユーザー表示" -#: authentication/models/connection_token.py:42 +#: authentication/models/connection_token.py:43 msgid "Asset display" msgstr "アセット名" -#: authentication/models/connection_token.py:43 +#: authentication/models/connection_token.py:44 msgid "Reusable" msgstr "再利用可能" -#: authentication/models/connection_token.py:44 +#: authentication/models/connection_token.py:45 #: authentication/models/temp_token.py:13 perms/models/asset_permission.py:74 #: tickets/models/ticket/apply_application.py:31 #: tickets/models/ticket/apply_asset.py:20 users/models/user.py:797 msgid "Date expired" msgstr "期限切れの日付" -#: authentication/models/connection_token.py:48 +#: authentication/models/connection_token.py:49 #: perms/models/asset_permission.py:77 msgid "From ticket" msgstr "チケットから" -#: authentication/models/connection_token.py:54 +#: authentication/models/connection_token.py:55 msgid "Connection token" msgstr "接続トークン" -#: authentication/models/connection_token.py:56 +#: authentication/models/connection_token.py:57 msgid "Can view connection token secret" msgstr "接続トークンの秘密を表示できます" -#: authentication/models/connection_token.py:103 +#: authentication/models/connection_token.py:104 msgid "Connection token inactive" msgstr "接続トークンがアクティブ化されていません" -#: authentication/models/connection_token.py:106 +#: authentication/models/connection_token.py:107 msgid "Connection token expired at: {}" msgstr "接続トークンの有効期限: {}" -#: authentication/models/connection_token.py:109 +#: authentication/models/connection_token.py:110 msgid "No user or invalid user" msgstr "ユーザーなしまたは期限切れのユーザー" -#: authentication/models/connection_token.py:112 +#: authentication/models/connection_token.py:113 msgid "No asset or inactive asset" msgstr "アセットがないか、有効化されていないアセット" -#: authentication/models/connection_token.py:264 +#: authentication/models/connection_token.py:265 msgid "Super connection token" msgstr "スーパー接続トークン" @@ -3090,26 +3120,26 @@ msgstr "テキストフィールドへのマーシャルデータ" msgid "Encrypt field using Secret Key" msgstr "Secret Keyを使用したフィールドの暗号化" -#: common/db/fields.py:535 +#: common/db/fields.py:539 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" -#: common/db/fields.py:542 +#: common/db/fields.py:546 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "無効なタイプです。all、ids、またはattrsでなければなりません" -#: common/db/fields.py:545 +#: common/db/fields.py:549 msgid "Invalid ids for ids, should be a list" msgstr "無効なID、リストでなければなりません" -#: common/db/fields.py:548 common/db/fields.py:551 +#: common/db/fields.py:552 common/db/fields.py:555 msgid "Invalid attrs, should be a list of dict" msgstr "無効な属性、dictリストでなければなりません" -#: common/db/fields.py:553 +#: common/db/fields.py:557 msgid "Invalid attrs, should be has name and value" msgstr "名前と値が必要な無効な属性" @@ -3783,7 +3813,7 @@ msgstr "組織" msgid "Org name" msgstr "組織名" -#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:34 +#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:39 msgid "Builtin" msgstr "ビルトイン" @@ -4028,7 +4058,7 @@ msgstr "パーマ" msgid "Users amount" msgstr "ユーザー数" -#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:29 +#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:33 msgid "Display name" msgstr "表示名" @@ -4092,8 +4122,8 @@ msgstr "タスクセンター" msgid "My assets" msgstr "私の資産" -#: rbac/tree.py:56 terminal/models/applet/applet.py:45 -#: terminal/models/applet/applet.py:233 terminal/models/applet/host.py:28 +#: rbac/tree.py:56 terminal/models/applet/applet.py:50 +#: terminal/models/applet/applet.py:238 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "リモートアプリケーション" @@ -4520,46 +4550,46 @@ msgstr "SMSの有効化" msgid "SMS provider / Protocol" msgstr "SMSプロバイダ / プロトコル" -#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:46 -#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 -#: settings/serializers/auth/sms.py:74 settings/serializers/email.py:69 +#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:45 +#: settings/serializers/auth/sms.py:53 settings/serializers/auth/sms.py:62 +#: settings/serializers/auth/sms.py:73 settings/serializers/email.py:69 msgid "Signature" msgstr "署名" -#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:47 -#: settings/serializers/auth/sms.py:55 settings/serializers/auth/sms.py:64 +#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:46 +#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 msgid "Template code" msgstr "テンプレートコード" -#: settings/serializers/auth/sms.py:32 +#: settings/serializers/auth/sms.py:31 msgid "Test phone" msgstr "テスト電話" -#: settings/serializers/auth/sms.py:61 +#: settings/serializers/auth/sms.py:60 msgid "App Access Address" msgstr "アプリケーションアドレス" -#: settings/serializers/auth/sms.py:62 +#: settings/serializers/auth/sms.py:61 msgid "Signature channel number" msgstr "署名チャネル番号" -#: settings/serializers/auth/sms.py:70 +#: settings/serializers/auth/sms.py:69 msgid "Enterprise code(SP id)" msgstr "企業コード(SP id)" -#: settings/serializers/auth/sms.py:71 +#: settings/serializers/auth/sms.py:70 msgid "Shared secret(Shared secret)" msgstr "パスワードを共有する(Shared secret)" -#: settings/serializers/auth/sms.py:72 +#: settings/serializers/auth/sms.py:71 msgid "Original number(Src id)" msgstr "元の番号(Src id)" -#: settings/serializers/auth/sms.py:73 +#: settings/serializers/auth/sms.py:72 msgid "Business type(Service id)" msgstr "ビジネス・タイプ(Service id)" -#: settings/serializers/auth/sms.py:77 +#: settings/serializers/auth/sms.py:76 #, python-brace-format msgid "" "Template need contain {code} and Signature + template length does not exceed " @@ -4570,24 +4600,24 @@ msgstr "" "満です。たとえば、認証コードは{code}で、有効期間は5分です。他の人には言わない" "でください。" -#: settings/serializers/auth/sms.py:86 +#: settings/serializers/auth/sms.py:85 #, python-brace-format msgid "The template needs to contain {code}" msgstr "テンプレートには{code}を含める必要があります" -#: settings/serializers/auth/sms.py:89 +#: settings/serializers/auth/sms.py:88 msgid "Signature + Template must not exceed 65 words" msgstr "署名+テンプレートの長さは65文字以内" -#: settings/serializers/auth/sms.py:98 +#: settings/serializers/auth/sms.py:97 msgid "URL" msgstr "" -#: settings/serializers/auth/sms.py:103 +#: settings/serializers/auth/sms.py:102 msgid "Request method" msgstr "請求方法です" -#: settings/serializers/auth/sms.py:112 +#: settings/serializers/auth/sms.py:111 #, python-format msgid "The value in the parameter must contain %s" msgstr "パラメータの値には必ず %s が含まれます" @@ -4606,7 +4636,7 @@ msgid "SSO auth key TTL" msgstr "Token有効期間" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Unit: second" msgstr "単位: 秒" @@ -5546,7 +5576,7 @@ msgstr "コマンドストア" msgid "Invalid" msgstr "無効" -#: terminal/api/component/storage.py:119 terminal/tasks.py:139 +#: terminal/api/component/storage.py:119 terminal/tasks.py:140 msgid "Test failure: {}" msgstr "テスト失敗: {}" @@ -5555,7 +5585,7 @@ msgid "Test successful" msgstr "テスト成功" #: terminal/api/component/storage.py:124 terminal/notifications.py:179 -#: terminal/tasks.py:143 +#: terminal/tasks.py:144 msgid "Test failure: Account invalid" msgstr "テスト失敗: アカウントが無効" @@ -5599,20 +5629,11 @@ msgstr "入力" msgid "Output" msgstr "出力" -#: terminal/backends/command/models.py:24 terminal/models/session/replay.py:9 -#: terminal/models/session/sharing.py:18 terminal/models/session/sharing.py:81 -#: terminal/templates/terminal/_msg_command_alert.html:10 -#: tickets/models/ticket/command_confirm.py:15 -msgid "Session" -msgstr "セッション" - #: terminal/backends/command/models.py:27 terminal/serializers/command.py:22 msgid "Risk level" msgstr "リスクレベル" -#: terminal/connect_methods.py:54 terminal/connect_methods.py:55 -#: terminal/connect_methods.py:56 terminal/connect_methods.py:57 -#: terminal/connect_methods.py:58 +#: terminal/connect_methods.py:55 msgid "DB Client" msgstr "データベース クライアント" @@ -5657,39 +5678,57 @@ msgstr "一括作成非サポート" msgid "Storage is invalid" msgstr "ストレージが無効です" -#: terminal/models/applet/applet.py:31 +#: terminal/models/applet/applet.py:29 +#, fuzzy +#| msgid "Comment" +msgid "Community" +msgstr "コメント" + +#: terminal/models/applet/applet.py:30 +#, fuzzy +#| msgid "Enterprise edition" +msgid "Enterprise" +msgstr "エンタープライズ版" + +#: terminal/models/applet/applet.py:35 msgid "Author" msgstr "著者" #: terminal/models/applet/applet.py:36 +#, fuzzy +#| msgid "Action" +msgid "Edition" +msgstr "アクション" + +#: terminal/models/applet/applet.py:41 msgid "Can concurrent" msgstr "同時実行可能" -#: terminal/models/applet/applet.py:37 +#: terminal/models/applet/applet.py:42 msgid "Tags" msgstr "ラベル" -#: terminal/models/applet/applet.py:41 terminal/serializers/storage.py:157 +#: terminal/models/applet/applet.py:46 terminal/serializers/storage.py:157 msgid "Hosts" msgstr "ホスト" -#: terminal/models/applet/applet.py:86 +#: terminal/models/applet/applet.py:91 msgid "Applet pkg not valid, Missing file {}" msgstr "無効なアプレット パッケージ、ファイル {} がありません" -#: terminal/models/applet/applet.py:105 +#: terminal/models/applet/applet.py:110 msgid "Load platform.yml failed: {}" msgstr "" -#: terminal/models/applet/applet.py:108 +#: terminal/models/applet/applet.py:113 msgid "Only support custom platform" msgstr "" -#: terminal/models/applet/applet.py:113 +#: terminal/models/applet/applet.py:118 msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:235 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:240 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "ホスト マシン" @@ -5816,7 +5855,7 @@ msgstr "リモートアドレス" msgid "Application User" msgstr "ユーザーの適用" -#: terminal/models/component/terminal.py:164 +#: terminal/models/component/terminal.py:165 msgid "Can view terminal config" msgstr "ターミナル構成を表示できます" @@ -6185,19 +6224,19 @@ msgstr "オフライン セッションをクリアする" msgid "Upload session replay to external storage" msgstr "セッションの記録を外部ストレージにアップロードする" -#: terminal/tasks.py:89 +#: terminal/tasks.py:90 msgid "Run applet host deployment" msgstr "アプリケーション マシンの展開を実行する" -#: terminal/tasks.py:99 +#: terminal/tasks.py:100 msgid "Install applet" msgstr "アプリをインストールする" -#: terminal/tasks.py:109 +#: terminal/tasks.py:110 msgid "Generate applet host accounts" msgstr "リモートアプリケーション上のアカウントを収集する" -#: terminal/tasks.py:121 +#: terminal/tasks.py:122 msgid "Check command replay storage connectivity" msgstr "チェックコマンドと録画ストレージの接続性" @@ -7276,7 +7315,7 @@ msgstr "クラウドアカウント" msgid "Test cloud account" msgstr "クラウドアカウントのテスト" -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 msgid "Regions" msgstr "リージョン" @@ -7284,15 +7323,15 @@ msgstr "リージョン" msgid "Hostname strategy" msgstr "ホスト名戦略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 msgid "IP network segment group" msgstr "IPネットワークセグメントグループ" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 msgid "Sync IP type" msgstr "同期IPタイプ" -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 msgid "Always update" msgstr "常に更新" @@ -7577,11 +7616,15 @@ msgstr "ファイルはJSON形式です。" msgid "IP address invalid `{}`, {}" msgstr "IPアドレスが無効: '{}', {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:172 -msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +#: xpack/plugins/cloud/serializers/account_attrs.py:162 +#, fuzzy +#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgid "" +"Format for comma-delimited string,Such as: 192.168.1.0/24, " +"10.0.0.0-10.0.0.255" msgstr "例: 192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/account_attrs.py:175 +#: xpack/plugins/cloud/serializers/account_attrs.py:166 msgid "" "The port is used to detect the validity of the IP address. When the " "synchronization task is executed, only the valid IP address will be " @@ -7591,29 +7634,36 @@ msgstr "" "実行されると、有効な IP アドレスのみが同期されます。
ポートが0の場合、す" "べてのIPアドレスが有効です。" -#: xpack/plugins/cloud/serializers/account_attrs.py:183 +#: xpack/plugins/cloud/serializers/account_attrs.py:174 msgid "Hostname prefix" msgstr "ホスト名プレフィックス" -#: xpack/plugins/cloud/serializers/account_attrs.py:186 +#: xpack/plugins/cloud/serializers/account_attrs.py:177 msgid "IP segment" msgstr "IP セグメント" -#: xpack/plugins/cloud/serializers/account_attrs.py:190 +#: xpack/plugins/cloud/serializers/account_attrs.py:181 msgid "Test port" msgstr "テストポート" -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Test timeout" msgstr "テストタイムアウト" #: xpack/plugins/cloud/serializers/task.py:28 +#, fuzzy +#| msgid "" +#| "Only instances matching the IP range will be synced.
If the instance " +#| "contains multiple IP addresses, the first IP address that matches will be " +#| "used as the IP for the created asset.
The default value of * means " +#| "sync all instances and randomly match IP addresses.
Such as: " +#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" msgid "" "Only instances matching the IP range will be synced.
If the instance " "contains multiple IP addresses, the first IP address that matches will be " "used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " -"10.1.1.1-10.1.1.20" +"all instances and randomly match IP addresses.
Format for comma-" +"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" msgstr "" "IP範囲に一致するインスタンスのみが同期されます。
インスタンスに複数のIPア" "ドレスが含まれている場合、一致する最初のIPアドレスが作成されたアセットのIPと" @@ -7621,11 +7671,11 @@ msgstr "" "ドレスをランダムに一致させることを意味します。
例: " "192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/cloud/serializers/task.py:34 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "History count" msgstr "実行回数" -#: xpack/plugins/cloud/serializers/task.py:35 +#: xpack/plugins/cloud/serializers/task.py:36 msgid "Instance count" msgstr "インスタンス数" @@ -7685,22 +7735,25 @@ msgstr "ライセンスのインポートに成功" msgid "License is invalid" msgstr "ライセンスが無効です" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 msgid "License" msgstr "ライセンス" -#: xpack/plugins/license/models.py:80 +#: xpack/plugins/license/models.py:79 msgid "Standard edition" msgstr "標準版" -#: xpack/plugins/license/models.py:82 +#: xpack/plugins/license/models.py:81 msgid "Enterprise edition" msgstr "エンタープライズ版" -#: xpack/plugins/license/models.py:84 +#: xpack/plugins/license/models.py:83 msgid "Ultimate edition" msgstr "究極のエディション" -#: xpack/plugins/license/models.py:86 +#: xpack/plugins/license/models.py:85 msgid "Community edition" msgstr "コミュニティ版" + +#~ msgid "Reviewers amount" +#~ msgstr "承認者数" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 6a20beeda..ad2f7c7f8 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f236155485cdb4b453ff317d3c932ef4455d29e856ef3c2902a349d430992404 -size 117637 +oid sha256:4a22b436e9707729e51614e9942bb9715084ddf613152fa35be7a092a77daca7 +size 117063 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 04c98066b..7540ebf5d 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-31 18:12+0800\n" +"POT-Creation-Date: 2023-06-09 10:59+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -70,7 +70,7 @@ msgid "Collected" msgstr "收集" #: accounts/const/account.py:21 accounts/serializers/account/account.py:26 -#: settings/serializers/auth/sms.py:76 +#: settings/serializers/auth/sms.py:75 msgid "Template" msgstr "模板" @@ -78,13 +78,13 @@ msgstr "模板" msgid "Skip" msgstr "跳过" -#: accounts/const/account.py:26 audits/const.py:23 rbac/tree.py:229 +#: accounts/const/account.py:26 audits/const.py:24 rbac/tree.py:229 #: templates/_csv_import_export.html:18 templates/_csv_update_modal.html:6 msgid "Update" msgstr "更新" #: accounts/const/account.py:27 -#: accounts/serializers/automations/change_secret.py:156 audits/const.py:53 +#: accounts/serializers/automations/change_secret.py:156 audits/const.py:54 #: audits/signal_handlers/activity_log.py:33 common/const/choices.py:19 #: ops/const.py:58 terminal/const.py:61 xpack/plugins/cloud/const.py:41 msgid "Failed" @@ -185,10 +185,10 @@ msgstr "仅创建" #: accounts/serializers/account/gathered_account.py:10 #: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:132 -#: acls/serializers/base.py:76 assets/models/asset/common.py:93 +#: acls/serializers/base.py:118 assets/models/asset/common.py:93 #: assets/models/asset/common.py:332 assets/models/cmd_filter.py:36 #: assets/serializers/domain.py:19 assets/serializers/label.py:27 -#: audits/models.py:48 authentication/models/connection_token.py:34 +#: audits/models.py:53 authentication/models/connection_token.py:34 #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 @@ -205,7 +205,7 @@ msgid "Su from" msgstr "切换自" #: accounts/models/account.py:55 settings/serializers/auth/cas.py:20 -#: settings/serializers/auth/feishu.py:20 terminal/models/applet/applet.py:30 +#: settings/serializers/auth/feishu.py:20 terminal/models/applet/applet.py:34 msgid "Version" msgstr "版本" @@ -221,8 +221,8 @@ msgstr "来源 ID" #: accounts/models/account.py:61 #: accounts/serializers/automations/change_secret.py:113 #: accounts/serializers/automations/change_secret.py:133 -#: acls/serializers/base.py:77 assets/serializers/asset/common.py:125 -#: assets/serializers/gateway.py:28 audits/models.py:49 ops/models/base.py:18 +#: acls/serializers/base.py:119 assets/serializers/asset/common.py:125 +#: assets/serializers/gateway.py:28 audits/models.py:54 ops/models/base.py:18 #: perms/models/asset_permission.py:70 perms/serializers/permission.py:39 #: terminal/backends/command/models.py:21 terminal/models/session/session.py:34 #: tickets/models/ticket/command_confirm.py:13 xpack/plugins/cloud/models.py:85 @@ -274,7 +274,7 @@ msgid "Account backup plan" msgstr "账号备份计划" #: accounts/models/automations/backup_account.py:83 -#: assets/models/automations/base.py:115 audits/models.py:55 +#: assets/models/automations/base.py:115 audits/models.py:60 #: ops/models/base.py:55 ops/models/celery.py:63 ops/models/job.py:192 #: ops/templates/ops/celery_task_log.html:75 #: perms/models/asset_permission.py:72 terminal/models/applet/host.py:137 @@ -302,7 +302,7 @@ msgstr "账号备份快照" msgid "Trigger mode" msgstr "触发模式" -#: accounts/models/automations/backup_account.py:97 audits/models.py:172 +#: accounts/models/automations/backup_account.py:97 audits/models.py:194 #: terminal/models/session/sharing.py:111 xpack/plugins/cloud/models.py:168 msgid "Reason" msgstr "原因" @@ -425,8 +425,8 @@ msgstr "最后登录日期" #: accounts/models/automations/gather_account.py:17 #: accounts/models/automations/push_account.py:15 accounts/models/base.py:34 -#: acls/serializers/base.py:19 acls/serializers/base.py:50 -#: assets/models/_user.py:23 audits/models.py:157 authentication/forms.py:25 +#: acls/serializers/base.py:18 acls/serializers/base.py:49 +#: assets/models/_user.py:23 audits/models.py:179 authentication/forms.py:25 #: authentication/forms.py:27 authentication/models/temp_token.py:9 #: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_oauth_bind.html:9 @@ -458,8 +458,8 @@ msgid "Triggers" msgstr "触发方式" #: accounts/models/automations/push_account.py:16 acls/models/base.py:43 -#: acls/serializers/base.py:57 assets/models/cmd_filter.py:81 -#: audits/models.py:65 audits/serializers.py:82 +#: acls/serializers/base.py:56 assets/models/cmd_filter.py:81 +#: audits/models.py:87 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:116 #: authentication/templates/authentication/_access_key_modal.html:34 msgid "Action" @@ -473,8 +473,8 @@ msgstr "账号推送" msgid "Verify asset account" msgstr "账号验证" -#: accounts/models/base.py:33 acls/models/base.py:37 -#: acls/models/command_acl.py:21 acls/serializers/base.py:35 +#: accounts/models/base.py:33 acls/models/base.py:37 acls/models/base.py:97 +#: acls/models/command_acl.py:21 acls/serializers/base.py:34 #: applications/models.py:9 assets/models/_user.py:22 #: assets/models/asset/common.py:91 assets/models/asset/common.py:149 #: assets/models/cmd_filter.py:21 assets/models/domain.py:18 @@ -487,7 +487,7 @@ msgstr "账号验证" #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 #: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29 #: settings/models.py:33 settings/serializers/sms.py:6 -#: terminal/models/applet/applet.py:28 terminal/models/component/endpoint.py:12 +#: terminal/models/applet/applet.py:32 terminal/models/component/endpoint.py:12 #: terminal/models/component/endpoint.py:90 #: terminal/models/component/storage.py:26 terminal/models/component/task.py:15 #: terminal/models/component/terminal.py:84 users/forms/profile.py:33 @@ -504,7 +504,7 @@ msgstr "特权账号" #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:114 -#: terminal/models/applet/applet.py:33 users/serializers/user.py:170 +#: terminal/models/applet/applet.py:38 users/serializers/user.py:170 msgid "Is active" msgstr "激活" @@ -571,7 +571,7 @@ msgstr "类别" #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 #: assets/serializers/platform.py:109 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 -#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:32 +#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:37 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/serializers/session.py:22 terminal/serializers/storage.py:224 @@ -603,7 +603,7 @@ msgid "Changed" msgstr "已修改" #: accounts/serializers/account/account.py:249 -#: accounts/serializers/automations/base.py:22 acls/models/base.py:84 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:98 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -625,16 +625,15 @@ msgid "Account has exist" msgstr "账号已存在" #: accounts/serializers/account/account.py:417 -#: authentication/serializers/connect_token_secret.py:154 +#: authentication/serializers/connect_token_secret.py:156 #: authentication/templates/authentication/_access_key_modal.html:30 #: perms/models/perm_node.py:21 users/serializers/group.py:33 msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:424 acls/models/login_acl.py:12 -#: acls/serializers/base.py:75 acls/serializers/login_acl.py:21 -#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:44 -#: audits/models.py:63 audits/models.py:141 +#: accounts/serializers/account/account.py:424 acls/serializers/base.py:111 +#: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:49 +#: audits/models.py:85 audits/models.py:163 #: authentication/models/connection_token.py:30 #: authentication/models/sso_token.py:16 #: notifications/models/notification.py:12 @@ -723,8 +722,8 @@ msgstr "* 密码长度范围 6-30 位" msgid "Automation task execution" msgstr "自动化任务执行历史" -#: accounts/serializers/automations/change_secret.py:155 audits/const.py:52 -#: audits/models.py:54 audits/signal_handlers/activity_log.py:33 +#: accounts/serializers/automations/change_secret.py:155 audits/const.py:53 +#: audits/models.py:59 audits/signal_handlers/activity_log.py:33 #: common/const/choices.py:18 ops/const.py:56 ops/serializers/celery.py:40 #: terminal/const.py:60 terminal/models/session/sharing.py:107 #: tickets/views/approve.py:114 @@ -798,14 +797,13 @@ msgstr "优先级" msgid "1-100, the lower the value will be match first" msgstr "优先级可选范围为 1-100 (数值越小越优先)" -#: acls/models/base.py:44 acls/serializers/base.py:79 -#: acls/serializers/login_acl.py:23 assets/models/cmd_filter.py:86 +#: acls/models/base.py:44 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "审批人" #: acls/models/base.py:45 authentication/models/access_key.py:17 -#: authentication/models/connection_token.py:50 +#: authentication/models/connection_token.py:51 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 #: tickets/const.py:37 @@ -816,7 +814,7 @@ msgstr "激活中" msgid "Users" msgstr "用户管理" -#: acls/models/base.py:85 assets/models/automations/base.py:17 +#: acls/models/base.py:99 assets/models/automations/base.py:17 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 #: rbac/tree.py:35 msgid "Accounts" @@ -835,7 +833,7 @@ msgid "Regex" msgstr "正则表达式" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 msgid "Content" msgstr "内容" @@ -865,16 +863,22 @@ msgstr "命令过滤" msgid "Command confirm" msgstr "命令复核" -#: acls/models/login_acl.py:15 acls/models/login_asset_acl.py:9 -#: acls/serializers/login_acl.py:28 acls/serializers/login_asset_acl.py:13 +#: acls/models/connect_method.py:10 +#, fuzzy +#| msgid "Connect method" +msgid "Connect methods" +msgstr "连接方式" + +#: acls/models/login_acl.py:11 acls/models/login_asset_acl.py:9 +#: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:13 msgid "Rule" msgstr "规则" -#: acls/models/login_acl.py:18 +#: acls/models/login_acl.py:14 msgid "Login acl" msgstr "登录访问控制" -#: acls/models/login_acl.py:39 tickets/const.py:10 +#: acls/models/login_acl.py:27 tickets/const.py:10 msgid "Login confirm" msgstr "登录复核" @@ -886,11 +890,11 @@ msgstr "登录资产访问控制" msgid "Login asset confirm" msgstr "登录资产复核" -#: acls/serializers/base.py:11 acls/serializers/login_acl.py:16 +#: acls/serializers/base.py:10 acls/serializers/login_acl.py:11 msgid "With * indicating a match all. " msgstr "* 表示匹配所有. " -#: acls/serializers/base.py:26 +#: acls/serializers/base.py:25 msgid "" "With * indicating a match all. Such as: 192.168.10.1, 192.168.1.0/24, " "10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64 (Domain name " @@ -899,19 +903,15 @@ msgstr "" "* 表示匹配所有。例如: 192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:" "db8:2de::e13, 2001:db8:1a:1110::/64 (支持网域)" -#: acls/serializers/base.py:41 assets/serializers/asset/host.py:19 +#: acls/serializers/base.py:40 assets/serializers/asset/host.py:19 msgid "IP/Host" msgstr "IP/主机" -#: acls/serializers/base.py:82 acls/serializers/login_acl.py:26 -msgid "Reviewers amount" -msgstr "审批人数量" - -#: acls/serializers/base.py:108 tickets/serializers/ticket/ticket.py:77 +#: acls/serializers/base.py:98 tickets/serializers/ticket/ticket.py:77 msgid "The organization `{}` does not exist" msgstr "组织 `{}` 不存在" -#: acls/serializers/base.py:114 +#: acls/serializers/base.py:104 msgid "None of the reviewers belong to Organization `{}`" msgstr "所有复核人都不属于组织 `{}`" @@ -981,6 +981,10 @@ msgstr "不能删除根节点 ({})" msgid "Deletion failed and the node contains assets" msgstr "删除失败,节点包含资产" +#: assets/api/tree.py:49 assets/serializers/node.py:41 +msgid "The same level node name cannot be the same" +msgstr "同级别节点名字不能重复" + #: assets/apps.py:9 msgid "App assets" msgstr "资产管理" @@ -990,7 +994,7 @@ msgid "{} disabled" msgstr "{} 已禁用" #: assets/automations/ping_gateway/manager.py:33 -#: authentication/models/connection_token.py:115 +#: authentication/models/connection_token.py:116 msgid "No account" msgstr "没有账号" @@ -1013,7 +1017,7 @@ msgstr "认证失败" msgid "Connect failed" msgstr "连接失败" -#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:35 +#: assets/const/automation.py:6 audits/const.py:6 audits/const.py:36 #: audits/signal_handlers/activity_log.py:62 common/utils/ip/geoip/utils.py:31 #: common/utils/ip/geoip/utils.py:37 common/utils/ip/utils.py:104 msgid "Unknown" @@ -1036,7 +1040,7 @@ msgid "Gather facts" msgstr "收集资产信息" #: assets/const/category.py:10 assets/models/asset/host.py:8 -#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:68 +#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 #: terminal/models/component/endpoint.py:13 terminal/serializers/applet.py:17 #: xpack/plugins/cloud/serializers/account_attrs.py:72 msgid "Host" @@ -1055,7 +1059,7 @@ msgstr "数据库" msgid "Cloud service" msgstr "云服务" -#: assets/const/category.py:14 assets/models/asset/web.py:16 audits/const.py:33 +#: assets/const/category.py:14 assets/models/asset/web.py:16 audits/const.py:34 #: terminal/models/applet/applet.py:26 msgid "Web" msgstr "Web" @@ -1105,7 +1109,7 @@ msgstr "所有类型" msgid "Website" msgstr "网站" -#: assets/const/web.py:59 audits/const.py:46 +#: assets/const/web.py:59 audits/const.py:47 #: terminal/serializers/applet_host.py:28 msgid "Disabled" msgstr "禁用" @@ -1135,7 +1139,7 @@ msgstr "SSH公钥" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:38 terminal/models/applet/applet.py:237 +#: terminal/models/applet/applet.py:43 terminal/models/applet/applet.py:242 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 @@ -1185,7 +1189,7 @@ msgstr "用户名与用户相同" #: assets/models/_user.py:52 authentication/models/connection_token.py:39 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:35 terminal/serializers/session.py:20 +#: terminal/models/applet/applet.py:40 terminal/serializers/session.py:20 #: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "协议" @@ -1239,7 +1243,7 @@ msgid "Cloud" msgstr "云服务" #: assets/models/asset/common.py:92 assets/models/platform.py:14 -#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:69 +#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 #: xpack/plugins/cloud/serializers/account_attrs.py:73 msgid "Port" msgstr "端口" @@ -1251,7 +1255,7 @@ msgstr "地址" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:196 +#: xpack/plugins/cloud/serializers/account_attrs.py:187 msgid "Platform" msgstr "系统平台" @@ -1332,7 +1336,7 @@ msgid "Submit selector" msgstr "确认按钮选择器" #: assets/models/automations/base.py:22 ops/models/job.py:187 -#: settings/serializers/auth/sms.py:100 +#: settings/serializers/auth/sms.py:99 msgid "Parameters" msgstr "参数" @@ -1344,9 +1348,9 @@ msgstr "自动化任务" msgid "Asset automation task" msgstr "资产自动化任务" -#: assets/models/automations/base.py:113 audits/models.py:177 +#: assets/models/automations/base.py:113 audits/models.py:199 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:236 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:241 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 @@ -1490,7 +1494,7 @@ msgstr "开放的" msgid "Setting" msgstr "设置" -#: assets/models/platform.py:31 audits/const.py:47 settings/models.py:37 +#: assets/models/platform.py:31 audits/const.py:48 settings/models.py:37 #: terminal/serializers/applet_host.py:29 msgid "Enabled" msgstr "启用" @@ -1715,10 +1719,6 @@ msgstr "值" msgid "Can't contains: /" msgstr "不能包含: /" -#: assets/serializers/node.py:41 -msgid "The same level node name cannot be the same" -msgstr "同级别节点名字不能重复" - #: assets/serializers/platform.py:26 msgid "SFTP enabled" msgstr "SFTP 已启用" @@ -1849,7 +1849,7 @@ msgstr "创建目录" msgid "Rmdir" msgstr "删除目录" -#: audits/const.py:14 audits/const.py:24 +#: audits/const.py:14 audits/const.py:25 #: authentication/templates/authentication/_access_key_modal.html:65 #: perms/const.py:17 rbac/tree.py:230 msgid "Delete" @@ -1871,54 +1871,60 @@ msgstr "建立软链接" msgid "Download" msgstr "下载" -#: audits/const.py:22 rbac/tree.py:228 +#: audits/const.py:19 +#, fuzzy +#| msgid "Rename attr" +msgid "Rename dir" +msgstr "映射属性" + +#: audits/const.py:23 rbac/tree.py:228 msgid "View" msgstr "查看" -#: audits/const.py:25 +#: audits/const.py:26 #: authentication/templates/authentication/_access_key_modal.html:22 #: rbac/tree.py:227 msgid "Create" msgstr "创建" -#: audits/const.py:27 perms/const.py:12 +#: audits/const.py:28 perms/const.py:12 msgid "Connect" msgstr "连接" -#: audits/const.py:28 authentication/templates/authentication/login.html:240 +#: audits/const.py:29 authentication/templates/authentication/login.html:240 #: authentication/templates/authentication/login.html:313 #: templates/_header_bar.html:89 msgid "Login" msgstr "登录" -#: audits/const.py:29 ops/const.py:9 +#: audits/const.py:30 ops/const.py:9 msgid "Change password" msgstr "改密" -#: audits/const.py:34 settings/serializers/terminal.py:6 -#: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:162 +#: audits/const.py:35 settings/serializers/terminal.py:6 +#: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:163 #: terminal/serializers/session.py:48 msgid "Terminal" msgstr "终端" -#: audits/const.py:39 audits/models.py:105 +#: audits/const.py:40 audits/models.py:127 msgid "Operate log" msgstr "操作日志" -#: audits/const.py:40 +#: audits/const.py:41 msgid "Session log" msgstr "会话日志" -#: audits/const.py:41 +#: audits/const.py:42 msgid "Login log" msgstr "登录日志" -#: audits/const.py:42 terminal/models/applet/host.py:140 +#: audits/const.py:43 terminal/models/applet/host.py:140 #: terminal/models/component/task.py:24 msgid "Task" msgstr "任务" -#: audits/const.py:48 +#: audits/const.py:49 msgid "-" msgstr "-" @@ -1930,99 +1936,111 @@ msgstr "是" msgid "No" msgstr "否" -#: audits/models.py:39 +#: audits/models.py:42 msgid "Job audit log" msgstr "作业审计日志" -#: audits/models.py:46 audits/models.py:73 audits/models.py:144 +#: audits/models.py:51 audits/models.py:95 audits/models.py:166 #: terminal/models/session/session.py:39 terminal/models/session/sharing.py:99 msgid "Remote addr" msgstr "远端地址" -#: audits/models.py:51 audits/serializers.py:33 +#: audits/models.py:56 audits/serializers.py:33 msgid "Operate" msgstr "操作" -#: audits/models.py:53 +#: audits/models.py:58 msgid "Filename" msgstr "文件名" -#: audits/models.py:58 +#: audits/models.py:61 +msgid "File Record" +msgstr "" + +#: audits/models.py:62 terminal/backends/command/models.py:24 +#: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18 +#: terminal/models/session/sharing.py:81 +#: terminal/templates/terminal/_msg_command_alert.html:10 +#: tickets/models/ticket/command_confirm.py:15 +msgid "Session" +msgstr "会话" + +#: audits/models.py:65 msgid "File transfer log" msgstr "文件管理" -#: audits/models.py:67 audits/serializers.py:84 +#: audits/models.py:89 audits/serializers.py:84 msgid "Resource Type" msgstr "资源类型" -#: audits/models.py:68 audits/models.py:71 audits/models.py:117 +#: audits/models.py:90 audits/models.py:93 audits/models.py:139 #: audits/serializers.py:83 msgid "Resource" msgstr "资源" -#: audits/models.py:74 audits/models.py:120 audits/models.py:146 +#: audits/models.py:96 audits/models.py:142 audits/models.py:168 #: terminal/serializers/command.py:50 msgid "Datetime" msgstr "日期" -#: audits/models.py:113 +#: audits/models.py:135 msgid "Activity type" msgstr "活动类型" -#: audits/models.py:123 +#: audits/models.py:145 msgid "Detail" msgstr "详情" -#: audits/models.py:126 +#: audits/models.py:148 msgid "Detail ID" msgstr "详情 ID" -#: audits/models.py:130 +#: audits/models.py:152 msgid "Activity log" msgstr "活动日志" -#: audits/models.py:142 +#: audits/models.py:164 msgid "Change by" msgstr "修改者" -#: audits/models.py:152 +#: audits/models.py:174 msgid "Password change log" msgstr "改密日志" -#: audits/models.py:159 +#: audits/models.py:181 msgid "Login type" msgstr "登录方式" -#: audits/models.py:161 tickets/models/ticket/login_confirm.py:10 +#: audits/models.py:183 tickets/models/ticket/login_confirm.py:10 msgid "Login IP" msgstr "登录 IP" -#: audits/models.py:163 +#: audits/models.py:185 #: authentication/templates/authentication/_msg_different_city.html:11 #: tickets/models/ticket/login_confirm.py:11 msgid "Login city" msgstr "登录城市" -#: audits/models.py:166 audits/serializers.py:63 +#: audits/models.py:188 audits/serializers.py:63 msgid "User agent" msgstr "用户代理" -#: audits/models.py:169 audits/serializers.py:47 +#: audits/models.py:191 audits/serializers.py:47 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 #: users/forms/profile.py:65 users/models/user.py:776 #: users/serializers/profile.py:126 msgid "MFA" msgstr "MFA" -#: audits/models.py:179 +#: audits/models.py:201 msgid "Date login" msgstr "登录日期" -#: audits/models.py:181 audits/serializers.py:65 +#: audits/models.py:203 audits/serializers.py:65 msgid "Authentication backend" msgstr "认证方式" -#: audits/models.py:225 +#: audits/models.py:247 msgid "User login log" msgstr "用户登录日志" @@ -2089,10 +2107,16 @@ msgstr "钉钉" msgid "Temporary token" msgstr "临时密码" -#: audits/tasks.py:90 +#: audits/tasks.py:101 msgid "Clean audits session task log" msgstr "清理审计会话任务日志" +#: audits/tasks.py:114 +#, fuzzy +#| msgid "Upload session replay to external storage" +msgid "Upload FTP file to external storage" +msgstr "上传会话录像到外部存储" + #: authentication/api/confirm.py:40 msgid "This action require verify your MFA" msgstr "该操作需要验证您的 MFA, 请先开启并配置" @@ -2495,55 +2519,61 @@ msgid "Connect method" msgstr "连接方式" #: authentication/models/connection_token.py:41 +#, fuzzy +#| msgid "Connections" +msgid "Connect options" +msgstr "连接数" + +#: authentication/models/connection_token.py:42 #: rbac/serializers/rolebinding.py:21 msgid "User display" msgstr "用户名称" -#: authentication/models/connection_token.py:42 +#: authentication/models/connection_token.py:43 msgid "Asset display" msgstr "资产名称" -#: authentication/models/connection_token.py:43 +#: authentication/models/connection_token.py:44 msgid "Reusable" msgstr "可以重复使用" -#: authentication/models/connection_token.py:44 +#: authentication/models/connection_token.py:45 #: authentication/models/temp_token.py:13 perms/models/asset_permission.py:74 #: tickets/models/ticket/apply_application.py:31 #: tickets/models/ticket/apply_asset.py:20 users/models/user.py:797 msgid "Date expired" msgstr "失效日期" -#: authentication/models/connection_token.py:48 +#: authentication/models/connection_token.py:49 #: perms/models/asset_permission.py:77 msgid "From ticket" msgstr "来自工单" -#: authentication/models/connection_token.py:54 +#: authentication/models/connection_token.py:55 msgid "Connection token" msgstr "连接令牌" -#: authentication/models/connection_token.py:56 +#: authentication/models/connection_token.py:57 msgid "Can view connection token secret" msgstr "可以查看连接令牌密文" -#: authentication/models/connection_token.py:103 +#: authentication/models/connection_token.py:104 msgid "Connection token inactive" msgstr "连接令牌未激活" -#: authentication/models/connection_token.py:106 +#: authentication/models/connection_token.py:107 msgid "Connection token expired at: {}" msgstr "连接令牌过期: {}" -#: authentication/models/connection_token.py:109 +#: authentication/models/connection_token.py:110 msgid "No user or invalid user" msgstr "没有用户或用户失效" -#: authentication/models/connection_token.py:112 +#: authentication/models/connection_token.py:113 msgid "No asset or inactive asset" msgstr "没有资产或资产未激活" -#: authentication/models/connection_token.py:264 +#: authentication/models/connection_token.py:265 msgid "Super connection token" msgstr "超级连接令牌" @@ -3057,26 +3087,26 @@ msgstr "编码数据为 text" msgid "Encrypt field using Secret Key" msgstr "加密的字段" -#: common/db/fields.py:535 +#: common/db/fields.py:539 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" -#: common/db/fields.py:542 +#: common/db/fields.py:546 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "无效类型,应为 all、ids 或 attrs" -#: common/db/fields.py:545 +#: common/db/fields.py:549 msgid "Invalid ids for ids, should be a list" msgstr "无效的ID,应为列表" -#: common/db/fields.py:548 common/db/fields.py:551 +#: common/db/fields.py:552 common/db/fields.py:555 msgid "Invalid attrs, should be a list of dict" msgstr "无效的属性,应为dict列表" -#: common/db/fields.py:553 +#: common/db/fields.py:557 msgid "Invalid attrs, should be has name and value" msgstr "无效属性,应具有名称和值" @@ -3742,7 +3772,7 @@ msgstr "组织" msgid "Org name" msgstr "组织名称" -#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:34 +#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:39 msgid "Builtin" msgstr "内置的" @@ -3986,7 +4016,7 @@ msgstr "权限" msgid "Users amount" msgstr "用户数量" -#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:29 +#: rbac/serializers/role.py:28 terminal/models/applet/applet.py:33 msgid "Display name" msgstr "显示名称" @@ -4050,8 +4080,8 @@ msgstr "任务中心" msgid "My assets" msgstr "我的资产" -#: rbac/tree.py:56 terminal/models/applet/applet.py:45 -#: terminal/models/applet/applet.py:233 terminal/models/applet/host.py:28 +#: rbac/tree.py:56 terminal/models/applet/applet.py:50 +#: terminal/models/applet/applet.py:238 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "远程应用" @@ -4478,46 +4508,46 @@ msgstr "启用 SMS" msgid "SMS provider / Protocol" msgstr "短信服务商 / 协议" -#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:46 -#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 -#: settings/serializers/auth/sms.py:74 settings/serializers/email.py:69 +#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:45 +#: settings/serializers/auth/sms.py:53 settings/serializers/auth/sms.py:62 +#: settings/serializers/auth/sms.py:73 settings/serializers/email.py:69 msgid "Signature" msgstr "签名" -#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:47 -#: settings/serializers/auth/sms.py:55 settings/serializers/auth/sms.py:64 +#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:46 +#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 msgid "Template code" msgstr "模板" -#: settings/serializers/auth/sms.py:32 +#: settings/serializers/auth/sms.py:31 msgid "Test phone" msgstr "测试手机号" -#: settings/serializers/auth/sms.py:61 +#: settings/serializers/auth/sms.py:60 msgid "App Access Address" msgstr "应用地址" -#: settings/serializers/auth/sms.py:62 +#: settings/serializers/auth/sms.py:61 msgid "Signature channel number" msgstr "签名通道号" -#: settings/serializers/auth/sms.py:70 +#: settings/serializers/auth/sms.py:69 msgid "Enterprise code(SP id)" msgstr "企业代码(SP id)" -#: settings/serializers/auth/sms.py:71 +#: settings/serializers/auth/sms.py:70 msgid "Shared secret(Shared secret)" msgstr "共享密码(Shared secret)" -#: settings/serializers/auth/sms.py:72 +#: settings/serializers/auth/sms.py:71 msgid "Original number(Src id)" msgstr "原始号码(Src id)" -#: settings/serializers/auth/sms.py:73 +#: settings/serializers/auth/sms.py:72 msgid "Business type(Service id)" msgstr "业务类型(Service id)" -#: settings/serializers/auth/sms.py:77 +#: settings/serializers/auth/sms.py:76 #, python-brace-format msgid "" "Template need contain {code} and Signature + template length does not exceed " @@ -4527,24 +4557,24 @@ msgstr "" "模板需要包含 {code},并且模板+签名长度不能超过67个字。例如, 您的验证码是 " "{code}, 有效期为5分钟。请不要泄露给其他人。" -#: settings/serializers/auth/sms.py:86 +#: settings/serializers/auth/sms.py:85 #, python-brace-format msgid "The template needs to contain {code}" msgstr "模板需要包含 {code}" -#: settings/serializers/auth/sms.py:89 +#: settings/serializers/auth/sms.py:88 msgid "Signature + Template must not exceed 65 words" msgstr "模板+签名不能超过65个字" -#: settings/serializers/auth/sms.py:98 +#: settings/serializers/auth/sms.py:97 msgid "URL" msgstr "" -#: settings/serializers/auth/sms.py:103 +#: settings/serializers/auth/sms.py:102 msgid "Request method" msgstr "请求方式" -#: settings/serializers/auth/sms.py:112 +#: settings/serializers/auth/sms.py:111 #, python-format msgid "The value in the parameter must contain %s" msgstr "参数中的值必须包含 %s" @@ -4562,7 +4592,7 @@ msgid "SSO auth key TTL" msgstr "令牌有效期" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Unit: second" msgstr "单位: 秒" @@ -5466,7 +5496,7 @@ msgstr "命令存储" msgid "Invalid" msgstr "无效" -#: terminal/api/component/storage.py:119 terminal/tasks.py:139 +#: terminal/api/component/storage.py:119 terminal/tasks.py:140 msgid "Test failure: {}" msgstr "测试失败: {}" @@ -5475,7 +5505,7 @@ msgid "Test successful" msgstr "测试成功" #: terminal/api/component/storage.py:124 terminal/notifications.py:179 -#: terminal/tasks.py:143 +#: terminal/tasks.py:144 msgid "Test failure: Account invalid" msgstr "测试失败: 账号无效" @@ -5519,20 +5549,11 @@ msgstr "输入" msgid "Output" msgstr "输出" -#: terminal/backends/command/models.py:24 terminal/models/session/replay.py:9 -#: terminal/models/session/sharing.py:18 terminal/models/session/sharing.py:81 -#: terminal/templates/terminal/_msg_command_alert.html:10 -#: tickets/models/ticket/command_confirm.py:15 -msgid "Session" -msgstr "会话" - #: terminal/backends/command/models.py:27 terminal/serializers/command.py:22 msgid "Risk level" msgstr "风险等级" -#: terminal/connect_methods.py:54 terminal/connect_methods.py:55 -#: terminal/connect_methods.py:56 terminal/connect_methods.py:57 -#: terminal/connect_methods.py:58 +#: terminal/connect_methods.py:55 msgid "DB Client" msgstr "数据库客户端" @@ -5577,39 +5598,51 @@ msgstr "不支持批量创建" msgid "Storage is invalid" msgstr "存储无效" -#: terminal/models/applet/applet.py:31 +#: terminal/models/applet/applet.py:29 +msgid "Community" +msgstr "社区版" + +#: terminal/models/applet/applet.py:30 +msgid "Enterprise" +msgstr "企业版" + +#: terminal/models/applet/applet.py:35 msgid "Author" msgstr "作者" #: terminal/models/applet/applet.py:36 +msgid "Edition" +msgstr "版本" + +#: terminal/models/applet/applet.py:41 msgid "Can concurrent" msgstr "可以并发" -#: terminal/models/applet/applet.py:37 +#: terminal/models/applet/applet.py:42 msgid "Tags" msgstr "标签" -#: terminal/models/applet/applet.py:41 terminal/serializers/storage.py:157 +#: terminal/models/applet/applet.py:46 terminal/serializers/storage.py:157 msgid "Hosts" msgstr "主机" -#: terminal/models/applet/applet.py:86 +#: terminal/models/applet/applet.py:91 msgid "Applet pkg not valid, Missing file {}" msgstr "Applet pkg 无效,缺少文件 {}" -#: terminal/models/applet/applet.py:105 +#: terminal/models/applet/applet.py:110 msgid "Load platform.yml failed: {}" msgstr "" -#: terminal/models/applet/applet.py:108 +#: terminal/models/applet/applet.py:113 msgid "Only support custom platform" msgstr "" -#: terminal/models/applet/applet.py:113 +#: terminal/models/applet/applet.py:118 msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:235 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:240 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "宿主机" @@ -5736,7 +5769,7 @@ msgstr "远端地址" msgid "Application User" msgstr "应用用户" -#: terminal/models/component/terminal.py:164 +#: terminal/models/component/terminal.py:165 msgid "Can view terminal config" msgstr "可以查看终端配置" @@ -6100,19 +6133,19 @@ msgstr "清除离线会话" msgid "Upload session replay to external storage" msgstr "上传会话录像到外部存储" -#: terminal/tasks.py:89 +#: terminal/tasks.py:90 msgid "Run applet host deployment" msgstr "运行应用机部署" -#: terminal/tasks.py:99 +#: terminal/tasks.py:100 msgid "Install applet" msgstr "安装应用" -#: terminal/tasks.py:109 +#: terminal/tasks.py:110 msgid "Generate applet host accounts" msgstr "收集远程应用上的账号" -#: terminal/tasks.py:121 +#: terminal/tasks.py:122 msgid "Check command replay storage connectivity" msgstr "检查命令及录像存储可连接性 " @@ -7172,7 +7205,7 @@ msgstr "云账号" msgid "Test cloud account" msgstr "测试云账号" -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 msgid "Regions" msgstr "地域" @@ -7180,15 +7213,15 @@ msgstr "地域" msgid "Hostname strategy" msgstr "主机名策略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 msgid "IP network segment group" msgstr "IP网段组" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 msgid "Sync IP type" msgstr "同步IP类型" -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 msgid "Always update" msgstr "总是更新" @@ -7473,11 +7506,15 @@ msgstr "JSON 格式的文件" msgid "IP address invalid `{}`, {}" msgstr "IP 地址无效: `{}`, {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:172 -msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +#: xpack/plugins/cloud/serializers/account_attrs.py:162 +#, fuzzy +#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgid "" +"Format for comma-delimited string,Such as: 192.168.1.0/24, " +"10.0.0.0-10.0.0.255" msgstr "如: 192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/account_attrs.py:175 +#: xpack/plugins/cloud/serializers/account_attrs.py:166 msgid "" "The port is used to detect the validity of the IP address. When the " "synchronization task is executed, only the valid IP address will be " @@ -7486,39 +7523,46 @@ msgstr "" "端口用来检测 IP 地址的有效性,在同步任务执行时,只会同步有效的 IP 地址。
" "如果端口为 0,则表示所有 IP 地址均有效。" -#: xpack/plugins/cloud/serializers/account_attrs.py:183 +#: xpack/plugins/cloud/serializers/account_attrs.py:174 msgid "Hostname prefix" msgstr "主机名前缀" -#: xpack/plugins/cloud/serializers/account_attrs.py:186 +#: xpack/plugins/cloud/serializers/account_attrs.py:177 msgid "IP segment" msgstr "IP 网段" -#: xpack/plugins/cloud/serializers/account_attrs.py:190 +#: xpack/plugins/cloud/serializers/account_attrs.py:181 msgid "Test port" msgstr "测试端口" -#: xpack/plugins/cloud/serializers/account_attrs.py:193 +#: xpack/plugins/cloud/serializers/account_attrs.py:184 msgid "Test timeout" msgstr "测试超时时间" #: xpack/plugins/cloud/serializers/task.py:28 +#, fuzzy +#| msgid "" +#| "Only instances matching the IP range will be synced.
If the instance " +#| "contains multiple IP addresses, the first IP address that matches will be " +#| "used as the IP for the created asset.
The default value of * means " +#| "sync all instances and randomly match IP addresses.
Such as: " +#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" msgid "" "Only instances matching the IP range will be synced.
If the instance " "contains multiple IP addresses, the first IP address that matches will be " "used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " -"10.1.1.1-10.1.1.20" +"all instances and randomly match IP addresses.
Format for comma-" +"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" msgstr "" "只有匹配到 IP 段的实例会被同步。
如果实例包含多个 IP 地址,那么第一个匹配" "到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示同步所有实例和随机匹配 " "IP 地址。
例如: 192.168.1.0/24,10.1.1.1-10.1.1.20" -#: xpack/plugins/cloud/serializers/task.py:34 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "History count" msgstr "执行次数" -#: xpack/plugins/cloud/serializers/task.py:35 +#: xpack/plugins/cloud/serializers/task.py:36 msgid "Instance count" msgstr "实例个数" @@ -7578,22 +7622,25 @@ msgstr "许可证导入成功" msgid "License is invalid" msgstr "无效的许可证" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 msgid "License" msgstr "许可证" -#: xpack/plugins/license/models.py:80 +#: xpack/plugins/license/models.py:79 msgid "Standard edition" msgstr "标准版" -#: xpack/plugins/license/models.py:82 +#: xpack/plugins/license/models.py:81 msgid "Enterprise edition" msgstr "企业版" -#: xpack/plugins/license/models.py:84 +#: xpack/plugins/license/models.py:83 msgid "Ultimate edition" msgstr "旗舰版" -#: xpack/plugins/license/models.py:86 +#: xpack/plugins/license/models.py:85 msgid "Community edition" msgstr "社区版" + +#~ msgid "Reviewers amount" +#~ msgstr "审批人数量" diff --git a/apps/terminal/migrations/0062_applet_edition.py b/apps/terminal/migrations/0062_applet_edition.py new file mode 100644 index 000000000..1b1c0471e --- /dev/null +++ b/apps/terminal/migrations/0062_applet_edition.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.17 on 2023-06-09 02:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('terminal', '0061_applet_can_concurrent'), + ] + + operations = [ + migrations.AddField( + model_name='applet', + name='edition', + field=models.CharField(default='community', max_length=128, verbose_name='Edition'), + ), + ] diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index bd9543f40..86c21f7e5 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -25,10 +25,16 @@ class Applet(JMSBaseModel): general = 'general', _('General') web = 'web', _('Web') + class Edition(models.TextChoices): + community = 'community', _('Community') + enterprise = 'enterprise', _('Enterprise') + name = models.SlugField(max_length=128, verbose_name=_('Name'), unique=True) display_name = models.CharField(max_length=128, verbose_name=_('Display name')) version = models.CharField(max_length=16, verbose_name=_('Version')) author = models.CharField(max_length=128, verbose_name=_('Author')) + edition = models.CharField(max_length=128, choices=Edition.choices, default=Edition.community, + verbose_name=_('Edition')) type = models.CharField(max_length=16, verbose_name=_('Type'), default='general', choices=Type.choices) is_active = models.BooleanField(default=True, verbose_name=_('Is active')) builtin = models.BooleanField(default=False, verbose_name=_('Builtin')) diff --git a/apps/terminal/serializers/applet.py b/apps/terminal/serializers/applet.py index 3e656747f..79427b4b6 100644 --- a/apps/terminal/serializers/applet.py +++ b/apps/terminal/serializers/applet.py @@ -27,6 +27,7 @@ class AppletPublicationSerializer(serializers.ModelSerializer): class AppletSerializer(serializers.ModelSerializer): icon = serializers.ReadOnlyField(label=_("Icon")) type = LabeledChoiceField(choices=Applet.Type.choices, label=_("Type")) + edition = LabeledChoiceField(choices=Applet.Edition.choices, label=_("Edition")) class Meta: model = Applet @@ -35,6 +36,6 @@ class AppletSerializer(serializers.ModelSerializer): 'icon', 'readme', 'date_created', 'date_updated', ] fields = fields_mini + [ - 'version', 'author', 'type', 'protocols', - 'tags', 'comment' + 'version', 'author', 'type', 'edition', + 'can_concurrent', 'protocols', 'tags', 'comment', ] + read_only_fields From a86378601a04b85bd38415a64894bb6c07dfd2fa Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 9 Jun 2023 15:58:30 +0800 Subject: [PATCH 091/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E6=8F=92?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../content_script.js | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js index d1a6bf8ea..b09cb7531 100644 --- a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js +++ b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js @@ -1,13 +1,31 @@ // content_script.js -// 获取所有的
标签元素 -const links = document.getElementsByTagName('a'); +// 创建一个 Mutation Observer 实例 +const observer = new MutationObserver(function (mutationsList) { + // 遍历每个发生变化的 mutation + for (let mutation of mutationsList) { + // 检查是否有节点添加 + if (mutation.type === 'childList') { + // 获取所有的 标签元素 + const links = document.getElementsByTagName('a'); -// 遍历 标签元素并修改链接属性 -for (let i = 0; i < links.length; i++) { - links[i].target = '_self'; // 将 target 属性设置为 _self,当前窗口打开 -} + // 遍历 标签元素并修改链接属性 + console.log("开始替换标签") + for (let i = 0; i < links.length; i++) { + links[i].target = '_self'; // 将 target 属性设置为 _self,当前窗口打开 + } + // 停止监听,已经完成替换操作 + observer.disconnect(); + + // 退出循环,不再处理后续的 mutations + break; + } + } +}); + +// 开始观察 document.body 的子节点变化 +observer.observe(document.body, {childList: true, subtree: true}); chrome.runtime.onMessage.addListener( function (request, sender, sendResponse) { @@ -18,7 +36,7 @@ chrome.runtime.onMessage.addListener( ) document.addEventListener("contextmenu", function (event) { - console.log('On contextmenu event') + console.log('On context') event.preventDefault(); }); @@ -31,6 +49,21 @@ window.addEventListener("keydown", function (e) { } }, true); +// 保存原始的 window.open 函数引用 +var originalOpen = window.open; + +// 修改 window.open 函数 +window.open = function (url, target, features) { + // 将 target 强制设置为 "_self",使得新页面在当前标签页中打开 + target = "_self"; + + // 修改当前页面的 URL + location.href = url; + + // 调用原始的 window.open 函数 + return originalOpen.call(this, url, target, features); +}; + chrome.runtime.sendMessage({greeting: "hello"}, function (response) { }); From b3c5674213d2df05024e2ff8a42c596ba2c6f818 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:23:44 +0800 Subject: [PATCH 092/153] =?UTF-8?q?fix:=20=E8=B5=84=E4=BA=A7=E7=94=A8?= =?UTF-8?q?=E6=A8=A1=E7=89=88=E5=88=9B=E5=BB=BA=E8=B4=A6=E5=8F=B7=E6=97=A0?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E8=87=B3=20(#10662)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/accounts/serializers/account/account.py | 37 +++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/apps/accounts/serializers/account/account.py b/apps/accounts/serializers/account/account.py index 7b4abefa2..cc1952a1c 100644 --- a/apps/accounts/serializers/account/account.py +++ b/apps/accounts/serializers/account/account.py @@ -5,6 +5,7 @@ from django.db import IntegrityError from django.db.models import Q from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers +from rest_framework.generics import get_object_or_404 from rest_framework.validators import UniqueTogetherValidator from accounts.const import SecretType, Source, AccountInvalidPolicy @@ -60,10 +61,6 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer): self.from_template_if_need(data) self.set_uniq_name_if_need(data, asset) - def to_internal_value(self, data): - self.from_template_if_need(data) - return super().to_internal_value(data) - def set_uniq_name_if_need(self, initial_data, asset): name = initial_data.get('name') if name is not None: @@ -105,6 +102,15 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer): continue attrs[name] = value initial_data.update(attrs) + initial_data.update({ + 'source': Source.TEMPLATE, + 'source_id': str(template.id) + }) + asset_id = initial_data.get('asset') + if isinstance(asset_id, list) or not asset_id: + return + asset = get_object_or_404(Asset, pk=asset_id) + initial_data['su_from'] = template.get_su_from_account(asset) @staticmethod def push_account_if_need(instance, push_now, params, stat): @@ -149,19 +155,10 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer): else: raise serializers.ValidationError('Account already exists') - def generate_source_data(self, validated_data): - template = self._template - if template is None: - return - - validated_data['source'] = Source.TEMPLATE - validated_data['source_id'] = str(template.id) - def create(self, validated_data): push_now = validated_data.pop('push_now', None) params = validated_data.pop('params', None) self.clean_auth_fields(validated_data) - self.generate_source_data(validated_data) instance, stat = self.do_create(validated_data) self.push_account_if_need(instance, push_now, params, stat) return instance @@ -201,8 +198,11 @@ class AccountAssetSerializer(serializers.ModelSerializer): class AccountSerializer(AccountCreateUpdateSerializerMixin, BaseAccountSerializer): asset = AccountAssetSerializer(label=_('Asset')) - source = LabeledChoiceField(choices=Source.choices, label=_("Source"), read_only=True) has_secret = serializers.BooleanField(label=_("Has secret"), read_only=True) + source = LabeledChoiceField( + choices=Source.choices, label=_("Source"), required=False, + allow_null=True, default=Source.LOCAL + ) su_from = ObjectRelatedField( required=False, queryset=Account.objects, allow_null=True, allow_empty=True, label=_('Su from'), attrs=('id', 'name', 'username') @@ -215,11 +215,12 @@ class AccountSerializer(AccountCreateUpdateSerializerMixin, BaseAccountSerialize 'source', 'source_id', 'connectivity', ] + AccountCreateUpdateSerializerMixin.Meta.fields read_only_fields = BaseAccountSerializer.Meta.read_only_fields + [ - 'source', 'source_id', 'connectivity' + 'connectivity' ] extra_kwargs = { **BaseAccountSerializer.Meta.extra_kwargs, 'name': {'required': False}, + 'source_id': {'required': False, 'allow_null': True}, } @classmethod @@ -253,11 +254,14 @@ class AssetAccountBulkSerializer( fields = [ 'name', 'username', 'secret', 'secret_type', 'passphrase', 'privileged', 'is_active', 'comment', 'template', - 'on_invalid', 'push_now', 'assets', 'su_from_username' + 'on_invalid', 'push_now', 'assets', 'su_from_username', + 'source', 'source_id', ] extra_kwargs = { 'name': {'required': False}, 'secret_type': {'required': False}, + 'source': {'required': False, 'allow_null': True}, + 'source_id': {'required': False, 'allow_null': True}, } def set_initial_value(self): @@ -397,7 +401,6 @@ class AssetAccountBulkSerializer( def create(self, validated_data): push_now = validated_data.pop('push_now', False) - self.generate_source_data(validated_data) results = self.perform_bulk_create(validated_data) self.push_accounts_if_need(results, push_now) for res in results: From 2333a29a566de129ad0bc50b94c873d3ec76bc18 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Fri, 9 Jun 2023 16:52:54 +0800 Subject: [PATCH 093/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E6=94=B9=E5=AF=86=E5=8E=9F=E5=AD=90=E6=80=A7?= =?UTF-8?q?=20(#10663)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- .../accounts/automations/change_secret/custom/ssh/main.yml | 4 +--- .../automations/change_secret/database/mongodb/main.yml | 5 +---- .../automations/change_secret/database/mysql/main.yml | 5 +---- .../automations/change_secret/database/oracle/main.yml | 5 +---- .../automations/change_secret/database/postgresql/main.yml | 7 +------ .../automations/change_secret/database/sqlserver/main.yml | 7 ++----- .../automations/push_account/database/mongodb/main.yml | 5 +---- .../automations/push_account/database/mysql/main.yml | 5 +---- .../automations/push_account/database/oracle/main.yml | 5 +---- .../automations/push_account/database/postgresql/main.yml | 4 +--- .../automations/push_account/database/sqlserver/main.yml | 5 ++--- 11 files changed, 13 insertions(+), 44 deletions(-) diff --git a/apps/accounts/automations/change_secret/custom/ssh/main.yml b/apps/accounts/automations/change_secret/custom/ssh/main.yml index 027133496..853a666d4 100644 --- a/apps/accounts/automations/change_secret/custom/ssh/main.yml +++ b/apps/accounts/automations/change_secret/custom/ssh/main.yml @@ -26,6 +26,7 @@ password: "{{ account.secret }}" commands: "{{ params.commands }}" first_conn_delay_time: "{{ first_conn_delay_time | default(0.5) }}" + ignore_errors: true when: ping_info is succeeded register: change_info @@ -35,6 +36,3 @@ login_password: "{{ account.secret }}" login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" - when: - - ping_info is succeeded - - change_info is succeeded diff --git a/apps/accounts/automations/change_secret/database/mongodb/main.yml b/apps/accounts/automations/change_secret/database/mongodb/main.yml index 42ccd78ea..168607289 100644 --- a/apps/accounts/automations/change_secret/database/mongodb/main.yml +++ b/apps/accounts/automations/change_secret/database/mongodb/main.yml @@ -38,8 +38,8 @@ db: "{{ jms_asset.spec_info.db_name }}" name: "{{ account.username }}" password: "{{ account.secret }}" + ignore_errors: true when: db_info is succeeded - register: change_info - name: Verify password mongodb_ping: @@ -53,6 +53,3 @@ ssl_certfile: "{{ jms_asset.secret_info.client_key }}" connection_options: - tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}" - when: - - db_info is succeeded - - change_info is succeeded diff --git a/apps/accounts/automations/change_secret/database/mysql/main.yml b/apps/accounts/automations/change_secret/database/mysql/main.yml index 26858c94e..2c6965df9 100644 --- a/apps/accounts/automations/change_secret/database/mysql/main.yml +++ b/apps/accounts/automations/change_secret/database/mysql/main.yml @@ -28,8 +28,8 @@ password: "{{ account.secret }}" host: "%" priv: "{{ account.username + '.*:USAGE' if db_name == '' else db_name + '.*:ALL' }}" + ignore_errors: true when: db_info is succeeded - register: change_info - name: Verify password community.mysql.mysql_info: @@ -38,6 +38,3 @@ login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" filter: version - when: - - db_info is succeeded - - change_info is succeeded \ No newline at end of file diff --git a/apps/accounts/automations/change_secret/database/oracle/main.yml b/apps/accounts/automations/change_secret/database/oracle/main.yml index ad58e0584..873b0b007 100644 --- a/apps/accounts/automations/change_secret/database/oracle/main.yml +++ b/apps/accounts/automations/change_secret/database/oracle/main.yml @@ -29,8 +29,8 @@ mode: "{{ jms_account.mode }}" name: "{{ account.username }}" password: "{{ account.secret }}" + ignore_errors: true when: db_info is succeeded - register: change_info - name: Verify password oracle_ping: @@ -39,6 +39,3 @@ login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" login_database: "{{ jms_asset.spec_info.db_name }}" - when: - - db_info is succeeded - - change_info is succeeded diff --git a/apps/accounts/automations/change_secret/database/postgresql/main.yml b/apps/accounts/automations/change_secret/database/postgresql/main.yml index dbb11af12..a60bdee84 100644 --- a/apps/accounts/automations/change_secret/database/postgresql/main.yml +++ b/apps/accounts/automations/change_secret/database/postgresql/main.yml @@ -29,8 +29,8 @@ name: "{{ account.username }}" password: "{{ account.secret }}" role_attr_flags: LOGIN + ignore_errors: true when: result is succeeded - register: change_info - name: Verify password community.postgresql.postgresql_ping: @@ -39,8 +39,3 @@ login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" db: "{{ jms_asset.spec_info.db_name }}" - when: - - result is succeeded - - change_info is succeeded - register: result - failed_when: not result.is_available diff --git a/apps/accounts/automations/change_secret/database/sqlserver/main.yml b/apps/accounts/automations/change_secret/database/sqlserver/main.yml index da0427f5c..a1d83f179 100644 --- a/apps/accounts/automations/change_secret/database/sqlserver/main.yml +++ b/apps/accounts/automations/change_secret/database/sqlserver/main.yml @@ -41,8 +41,8 @@ login_port: "{{ jms_asset.port }}" name: '{{ jms_asset.spec_info.db_name }}' script: "ALTER LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version" + ignore_errors: true when: user_exist.query_results[0] | length != 0 - register: change_info - name: Add SQLServer user community.general.mssql_script: @@ -52,8 +52,8 @@ login_port: "{{ jms_asset.port }}" name: '{{ jms_asset.spec_info.db_name }}' script: "CREATE LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version" + ignore_errors: true when: user_exist.query_results[0] | length == 0 - register: change_info - name: Verify password community.general.mssql_script: @@ -64,6 +64,3 @@ name: '{{ jms_asset.spec_info.db_name }}' script: | SELECT @@version - when: - - db_info is succeeded - - change_info is succeeded diff --git a/apps/accounts/automations/push_account/database/mongodb/main.yml b/apps/accounts/automations/push_account/database/mongodb/main.yml index 42ccd78ea..168607289 100644 --- a/apps/accounts/automations/push_account/database/mongodb/main.yml +++ b/apps/accounts/automations/push_account/database/mongodb/main.yml @@ -38,8 +38,8 @@ db: "{{ jms_asset.spec_info.db_name }}" name: "{{ account.username }}" password: "{{ account.secret }}" + ignore_errors: true when: db_info is succeeded - register: change_info - name: Verify password mongodb_ping: @@ -53,6 +53,3 @@ ssl_certfile: "{{ jms_asset.secret_info.client_key }}" connection_options: - tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}" - when: - - db_info is succeeded - - change_info is succeeded diff --git a/apps/accounts/automations/push_account/database/mysql/main.yml b/apps/accounts/automations/push_account/database/mysql/main.yml index 26858c94e..2c6965df9 100644 --- a/apps/accounts/automations/push_account/database/mysql/main.yml +++ b/apps/accounts/automations/push_account/database/mysql/main.yml @@ -28,8 +28,8 @@ password: "{{ account.secret }}" host: "%" priv: "{{ account.username + '.*:USAGE' if db_name == '' else db_name + '.*:ALL' }}" + ignore_errors: true when: db_info is succeeded - register: change_info - name: Verify password community.mysql.mysql_info: @@ -38,6 +38,3 @@ login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" filter: version - when: - - db_info is succeeded - - change_info is succeeded \ No newline at end of file diff --git a/apps/accounts/automations/push_account/database/oracle/main.yml b/apps/accounts/automations/push_account/database/oracle/main.yml index ad58e0584..873b0b007 100644 --- a/apps/accounts/automations/push_account/database/oracle/main.yml +++ b/apps/accounts/automations/push_account/database/oracle/main.yml @@ -29,8 +29,8 @@ mode: "{{ jms_account.mode }}" name: "{{ account.username }}" password: "{{ account.secret }}" + ignore_errors: true when: db_info is succeeded - register: change_info - name: Verify password oracle_ping: @@ -39,6 +39,3 @@ login_host: "{{ jms_asset.address }}" login_port: "{{ jms_asset.port }}" login_database: "{{ jms_asset.spec_info.db_name }}" - when: - - db_info is succeeded - - change_info is succeeded diff --git a/apps/accounts/automations/push_account/database/postgresql/main.yml b/apps/accounts/automations/push_account/database/postgresql/main.yml index dbb11af12..68fc95324 100644 --- a/apps/accounts/automations/push_account/database/postgresql/main.yml +++ b/apps/accounts/automations/push_account/database/postgresql/main.yml @@ -29,8 +29,8 @@ name: "{{ account.username }}" password: "{{ account.secret }}" role_attr_flags: LOGIN + ignore_errors: true when: result is succeeded - register: change_info - name: Verify password community.postgresql.postgresql_ping: @@ -42,5 +42,3 @@ when: - result is succeeded - change_info is succeeded - register: result - failed_when: not result.is_available diff --git a/apps/accounts/automations/push_account/database/sqlserver/main.yml b/apps/accounts/automations/push_account/database/sqlserver/main.yml index da0427f5c..17b64a66a 100644 --- a/apps/accounts/automations/push_account/database/sqlserver/main.yml +++ b/apps/accounts/automations/push_account/database/sqlserver/main.yml @@ -41,6 +41,7 @@ login_port: "{{ jms_asset.port }}" name: '{{ jms_asset.spec_info.db_name }}' script: "ALTER LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version" + ignore_errors: true when: user_exist.query_results[0] | length != 0 register: change_info @@ -52,6 +53,7 @@ login_port: "{{ jms_asset.port }}" name: '{{ jms_asset.spec_info.db_name }}' script: "CREATE LOGIN {{ account.username }} WITH PASSWORD = '{{ account.secret }}'; select @@version" + ignore_errors: true when: user_exist.query_results[0] | length == 0 register: change_info @@ -64,6 +66,3 @@ name: '{{ jms_asset.spec_info.db_name }}' script: | SELECT @@version - when: - - db_info is succeeded - - change_info is succeeded From 00d3caf80c3da748222a813c3a016fb20c3121d8 Mon Sep 17 00:00:00 2001 From: Bai Date: Fri, 9 Jun 2023 15:57:27 +0800 Subject: [PATCH 094/153] =?UTF-8?q?perf:=20=E5=88=A0=E9=99=A4=E4=B8=8D?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/utils.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/apps/audits/utils.py b/apps/audits/utils.py index d2f6b61cd..239dcfa3f 100644 --- a/apps/audits/utils.py +++ b/apps/audits/utils.py @@ -1,10 +1,8 @@ -import codecs import copy from itertools import chain from datetime import datetime from django.db import models -from django.http import HttpResponse from common.utils.timezone import as_current_tz from common.utils import validate_ip, get_ip_city, get_logger @@ -13,25 +11,6 @@ from .const import DEFAULT_CITY logger = get_logger(__name__) -def get_excel_response(filename): - excel_response = HttpResponse(content_type='text/csv') - excel_response[ - 'Content-Disposition'] = 'attachment; filename="%s"' % filename - excel_response.write(codecs.BOM_UTF8) - return excel_response - - -def write_content_to_excel(response, header=None, login_logs=None, fields=None): - writer = csv.writer(response, dialect='excel', quoting=csv.QUOTE_MINIMAL) - if header: - writer.writerow(header) - if login_logs: - for log in login_logs: - data = [getattr(log, field.name) for field in fields] - writer.writerow(data) - return response - - def write_login_log(*args, **kwargs): from audits.models import UserLoginLog From 9574d03c12462ff55f49dff1fae20e5f16230eb6 Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 9 Jun 2023 17:16:23 +0800 Subject: [PATCH 095/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E6=96=B9=E5=BC=8F=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/component/connect_methods.py | 17 ++--------------- apps/terminal/connect_methods.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/terminal/api/component/connect_methods.py b/apps/terminal/api/component/connect_methods.py index d928c7329..4891ec5bd 100644 --- a/apps/terminal/api/component/connect_methods.py +++ b/apps/terminal/api/component/connect_methods.py @@ -17,28 +17,15 @@ class ConnectMethodListApi(generics.ListAPIView): serializer_class = serializers.ConnectMethodSerializer permission_classes = [IsValidUser] - def filter_user_connect_methods(self, d): - from acls.models import ConnectMethodACL - # 这里要根据用户来了,受 acl 影响 - acls = ConnectMethodACL.get_user_acls(self.request.user) - disabled_connect_methods = acls.values_list('connect_methods', flat=True) - disabled_connect_methods = set(itertools.chain.from_iterable(disabled_connect_methods)) - new_queryset = {} - for protocol, methods in d.items(): - new_queryset[protocol] = [x for x in methods if x['value'] not in disabled_connect_methods] - return new_queryset - def get_queryset(self): os = self.request.query_params.get('os') or get_request_os(self.request) - queryset = ConnectMethodUtil.get_filtered_protocols_connect_methods(os) flat = self.request.query_params.get('flat') - - # 先这么处理, 这里不用过滤包含的事所有 if is_true(flat): + queryset = ConnectMethodUtil.get_filtered_protocols_connect_methods(os) queryset = itertools.chain.from_iterable(queryset.values()) queryset = distinct(queryset, key=lambda x: x['value']) else: - queryset = self.filter_queryset(queryset) + queryset = ConnectMethodUtil.get_user_allowed_connect_methods(os, self.request.user) return queryset def list(self, request, *args, **kwargs): diff --git a/apps/terminal/connect_methods.py b/apps/terminal/connect_methods.py index aefdc7675..0d1571489 100644 --- a/apps/terminal/connect_methods.py +++ b/apps/terminal/connect_methods.py @@ -227,6 +227,19 @@ class ConnectMethodUtil: methods = cls._filter_disable_protocols_connect_methods(methods) return methods + @classmethod + def get_user_allowed_connect_methods(cls, os, user): + from acls.models import ConnectMethodACL + methods = cls.get_filtered_protocols_connect_methods(os) + acls = ConnectMethodACL.get_user_acls(user) + disabled_connect_methods = acls.values_list('connect_methods', flat=True) + disabled_connect_methods = set(itertools.chain.from_iterable(disabled_connect_methods)) + + new_queryset = {} + for protocol, methods in methods.items(): + new_queryset[protocol] = [x for x in methods if x['value'] not in disabled_connect_methods] + return new_queryset + @classmethod def _filter_disable_components_connect_methods(cls, methods): component_setting = { From ef2ecb225a7941271951cebb826304d7c7b88cc1 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Fri, 9 Jun 2023 18:19:04 +0800 Subject: [PATCH 096/153] =?UTF-8?q?fix:=20=E8=B5=84=E4=BA=A7=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E8=A7=84=E5=88=99=E6=93=8D=E4=BD=9C=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/handler.py | 2 -- apps/audits/utils.py | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/audits/handler.py b/apps/audits/handler.py index 5c069ac09..a304ba7c1 100644 --- a/apps/audits/handler.py +++ b/apps/audits/handler.py @@ -103,8 +103,6 @@ class OperatorLogHandler(metaclass=Singleton): return '' if isinstance(value[0], str): return ','.join(value) - if isinstance(value[0], dict) and value[0].get('value') and isinstance(value[0]['value'], str): - return ','.join([str(i['value']) for i in value]) return json.dumps(value) def __data_processing(self, dict_item, loop=True): diff --git a/apps/audits/utils.py b/apps/audits/utils.py index 239dcfa3f..33e0d9639 100644 --- a/apps/audits/utils.py +++ b/apps/audits/utils.py @@ -6,6 +6,7 @@ from django.db import models from common.utils.timezone import as_current_tz from common.utils import validate_ip, get_ip_city, get_logger +from common.db.fields import RelatedManager from .const import DEFAULT_CITY logger = get_logger(__name__) @@ -53,6 +54,8 @@ def _get_instance_field_value( value = dict(copy.deepcopy(value)) elif isinstance(value, datetime): value = as_current_tz(value).strftime('%Y-%m-%d %H:%M:%S') + elif isinstance(value, RelatedManager): + value = value.value elif isinstance(f, models.OneToOneField) and isinstance(value, models.Model): nested_data = _get_instance_field_value( value, include_model_fields, model_need_continue_fields, ('id',) From adfc22ae85b2b522007b3ef63226eb99e37d0487 Mon Sep 17 00:00:00 2001 From: ibuler Date: Fri, 9 Jun 2023 18:32:56 +0800 Subject: [PATCH 097/153] =?UTF-8?q?perf:=20=E4=BF=AE=E5=A4=8D=20=E6=AD=A3?= =?UTF-8?q?=E5=88=99=E5=8C=B9=E9=85=8D=E7=9A=84=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index adc3a3b89..41c2cf357 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -468,7 +468,12 @@ class JSONManyToManyDescriptor: elif rule_match == 'endswith': res &= str(value).endswith(str(rule_value)) elif rule_match == 'regex': - res &= re.match(rule_value, value) + try: + matched = bool(re.match(rule_value, value)) + except Exception as e: + logging.error('Error regex match: %s', e) + matched = False + res &= matched elif rule_match == 'not': res &= value != rule_value elif rule['match'] == 'gte': From 5708e57631dc576ee4740c507bf4bf5c74c431c8 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 10:25:14 +0800 Subject: [PATCH 098/153] =?UTF-8?q?perf:=20m2m=20json=20field=20=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=BF=85=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 41c2cf357..536f15cb3 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -552,9 +552,13 @@ class JSONManyToManyField(models.JSONField): if val["type"] == "ids": if not isinstance(val["ids"], list): raise ValueError(_("Invalid ids for ids, should be a list")) + if not val["ids"]: + raise ValueError(_("This field is required.")) elif val["type"] == "attrs": if not isinstance(val["attrs"], list): raise ValueError(_("Invalid attrs, should be a list of dict")) + if not val["attrs"]: + raise ValueError(_("This field is required.")) for attr in val["attrs"]: if not isinstance(attr, dict): raise ValueError(_("Invalid attrs, should be a list of dict")) From 6058f1bdc015112e453a262ca8f9e70103aad340 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 10:25:14 +0800 Subject: [PATCH 099/153] =?UTF-8?q?perf:=20m2m=20json=20field=20=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=BF=85=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 41c2cf357..536f15cb3 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -552,9 +552,13 @@ class JSONManyToManyField(models.JSONField): if val["type"] == "ids": if not isinstance(val["ids"], list): raise ValueError(_("Invalid ids for ids, should be a list")) + if not val["ids"]: + raise ValueError(_("This field is required.")) elif val["type"] == "attrs": if not isinstance(val["attrs"], list): raise ValueError(_("Invalid attrs, should be a list of dict")) + if not val["attrs"]: + raise ValueError(_("This field is required.")) for attr in val["attrs"]: if not isinstance(attr, dict): raise ValueError(_("Invalid attrs, should be a list of dict")) From b4008338c682dd00e02087d3c18090a4bf7c332c Mon Sep 17 00:00:00 2001 From: Bai Date: Mon, 12 Jun 2023 11:24:12 +0800 Subject: [PATCH 100/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/jumpserver/conf.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 1cb70f97a..dd056b091 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -219,9 +219,11 @@ class Config(dict): 'ANNOUNCEMENT_ENABLED': True, 'ANNOUNCEMENT': {}, + # 未使用的配置 'CAPTCHA_TEST_MODE': None, - 'TOKEN_EXPIRATION': 3600 * 24, 'DISPLAY_PER_PAGE': 25, + + 'TOKEN_EXPIRATION': 3600 * 24, 'DEFAULT_EXPIRED_YEARS': 70, 'SESSION_COOKIE_DOMAIN': None, 'CSRF_COOKIE_DOMAIN': None, @@ -241,6 +243,9 @@ class Config(dict): 'MFA_CUSTOM': False, 'MFA_CUSTOM_FILE_MD5': '', + # 临时密码 + 'AUTH_TEMP_TOKEN': False, + # Auth LDAP settings 'AUTH_LDAP': False, 'AUTH_LDAP_SERVER_URI': 'ldap://localhost:389', @@ -360,8 +365,6 @@ class Config(dict): 'name': 'name', 'username': 'username', 'email': 'email' }, - 'AUTH_TEMP_TOKEN': False, - # 企业微信 'AUTH_WECOM': False, 'WECOM_CORPID': '', @@ -495,9 +498,11 @@ class Config(dict): 'HTTP_BIND_HOST': '0.0.0.0', 'HTTP_LISTEN_PORT': 8080, 'WS_LISTEN_PORT': 8070, + 'SYSLOG_ADDR': '', # '192.168.0.1:514' 'SYSLOG_FACILITY': 'user', 'SYSLOG_SOCKTYPE': 2, + 'PERM_EXPIRED_CHECK_PERIODIC': 60 * 60, 'FLOWER_URL': "127.0.0.1:5555", 'LANGUAGE_CODE': 'zh', From dc35a8c52b802e3a73b2577a957b873fb995bc4a Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 13:59:54 +0800 Subject: [PATCH 101/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20acl=20?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E6=8E=92=E5=BA=8F=E5=92=8Cmanager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/api/login_asset_check.py | 2 +- apps/acls/migrations/0001_initial.py | 42 ++++++++++++------- .../migrations/0002_auto_20210926_1047.py | 5 +-- .../migrations/0003_auto_20211130_1037.py | 5 +-- .../0006_commandfilteracl_commandgroup.py | 2 +- apps/acls/models/base.py | 7 ++-- 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/apps/acls/api/login_asset_check.py b/apps/acls/api/login_asset_check.py index bb61a9043..0bdaef46a 100644 --- a/apps/acls/api/login_asset_check.py +++ b/apps/acls/api/login_asset_check.py @@ -43,7 +43,7 @@ class LoginAssetCheckAPI(CreateAPIView): queryset = queryset.filter(accounts__contains=account_username) with tmp_to_org(self.serializer.asset.org): - acl = queryset.order_by('priority').valid().first() + acl = queryset.valid().first() if acl: need_review = True diff --git a/apps/acls/migrations/0001_initial.py b/apps/acls/migrations/0001_initial.py index 83ebc4bf1..378f33de3 100644 --- a/apps/acls/migrations/0001_initial.py +++ b/apps/acls/migrations/0001_initial.py @@ -1,14 +1,14 @@ # Generated by Django 3.1 on 2021-03-11 09:53 -from django.conf import settings -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion import uuid +import django.core.validators +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + class Migration(migrations.Migration): - initial = True dependencies = [ @@ -24,37 +24,51 @@ class Migration(migrations.Migration): ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), ('name', models.CharField(max_length=128, verbose_name='Name')), - ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')), + ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', + validators=[django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100)], + verbose_name='Priority')), ('is_active', models.BooleanField(default=True, verbose_name='Active')), ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), ('ip_group', models.JSONField(default=list, verbose_name='Login IP')), - ('action', models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow')], default='reject', max_length=64, verbose_name='Action')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='login_acls', to=settings.AUTH_USER_MODEL, verbose_name='User')), + ('action', + models.CharField(choices=[('reject', 'Reject'), ('allow', 'Allow')], default='reject', max_length=64, + verbose_name='Action')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='login_acls', + to=settings.AUTH_USER_MODEL, verbose_name='User')), ], options={ - 'ordering': ('priority', '-date_updated', 'name'), + 'ordering': ('priority', 'name'), }, ), migrations.CreateModel( name='LoginAssetACL', fields=[ - ('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), + ('org_id', + models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), ('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')), ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), ('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')), ('name', models.CharField(max_length=128, verbose_name='Name')), - ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100)], verbose_name='Priority')), + ('priority', models.IntegerField(default=50, help_text='1-100, the lower the value will be match first', + validators=[django.core.validators.MinValueValidator(1), + django.core.validators.MaxValueValidator(100)], + verbose_name='Priority')), ('is_active', models.BooleanField(default=True, verbose_name='Active')), ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), ('users', models.JSONField(verbose_name='User')), ('system_users', models.JSONField(verbose_name='System User')), ('assets', models.JSONField(verbose_name='Asset')), - ('action', models.CharField(choices=[('login_confirm', 'Login confirm')], default='login_confirm', max_length=64, verbose_name='Action')), - ('reviewers', models.ManyToManyField(blank=True, related_name='review_login_asset_acls', to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')), + ('action', + models.CharField(choices=[('login_confirm', 'Login confirm')], default='login_confirm', max_length=64, + verbose_name='Action')), + ('reviewers', + models.ManyToManyField(blank=True, related_name='review_login_asset_acls', to=settings.AUTH_USER_MODEL, + verbose_name='Reviewers')), ], options={ - 'ordering': ('priority', '-date_updated', 'name'), + 'ordering': ('priority', 'name'), 'unique_together': {('name', 'org_id')}, }, ), diff --git a/apps/acls/migrations/0002_auto_20210926_1047.py b/apps/acls/migrations/0002_auto_20210926_1047.py index 2429b7cea..a4af4bd69 100644 --- a/apps/acls/migrations/0002_auto_20210926_1047.py +++ b/apps/acls/migrations/0002_auto_20210926_1047.py @@ -2,7 +2,6 @@ import django from django.conf import settings from django.db import migrations, models, transaction -from acls.models import LoginACL LOGIN_CONFIRM_ZH = '登录复核' LOGIN_CONFIRM_EN = 'Login confirm' @@ -90,10 +89,10 @@ class Migration(migrations.Migration): ), migrations.AlterModelOptions( name='loginacl', - options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login acl'}, + options={'ordering': ('priority', 'name'), 'verbose_name': 'Login acl'}, ), migrations.AlterModelOptions( name='loginassetacl', - options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login asset acl'}, + options={'ordering': ('priority', 'name'), 'verbose_name': 'Login asset acl'}, ), ] diff --git a/apps/acls/migrations/0003_auto_20211130_1037.py b/apps/acls/migrations/0003_auto_20211130_1037.py index d4d3524be..cf32bca45 100644 --- a/apps/acls/migrations/0003_auto_20211130_1037.py +++ b/apps/acls/migrations/0003_auto_20211130_1037.py @@ -4,7 +4,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('acls', '0002_auto_20210926_1047'), ] @@ -12,10 +11,10 @@ class Migration(migrations.Migration): operations = [ migrations.AlterModelOptions( name='loginacl', - options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login acl'}, + options={'ordering': ('priority', 'name'), 'verbose_name': 'Login acl'}, ), migrations.AlterModelOptions( name='loginassetacl', - options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login asset acl'}, + options={'ordering': ('priority', 'name'), 'verbose_name': 'Login asset acl'}, ), ] diff --git a/apps/acls/migrations/0006_commandfilteracl_commandgroup.py b/apps/acls/migrations/0006_commandfilteracl_commandgroup.py index cc91c998e..991efe556 100644 --- a/apps/acls/migrations/0006_commandfilteracl_commandgroup.py +++ b/apps/acls/migrations/0006_commandfilteracl_commandgroup.py @@ -63,7 +63,7 @@ class Migration(migrations.Migration): ], options={ 'verbose_name': 'Command acl', - 'ordering': ('priority', '-date_updated', 'name'), + 'ordering': ('priority', 'name'), 'unique_together': {('name', 'org_id')}, }, ), diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 63b49bcf7..9bd46aa53 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -6,7 +6,7 @@ from common.db.fields import JSONManyToManyField from common.db.models import JMSBaseModel from common.utils import contains_ip from common.utils.time_period import contains_time_period -from orgs.mixins.models import OrgModelMixin +from orgs.mixins.models import OrgModelMixin, OrgManager __all__ = [ 'BaseACL', 'UserBaseACL', 'UserAssetAccountBaseACL', @@ -48,7 +48,7 @@ class BaseACL(JMSBaseModel): objects = BaseACLQuerySet.as_manager() class Meta: - ordering = ('priority', 'date_updated', 'name') + ordering = ('priority', 'name') abstract = True def is_action(self, action): @@ -97,6 +97,7 @@ class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL): name = models.CharField(max_length=128, verbose_name=_('Name')) assets = JSONManyToManyField('assets.Asset', default=dict, verbose_name=_('Assets')) accounts = models.JSONField(default=list, verbose_name=_("Accounts")) + objects = OrgManager.from_queryset(BaseACLQuerySet)() class Meta(UserBaseACL.Meta): unique_together = [('name', 'org_id')] @@ -125,4 +126,4 @@ class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL): kwargs['org_id'] = org_id if kwargs: queryset = queryset.filter(**kwargs) - return queryset.filter(is_active=True).distinct().order_by('priority', 'date_created') + return queryset.valid().distinct() From a99d22708c0b897df0c0d8e4549fad4b0beaaf1a Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 14:03:32 +0800 Subject: [PATCH 102/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20migrations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/migrations/0008_commandgroup_comment.py | 6 +++--- apps/acls/migrations/0015_connectmethodacl.py | 2 +- apps/terminal/migrations/0062_applet_edition.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/acls/migrations/0008_commandgroup_comment.py b/apps/acls/migrations/0008_commandgroup_comment.py index 8937d2a93..82e44912c 100644 --- a/apps/acls/migrations/0008_commandgroup_comment.py +++ b/apps/acls/migrations/0008_commandgroup_comment.py @@ -20,14 +20,14 @@ class Migration(migrations.Migration): ), migrations.AlterModelOptions( name='commandfilteracl', - options={'ordering': ('priority', 'date_updated', 'name'), 'verbose_name': 'Command acl'}, + options={'ordering': ('priority', 'name'), 'verbose_name': 'Command acl'}, ), migrations.AlterModelOptions( name='loginacl', - options={'ordering': ('priority', 'date_updated', 'name'), 'verbose_name': 'Login acl'}, + options={'ordering': ('priority', 'name'), 'verbose_name': 'Login acl'}, ), migrations.AlterModelOptions( name='loginassetacl', - options={'ordering': ('priority', 'date_updated', 'name'), 'verbose_name': 'Login asset acl'}, + options={'ordering': ('priority', 'name'), 'verbose_name': 'Login asset acl'}, ), ] diff --git a/apps/acls/migrations/0015_connectmethodacl.py b/apps/acls/migrations/0015_connectmethodacl.py index 66beca0cc..a786b87eb 100644 --- a/apps/acls/migrations/0015_connectmethodacl.py +++ b/apps/acls/migrations/0015_connectmethodacl.py @@ -39,7 +39,7 @@ class Migration(migrations.Migration): models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')), ], options={ - 'ordering': ('priority', 'date_updated', 'name'), + 'ordering': ('priority', 'name'), 'abstract': False, }, ), diff --git a/apps/terminal/migrations/0062_applet_edition.py b/apps/terminal/migrations/0062_applet_edition.py index 1b1c0471e..bd5118edf 100644 --- a/apps/terminal/migrations/0062_applet_edition.py +++ b/apps/terminal/migrations/0062_applet_edition.py @@ -4,7 +4,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('terminal', '0061_applet_can_concurrent'), ] @@ -13,6 +12,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='applet', name='edition', - field=models.CharField(default='community', max_length=128, verbose_name='Edition'), + field=models.CharField(choices=[('community', 'Community'), ('enterprise', 'Enterprise')], + default='community', max_length=128, verbose_name='Edition'), ), ] From 24272d3162b92a38e12e4f1e394845beec4ed45e Mon Sep 17 00:00:00 2001 From: Bai Date: Mon, 12 Jun 2023 14:06:55 +0800 Subject: [PATCH 103/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20Token=20API?= =?UTF-8?q?=20=E8=8E=B7=E5=8F=96=E5=91=BD=E4=BB=A4=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E5=99=A8=E5=A4=B1=E8=B4=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/models/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 9bd46aa53..c92bf09e2 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -99,6 +99,8 @@ class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL): accounts = models.JSONField(default=list, verbose_name=_("Accounts")) objects = OrgManager.from_queryset(BaseACLQuerySet)() + objects = OrgManager.from_queryset(BaseACLQuerySet)() + class Meta(UserBaseACL.Meta): unique_together = [('name', 'org_id')] abstract = True From 3604ef4228d025154b41c60b73cdebde4fb73eba Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Mon, 12 Jun 2023 15:35:39 +0800 Subject: [PATCH 104/153] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3=E5=BD=95?= =?UTF-8?q?=E5=83=8F=E6=97=A0=E6=B3=95=E5=9C=A8=E7=BA=BF=E8=A7=82=E7=9C=8B?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/session/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/terminal/api/session/session.py b/apps/terminal/api/session/session.py index ab80293b1..9fdd855c8 100644 --- a/apps/terminal/api/session/session.py +++ b/apps/terminal/api/session/session.py @@ -212,7 +212,7 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet): storage = ReplayStorageHandler(session) local_path, url_or_err = storage.get_file_path_url() - if url_or_err: + if local_path is None: return Response({"error": url_or_err}, status=404) data = self.get_replay_data(session, url_or_err) return Response(data) From 3fd8e5755d5b2459c479ebe0050ec3422e98df49 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Mon, 12 Jun 2023 15:39:04 +0800 Subject: [PATCH 105/153] =?UTF-8?q?fix:=20=E4=BF=AE=E6=94=B9=E5=8F=98?= =?UTF-8?q?=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/session/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/terminal/api/session/session.py b/apps/terminal/api/session/session.py index 9fdd855c8..f80617fd6 100644 --- a/apps/terminal/api/session/session.py +++ b/apps/terminal/api/session/session.py @@ -214,7 +214,7 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet): local_path, url_or_err = storage.get_file_path_url() if local_path is None: return Response({"error": url_or_err}, status=404) - data = self.get_replay_data(session, url_or_err) + data = self.get_replay_data(session, local_path) return Response(data) From b79aaff4a0d87d7cd8a6d03ea4e570fe3c2fa443 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 12 Jun 2023 14:40:50 +0800 Subject: [PATCH 106/153] =?UTF-8?q?perf:=20=E8=B5=84=E4=BA=A7=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=20ssh=20=E5=8D=8F=E8=AE=AE=E8=BF=87=E6=BB=A4=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E5=90=AF=E7=94=A8=20sftp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/api/mixin.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/assets/api/mixin.py b/apps/assets/api/mixin.py index 39d51197b..2cd928605 100644 --- a/apps/assets/api/mixin.py +++ b/apps/assets/api/mixin.py @@ -2,7 +2,7 @@ from typing import List from rest_framework.request import Request -from assets.models import Node, PlatformProtocol +from assets.models import Node, PlatformProtocol, Protocol from assets.utils import get_node_from_request, is_query_node_all_assets from common.utils import lazyproperty, timeit @@ -78,7 +78,10 @@ class SerializeToTreeNodeMixin: get_pid = lambda asset: getattr(asset, 'parent_key', '') else: get_pid = lambda asset: node_key - + ssh_asset_ids = [ + str(i) for i in + Protocol.objects.filter(name='ssh').values_list('asset_id', flat=True) + ] data = [ { 'id': str(asset.id), @@ -96,7 +99,8 @@ class SerializeToTreeNodeMixin: 'data': { 'platform_type': asset.platform.type, 'org_name': asset.org_name, - 'sftp': asset.platform_id in sftp_enabled_platform, + 'sftp': (asset.platform_id in sftp_enabled_platform) \ + and (str(asset.id) in ssh_asset_ids), 'name': asset.name, 'address': asset.address }, From 5c2b54ad3bd9c0be2b72ec3be28ab17991a91784 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 16:00:14 +0800 Subject: [PATCH 107/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20manager=20?= =?UTF-8?q?=E5=92=8C=20acl=20=E7=9A=84=20=E7=BB=84=E7=BB=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/api/connect_method.py | 6 ++++++ apps/acls/api/login_acl.py | 7 +++++++ apps/acls/models/base.py | 7 ++++--- apps/authentication/mixins.py | 1 + apps/common/db/fields.py | 3 ++- 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/apps/acls/api/connect_method.py b/apps/acls/api/connect_method.py index ce65dcc34..9a8d8a9dc 100644 --- a/apps/acls/api/connect_method.py +++ b/apps/acls/api/connect_method.py @@ -1,6 +1,7 @@ from django_filters import rest_framework as drf_filters from common.api import JMSBulkModelViewSet +from orgs.utils import tmp_to_root_org from .common import ACLUserFilterMixin from .. import serializers from ..models import ConnectMethodACL @@ -21,3 +22,8 @@ class ConnectMethodACLViewSet(JMSBulkModelViewSet): filterset_class = ConnectMethodFilter search_fields = ('name',) serializer_class = serializers.ConnectMethodACLSerializer + + def filter_queryset(self, queryset): + with tmp_to_root_org(): + return super().filter_queryset(queryset) + diff --git a/apps/acls/api/login_acl.py b/apps/acls/api/login_acl.py index fc7693bd6..5dbd80e9f 100644 --- a/apps/acls/api/login_acl.py +++ b/apps/acls/api/login_acl.py @@ -1,4 +1,6 @@ from common.api import JMSBulkModelViewSet + +from orgs.utils import tmp_to_root_org from .common import ACLUserFilterMixin from .. import serializers from ..models import LoginACL @@ -17,3 +19,8 @@ class LoginACLViewSet(JMSBulkModelViewSet): filterset_class = LoginACLFilter search_fields = ('name',) serializer_class = serializers.LoginACLSerializer + + def filter_queryset(self, queryset): + with tmp_to_root_org(): + return super().filter_queryset(queryset) + diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index c92bf09e2..24857280f 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -12,6 +12,8 @@ __all__ = [ 'BaseACL', 'UserBaseACL', 'UserAssetAccountBaseACL', ] +from orgs.utils import tmp_to_root_org + class ActionChoices(models.TextChoices): reject = 'reject', _('Reject') @@ -88,7 +90,8 @@ class UserBaseACL(BaseACL): @classmethod def get_user_acls(cls, user): queryset = cls.objects.all() - q = cls.users.get_filter_q(user) + with tmp_to_root_org(): + q = cls.users.get_filter_q(user) queryset = queryset.filter(q) return queryset.filter(is_active=True).distinct() @@ -99,8 +102,6 @@ class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL): accounts = models.JSONField(default=list, verbose_name=_("Accounts")) objects = OrgManager.from_queryset(BaseACLQuerySet)() - objects = OrgManager.from_queryset(BaseACLQuerySet)() - class Meta(UserBaseACL.Meta): unique_together = [('name', 'org_id')] abstract = True diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index d3d84f560..647aac773 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -369,6 +369,7 @@ class AuthACLMixin: logger.debug('Login confirm acl id: {}'.format(acl_id)) if not acl_id: return + acl = LoginACL.get_user_acls(user).filter(id=acl_id).first() if not acl: return diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 536f15cb3..a84a9de6f 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -392,7 +392,8 @@ class RelatedManager: return self.filter_queryset_by_model(value, to_model) def get_attr_q(self): - q = self._get_filter_attrs_q(self.value, apps.get_model(self.field.to)) + to_model = apps.get_model(self.field.to) + q = self._get_filter_attrs_q(self.value, to_model) return q def all(self): From cb2b8bb70b6ace966bcc5312495d1363208e21eb Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 16:37:12 +0800 Subject: [PATCH 108/153] =?UTF-8?q?perf:=20=E6=94=BE=E8=A1=8C=E5=BF=AB?= =?UTF-8?q?=E6=8D=B7=E9=94=AE=20ctrl-c-v?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/models/base.py | 5 ++++- .../extensions/disable_new_tab_window_menu/content_script.js | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index c92bf09e2..44c03d2a2 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -12,6 +12,8 @@ __all__ = [ 'BaseACL', 'UserBaseACL', 'UserAssetAccountBaseACL', ] +from orgs.utils import tmp_to_org + class ActionChoices(models.TextChoices): reject = 'reject', _('Reject') @@ -115,7 +117,8 @@ class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL): queryset = queryset.filter(q) if asset: org_id = asset.org_id - q = cls.assets.get_filter_q(asset) + with tmp_to_org(org_id): + q = cls.assets.get_filter_q(asset) queryset = queryset.filter(q) if account and not account_username: account_username = account.username diff --git a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js index b09cb7531..0b6162430 100644 --- a/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js +++ b/apps/terminal/applets/chrome/extensions/disable_new_tab_window_menu/content_script.js @@ -40,9 +40,9 @@ document.addEventListener("contextmenu", function (event) { event.preventDefault(); }); -var AllowedKeys = ['P', 'F', 'p', 'f'] +var AllowedKeys = ['P', 'F', 'C', 'V'] window.addEventListener("keydown", function (e) { - if (e.key === "F12" || (e.ctrlKey && !AllowedKeys.includes(e.key))) { + if (e.key === "F12" || (e.ctrlKey && !AllowedKeys.includes(e.key.toUpperCase()))) { e.preventDefault(); e.stopPropagation(); console.log('Press key: ', e.ctrlKey ? 'Ctrl' : '', e.shiftKey ? ' Shift' : '', e.key) From d59a293bb9ad5aef3bdf3a3b17a4a288373a4521 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Mon, 12 Jun 2023 18:16:09 +0800 Subject: [PATCH 109/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=BB=84=E6=B7=BB=E5=8A=A0=E5=85=A8=E9=83=A8=E7=94=A8?= =?UTF-8?q?=E6=88=B7api=E7=9A=84=E6=9D=83=E9=99=90=E4=BD=8D=20(#10683)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/users/api/group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/users/api/group.py b/apps/users/api/group.py index a87f964e9..6cccfb4a2 100644 --- a/apps/users/api/group.py +++ b/apps/users/api/group.py @@ -18,7 +18,7 @@ class UserGroupViewSet(OrgBulkModelViewSet): serializer_class = UserGroupSerializer ordering = ('name',) rbac_perms = ( - ("add_all_users", "users.change_usergroup"), + ("add_all_users", "users.add_usergroup"), ) @action(methods=['post'], detail=True, url_path='add-all-users') From f9bc7ec4aab66f068ac3774c338ba554c2028867 Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 18:20:30 +0800 Subject: [PATCH 110/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E8=BF=87=E6=BB=A4=20acl=20=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/models/connection_token.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/authentication/models/connection_token.py b/apps/authentication/models/connection_token.py index e0793c7dc..f1db30d7f 100644 --- a/apps/authentication/models/connection_token.py +++ b/apps/authentication/models/connection_token.py @@ -16,6 +16,7 @@ from common.exceptions import JMSException from common.utils import lazyproperty, pretty_string, bulk_get from common.utils.timezone import as_current_tz from orgs.mixins.models import JMSOrgBaseModel +from orgs.utils import tmp_to_org from terminal.models import Applet @@ -253,9 +254,10 @@ class ConnectionToken(JMSOrgBaseModel): kwargs = { 'user': self.user, 'asset': self.asset, - 'account': self.account_object, + 'account_username': self.account, } - acls = CommandFilterACL.filter_queryset(**kwargs).valid() + with tmp_to_org(self.asset.org_id): + acls = CommandFilterACL.filter_queryset(**kwargs).valid() return acls From 09a5b63240ff4485de347bae17079c3d430f578e Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 18:28:04 +0800 Subject: [PATCH 111/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20acl=20filt?= =?UTF-8?q?er?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/models/connection_token.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/authentication/models/connection_token.py b/apps/authentication/models/connection_token.py index f1db30d7f..0407cf025 100644 --- a/apps/authentication/models/connection_token.py +++ b/apps/authentication/models/connection_token.py @@ -254,7 +254,7 @@ class ConnectionToken(JMSOrgBaseModel): kwargs = { 'user': self.user, 'asset': self.asset, - 'account_username': self.account, + 'account': self.account_object, } with tmp_to_org(self.asset.org_id): acls = CommandFilterACL.filter_queryset(**kwargs).valid() From 1e9310bf0c2f9b69958dd011f95ad0184eb1cd7c Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 19:00:59 +0800 Subject: [PATCH 112/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20applet=20?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/models/applet/applet.py | 2 +- apps/terminal/serializers/applet.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index 86c21f7e5..3193b5ea5 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -138,7 +138,7 @@ class Applet(JMSBaseModel): name = manifest['name'] instance = cls.objects.filter(name=name).first() serializer = AppletSerializer(instance=instance, data=manifest) - serializer.is_valid() + serializer.is_valid(raise_exception=True) instance = serializer.save(builtin=builtin) instance.load_platform_if_need(path) diff --git a/apps/terminal/serializers/applet.py b/apps/terminal/serializers/applet.py index 79427b4b6..aa3623436 100644 --- a/apps/terminal/serializers/applet.py +++ b/apps/terminal/serializers/applet.py @@ -27,7 +27,8 @@ class AppletPublicationSerializer(serializers.ModelSerializer): class AppletSerializer(serializers.ModelSerializer): icon = serializers.ReadOnlyField(label=_("Icon")) type = LabeledChoiceField(choices=Applet.Type.choices, label=_("Type")) - edition = LabeledChoiceField(choices=Applet.Edition.choices, label=_("Edition")) + edition = LabeledChoiceField(choices=Applet.Edition.choices, label=_("Edition"), required=False, + default=Applet.Edition.community) class Meta: model = Applet From 44d92b9dece05d851c2d6586d15badbd8bfea05d Mon Sep 17 00:00:00 2001 From: ibuler Date: Mon, 12 Jun 2023 19:12:11 +0800 Subject: [PATCH 113/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20acl=20user?= =?UTF-8?q?=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/orgs/models.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/apps/orgs/models.py b/apps/orgs/models.py index de2b087a3..647c37cb9 100644 --- a/apps/orgs/models.py +++ b/apps/orgs/models.py @@ -9,10 +9,21 @@ logger = get_logger(__name__) class OrgRoleMixin: + ROOT_ID = '00000000-0000-0000-0000-000000000000' + ROOT_NAME = _('GLOBAL') + DEFAULT_ID = '00000000-0000-0000-0000-000000000002' + DEFAULT_NAME = _('DEFAULT') + SYSTEM_ID = '00000000-0000-0000-0000-000000000004' + SYSTEM_NAME = _('SYSTEM') members: models.Manager + id: str def get_members(self): - return self.members.all().distinct() + from users.models import User + if self.id == self.ROOT_ID: + return User.objects.all().exclude(is_service_account=True) + else: + return self.members.all().distinct() def add_member(self, user, role=None): from rbac.builtin import BuiltinRole @@ -72,12 +83,6 @@ class Organization(OrgRoleMixin, JMSBaseModel): 'users.User', related_name='orgs', through='rbac.RoleBinding', through_fields=('org', 'user') ) - ROOT_ID = '00000000-0000-0000-0000-000000000000' - ROOT_NAME = _('GLOBAL') - DEFAULT_ID = '00000000-0000-0000-0000-000000000002' - DEFAULT_NAME = _('DEFAULT') - SYSTEM_ID = '00000000-0000-0000-0000-000000000004' - SYSTEM_NAME = _('SYSTEM') orgs_mapping = None class Meta: From 4a2f7d21f6e8ef19bd2c8217fe0aeb9ad4d83a08 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 13 Jun 2023 09:54:03 +0800 Subject: [PATCH 114/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=99=BB?= =?UTF-8?q?=E5=BD=95=20ticket=20=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/models/login_acl.py | 6 +++--- apps/authentication/mixins.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/acls/models/login_acl.py b/apps/acls/models/login_acl.py index ce678e236..7191fe4b6 100644 --- a/apps/acls/models/login_acl.py +++ b/apps/acls/models/login_acl.py @@ -20,18 +20,18 @@ class LoginACL(UserBaseACL): def is_action(self, action): return self.action == action - def create_confirm_ticket(self, request): + def create_confirm_ticket(self, request, user): from tickets import const from tickets.models import ApplyLoginTicket from orgs.models import Organization - title = _('Login confirm') + ' {}'.format(request.user) + title = _('Login confirm') + ' {}'.format(user) login_ip = get_request_ip(request) if request else '' login_ip = login_ip or '0.0.0.0' login_city = get_ip_city(login_ip) login_datetime = local_now_display() data = { 'title': title, - 'applicant': request.user, + 'applicant': user, 'apply_login_ip': login_ip, 'org_id': Organization.ROOT_ID, 'apply_login_city': login_city, diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index 647aac773..e859fe4de 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -375,13 +375,13 @@ class AuthACLMixin: return if not acl.is_action(acl.ActionChoices.review): return - self.get_ticket_or_create(acl) + self.get_ticket_or_create(acl, user) self.check_user_login_confirm() - def get_ticket_or_create(self, acl): + def get_ticket_or_create(self, acl, user): ticket = self.get_ticket() if not ticket or ticket.is_state(ticket.State.closed): - ticket = acl.create_confirm_ticket(self.request) + ticket = acl.create_confirm_ticket(self.request, user) self.request.session['auth_ticket_id'] = str(ticket.id) return ticket From 9a29cda2106f1b1f670f14ff056d55a4e7016b29 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Tue, 13 Jun 2023 11:21:48 +0800 Subject: [PATCH 115/153] =?UTF-8?q?fix:=20=E6=8F=90=E4=BE=9B=E7=BB=99luna?= =?UTF-8?q?=E7=9A=84=E5=BD=95=E5=83=8F=E5=9C=B0=E5=9D=80=E4=B8=8D=E8=83=BD?= =?UTF-8?q?=E4=B8=BA=E6=9C=AC=E5=9C=B0local=E5=9C=B0=E5=9D=80=EF=BC=8C?= =?UTF-8?q?=E5=BA=94=E8=AF=A5=E4=B8=BAurl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/session/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/terminal/api/session/session.py b/apps/terminal/api/session/session.py index f80617fd6..9fdd855c8 100644 --- a/apps/terminal/api/session/session.py +++ b/apps/terminal/api/session/session.py @@ -214,7 +214,7 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet): local_path, url_or_err = storage.get_file_path_url() if local_path is None: return Response({"error": url_or_err}, status=404) - data = self.get_replay_data(session, local_path) + data = self.get_replay_data(session, url_or_err) return Response(data) From a991a6c56c86c1c4c3ed26e4bb6c117cc955cbd5 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Tue, 13 Jun 2023 11:33:08 +0800 Subject: [PATCH 116/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/api.py | 5 +++-- apps/audits/tasks.py | 2 +- apps/terminal/api/session/session.py | 12 +++++++----- apps/terminal/tasks.py | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/apps/audits/api.py b/apps/audits/api.py index e88afe7ed..56fff6297 100644 --- a/apps/audits/api.py +++ b/apps/audits/api.py @@ -79,9 +79,10 @@ class FTPLogViewSet(OrgModelViewSet): def download(self, request, *args, **kwargs): ftp_log = self.get_object() ftp_storage = self.get_storage() - local_path, url_or_err = ftp_storage.get_file_path_url() + local_path, url = ftp_storage.get_file_path_url() if local_path is None: - return HttpResponse(url_or_err) + # url => error message + return HttpResponse(url) file = open(default_storage.path(local_path), 'rb') response = FileResponse(file) diff --git a/apps/audits/tasks.py b/apps/audits/tasks.py index a0da3f782..ffda01219 100644 --- a/apps/audits/tasks.py +++ b/apps/audits/tasks.py @@ -119,7 +119,7 @@ def upload_ftp_file_to_external_storage(ftp_log_id, file_name): logger.error(f'FTP db item not found: {ftp_log_id}') return ftp_storage = FTPFileStorageHandler(ftp_log) - local_path, url_or_err = ftp_storage.find_local() + local_path, url = ftp_storage.find_local() if not local_path: logger.error(f'FTP file record not found, may be upload error. file name: {file_name}') return diff --git a/apps/terminal/api/session/session.py b/apps/terminal/api/session/session.py index 9fdd855c8..c414dd289 100644 --- a/apps/terminal/api/session/session.py +++ b/apps/terminal/api/session/session.py @@ -117,9 +117,10 @@ class SessionViewSet(OrgBulkModelViewSet): url_name='replay-download') def download(self, request, *args, **kwargs): storage = self.get_storage() - local_path, url_or_err = storage.get_file_path_url() + local_path, url = storage.get_file_path_url() if local_path is None: - return Response({'error': url_or_err}, status=404) + # url => error message + return Response({'error': url}, status=404) file = self.prepare_offline_file(storage.obj, local_path) response = FileResponse(file) @@ -211,10 +212,11 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet): session = get_object_or_404(Session, id=session_id) storage = ReplayStorageHandler(session) - local_path, url_or_err = storage.get_file_path_url() + local_path, url = storage.get_file_path_url() if local_path is None: - return Response({"error": url_or_err}, status=404) - data = self.get_replay_data(session, url_or_err) + # url => error message + return Response({"error": url}, status=404) + data = self.get_replay_data(session, url) return Response(data) diff --git a/apps/terminal/tasks.py b/apps/terminal/tasks.py index e6f8a9140..380bd94f6 100644 --- a/apps/terminal/tasks.py +++ b/apps/terminal/tasks.py @@ -67,7 +67,7 @@ def upload_session_replay_to_external_storage(session_id): return replay_storage = ReplayStorageHandler(session) - local_path, url_or_err = replay_storage.find_local() + local_path, url = replay_storage.find_local() if not local_path: logger.error(f'Session replay not found, may be upload error: {local_path}') return From 71ccfe66ec94c5deabded6fbe89b2b1f3ebf6a0d Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Tue, 13 Jun 2023 13:14:38 +0800 Subject: [PATCH 117/153] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3migrate?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=B8=AD=E8=BF=81=E7=A7=BB=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E4=BC=9A=E8=A7=A6=E5=8F=91=E4=BF=A1=E5=8F=B7=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E4=B8=8D=E5=AF=B9=E5=BA=94=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=BC=95=E5=8F=91=E8=BF=81=E7=A7=BB=E5=A4=B1=E8=B4=A5=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/handler.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/audits/handler.py b/apps/audits/handler.py index a304ba7c1..6ac055778 100644 --- a/apps/audits/handler.py +++ b/apps/audits/handler.py @@ -72,7 +72,12 @@ class OperatorLogHandler(metaclass=Singleton): if instance_id is None: return log_id, before, after - log_id, cache_instance = self.get_instance_dict_from_cache(instance_id) + try: + log_id, cache_instance = self.get_instance_dict_from_cache(instance_id) + except Exception as err: + logger.error('Get instance diff from cache error: %s' % err) + return log_id, before, after + if not cache_instance: return log_id, before, after From af018ea26248228d533cefb9c09514aee91e141e Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Tue, 13 Jun 2023 13:18:50 +0800 Subject: [PATCH 118/153] =?UTF-8?q?perf:=20=E5=AD=97=E6=AE=B5=E5=90=AB?= =?UTF-8?q?=E4=B9=89=E5=92=8CSession=20model=E4=BF=9D=E6=8C=81=E4=B8=80?= =?UTF-8?q?=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/audits/models.py b/apps/audits/models.py index 1b93c5715..a0de58d05 100644 --- a/apps/audits/models.py +++ b/apps/audits/models.py @@ -58,7 +58,7 @@ class FTPLog(OrgModelMixin): filename = models.CharField(max_length=1024, verbose_name=_("Filename")) is_success = models.BooleanField(default=True, verbose_name=_("Success")) date_start = models.DateTimeField(auto_now_add=True, verbose_name=_("Date start")) - has_file = models.BooleanField(default=False, verbose_name=_("File Record")) + has_file = models.BooleanField(default=False, verbose_name=_("File")) session = models.CharField(max_length=36, verbose_name=_("Session"), default=uuid.uuid4) class Meta: From 7e9d1fc945df239857a415b8c683daf690c4340d Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 13 Jun 2023 13:48:32 +0800 Subject: [PATCH 119/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20json=20m2m?= =?UTF-8?q?=20field=20=E6=AD=A3=E5=90=91=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index a84a9de6f..9ebd149c9 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -442,9 +442,7 @@ class JSONManyToManyDescriptor: # 自定义的情况:比如 nodes, category res = True to_model = apps.get_model(self.field.to) - src_model = self.field.model - field_name = self.field.name - custom_attr_filter = getattr(src_model, "get_filter_{}_attr_q".format(field_name), None) + custom_attr_filter = getattr(to_model, "get_json_filter_attr_q", None) custom_q = Q() for rule in attr_rules: @@ -510,14 +508,23 @@ class JSONManyToManyDescriptor: return res def get_filter_q(self, instance): + """ + 这个是某个 instance 获取 关联 资源的 filter q + :param instance: + :return: + """ model_cls = self.field.model field_name = self.field.column q = Q(**{f'{field_name}__type': 'all'}) | \ - Q(**{f'{field_name}__type': 'ids', f'{field_name}__ids__contains': [str(instance.id)]}) + Q(**{ + f'{field_name}__type': 'ids', + f'{field_name}__ids__contains': [str(instance.id)] + }) queryset_id_attrs = model_cls.objects \ .filter(**{'{}__type'.format(field_name): 'attrs'}) \ .values_list('id', '{}__attrs'.format(field_name)) - ids = [str(_id) for _id, attr_rules in queryset_id_attrs if self.is_match(instance, attr_rules)] + ids = [str(_id) for _id, attr_rules in queryset_id_attrs + if self.is_match(instance, attr_rules)] if ids: q |= Q(id__in=ids) return q From 4683ae8c09c41831547b7c4a5cd43bc27537b091 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Tue, 13 Jun 2023 13:54:59 +0800 Subject: [PATCH 120/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E8=BF=81?= =?UTF-8?q?=E7=A7=BB=E6=96=87=E4=BB=B6=E4=B8=AD=E7=9A=84=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/audits/migrations/0022_auto_20230605_1555.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/audits/migrations/0022_auto_20230605_1555.py b/apps/audits/migrations/0022_auto_20230605_1555.py index 97db7b341..c5ec8847f 100644 --- a/apps/audits/migrations/0022_auto_20230605_1555.py +++ b/apps/audits/migrations/0022_auto_20230605_1555.py @@ -14,7 +14,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='ftplog', name='has_file', - field=models.BooleanField(default=False, verbose_name='File Record'), + field=models.BooleanField(default=False, verbose_name='File'), ), migrations.AddField( model_name='ftplog', From dfd1ececdb7f5b038087f75dee15ba9e0177d1d8 Mon Sep 17 00:00:00 2001 From: jiangweidong Date: Tue, 13 Jun 2023 13:58:27 +0800 Subject: [PATCH 121/153] =?UTF-8?q?perf:=20=E5=88=A0=E9=99=A4=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.po | 4 ---- apps/locale/zh/LC_MESSAGES/django.po | 4 ---- 2 files changed, 8 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 9688219e7..b32824b18 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -1964,10 +1964,6 @@ msgstr "操作" msgid "Filename" msgstr "ファイル名" -#: audits/models.py:61 -msgid "File Record" -msgstr "" - #: audits/models.py:62 terminal/backends/command/models.py:24 #: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18 #: terminal/models/session/sharing.py:81 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 7540ebf5d..3b99bfe8d 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -1953,10 +1953,6 @@ msgstr "操作" msgid "Filename" msgstr "文件名" -#: audits/models.py:61 -msgid "File Record" -msgstr "" - #: audits/models.py:62 terminal/backends/command/models.py:24 #: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18 #: terminal/models/session/sharing.py:81 From 0d3478c728282396cba87d1670576a946626d6dc Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 13 Jun 2023 14:38:52 +0800 Subject: [PATCH 122/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20acl=20?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E4=B8=AD=E7=9A=84=20accounts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/migrations/0012_auto_20230426_1111.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/acls/migrations/0012_auto_20230426_1111.py b/apps/acls/migrations/0012_auto_20230426_1111.py index 277905fcd..c0e225138 100644 --- a/apps/acls/migrations/0012_auto_20230426_1111.py +++ b/apps/acls/migrations/0012_auto_20230426_1111.py @@ -25,10 +25,9 @@ def migrate_base_acl_users_assets_accounts(apps, *args): obj.new_assets = {"type": "attrs", "attrs": asset_attrs} account_usernames = (obj.accounts or {}).get('username_group', []) - obj.new_accounts = { - "type": "attrs", - "attrs": [{"name": "username", "value": account_usernames, "match": "in"}] - } + if '*' in account_usernames: + account_usernames = ['@ALL'] + obj.new_accounts = account_usernames obj.save() From 93c0f11a5f20dc1ea3ae7f8c022d69315aa956c1 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 13 Jun 2023 15:50:21 +0800 Subject: [PATCH 123/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=AD=A3=E5=8F=91?= =?UTF-8?q?=E5=B8=83=E6=9C=BA=E9=83=A8=E7=BD=B2=E5=8D=95=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=8D=95=E4=BC=9A=E8=AF=9D=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/serializers/applet_host.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/terminal/serializers/applet_host.py b/apps/terminal/serializers/applet_host.py index 158dfeafa..f866d6213 100644 --- a/apps/terminal/serializers/applet_host.py +++ b/apps/terminal/serializers/applet_host.py @@ -25,8 +25,8 @@ class DeployOptionsSerializer(serializers.Serializer): (2, _('Per Device')), ) SESSION_PER_USER = ( - (1, _("Disabled")), - (0, _("Enabled")), + (0, _("Disabled")), + (1, _("Enabled")), ) CORE_HOST = serializers.CharField( From c056cde2b70c783be2d1700e472f64a689ed0932 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Tue, 13 Jun 2023 15:51:52 +0800 Subject: [PATCH 124/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=20(#10697)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- .../0017_alter_connectmethodacl_options.py | 17 ++ apps/acls/models/connect_method.py | 4 + apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 286 ++++++++---------- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 276 ++++++++--------- 6 files changed, 289 insertions(+), 302 deletions(-) create mode 100644 apps/acls/migrations/0017_alter_connectmethodacl_options.py diff --git a/apps/acls/migrations/0017_alter_connectmethodacl_options.py b/apps/acls/migrations/0017_alter_connectmethodacl_options.py new file mode 100644 index 000000000..39132b450 --- /dev/null +++ b/apps/acls/migrations/0017_alter_connectmethodacl_options.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.19 on 2023-06-13 07:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('acls', '0016_auto_20230606_1857'), + ] + + operations = [ + migrations.AlterModelOptions( + name='connectmethodacl', + options={'ordering': ('priority', 'name'), 'verbose_name': 'Connect method acl'}, + ), + ] diff --git a/apps/acls/models/connect_method.py b/apps/acls/models/connect_method.py index 2ae61a13c..5ee9c9cfb 100644 --- a/apps/acls/models/connect_method.py +++ b/apps/acls/models/connect_method.py @@ -8,3 +8,7 @@ __all__ = ['ConnectMethodACL'] class ConnectMethodACL(UserBaseACL): connect_methods = models.JSONField(default=list, verbose_name=_('Connect methods')) + + class Meta(UserBaseACL.Meta): + verbose_name = _('Connect method acl') + abstract = False diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 30c105fcf..09f2ef0d4 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7db1805061d28a0ba931846140e9f106b71ed5ebeb414f741b68d6c3d93130be -size 142961 +oid sha256:70eb1665cc86e50cf78d3b80730aadf7963b51640b80fde21b4e207b7cbb5d0c +size 144416 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index b32824b18..97fd54244 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-09 10:59+0800\n" +"POT-Creation-Date: 2023-06-13 15:47+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -70,7 +70,7 @@ msgstr "ローカル" msgid "Collected" msgstr "集めました" -#: accounts/const/account.py:21 accounts/serializers/account/account.py:26 +#: accounts/const/account.py:21 accounts/serializers/account/account.py:27 #: settings/serializers/auth/sms.py:75 msgid "Template" msgstr "テンプレート" @@ -181,15 +181,15 @@ msgstr "作成のみ" #: accounts/models/account.py:49 #: accounts/models/automations/gather_account.py:16 -#: accounts/serializers/account/account.py:203 -#: accounts/serializers/account/account.py:236 +#: accounts/serializers/account/account.py:200 +#: accounts/serializers/account/account.py:237 #: accounts/serializers/account/gathered_account.py:10 #: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:132 #: acls/serializers/base.py:118 assets/models/asset/common.py:93 #: assets/models/asset/common.py:332 assets/models/cmd_filter.py:36 #: assets/serializers/domain.py:19 assets/serializers/label.py:27 -#: audits/models.py:53 authentication/models/connection_token.py:34 +#: audits/models.py:53 authentication/models/connection_token.py:35 #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 @@ -199,7 +199,7 @@ msgstr "資産" #: accounts/models/account.py:53 accounts/models/account.py:113 #: accounts/serializers/account/account.py:208 -#: accounts/serializers/account/account.py:246 +#: accounts/serializers/account/account.py:247 #: accounts/serializers/account/template.py:16 #: authentication/serializers/connect_token_secret.py:49 msgid "Su from" @@ -210,7 +210,7 @@ msgstr "から切り替え" msgid "Version" msgstr "バージョン" -#: accounts/models/account.py:57 accounts/serializers/account/account.py:204 +#: accounts/models/account.py:57 accounts/serializers/account/account.py:203 #: users/models/user.py:804 msgid "Source" msgstr "ソース" @@ -356,7 +356,7 @@ msgid "Can add push account execution" msgstr "プッシュ アカウントの作成の実行" #: accounts/models/automations/change_secret.py:18 accounts/models/base.py:36 -#: accounts/serializers/account/account.py:416 +#: accounts/serializers/account/account.py:419 #: accounts/serializers/account/base.py:16 #: accounts/serializers/automations/change_secret.py:46 #: authentication/serializers/connect_token_secret.py:41 @@ -406,7 +406,7 @@ msgid "Date finished" msgstr "終了日" #: accounts/models/automations/change_secret.py:93 -#: accounts/serializers/account/account.py:238 assets/const/automation.py:8 +#: accounts/serializers/account/account.py:239 assets/const/automation.py:8 #: authentication/views/base.py:29 authentication/views/base.py:30 #: authentication/views/base.py:31 common/const/choices.py:20 msgid "Error" @@ -458,7 +458,7 @@ msgstr "アカウントのコレクション" msgid "Triggers" msgstr "トリガー方式" -#: accounts/models/automations/push_account.py:16 acls/models/base.py:43 +#: accounts/models/automations/push_account.py:16 acls/models/base.py:46 #: acls/serializers/base.py:56 assets/models/cmd_filter.py:81 #: audits/models.py:87 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:116 @@ -474,7 +474,7 @@ msgstr "アカウントプッシュ" msgid "Verify asset account" msgstr "アカウントの確認" -#: accounts/models/base.py:33 acls/models/base.py:37 acls/models/base.py:97 +#: accounts/models/base.py:33 acls/models/base.py:40 acls/models/base.py:101 #: acls/models/command_acl.py:21 acls/serializers/base.py:34 #: applications/models.py:9 assets/models/_user.py:22 #: assets/models/asset/common.py:91 assets/models/asset/common.py:149 @@ -486,7 +486,7 @@ msgstr "アカウントの確認" #: authentication/serializers/connect_token_secret.py:110 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 -#: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29 +#: orgs/models.py:80 perms/models/asset_permission.py:56 rbac/models/role.py:29 #: settings/models.py:33 settings/serializers/sms.py:6 #: terminal/models/applet/applet.py:32 terminal/models/component/endpoint.py:12 #: terminal/models/component/endpoint.py:90 @@ -505,7 +505,7 @@ msgstr "特権アカウント" #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:114 -#: terminal/models/applet/applet.py:38 users/serializers/user.py:170 +#: terminal/models/applet/applet.py:39 users/serializers/user.py:170 msgid "Is active" msgstr "アクティブです。" @@ -550,15 +550,15 @@ msgstr "" "{} -暗号化変更タスクが完了しました: 暗号化パスワードが設定されていません-個人" "情報にアクセスしてください-> ファイル暗号化パスワードを設定してください" -#: accounts/serializers/account/account.py:29 +#: accounts/serializers/account/account.py:30 msgid "Push now" msgstr "今すぐプッシュ" -#: accounts/serializers/account/account.py:36 +#: accounts/serializers/account/account.py:37 msgid "Exist policy" msgstr "アカウントの存在ポリシー" -#: accounts/serializers/account/account.py:183 applications/models.py:11 +#: accounts/serializers/account/account.py:180 applications/models.py:11 #: assets/models/label.py:21 assets/models/platform.py:82 #: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8 #: assets/serializers/platform.py:110 assets/serializers/platform.py:193 @@ -567,7 +567,7 @@ msgstr "アカウントの存在ポリシー" msgid "Category" msgstr "カテゴリ" -#: accounts/serializers/account/account.py:184 +#: accounts/serializers/account/account.py:181 #: accounts/serializers/automations/base.py:54 acls/models/command_acl.py:24 #: acls/serializers/command_acl.py:18 applications/models.py:14 #: assets/models/_user.py:50 assets/models/automations/base.py:20 @@ -575,7 +575,7 @@ msgstr "カテゴリ" #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 #: assets/serializers/platform.py:109 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 -#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:37 +#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/serializers/session.py:22 terminal/serializers/storage.py:224 @@ -586,28 +586,28 @@ msgstr "カテゴリ" msgid "Type" msgstr "タイプ" -#: accounts/serializers/account/account.py:199 +#: accounts/serializers/account/account.py:196 msgid "Asset not found" msgstr "資産が存在しません" -#: accounts/serializers/account/account.py:205 +#: accounts/serializers/account/account.py:201 #: accounts/serializers/account/base.py:64 msgid "Has secret" msgstr "エスクローされたパスワード" -#: accounts/serializers/account/account.py:237 ops/models/celery.py:60 +#: accounts/serializers/account/account.py:238 ops/models/celery.py:60 #: tickets/models/comment.py:13 tickets/models/ticket/general.py:45 #: tickets/models/ticket/general.py:279 tickets/serializers/super_ticket.py:14 #: tickets/serializers/ticket/ticket.py:21 msgid "State" msgstr "状態" -#: accounts/serializers/account/account.py:239 +#: accounts/serializers/account/account.py:240 msgid "Changed" msgstr "編集済み" -#: accounts/serializers/account/account.py:249 -#: accounts/serializers/automations/base.py:22 acls/models/base.py:98 +#: accounts/serializers/account/account.py:250 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:102 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -615,30 +615,30 @@ msgstr "編集済み" msgid "Assets" msgstr "資産" -#: accounts/serializers/account/account.py:301 +#: accounts/serializers/account/account.py:305 msgid "Account already exists" msgstr "アカウントはすでに存在しています" -#: accounts/serializers/account/account.py:351 +#: accounts/serializers/account/account.py:355 #, python-format msgid "Asset does not support this secret type: %s" msgstr "アセットはアカウント タイプをサポートしていません: %s" -#: accounts/serializers/account/account.py:383 +#: accounts/serializers/account/account.py:387 msgid "Account has exist" msgstr "アカウントはすでに存在しています" -#: accounts/serializers/account/account.py:417 +#: accounts/serializers/account/account.py:420 #: authentication/serializers/connect_token_secret.py:156 #: authentication/templates/authentication/_access_key_modal.html:30 #: perms/models/perm_node.py:21 users/serializers/group.py:33 msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:424 acls/serializers/base.py:111 +#: accounts/serializers/account/account.py:427 acls/serializers/base.py:111 #: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:49 #: audits/models.py:85 audits/models.py:163 -#: authentication/models/connection_token.py:30 +#: authentication/models/connection_token.py:31 #: authentication/models/sso_token.py:16 #: notifications/models/notification.py:12 #: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:58 @@ -652,7 +652,7 @@ msgstr "ID" msgid "User" msgstr "ユーザー" -#: accounts/serializers/account/account.py:425 +#: accounts/serializers/account/account.py:428 #: authentication/templates/authentication/_access_key_modal.html:33 #: terminal/notifications.py:98 terminal/notifications.py:146 msgid "Date" @@ -778,47 +778,47 @@ msgstr "秘密鍵が無効またはpassphraseエラー" msgid "Acls" msgstr "Acls" -#: acls/models/base.py:17 tickets/const.py:45 +#: acls/models/base.py:20 tickets/const.py:45 #: tickets/templates/tickets/approve_check_password.html:49 msgid "Reject" msgstr "拒否" -#: acls/models/base.py:18 +#: acls/models/base.py:21 msgid "Accept" msgstr "受け入れられる" -#: acls/models/base.py:19 +#: acls/models/base.py:22 msgid "Review" msgstr "レビュー担当者" -#: acls/models/base.py:39 assets/models/_user.py:51 +#: acls/models/base.py:42 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:93 msgid "Priority" msgstr "優先順位" -#: acls/models/base.py:40 assets/models/_user.py:51 +#: acls/models/base.py:43 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:94 msgid "1-100, the lower the value will be match first" msgstr "1-100、低い値は最初に一致します" -#: acls/models/base.py:44 assets/models/cmd_filter.py:86 +#: acls/models/base.py:47 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "レビュー担当者" -#: acls/models/base.py:45 authentication/models/access_key.py:17 -#: authentication/models/connection_token.py:51 +#: acls/models/base.py:48 authentication/models/access_key.py:17 +#: authentication/models/connection_token.py:52 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 #: tickets/const.py:37 msgid "Active" msgstr "アクティブ" -#: acls/models/base.py:83 users/apps.py:9 +#: acls/models/base.py:86 users/apps.py:9 msgid "Users" msgstr "ユーザー" -#: acls/models/base.py:99 assets/models/automations/base.py:17 +#: acls/models/base.py:103 assets/models/automations/base.py:17 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 #: rbac/tree.py:35 msgid "Accounts" @@ -837,7 +837,7 @@ msgid "Regex" msgstr "正規情報" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 msgid "Content" msgstr "コンテンツ" @@ -868,11 +868,13 @@ msgid "Command confirm" msgstr "コマンドの確認" #: acls/models/connect_method.py:10 -#, fuzzy -#| msgid "Connect method" msgid "Connect methods" msgstr "接続方法" +#: acls/models/connect_method.py:13 +msgid "Connect method acl" +msgstr "接続方法acl" + #: acls/models/login_acl.py:11 acls/models/login_asset_acl.py:9 #: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:13 msgid "Rule" @@ -1001,7 +1003,7 @@ msgid "{} disabled" msgstr "{} 無効" #: assets/automations/ping_gateway/manager.py:33 -#: authentication/models/connection_token.py:116 +#: authentication/models/connection_token.py:117 msgid "No account" msgstr "アカウントなし" @@ -1146,7 +1148,7 @@ msgstr "SSHパブリックキー" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:43 terminal/models/applet/applet.py:242 +#: terminal/models/applet/applet.py:44 terminal/models/applet/applet.py:243 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 @@ -1194,9 +1196,9 @@ msgstr "管理ユーザー" msgid "Username same with user" msgstr "ユーザーと同じユーザー名" -#: assets/models/_user.py:52 authentication/models/connection_token.py:39 +#: assets/models/_user.py:52 authentication/models/connection_token.py:40 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:40 terminal/serializers/session.py:20 +#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:20 #: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "プロトコル" @@ -1262,7 +1264,7 @@ msgstr "アドレス" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:187 +#: xpack/plugins/cloud/serializers/account_attrs.py:196 msgid "Platform" msgstr "プラットフォーム" @@ -1357,7 +1359,7 @@ msgstr "アセットの自動化タスク" #: assets/models/automations/base.py:113 audits/models.py:199 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:241 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:242 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 @@ -1440,7 +1442,7 @@ msgstr "システム" #: assets/models/label.py:19 assets/models/node.py:557 #: assets/serializers/cagegory.py:7 assets/serializers/cagegory.py:14 -#: authentication/models/connection_token.py:27 +#: authentication/models/connection_token.py:28 #: authentication/serializers/connect_token_secret.py:122 #: common/serializers/common.py:86 settings/models.py:34 msgid "Value" @@ -1646,7 +1648,8 @@ msgstr "プロトコルが必要です: {}" msgid "Default database" msgstr "デフォルト・データベース" -#: assets/serializers/asset/database.py:28 common/serializers/fields.py:104 +#: assets/serializers/asset/database.py:28 common/db/fields.py:557 +#: common/db/fields.py:562 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -1883,10 +1886,8 @@ msgid "Download" msgstr "ダウンロード" #: audits/const.py:19 -#, fuzzy -#| msgid "Rename attr" msgid "Rename dir" -msgstr "マッピングのプロパティ" +msgstr "マップディレクトリ" #: audits/const.py:23 rbac/tree.py:228 msgid "View" @@ -1939,11 +1940,11 @@ msgstr "タスク" msgid "-" msgstr "-" -#: audits/handler.py:114 +#: audits/handler.py:112 msgid "Yes" msgstr "是" -#: audits/handler.py:114 +#: audits/handler.py:112 msgid "No" msgstr "否" @@ -2119,10 +2120,8 @@ msgid "Clean audits session task log" msgstr "監査セッション タスク ログのクリーンアップ" #: audits/tasks.py:114 -#, fuzzy -#| msgid "Upload session replay to external storage" msgid "Upload FTP file to external storage" -msgstr "セッションの記録を外部ストレージにアップロードする" +msgstr "外部ストレージへのFTPファイルのアップロード" #: authentication/api/confirm.py:40 msgid "This action require verify your MFA" @@ -2521,80 +2520,78 @@ msgstr "MFAタイプ ({}) が有効になっていない" msgid "Please change your password" msgstr "パスワードを変更してください" -#: authentication/models/connection_token.py:36 +#: authentication/models/connection_token.py:37 #: terminal/serializers/storage.py:111 msgid "Account name" msgstr "アカウント名" -#: authentication/models/connection_token.py:37 +#: authentication/models/connection_token.py:38 msgid "Input username" msgstr "カスタム ユーザー名" -#: authentication/models/connection_token.py:38 +#: authentication/models/connection_token.py:39 #: authentication/serializers/connection_token.py:20 msgid "Input secret" msgstr "カスタムパスワード" -#: authentication/models/connection_token.py:40 +#: authentication/models/connection_token.py:41 msgid "Connect method" msgstr "接続方法" -#: authentication/models/connection_token.py:41 -#, fuzzy -#| msgid "Connections" -msgid "Connect options" -msgstr "接続" - #: authentication/models/connection_token.py:42 +msgid "Connect options" +msgstr "接続アイテム" + +#: authentication/models/connection_token.py:43 #: rbac/serializers/rolebinding.py:21 msgid "User display" msgstr "ユーザー表示" -#: authentication/models/connection_token.py:43 +#: authentication/models/connection_token.py:44 msgid "Asset display" msgstr "アセット名" -#: authentication/models/connection_token.py:44 +#: authentication/models/connection_token.py:45 msgid "Reusable" msgstr "再利用可能" -#: authentication/models/connection_token.py:45 +#: authentication/models/connection_token.py:46 #: authentication/models/temp_token.py:13 perms/models/asset_permission.py:74 #: tickets/models/ticket/apply_application.py:31 #: tickets/models/ticket/apply_asset.py:20 users/models/user.py:797 msgid "Date expired" msgstr "期限切れの日付" -#: authentication/models/connection_token.py:49 +#: authentication/models/connection_token.py:50 #: perms/models/asset_permission.py:77 msgid "From ticket" msgstr "チケットから" -#: authentication/models/connection_token.py:55 +#: authentication/models/connection_token.py:56 msgid "Connection token" msgstr "接続トークン" -#: authentication/models/connection_token.py:57 +#: authentication/models/connection_token.py:58 msgid "Can view connection token secret" msgstr "接続トークンの秘密を表示できます" -#: authentication/models/connection_token.py:104 +#: authentication/models/connection_token.py:105 msgid "Connection token inactive" msgstr "接続トークンがアクティブ化されていません" -#: authentication/models/connection_token.py:107 +#: authentication/models/connection_token.py:108 msgid "Connection token expired at: {}" msgstr "接続トークンの有効期限: {}" -#: authentication/models/connection_token.py:110 +#: authentication/models/connection_token.py:111 msgid "No user or invalid user" msgstr "ユーザーなしまたは期限切れのユーザー" -#: authentication/models/connection_token.py:113 +#: authentication/models/connection_token.py:114 msgid "No asset or inactive asset" msgstr "アセットがないか、有効化されていないアセット" -#: authentication/models/connection_token.py:265 +#: authentication/models/connection_token.py:267 msgid "Super connection token" msgstr "スーパー接続トークン" @@ -2758,7 +2755,7 @@ msgstr "コードエラー" #: authentication/templates/authentication/_msg_reset_password_code.html:9 #: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_public_key_success.html:2 -#: jumpserver/conf.py:423 +#: jumpserver/conf.py:426 #: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3 #: tickets/templates/tickets/approve_check_password.html:33 @@ -3116,26 +3113,26 @@ msgstr "テキストフィールドへのマーシャルデータ" msgid "Encrypt field using Secret Key" msgstr "Secret Keyを使用したフィールドの暗号化" -#: common/db/fields.py:539 +#: common/db/fields.py:545 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" -#: common/db/fields.py:546 +#: common/db/fields.py:552 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "無効なタイプです。all、ids、またはattrsでなければなりません" -#: common/db/fields.py:549 +#: common/db/fields.py:555 msgid "Invalid ids for ids, should be a list" msgstr "無効なID、リストでなければなりません" -#: common/db/fields.py:552 common/db/fields.py:555 +#: common/db/fields.py:560 common/db/fields.py:565 msgid "Invalid attrs, should be a list of dict" msgstr "無効な属性、dictリストでなければなりません" -#: common/db/fields.py:557 +#: common/db/fields.py:567 msgid "Invalid attrs, should be has name and value" msgstr "名前と値が必要な無効な属性" @@ -3353,11 +3350,11 @@ msgstr "検索のエクスポート: %s" msgid "User %s view/export secret" msgstr "ユーザー %s がパスワードを閲覧/導き出しました" -#: jumpserver/conf.py:422 +#: jumpserver/conf.py:425 msgid "Create account successfully" msgstr "アカウントを正常に作成" -#: jumpserver/conf.py:424 +#: jumpserver/conf.py:427 msgid "Your account has been created successfully" msgstr "アカウントが正常に作成されました" @@ -3798,7 +3795,7 @@ msgstr "組織のリソース ({}) は削除できません" msgid "App organizations" msgstr "アプリ組織" -#: orgs/mixins/models.py:57 orgs/mixins/serializers.py:25 orgs/models.py:84 +#: orgs/mixins/models.py:57 orgs/mixins/serializers.py:25 orgs/models.py:89 #: rbac/const.py:7 rbac/models/rolebinding.py:56 #: rbac/serializers/rolebinding.py:40 settings/serializers/auth/ldap.py:63 #: tickets/models/ticket/general.py:302 tickets/serializers/ticket/ticket.py:60 @@ -3809,27 +3806,27 @@ msgstr "組織" msgid "Org name" msgstr "組織名" -#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:39 -msgid "Builtin" -msgstr "ビルトイン" - -#: orgs/models.py:76 +#: orgs/models.py:13 msgid "GLOBAL" msgstr "グローバル組織" -#: orgs/models.py:78 +#: orgs/models.py:15 msgid "DEFAULT" msgstr "デフォルト組織" -#: orgs/models.py:80 +#: orgs/models.py:17 msgid "SYSTEM" msgstr "システム組織" -#: orgs/models.py:86 +#: orgs/models.py:81 rbac/models/role.py:36 terminal/models/applet/applet.py:40 +msgid "Builtin" +msgstr "ビルトイン" + +#: orgs/models.py:91 msgid "Can view root org" msgstr "グローバル組織を表示できます" -#: orgs/models.py:87 +#: orgs/models.py:92 msgid "Can view all joined org" msgstr "参加しているすべての組織を表示できます" @@ -4118,8 +4115,8 @@ msgstr "タスクセンター" msgid "My assets" msgstr "私の資産" -#: rbac/tree.py:56 terminal/models/applet/applet.py:50 -#: terminal/models/applet/applet.py:238 terminal/models/applet/host.py:28 +#: rbac/tree.py:56 terminal/models/applet/applet.py:51 +#: terminal/models/applet/applet.py:239 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "リモートアプリケーション" @@ -4448,7 +4445,7 @@ msgstr "有効 PKCE" #: settings/serializers/auth/oidc.py:43 msgid "Code challenge method" -msgstr "接続方法" +msgstr "検証コード方式" #: settings/serializers/auth/oidc.py:51 msgid "Use Keycloak" @@ -4632,7 +4629,7 @@ msgid "SSO auth key TTL" msgstr "Token有効期間" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:184 +#: xpack/plugins/cloud/serializers/account_attrs.py:193 msgid "Unit: second" msgstr "単位: 秒" @@ -5675,14 +5672,10 @@ msgid "Storage is invalid" msgstr "ストレージが無効です" #: terminal/models/applet/applet.py:29 -#, fuzzy -#| msgid "Comment" msgid "Community" -msgstr "コメント" +msgstr "コミュニティ版" #: terminal/models/applet/applet.py:30 -#, fuzzy -#| msgid "Enterprise edition" msgid "Enterprise" msgstr "エンタープライズ版" @@ -5690,41 +5683,39 @@ msgstr "エンタープライズ版" msgid "Author" msgstr "著者" -#: terminal/models/applet/applet.py:36 -#, fuzzy -#| msgid "Action" +#: terminal/models/applet/applet.py:37 terminal/serializers/applet.py:30 msgid "Edition" -msgstr "アクション" +msgstr "バージョン" -#: terminal/models/applet/applet.py:41 +#: terminal/models/applet/applet.py:42 msgid "Can concurrent" msgstr "同時実行可能" -#: terminal/models/applet/applet.py:42 +#: terminal/models/applet/applet.py:43 msgid "Tags" msgstr "ラベル" -#: terminal/models/applet/applet.py:46 terminal/serializers/storage.py:157 +#: terminal/models/applet/applet.py:47 terminal/serializers/storage.py:157 msgid "Hosts" msgstr "ホスト" -#: terminal/models/applet/applet.py:91 +#: terminal/models/applet/applet.py:92 msgid "Applet pkg not valid, Missing file {}" msgstr "無効なアプレット パッケージ、ファイル {} がありません" -#: terminal/models/applet/applet.py:110 +#: terminal/models/applet/applet.py:111 msgid "Load platform.yml failed: {}" msgstr "" -#: terminal/models/applet/applet.py:113 +#: terminal/models/applet/applet.py:114 msgid "Only support custom platform" msgstr "" -#: terminal/models/applet/applet.py:118 +#: terminal/models/applet/applet.py:119 msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:240 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:241 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "ホスト マシン" @@ -7311,7 +7302,7 @@ msgstr "クラウドアカウント" msgid "Test cloud account" msgstr "クラウドアカウントのテスト" -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 msgid "Regions" msgstr "リージョン" @@ -7319,15 +7310,15 @@ msgstr "リージョン" msgid "Hostname strategy" msgstr "ホスト名戦略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 msgid "IP network segment group" msgstr "IPネットワークセグメントグループ" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 msgid "Sync IP type" msgstr "同期IPタイプ" -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 msgid "Always update" msgstr "常に更新" @@ -7612,15 +7603,11 @@ msgstr "ファイルはJSON形式です。" msgid "IP address invalid `{}`, {}" msgstr "IPアドレスが無効: '{}', {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:162 -#, fuzzy -#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" -msgid "" -"Format for comma-delimited string,Such as: 192.168.1.0/24, " -"10.0.0.0-10.0.0.255" -msgstr "例: 192.168.1.0/24,10.0.0.0-10.0.0.255" +#: xpack/plugins/cloud/serializers/account_attrs.py:172 +msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgstr "例:192.168.1.0/24、10.0.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/account_attrs.py:166 +#: xpack/plugins/cloud/serializers/account_attrs.py:175 msgid "" "The port is used to detect the validity of the IP address. When the " "synchronization task is executed, only the valid IP address will be " @@ -7630,48 +7617,41 @@ msgstr "" "実行されると、有効な IP アドレスのみが同期されます。
ポートが0の場合、す" "べてのIPアドレスが有効です。" -#: xpack/plugins/cloud/serializers/account_attrs.py:174 +#: xpack/plugins/cloud/serializers/account_attrs.py:183 msgid "Hostname prefix" msgstr "ホスト名プレフィックス" -#: xpack/plugins/cloud/serializers/account_attrs.py:177 +#: xpack/plugins/cloud/serializers/account_attrs.py:186 msgid "IP segment" msgstr "IP セグメント" -#: xpack/plugins/cloud/serializers/account_attrs.py:181 +#: xpack/plugins/cloud/serializers/account_attrs.py:190 msgid "Test port" msgstr "テストポート" -#: xpack/plugins/cloud/serializers/account_attrs.py:184 +#: xpack/plugins/cloud/serializers/account_attrs.py:193 msgid "Test timeout" msgstr "テストタイムアウト" #: xpack/plugins/cloud/serializers/task.py:28 -#, fuzzy -#| msgid "" -#| "Only instances matching the IP range will be synced.
If the instance " -#| "contains multiple IP addresses, the first IP address that matches will be " -#| "used as the IP for the created asset.
The default value of * means " -#| "sync all instances and randomly match IP addresses.
Such as: " -#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" msgid "" "Only instances matching the IP range will be synced.
If the instance " "contains multiple IP addresses, the first IP address that matches will be " "used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Format for comma-" -"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" +"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " +"10.1.1.1-10.1.1.20" msgstr "" "IP範囲に一致するインスタンスのみが同期されます。
インスタンスに複数のIPア" "ドレスが含まれている場合、一致する最初のIPアドレスが作成されたアセットのIPと" "して使用されます。
デフォルト値の*は、すべてのインスタンスを同期し、IPア" "ドレスをランダムに一致させることを意味します。
例: " -"192.168.1.0/24,10.1.1.1-10.1.1.20" +"192.168.1.0/24,10.1.1.1-10.1.1.20。" -#: xpack/plugins/cloud/serializers/task.py:35 +#: xpack/plugins/cloud/serializers/task.py:34 msgid "History count" msgstr "実行回数" -#: xpack/plugins/cloud/serializers/task.py:36 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "Instance count" msgstr "インスタンス数" @@ -7731,23 +7711,23 @@ msgstr "ライセンスのインポートに成功" msgid "License is invalid" msgstr "ライセンスが無効です" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 msgid "License" msgstr "ライセンス" -#: xpack/plugins/license/models.py:79 +#: xpack/plugins/license/models.py:80 msgid "Standard edition" msgstr "標準版" -#: xpack/plugins/license/models.py:81 +#: xpack/plugins/license/models.py:82 msgid "Enterprise edition" msgstr "エンタープライズ版" -#: xpack/plugins/license/models.py:83 +#: xpack/plugins/license/models.py:84 msgid "Ultimate edition" msgstr "究極のエディション" -#: xpack/plugins/license/models.py:85 +#: xpack/plugins/license/models.py:86 msgid "Community edition" msgstr "コミュニティ版" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index ad2f7c7f8..ad1bb99ae 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4a22b436e9707729e51614e9942bb9715084ddf613152fa35be7a092a77daca7 -size 117063 +oid sha256:1ba7d3f3f44c44ef691d93294e8e0ac61cee48a35cdc32baf45f772b4997520b +size 118115 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 3b99bfe8d..47ed71d81 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-09 10:59+0800\n" +"POT-Creation-Date: 2023-06-13 15:47+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -69,7 +69,7 @@ msgstr "数据库" msgid "Collected" msgstr "收集" -#: accounts/const/account.py:21 accounts/serializers/account/account.py:26 +#: accounts/const/account.py:21 accounts/serializers/account/account.py:27 #: settings/serializers/auth/sms.py:75 msgid "Template" msgstr "模板" @@ -180,15 +180,15 @@ msgstr "仅创建" #: accounts/models/account.py:49 #: accounts/models/automations/gather_account.py:16 -#: accounts/serializers/account/account.py:203 -#: accounts/serializers/account/account.py:236 +#: accounts/serializers/account/account.py:200 +#: accounts/serializers/account/account.py:237 #: accounts/serializers/account/gathered_account.py:10 #: accounts/serializers/automations/change_secret.py:112 #: accounts/serializers/automations/change_secret.py:132 #: acls/serializers/base.py:118 assets/models/asset/common.py:93 #: assets/models/asset/common.py:332 assets/models/cmd_filter.py:36 #: assets/serializers/domain.py:19 assets/serializers/label.py:27 -#: audits/models.py:53 authentication/models/connection_token.py:34 +#: audits/models.py:53 authentication/models/connection_token.py:35 #: perms/models/asset_permission.py:64 perms/serializers/permission.py:34 #: terminal/backends/command/models.py:20 terminal/models/session/session.py:32 #: terminal/notifications.py:95 terminal/serializers/command.py:17 @@ -198,7 +198,7 @@ msgstr "资产" #: accounts/models/account.py:53 accounts/models/account.py:113 #: accounts/serializers/account/account.py:208 -#: accounts/serializers/account/account.py:246 +#: accounts/serializers/account/account.py:247 #: accounts/serializers/account/template.py:16 #: authentication/serializers/connect_token_secret.py:49 msgid "Su from" @@ -209,7 +209,7 @@ msgstr "切换自" msgid "Version" msgstr "版本" -#: accounts/models/account.py:57 accounts/serializers/account/account.py:204 +#: accounts/models/account.py:57 accounts/serializers/account/account.py:203 #: users/models/user.py:804 msgid "Source" msgstr "来源" @@ -355,7 +355,7 @@ msgid "Can add push account execution" msgstr "创建推送账号执行" #: accounts/models/automations/change_secret.py:18 accounts/models/base.py:36 -#: accounts/serializers/account/account.py:416 +#: accounts/serializers/account/account.py:419 #: accounts/serializers/account/base.py:16 #: accounts/serializers/automations/change_secret.py:46 #: authentication/serializers/connect_token_secret.py:41 @@ -405,7 +405,7 @@ msgid "Date finished" msgstr "结束日期" #: accounts/models/automations/change_secret.py:93 -#: accounts/serializers/account/account.py:238 assets/const/automation.py:8 +#: accounts/serializers/account/account.py:239 assets/const/automation.py:8 #: authentication/views/base.py:29 authentication/views/base.py:30 #: authentication/views/base.py:31 common/const/choices.py:20 msgid "Error" @@ -457,7 +457,7 @@ msgstr "收集账号" msgid "Triggers" msgstr "触发方式" -#: accounts/models/automations/push_account.py:16 acls/models/base.py:43 +#: accounts/models/automations/push_account.py:16 acls/models/base.py:46 #: acls/serializers/base.py:56 assets/models/cmd_filter.py:81 #: audits/models.py:87 audits/serializers.py:82 #: authentication/serializers/connect_token_secret.py:116 @@ -473,7 +473,7 @@ msgstr "账号推送" msgid "Verify asset account" msgstr "账号验证" -#: accounts/models/base.py:33 acls/models/base.py:37 acls/models/base.py:97 +#: accounts/models/base.py:33 acls/models/base.py:40 acls/models/base.py:101 #: acls/models/command_acl.py:21 acls/serializers/base.py:34 #: applications/models.py:9 assets/models/_user.py:22 #: assets/models/asset/common.py:91 assets/models/asset/common.py:149 @@ -485,7 +485,7 @@ msgstr "账号验证" #: authentication/serializers/connect_token_secret.py:110 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 -#: orgs/models.py:69 perms/models/asset_permission.py:56 rbac/models/role.py:29 +#: orgs/models.py:80 perms/models/asset_permission.py:56 rbac/models/role.py:29 #: settings/models.py:33 settings/serializers/sms.py:6 #: terminal/models/applet/applet.py:32 terminal/models/component/endpoint.py:12 #: terminal/models/component/endpoint.py:90 @@ -504,7 +504,7 @@ msgstr "特权账号" #: assets/models/automations/base.py:21 assets/models/cmd_filter.py:39 #: assets/models/label.py:22 #: authentication/serializers/connect_token_secret.py:114 -#: terminal/models/applet/applet.py:38 users/serializers/user.py:170 +#: terminal/models/applet/applet.py:39 users/serializers/user.py:170 msgid "Is active" msgstr "激活" @@ -546,15 +546,15 @@ msgstr "" "{} - 改密任务已完成: 未设置加密密码 - 请前往个人信息 -> 文件加密密码中设置加" "密密码" -#: accounts/serializers/account/account.py:29 +#: accounts/serializers/account/account.py:30 msgid "Push now" msgstr "立即推送" -#: accounts/serializers/account/account.py:36 +#: accounts/serializers/account/account.py:37 msgid "Exist policy" msgstr "账号存在策略" -#: accounts/serializers/account/account.py:183 applications/models.py:11 +#: accounts/serializers/account/account.py:180 applications/models.py:11 #: assets/models/label.py:21 assets/models/platform.py:82 #: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8 #: assets/serializers/platform.py:110 assets/serializers/platform.py:193 @@ -563,7 +563,7 @@ msgstr "账号存在策略" msgid "Category" msgstr "类别" -#: accounts/serializers/account/account.py:184 +#: accounts/serializers/account/account.py:181 #: accounts/serializers/automations/base.py:54 acls/models/command_acl.py:24 #: acls/serializers/command_acl.py:18 applications/models.py:14 #: assets/models/_user.py:50 assets/models/automations/base.py:20 @@ -571,7 +571,7 @@ msgstr "类别" #: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 #: assets/serializers/platform.py:109 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 -#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:37 +#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 #: terminal/serializers/session.py:22 terminal/serializers/storage.py:224 @@ -582,28 +582,28 @@ msgstr "类别" msgid "Type" msgstr "类型" -#: accounts/serializers/account/account.py:199 +#: accounts/serializers/account/account.py:196 msgid "Asset not found" msgstr "资产不存在" -#: accounts/serializers/account/account.py:205 +#: accounts/serializers/account/account.py:201 #: accounts/serializers/account/base.py:64 msgid "Has secret" msgstr "已托管密码" -#: accounts/serializers/account/account.py:237 ops/models/celery.py:60 +#: accounts/serializers/account/account.py:238 ops/models/celery.py:60 #: tickets/models/comment.py:13 tickets/models/ticket/general.py:45 #: tickets/models/ticket/general.py:279 tickets/serializers/super_ticket.py:14 #: tickets/serializers/ticket/ticket.py:21 msgid "State" msgstr "状态" -#: accounts/serializers/account/account.py:239 +#: accounts/serializers/account/account.py:240 msgid "Changed" msgstr "已修改" -#: accounts/serializers/account/account.py:249 -#: accounts/serializers/automations/base.py:22 acls/models/base.py:98 +#: accounts/serializers/account/account.py:250 +#: accounts/serializers/automations/base.py:22 acls/models/base.py:102 #: assets/models/automations/base.py:19 #: assets/serializers/automations/base.py:20 ops/models/base.py:17 #: ops/models/job.py:105 ops/serializers/job.py:21 @@ -611,30 +611,30 @@ msgstr "已修改" msgid "Assets" msgstr "资产" -#: accounts/serializers/account/account.py:301 +#: accounts/serializers/account/account.py:305 msgid "Account already exists" msgstr "账号已存在" -#: accounts/serializers/account/account.py:351 +#: accounts/serializers/account/account.py:355 #, python-format msgid "Asset does not support this secret type: %s" msgstr "资产不支持账号类型: %s" -#: accounts/serializers/account/account.py:383 +#: accounts/serializers/account/account.py:387 msgid "Account has exist" msgstr "账号已存在" -#: accounts/serializers/account/account.py:417 +#: accounts/serializers/account/account.py:420 #: authentication/serializers/connect_token_secret.py:156 #: authentication/templates/authentication/_access_key_modal.html:30 #: perms/models/perm_node.py:21 users/serializers/group.py:33 msgid "ID" msgstr "ID" -#: accounts/serializers/account/account.py:424 acls/serializers/base.py:111 +#: accounts/serializers/account/account.py:427 acls/serializers/base.py:111 #: assets/models/cmd_filter.py:24 assets/models/label.py:16 audits/models.py:49 #: audits/models.py:85 audits/models.py:163 -#: authentication/models/connection_token.py:30 +#: authentication/models/connection_token.py:31 #: authentication/models/sso_token.py:16 #: notifications/models/notification.py:12 #: perms/api/user_permission/mixin.py:55 perms/models/asset_permission.py:58 @@ -648,7 +648,7 @@ msgstr "ID" msgid "User" msgstr "用户" -#: accounts/serializers/account/account.py:425 +#: accounts/serializers/account/account.py:428 #: authentication/templates/authentication/_access_key_modal.html:33 #: terminal/notifications.py:98 terminal/notifications.py:146 msgid "Date" @@ -774,47 +774,47 @@ msgstr "密钥不合法或密钥密码错误" msgid "Acls" msgstr "访问控制" -#: acls/models/base.py:17 tickets/const.py:45 +#: acls/models/base.py:20 tickets/const.py:45 #: tickets/templates/tickets/approve_check_password.html:49 msgid "Reject" msgstr "拒绝" -#: acls/models/base.py:18 +#: acls/models/base.py:21 msgid "Accept" msgstr "接受" -#: acls/models/base.py:19 +#: acls/models/base.py:22 msgid "Review" msgstr "审批" -#: acls/models/base.py:39 assets/models/_user.py:51 +#: acls/models/base.py:42 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:93 msgid "Priority" msgstr "优先级" -#: acls/models/base.py:40 assets/models/_user.py:51 +#: acls/models/base.py:43 assets/models/_user.py:51 #: assets/models/cmd_filter.py:76 terminal/models/component/endpoint.py:94 msgid "1-100, the lower the value will be match first" msgstr "优先级可选范围为 1-100 (数值越小越优先)" -#: acls/models/base.py:44 assets/models/cmd_filter.py:86 +#: acls/models/base.py:47 assets/models/cmd_filter.py:86 #: authentication/serializers/connect_token_secret.py:88 msgid "Reviewers" msgstr "审批人" -#: acls/models/base.py:45 authentication/models/access_key.py:17 -#: authentication/models/connection_token.py:51 +#: acls/models/base.py:48 authentication/models/access_key.py:17 +#: authentication/models/connection_token.py:52 #: authentication/templates/authentication/_access_key_modal.html:32 #: perms/models/asset_permission.py:76 terminal/models/session/sharing.py:27 #: tickets/const.py:37 msgid "Active" msgstr "激活中" -#: acls/models/base.py:83 users/apps.py:9 +#: acls/models/base.py:86 users/apps.py:9 msgid "Users" msgstr "用户管理" -#: acls/models/base.py:99 assets/models/automations/base.py:17 +#: acls/models/base.py:103 assets/models/automations/base.py:17 #: assets/models/cmd_filter.py:38 assets/serializers/asset/common.py:305 #: rbac/tree.py:35 msgid "Accounts" @@ -833,7 +833,7 @@ msgid "Regex" msgstr "正则表达式" #: acls/models/command_acl.py:26 assets/models/cmd_filter.py:79 -#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:29 +#: settings/serializers/basic.py:10 xpack/plugins/license/models.py:30 msgid "Content" msgstr "内容" @@ -864,11 +864,13 @@ msgid "Command confirm" msgstr "命令复核" #: acls/models/connect_method.py:10 -#, fuzzy -#| msgid "Connect method" msgid "Connect methods" msgstr "连接方式" +#: acls/models/connect_method.py:13 +msgid "Connect method acl" +msgstr "连接方式控制" + #: acls/models/login_acl.py:11 acls/models/login_asset_acl.py:9 #: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:13 msgid "Rule" @@ -994,7 +996,7 @@ msgid "{} disabled" msgstr "{} 已禁用" #: assets/automations/ping_gateway/manager.py:33 -#: authentication/models/connection_token.py:116 +#: authentication/models/connection_token.py:117 msgid "No account" msgstr "没有账号" @@ -1139,7 +1141,7 @@ msgstr "SSH公钥" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:43 terminal/models/applet/applet.py:242 +#: terminal/models/applet/applet.py:44 terminal/models/applet/applet.py:243 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 @@ -1187,9 +1189,9 @@ msgstr "特权用户" msgid "Username same with user" msgstr "用户名与用户相同" -#: assets/models/_user.py:52 authentication/models/connection_token.py:39 +#: assets/models/_user.py:52 authentication/models/connection_token.py:40 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:40 terminal/serializers/session.py:20 +#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:20 #: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "协议" @@ -1255,7 +1257,7 @@ msgstr "地址" #: assets/models/asset/common.py:151 assets/models/platform.py:112 #: authentication/serializers/connect_token_secret.py:115 #: perms/serializers/user_permission.py:24 -#: xpack/plugins/cloud/serializers/account_attrs.py:187 +#: xpack/plugins/cloud/serializers/account_attrs.py:196 msgid "Platform" msgstr "系统平台" @@ -1350,7 +1352,7 @@ msgstr "资产自动化任务" #: assets/models/automations/base.py:113 audits/models.py:199 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:241 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:242 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 @@ -1433,7 +1435,7 @@ msgstr "系统" #: assets/models/label.py:19 assets/models/node.py:557 #: assets/serializers/cagegory.py:7 assets/serializers/cagegory.py:14 -#: authentication/models/connection_token.py:27 +#: authentication/models/connection_token.py:28 #: authentication/serializers/connect_token_secret.py:122 #: common/serializers/common.py:86 settings/models.py:34 msgid "Value" @@ -1637,7 +1639,8 @@ msgstr "协议是必填的: {}" msgid "Default database" msgstr "默认数据库" -#: assets/serializers/asset/database.py:28 common/serializers/fields.py:104 +#: assets/serializers/asset/database.py:28 common/db/fields.py:557 +#: common/db/fields.py:562 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -1872,10 +1875,8 @@ msgid "Download" msgstr "下载" #: audits/const.py:19 -#, fuzzy -#| msgid "Rename attr" msgid "Rename dir" -msgstr "映射属性" +msgstr "映射目录" #: audits/const.py:23 rbac/tree.py:228 msgid "View" @@ -1928,11 +1929,11 @@ msgstr "任务" msgid "-" msgstr "-" -#: audits/handler.py:114 +#: audits/handler.py:112 msgid "Yes" msgstr "是" -#: audits/handler.py:114 +#: audits/handler.py:112 msgid "No" msgstr "否" @@ -2108,10 +2109,8 @@ msgid "Clean audits session task log" msgstr "清理审计会话任务日志" #: audits/tasks.py:114 -#, fuzzy -#| msgid "Upload session replay to external storage" msgid "Upload FTP file to external storage" -msgstr "上传会话录像到外部存储" +msgstr "上传 FTP 文件到外部存储" #: authentication/api/confirm.py:40 msgid "This action require verify your MFA" @@ -2496,80 +2495,78 @@ msgstr "该 MFA ({}) 方式没有启用" msgid "Please change your password" msgstr "请修改密码" -#: authentication/models/connection_token.py:36 +#: authentication/models/connection_token.py:37 #: terminal/serializers/storage.py:111 msgid "Account name" msgstr "账号名称" -#: authentication/models/connection_token.py:37 +#: authentication/models/connection_token.py:38 msgid "Input username" msgstr "自定义用户名" -#: authentication/models/connection_token.py:38 +#: authentication/models/connection_token.py:39 #: authentication/serializers/connection_token.py:20 msgid "Input secret" msgstr "自定义密码" -#: authentication/models/connection_token.py:40 +#: authentication/models/connection_token.py:41 msgid "Connect method" msgstr "连接方式" -#: authentication/models/connection_token.py:41 -#, fuzzy -#| msgid "Connections" -msgid "Connect options" -msgstr "连接数" - #: authentication/models/connection_token.py:42 +msgid "Connect options" +msgstr "连接项" + +#: authentication/models/connection_token.py:43 #: rbac/serializers/rolebinding.py:21 msgid "User display" msgstr "用户名称" -#: authentication/models/connection_token.py:43 +#: authentication/models/connection_token.py:44 msgid "Asset display" msgstr "资产名称" -#: authentication/models/connection_token.py:44 +#: authentication/models/connection_token.py:45 msgid "Reusable" msgstr "可以重复使用" -#: authentication/models/connection_token.py:45 +#: authentication/models/connection_token.py:46 #: authentication/models/temp_token.py:13 perms/models/asset_permission.py:74 #: tickets/models/ticket/apply_application.py:31 #: tickets/models/ticket/apply_asset.py:20 users/models/user.py:797 msgid "Date expired" msgstr "失效日期" -#: authentication/models/connection_token.py:49 +#: authentication/models/connection_token.py:50 #: perms/models/asset_permission.py:77 msgid "From ticket" msgstr "来自工单" -#: authentication/models/connection_token.py:55 +#: authentication/models/connection_token.py:56 msgid "Connection token" msgstr "连接令牌" -#: authentication/models/connection_token.py:57 +#: authentication/models/connection_token.py:58 msgid "Can view connection token secret" msgstr "可以查看连接令牌密文" -#: authentication/models/connection_token.py:104 +#: authentication/models/connection_token.py:105 msgid "Connection token inactive" msgstr "连接令牌未激活" -#: authentication/models/connection_token.py:107 +#: authentication/models/connection_token.py:108 msgid "Connection token expired at: {}" msgstr "连接令牌过期: {}" -#: authentication/models/connection_token.py:110 +#: authentication/models/connection_token.py:111 msgid "No user or invalid user" msgstr "没有用户或用户失效" -#: authentication/models/connection_token.py:113 +#: authentication/models/connection_token.py:114 msgid "No asset or inactive asset" msgstr "没有资产或资产未激活" -#: authentication/models/connection_token.py:265 +#: authentication/models/connection_token.py:267 msgid "Super connection token" msgstr "超级连接令牌" @@ -2733,7 +2730,7 @@ msgstr "代码错误" #: authentication/templates/authentication/_msg_reset_password_code.html:9 #: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_public_key_success.html:2 -#: jumpserver/conf.py:423 +#: jumpserver/conf.py:426 #: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3 #: tickets/templates/tickets/approve_check_password.html:33 @@ -3083,26 +3080,26 @@ msgstr "编码数据为 text" msgid "Encrypt field using Secret Key" msgstr "加密的字段" -#: common/db/fields.py:539 +#: common/db/fields.py:545 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" -#: common/db/fields.py:546 +#: common/db/fields.py:552 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "无效类型,应为 all、ids 或 attrs" -#: common/db/fields.py:549 +#: common/db/fields.py:555 msgid "Invalid ids for ids, should be a list" msgstr "无效的ID,应为列表" -#: common/db/fields.py:552 common/db/fields.py:555 +#: common/db/fields.py:560 common/db/fields.py:565 msgid "Invalid attrs, should be a list of dict" msgstr "无效的属性,应为dict列表" -#: common/db/fields.py:557 +#: common/db/fields.py:567 msgid "Invalid attrs, should be has name and value" msgstr "无效属性,应具有名称和值" @@ -3318,11 +3315,11 @@ msgstr "导出搜素: %s" msgid "User %s view/export secret" msgstr "用户 %s 查看/导出 了密码" -#: jumpserver/conf.py:422 +#: jumpserver/conf.py:425 msgid "Create account successfully" msgstr "创建账号成功" -#: jumpserver/conf.py:424 +#: jumpserver/conf.py:427 msgid "Your account has been created successfully" msgstr "你的账号已创建成功" @@ -3757,7 +3754,7 @@ msgstr "组织存在资源 ({}) 不能被删除" msgid "App organizations" msgstr "组织管理" -#: orgs/mixins/models.py:57 orgs/mixins/serializers.py:25 orgs/models.py:84 +#: orgs/mixins/models.py:57 orgs/mixins/serializers.py:25 orgs/models.py:89 #: rbac/const.py:7 rbac/models/rolebinding.py:56 #: rbac/serializers/rolebinding.py:40 settings/serializers/auth/ldap.py:63 #: tickets/models/ticket/general.py:302 tickets/serializers/ticket/ticket.py:60 @@ -3768,27 +3765,27 @@ msgstr "组织" msgid "Org name" msgstr "组织名称" -#: orgs/models.py:70 rbac/models/role.py:36 terminal/models/applet/applet.py:39 -msgid "Builtin" -msgstr "内置的" - -#: orgs/models.py:76 +#: orgs/models.py:13 msgid "GLOBAL" msgstr "全局组织" -#: orgs/models.py:78 +#: orgs/models.py:15 msgid "DEFAULT" msgstr "默认组织" -#: orgs/models.py:80 +#: orgs/models.py:17 msgid "SYSTEM" msgstr "系统组织" -#: orgs/models.py:86 +#: orgs/models.py:81 rbac/models/role.py:36 terminal/models/applet/applet.py:40 +msgid "Builtin" +msgstr "内置的" + +#: orgs/models.py:91 msgid "Can view root org" msgstr "可以查看全局组织" -#: orgs/models.py:87 +#: orgs/models.py:92 msgid "Can view all joined org" msgstr "可以查看所有加入的组织" @@ -4076,8 +4073,8 @@ msgstr "任务中心" msgid "My assets" msgstr "我的资产" -#: rbac/tree.py:56 terminal/models/applet/applet.py:50 -#: terminal/models/applet/applet.py:238 terminal/models/applet/host.py:28 +#: rbac/tree.py:56 terminal/models/applet/applet.py:51 +#: terminal/models/applet/applet.py:239 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "远程应用" @@ -4406,7 +4403,7 @@ msgstr "启用 PKCE" #: settings/serializers/auth/oidc.py:43 msgid "Code challenge method" -msgstr "连接方式" +msgstr "验证校验码方式" #: settings/serializers/auth/oidc.py:51 msgid "Use Keycloak" @@ -4588,7 +4585,7 @@ msgid "SSO auth key TTL" msgstr "令牌有效期" #: settings/serializers/auth/sso.py:17 -#: xpack/plugins/cloud/serializers/account_attrs.py:184 +#: xpack/plugins/cloud/serializers/account_attrs.py:193 msgid "Unit: second" msgstr "单位: 秒" @@ -5606,39 +5603,39 @@ msgstr "企业版" msgid "Author" msgstr "作者" -#: terminal/models/applet/applet.py:36 +#: terminal/models/applet/applet.py:37 terminal/serializers/applet.py:30 msgid "Edition" msgstr "版本" -#: terminal/models/applet/applet.py:41 +#: terminal/models/applet/applet.py:42 msgid "Can concurrent" msgstr "可以并发" -#: terminal/models/applet/applet.py:42 +#: terminal/models/applet/applet.py:43 msgid "Tags" msgstr "标签" -#: terminal/models/applet/applet.py:46 terminal/serializers/storage.py:157 +#: terminal/models/applet/applet.py:47 terminal/serializers/storage.py:157 msgid "Hosts" msgstr "主机" -#: terminal/models/applet/applet.py:91 +#: terminal/models/applet/applet.py:92 msgid "Applet pkg not valid, Missing file {}" msgstr "Applet pkg 无效,缺少文件 {}" -#: terminal/models/applet/applet.py:110 +#: terminal/models/applet/applet.py:111 msgid "Load platform.yml failed: {}" msgstr "" -#: terminal/models/applet/applet.py:113 +#: terminal/models/applet/applet.py:114 msgid "Only support custom platform" msgstr "" -#: terminal/models/applet/applet.py:118 +#: terminal/models/applet/applet.py:119 msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:240 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:241 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "宿主机" @@ -7201,7 +7198,7 @@ msgstr "云账号" msgid "Test cloud account" msgstr "测试云账号" -#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:37 +#: xpack/plugins/cloud/models.py:88 xpack/plugins/cloud/serializers/task.py:36 msgid "Regions" msgstr "地域" @@ -7209,15 +7206,15 @@ msgstr "地域" msgid "Hostname strategy" msgstr "主机名策略" -#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:40 +#: xpack/plugins/cloud/models.py:102 xpack/plugins/cloud/serializers/task.py:39 msgid "IP network segment group" msgstr "IP网段组" -#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:45 +#: xpack/plugins/cloud/models.py:105 xpack/plugins/cloud/serializers/task.py:44 msgid "Sync IP type" msgstr "同步IP类型" -#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:62 +#: xpack/plugins/cloud/models.py:108 xpack/plugins/cloud/serializers/task.py:61 msgid "Always update" msgstr "总是更新" @@ -7502,15 +7499,11 @@ msgstr "JSON 格式的文件" msgid "IP address invalid `{}`, {}" msgstr "IP 地址无效: `{}`, {}" -#: xpack/plugins/cloud/serializers/account_attrs.py:162 -#, fuzzy -#| msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" -msgid "" -"Format for comma-delimited string,Such as: 192.168.1.0/24, " -"10.0.0.0-10.0.0.255" -msgstr "如: 192.168.1.0/24,10.0.0.0-10.0.0.255" +#: xpack/plugins/cloud/serializers/account_attrs.py:172 +msgid "Such as: 192.168.1.0/24, 10.0.0.0-10.0.0.255" +msgstr "例: 192.168.1.0/24,10.0.0.0-10.0.0.255" -#: xpack/plugins/cloud/serializers/account_attrs.py:166 +#: xpack/plugins/cloud/serializers/account_attrs.py:175 msgid "" "The port is used to detect the validity of the IP address. When the " "synchronization task is executed, only the valid IP address will be " @@ -7519,46 +7512,39 @@ msgstr "" "端口用来检测 IP 地址的有效性,在同步任务执行时,只会同步有效的 IP 地址。
" "如果端口为 0,则表示所有 IP 地址均有效。" -#: xpack/plugins/cloud/serializers/account_attrs.py:174 +#: xpack/plugins/cloud/serializers/account_attrs.py:183 msgid "Hostname prefix" msgstr "主机名前缀" -#: xpack/plugins/cloud/serializers/account_attrs.py:177 +#: xpack/plugins/cloud/serializers/account_attrs.py:186 msgid "IP segment" msgstr "IP 网段" -#: xpack/plugins/cloud/serializers/account_attrs.py:181 +#: xpack/plugins/cloud/serializers/account_attrs.py:190 msgid "Test port" msgstr "测试端口" -#: xpack/plugins/cloud/serializers/account_attrs.py:184 +#: xpack/plugins/cloud/serializers/account_attrs.py:193 msgid "Test timeout" msgstr "测试超时时间" #: xpack/plugins/cloud/serializers/task.py:28 -#, fuzzy -#| msgid "" -#| "Only instances matching the IP range will be synced.
If the instance " -#| "contains multiple IP addresses, the first IP address that matches will be " -#| "used as the IP for the created asset.
The default value of * means " -#| "sync all instances and randomly match IP addresses.
Such as: " -#| "192.168.1.0/24, 10.1.1.1-10.1.1.20" msgid "" "Only instances matching the IP range will be synced.
If the instance " "contains multiple IP addresses, the first IP address that matches will be " "used as the IP for the created asset.
The default value of * means sync " -"all instances and randomly match IP addresses.
Format for comma-" -"delimited string, Such as: 192.168.1.0/24, 10.1.1.1-10.1.1.20" +"all instances and randomly match IP addresses.
Such as: 192.168.1.0/24, " +"10.1.1.1-10.1.1.20" msgstr "" "只有匹配到 IP 段的实例会被同步。
如果实例包含多个 IP 地址,那么第一个匹配" "到的 IP 地址将被用作创建的资产的 IP。
默认值 * 表示同步所有实例和随机匹配 " -"IP 地址。
例如: 192.168.1.0/24,10.1.1.1-10.1.1.20" +"IP 地址。
例如: 192.168.1.0/24,10.1.1.1-10.1.1.20。" -#: xpack/plugins/cloud/serializers/task.py:35 +#: xpack/plugins/cloud/serializers/task.py:34 msgid "History count" msgstr "执行次数" -#: xpack/plugins/cloud/serializers/task.py:36 +#: xpack/plugins/cloud/serializers/task.py:35 msgid "Instance count" msgstr "实例个数" @@ -7618,23 +7604,23 @@ msgstr "许可证导入成功" msgid "License is invalid" msgstr "无效的许可证" -#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:135 +#: xpack/plugins/license/meta.py:11 xpack/plugins/license/models.py:138 msgid "License" msgstr "许可证" -#: xpack/plugins/license/models.py:79 +#: xpack/plugins/license/models.py:80 msgid "Standard edition" msgstr "标准版" -#: xpack/plugins/license/models.py:81 +#: xpack/plugins/license/models.py:82 msgid "Enterprise edition" msgstr "企业版" -#: xpack/plugins/license/models.py:83 +#: xpack/plugins/license/models.py:84 msgid "Ultimate edition" msgstr "旗舰版" -#: xpack/plugins/license/models.py:85 +#: xpack/plugins/license/models.py:86 msgid "Community edition" msgstr "社区版" From 5bd4a882cc9cdfaf1cc9e8b92dae3abbfea32ee6 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Tue, 13 Jun 2023 17:57:48 +0800 Subject: [PATCH 125/153] =?UTF-8?q?fix:=20=E5=B9=B3=E5=8F=B0=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E6=97=A0=E5=8D=8F=E8=AE=AEport=20(#10702)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/assets/serializers/platform.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/assets/serializers/platform.py b/apps/assets/serializers/platform.py index 80421d41b..b78e134f4 100644 --- a/apps/assets/serializers/platform.py +++ b/apps/assets/serializers/platform.py @@ -86,6 +86,13 @@ class PlatformProtocolSerializer(serializers.ModelSerializer): "secret_types", "setting", ] + def to_file_representation(self, data): + return '{name}/{port}'.format(**data) + + def to_file_internal_value(self, data): + name, port = data.split('/') + return {'name': name, 'port': port} + class PlatformCustomField(serializers.Serializer): TYPE_CHOICES = [(t, t) for t, c in type_field_map.items()] From df8baede4398de5abc433206152c63395eac0ef0 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 13 Jun 2023 18:25:03 +0800 Subject: [PATCH 126/153] =?UTF-8?q?perf:=20=E4=BF=AE=E5=A4=8D=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=BD=95=E5=83=8F=E6=92=AD=E6=94=BE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/api/session/session.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/apps/terminal/api/session/session.py b/apps/terminal/api/session/session.py index c414dd289..47432b60b 100644 --- a/apps/terminal/api/session/session.py +++ b/apps/terminal/api/session/session.py @@ -2,6 +2,7 @@ # import os import tarfile + from django.core.files.storage import default_storage from django.db.models import F from django.http import FileResponse @@ -15,21 +16,22 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from common.drf.filters import BaseFilterSet +from common.api import AsyncApiMixin from common.const.http import GET +from common.drf.filters import BaseFilterSet from common.drf.filters import DatetimeRangeFilter from common.drf.renders import PassthroughRenderer -from common.api import AsyncApiMixin +from common.storage.replay import ReplayStorageHandler from common.utils import data_to_json, is_uuid from common.utils import get_logger, get_object_or_none -from common.storage.replay import ReplayStorageHandler -from rbac.permissions import RBACPermission from orgs.mixins.api import OrgBulkModelViewSet from orgs.utils import tmp_to_root_org, tmp_to_org +from rbac.permissions import RBACPermission from terminal import serializers +from terminal.const import TerminalType from terminal.models import Session -from terminal.utils import is_session_approver from terminal.permissions import IsSessionAssignee +from terminal.utils import is_session_approver from users.models import User __all__ = [ @@ -182,14 +184,20 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet): @staticmethod def get_replay_data(session, url): - tp = 'json' - if session.protocol in ('rdp', 'vnc'): - # 需要考虑录像播放和离线播放器的约定,暂时不处理 - tp = 'guacamole' + all_guacamole_types = ( + TerminalType.lion, TerminalType.guacamole, + TerminalType.razor, TerminalType.xrdp + ) + if url.endswith('.cast.gz'): tp = 'asciicast' - if url.endswith('.replay.mp4'): + elif url.endswith('.replay.mp4'): tp = 'mp4' + elif (getattr(session.terminal, 'type', None) in all_guacamole_types) or \ + (session.protocol in ('rdp', 'vnc')): + tp = 'guacamole' + else: + tp = 'json' download_url = reverse('api-terminal:session-replay-download', kwargs={'pk': session.id}) data = { From 4112ad21c3fc9379d990ded580fac7e0d4c42589 Mon Sep 17 00:00:00 2001 From: Eric Date: Tue, 13 Jun 2023 18:58:26 +0800 Subject: [PATCH 127/153] =?UTF-8?q?perf:=20=E5=A2=9E=E5=8A=A0=20terminal?= =?UTF-8?q?=20=E6=98=BE=E7=A4=BA=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/serializers/session.py | 2 ++ apps/terminal/serializers/terminal.py | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/terminal/serializers/session.py b/apps/terminal/serializers/session.py index 67eea06be..db7346d51 100644 --- a/apps/terminal/serializers/session.py +++ b/apps/terminal/serializers/session.py @@ -4,6 +4,7 @@ from rest_framework import serializers from assets.const import Protocol from common.serializers.fields import LabeledChoiceField from orgs.mixins.serializers import BulkOrgResourceModelSerializer +from .terminal import TerminalSmallSerializer from ..const import SessionType from ..models import Session @@ -54,6 +55,7 @@ class SessionSerializer(BulkOrgResourceModelSerializer): class SessionDisplaySerializer(SessionSerializer): command_amount = serializers.IntegerField(read_only=True, label=_('Command amount')) + terminal = TerminalSmallSerializer(read_only=True, label=_('Terminal')) class Meta(SessionSerializer.Meta): fields = SessionSerializer.Meta.fields + ['command_amount', ] diff --git a/apps/terminal/serializers/terminal.py b/apps/terminal/serializers/terminal.py index 83ab1605b..2904c7938 100644 --- a/apps/terminal/serializers/terminal.py +++ b/apps/terminal/serializers/terminal.py @@ -1,8 +1,8 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers -from common.serializers.fields import LabeledChoiceField from common.serializers import BulkModelSerializer +from common.serializers.fields import LabeledChoiceField from common.utils import get_request_ip, pretty_string, is_uuid from users.serializers import ServiceAccountSerializer from .. import const @@ -32,6 +32,12 @@ class StatSerializer(serializers.ModelSerializer): } +class TerminalSmallSerializer(serializers.ModelSerializer): + class Meta: + model = Terminal + fields = ['id', 'name', 'type'] + + class TerminalSerializer(BulkModelSerializer): session_online = serializers.ReadOnlyField(source='get_online_session_count') is_alive = serializers.BooleanField(read_only=True) From 459176550db3e3009ce720bcd22307768eb071b2 Mon Sep 17 00:00:00 2001 From: ibuler Date: Tue, 13 Jun 2023 16:03:58 +0800 Subject: [PATCH 128/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20applet=20?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E6=94=AF=E6=8C=81=E5=B9=B6=E5=8F=91=EF=BC=8C?= =?UTF-8?q?=E4=B9=9F=E4=BE=9D=E8=B5=96=E4=BA=8E=20host?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/models/applet/applet.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index 3193b5ea5..e9fdc1b9d 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -194,7 +194,8 @@ class Applet(JMSBaseModel): host = self.select_host(user) if not host: return None - can_concurrent = self.can_concurrent or self.type == 'web' + host_concurrent = str(host.deploy_options.get('RDS_fSingleSessionPerUser', 0)) == '1' + can_concurrent = (self.can_concurrent or self.type == 'web') and host_concurrent accounts = host.accounts.all().filter(is_active=True, privileged=False) private_account = accounts.filter(username='js_{}'.format(user.username)).first() From de43df83705d1e06a58e0f20a51f284fe46c913c Mon Sep 17 00:00:00 2001 From: Bai Date: Wed, 14 Jun 2023 11:04:20 +0800 Subject: [PATCH 129/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=20LDAP=20?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=AF=BC=E5=85=A5=E4=BB=BB=E5=8A=A1=E5=90=8D?= =?UTF-8?q?=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/locale/ja/LC_MESSAGES/django.po | 125 ++++++++++++++------------- apps/locale/zh/LC_MESSAGES/django.po | 125 ++++++++++++++------------- apps/settings/tasks/ldap.py | 4 +- 3 files changed, 132 insertions(+), 122 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 97fd54244..8fa8f8465 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-13 15:47+0800\n" +"POT-Creation-Date: 2023-06-14 10:57+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -311,7 +311,7 @@ msgstr "理由" #: accounts/models/automations/backup_account.py:99 #: accounts/serializers/automations/change_secret.py:111 #: accounts/serializers/automations/change_secret.py:134 -#: ops/serializers/job.py:56 terminal/serializers/session.py:45 +#: ops/serializers/job.py:56 terminal/serializers/session.py:46 msgid "Is success" msgstr "成功は" @@ -481,8 +481,8 @@ msgstr "アカウントの確認" #: assets/models/cmd_filter.py:21 assets/models/domain.py:18 #: assets/models/group.py:20 assets/models/label.py:18 #: assets/models/platform.py:13 assets/models/platform.py:81 -#: assets/serializers/asset/common.py:145 assets/serializers/platform.py:92 -#: assets/serializers/platform.py:192 +#: assets/serializers/asset/common.py:145 assets/serializers/platform.py:99 +#: assets/serializers/platform.py:199 #: authentication/serializers/connect_token_secret.py:110 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 @@ -561,7 +561,7 @@ msgstr "アカウントの存在ポリシー" #: accounts/serializers/account/account.py:180 applications/models.py:11 #: assets/models/label.py:21 assets/models/platform.py:82 #: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8 -#: assets/serializers/platform.py:110 assets/serializers/platform.py:193 +#: assets/serializers/platform.py:117 assets/serializers/platform.py:200 #: perms/serializers/user_permission.py:26 settings/models.py:35 #: tickets/models/ticket/apply_application.py:13 msgid "Category" @@ -572,13 +572,13 @@ msgstr "カテゴリ" #: acls/serializers/command_acl.py:18 applications/models.py:14 #: assets/models/_user.py:50 assets/models/automations/base.py:20 #: assets/models/cmd_filter.py:74 assets/models/platform.py:83 -#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 -#: assets/serializers/platform.py:109 audits/serializers.py:48 +#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:101 +#: assets/serializers/platform.py:116 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 -#: terminal/serializers/session.py:22 terminal/serializers/storage.py:224 +#: terminal/serializers/session.py:23 terminal/serializers/storage.py:224 #: terminal/serializers/storage.py:236 tickets/models/comment.py:26 #: tickets/models/flow.py:56 tickets/models/ticket/apply_application.py:16 #: tickets/models/ticket/general.py:275 tickets/serializers/flow.py:53 @@ -1148,7 +1148,7 @@ msgstr "SSHパブリックキー" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:44 terminal/models/applet/applet.py:243 +#: terminal/models/applet/applet.py:44 terminal/models/applet/applet.py:244 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 @@ -1198,8 +1198,8 @@ msgstr "ユーザーと同じユーザー名" #: assets/models/_user.py:52 authentication/models/connection_token.py:40 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:20 -#: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 +#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:21 +#: terminal/serializers/session.py:42 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "プロトコル" @@ -1359,7 +1359,7 @@ msgstr "アセットの自動化タスク" #: assets/models/automations/base.py:113 audits/models.py:199 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:242 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:243 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 @@ -1427,7 +1427,7 @@ msgid "Asset group" msgstr "資産グループ" #: assets/models/group.py:34 assets/models/platform.py:17 -#: assets/serializers/platform.py:95 +#: assets/serializers/platform.py:102 #: xpack/plugins/cloud/providers/nutanix.py:30 msgid "Default" msgstr "デフォルト" @@ -1450,7 +1450,7 @@ msgstr "値" #: assets/models/label.py:40 assets/serializers/asset/common.py:123 #: assets/serializers/cagegory.py:6 assets/serializers/cagegory.py:13 -#: assets/serializers/platform.py:93 +#: assets/serializers/platform.py:100 #: authentication/serializers/connect_token_secret.py:121 #: common/serializers/common.py:85 perms/serializers/user_permission.py:28 #: settings/serializers/sms.py:7 @@ -1582,23 +1582,23 @@ msgstr "メタ" msgid "Internal" msgstr "ビルトイン" -#: assets/models/platform.py:89 assets/serializers/platform.py:108 +#: assets/models/platform.py:89 assets/serializers/platform.py:115 msgid "Charset" msgstr "シャーセット" -#: assets/models/platform.py:91 assets/serializers/platform.py:136 +#: assets/models/platform.py:91 assets/serializers/platform.py:143 msgid "Domain enabled" msgstr "ドメインを有効にする" -#: assets/models/platform.py:93 assets/serializers/platform.py:135 +#: assets/models/platform.py:93 assets/serializers/platform.py:142 msgid "Su enabled" msgstr "アカウントの切り替えを有効にする" -#: assets/models/platform.py:94 assets/serializers/platform.py:114 +#: assets/models/platform.py:94 assets/serializers/platform.py:121 msgid "Su method" msgstr "アカウントの切り替え方法" -#: assets/models/platform.py:95 assets/serializers/platform.py:117 +#: assets/models/platform.py:95 assets/serializers/platform.py:124 msgid "Custom fields" msgstr "カスタムフィールド" @@ -1615,7 +1615,7 @@ msgstr "" "プラットフォームタイプがスキップされた資産に合致しない、資産内の一括更新プ" "ラットフォーム" -#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:111 +#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:118 #: authentication/serializers/connect_token_secret.py:29 #: authentication/serializers/connect_token_secret.py:72 #: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 @@ -1648,8 +1648,8 @@ msgstr "プロトコルが必要です: {}" msgid "Default database" msgstr "デフォルト・データベース" -#: assets/serializers/asset/database.py:28 common/db/fields.py:557 -#: common/db/fields.py:562 common/serializers/fields.py:104 +#: assets/serializers/asset/database.py:28 common/db/fields.py:564 +#: common/db/fields.py:569 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -1751,27 +1751,27 @@ msgstr "アカウント収集を有効にする" msgid "Gather accounts method" msgstr "アカウントの収集方法" -#: assets/serializers/platform.py:96 +#: assets/serializers/platform.py:103 msgid "Help text" msgstr "ヘルプ" -#: assets/serializers/platform.py:97 +#: assets/serializers/platform.py:104 msgid "Choices" msgstr "" -#: assets/serializers/platform.py:112 +#: assets/serializers/platform.py:119 msgid "Automation" msgstr "オートメーション" -#: assets/serializers/platform.py:137 +#: assets/serializers/platform.py:144 msgid "Default Domain" msgstr "デフォルト ドメイン" -#: assets/serializers/platform.py:146 +#: assets/serializers/platform.py:153 msgid "type is required" msgstr "タイプ このフィールドは必須です." -#: assets/serializers/platform.py:169 +#: assets/serializers/platform.py:176 msgid "Protocols is required" msgstr "同意が必要です" @@ -1915,7 +1915,7 @@ msgstr "パスワードを変更する" #: audits/const.py:35 settings/serializers/terminal.py:6 #: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:163 -#: terminal/serializers/session.py:48 +#: terminal/serializers/session.py:49 terminal/serializers/session.py:58 msgid "Terminal" msgstr "ターミナル" @@ -1940,11 +1940,11 @@ msgstr "タスク" msgid "-" msgstr "-" -#: audits/handler.py:112 +#: audits/handler.py:117 msgid "Yes" msgstr "是" -#: audits/handler.py:112 +#: audits/handler.py:117 msgid "No" msgstr "否" @@ -1965,6 +1965,10 @@ msgstr "操作" msgid "Filename" msgstr "ファイル名" +#: audits/models.py:61 common/serializers/common.py:98 +msgid "File" +msgstr "書類" + #: audits/models.py:62 terminal/backends/command/models.py:24 #: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18 #: terminal/models/session/sharing.py:81 @@ -2147,7 +2151,7 @@ msgstr "ACL アクションはレビューです" msgid "Current user not support mfa type: {}" msgstr "現在のユーザーはmfaタイプをサポートしていません: {}" -#: authentication/api/password.py:31 terminal/api/session/session.py:249 +#: authentication/api/password.py:31 terminal/api/session/session.py:259 #: users/views/profile/reset.py:44 msgid "User does not exist: {}" msgstr "ユーザーが存在しない: {}" @@ -3113,26 +3117,26 @@ msgstr "テキストフィールドへのマーシャルデータ" msgid "Encrypt field using Secret Key" msgstr "Secret Keyを使用したフィールドの暗号化" -#: common/db/fields.py:545 +#: common/db/fields.py:552 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" -#: common/db/fields.py:552 +#: common/db/fields.py:559 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "無効なタイプです。all、ids、またはattrsでなければなりません" -#: common/db/fields.py:555 +#: common/db/fields.py:562 msgid "Invalid ids for ids, should be a list" msgstr "無効なID、リストでなければなりません" -#: common/db/fields.py:560 common/db/fields.py:565 +#: common/db/fields.py:567 common/db/fields.py:572 msgid "Invalid attrs, should be a list of dict" msgstr "無効な属性、dictリストでなければなりません" -#: common/db/fields.py:567 +#: common/db/fields.py:574 msgid "Invalid attrs, should be has name and value" msgstr "名前と値が必要な無効な属性" @@ -3277,10 +3281,6 @@ msgstr "{} 秒待ってから送信してください" msgid "Children" msgstr "" -#: common/serializers/common.py:98 -msgid "File" -msgstr "書類" - #: common/serializers/fields.py:105 #, python-brace-format msgid "Invalid pk \"{pk_value}\" - object does not exist." @@ -3700,7 +3700,7 @@ msgstr "保存後に実行" msgid "Job type" msgstr "タスクの種類" -#: ops/serializers/job.py:57 terminal/serializers/session.py:49 +#: ops/serializers/job.py:57 terminal/serializers/session.py:50 msgid "Is finished" msgstr "終了しました" @@ -4116,7 +4116,7 @@ msgid "My assets" msgstr "私の資産" #: rbac/tree.py:56 terminal/models/applet/applet.py:51 -#: terminal/models/applet/applet.py:239 terminal/models/applet/host.py:28 +#: terminal/models/applet/applet.py:240 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "リモートアプリケーション" @@ -5236,11 +5236,13 @@ msgstr "" "の解像度" #: settings/tasks/ldap.py:25 -msgid "Import ldap user" -msgstr "LDAP ユーザーのインポート" +msgid "Periodic import ldap user" +msgstr "LDAP ユーザーを定期的にインポートする" #: settings/tasks/ldap.py:47 -msgid "Periodic import ldap user" +#, fuzzy +#| msgid "Periodic import ldap user" +msgid "Registration periodic import ldap user task" msgstr "LDAP ユーザーを定期的にインポートする" #: settings/utils/ldap.py:472 @@ -5586,15 +5588,15 @@ msgstr "テスト失敗: アカウントが無効" msgid "Have online sessions" msgstr "オンラインセッションを持つ" -#: terminal/api/session/session.py:241 +#: terminal/api/session/session.py:251 msgid "Session does not exist: {}" msgstr "セッションが存在しません: {}" -#: terminal/api/session/session.py:244 +#: terminal/api/session/session.py:254 msgid "Session is finished or the protocol not supported" msgstr "セッションが終了したか、プロトコルがサポートされていません" -#: terminal/api/session/session.py:257 +#: terminal/api/session/session.py:267 msgid "User does not have permission" msgstr "ユーザーに権限がありません" @@ -5715,7 +5717,7 @@ msgstr "" msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:241 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:242 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "ホスト マシン" @@ -6042,7 +6044,7 @@ msgstr "最大切断時間" msgid "RDS Remote App Logoff Time Limit" msgstr "RDS 远程应用注销时间限制" -#: terminal/serializers/applet_host.py:55 terminal/serializers/terminal.py:41 +#: terminal/serializers/applet_host.py:55 terminal/serializers/terminal.py:47 msgid "Load status" msgstr "ロードステータス" @@ -6101,35 +6103,35 @@ msgstr "" msgid "Asset IP" msgstr "資産 IP" -#: terminal/serializers/session.py:24 terminal/serializers/session.py:46 +#: terminal/serializers/session.py:25 terminal/serializers/session.py:47 msgid "Can replay" msgstr "再生できます" -#: terminal/serializers/session.py:25 terminal/serializers/session.py:47 +#: terminal/serializers/session.py:26 terminal/serializers/session.py:48 msgid "Can join" msgstr "参加できます" -#: terminal/serializers/session.py:26 terminal/serializers/session.py:50 +#: terminal/serializers/session.py:27 terminal/serializers/session.py:51 msgid "Can terminate" msgstr "終了できます" -#: terminal/serializers/session.py:42 +#: terminal/serializers/session.py:43 msgid "User ID" msgstr "ユーザーID" -#: terminal/serializers/session.py:43 +#: terminal/serializers/session.py:44 msgid "Asset ID" msgstr "資産ID" -#: terminal/serializers/session.py:44 +#: terminal/serializers/session.py:45 msgid "Login from display" msgstr "表示からのログイン" -#: terminal/serializers/session.py:51 +#: terminal/serializers/session.py:52 msgid "Terminal display" msgstr "ターミナルディスプレイ" -#: terminal/serializers/session.py:56 +#: terminal/serializers/session.py:57 msgid "Command amount" msgstr "コマンド量" @@ -6195,7 +6197,7 @@ msgstr "インデックス" msgid "Doc type" msgstr "Docタイプ" -#: terminal/serializers/terminal.py:77 terminal/serializers/terminal.py:85 +#: terminal/serializers/terminal.py:83 terminal/serializers/terminal.py:91 msgid "Not found" msgstr "見つかりません" @@ -7731,5 +7733,8 @@ msgstr "究極のエディション" msgid "Community edition" msgstr "コミュニティ版" +#~ msgid "Import ldap user" +#~ msgstr "LDAP ユーザーのインポート" + #~ msgid "Reviewers amount" #~ msgstr "承認者数" diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 47ed71d81..35cd415c3 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-13 15:47+0800\n" +"POT-Creation-Date: 2023-06-14 10:57+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -310,7 +310,7 @@ msgstr "原因" #: accounts/models/automations/backup_account.py:99 #: accounts/serializers/automations/change_secret.py:111 #: accounts/serializers/automations/change_secret.py:134 -#: ops/serializers/job.py:56 terminal/serializers/session.py:45 +#: ops/serializers/job.py:56 terminal/serializers/session.py:46 msgid "Is success" msgstr "是否成功" @@ -480,8 +480,8 @@ msgstr "账号验证" #: assets/models/cmd_filter.py:21 assets/models/domain.py:18 #: assets/models/group.py:20 assets/models/label.py:18 #: assets/models/platform.py:13 assets/models/platform.py:81 -#: assets/serializers/asset/common.py:145 assets/serializers/platform.py:92 -#: assets/serializers/platform.py:192 +#: assets/serializers/asset/common.py:145 assets/serializers/platform.py:99 +#: assets/serializers/platform.py:199 #: authentication/serializers/connect_token_secret.py:110 ops/mixin.py:21 #: ops/models/adhoc.py:21 ops/models/celery.py:15 ops/models/celery.py:57 #: ops/models/job.py:92 ops/models/playbook.py:23 ops/serializers/job.py:20 @@ -557,7 +557,7 @@ msgstr "账号存在策略" #: accounts/serializers/account/account.py:180 applications/models.py:11 #: assets/models/label.py:21 assets/models/platform.py:82 #: assets/serializers/asset/common.py:121 assets/serializers/cagegory.py:8 -#: assets/serializers/platform.py:110 assets/serializers/platform.py:193 +#: assets/serializers/platform.py:117 assets/serializers/platform.py:200 #: perms/serializers/user_permission.py:26 settings/models.py:35 #: tickets/models/ticket/apply_application.py:13 msgid "Category" @@ -568,13 +568,13 @@ msgstr "类别" #: acls/serializers/command_acl.py:18 applications/models.py:14 #: assets/models/_user.py:50 assets/models/automations/base.py:20 #: assets/models/cmd_filter.py:74 assets/models/platform.py:83 -#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:94 -#: assets/serializers/platform.py:109 audits/serializers.py:48 +#: assets/serializers/asset/common.py:122 assets/serializers/platform.py:101 +#: assets/serializers/platform.py:116 audits/serializers.py:48 #: authentication/serializers/connect_token_secret.py:123 ops/models/job.py:103 #: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:38 #: terminal/models/component/storage.py:57 #: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29 -#: terminal/serializers/session.py:22 terminal/serializers/storage.py:224 +#: terminal/serializers/session.py:23 terminal/serializers/storage.py:224 #: terminal/serializers/storage.py:236 tickets/models/comment.py:26 #: tickets/models/flow.py:56 tickets/models/ticket/apply_application.py:16 #: tickets/models/ticket/general.py:275 tickets/serializers/flow.py:53 @@ -1141,7 +1141,7 @@ msgstr "SSH公钥" #: assets/models/cmd_filter.py:88 assets/models/group.py:23 #: common/db/models.py:36 ops/models/adhoc.py:27 ops/models/job.py:111 #: ops/models/playbook.py:26 rbac/models/role.py:37 settings/models.py:38 -#: terminal/models/applet/applet.py:44 terminal/models/applet/applet.py:243 +#: terminal/models/applet/applet.py:44 terminal/models/applet/applet.py:244 #: terminal/models/applet/host.py:139 terminal/models/component/endpoint.py:24 #: terminal/models/component/endpoint.py:100 #: terminal/models/session/session.py:47 tickets/models/comment.py:32 @@ -1191,8 +1191,8 @@ msgstr "用户名与用户相同" #: assets/models/_user.py:52 authentication/models/connection_token.py:40 #: authentication/serializers/connect_token_secret.py:111 -#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:20 -#: terminal/serializers/session.py:41 terminal/serializers/storage.py:68 +#: terminal/models/applet/applet.py:41 terminal/serializers/session.py:21 +#: terminal/serializers/session.py:42 terminal/serializers/storage.py:68 msgid "Protocol" msgstr "协议" @@ -1352,7 +1352,7 @@ msgstr "资产自动化任务" #: assets/models/automations/base.py:113 audits/models.py:199 #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 -#: terminal/models/applet/applet.py:242 terminal/models/applet/host.py:136 +#: terminal/models/applet/applet.py:243 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 #: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 @@ -1420,7 +1420,7 @@ msgid "Asset group" msgstr "资产组" #: assets/models/group.py:34 assets/models/platform.py:17 -#: assets/serializers/platform.py:95 +#: assets/serializers/platform.py:102 #: xpack/plugins/cloud/providers/nutanix.py:30 msgid "Default" msgstr "默认" @@ -1443,7 +1443,7 @@ msgstr "值" #: assets/models/label.py:40 assets/serializers/asset/common.py:123 #: assets/serializers/cagegory.py:6 assets/serializers/cagegory.py:13 -#: assets/serializers/platform.py:93 +#: assets/serializers/platform.py:100 #: authentication/serializers/connect_token_secret.py:121 #: common/serializers/common.py:85 perms/serializers/user_permission.py:28 #: settings/serializers/sms.py:7 @@ -1575,23 +1575,23 @@ msgstr "元数据" msgid "Internal" msgstr "内置" -#: assets/models/platform.py:89 assets/serializers/platform.py:108 +#: assets/models/platform.py:89 assets/serializers/platform.py:115 msgid "Charset" msgstr "编码" -#: assets/models/platform.py:91 assets/serializers/platform.py:136 +#: assets/models/platform.py:91 assets/serializers/platform.py:143 msgid "Domain enabled" msgstr "启用网域" -#: assets/models/platform.py:93 assets/serializers/platform.py:135 +#: assets/models/platform.py:93 assets/serializers/platform.py:142 msgid "Su enabled" msgstr "启用账号切换" -#: assets/models/platform.py:94 assets/serializers/platform.py:114 +#: assets/models/platform.py:94 assets/serializers/platform.py:121 msgid "Su method" msgstr "账号切换方式" -#: assets/models/platform.py:95 assets/serializers/platform.py:117 +#: assets/models/platform.py:95 assets/serializers/platform.py:124 msgid "Custom fields" msgstr "自定义属性" @@ -1606,7 +1606,7 @@ msgid "" "type" msgstr "资产中批量更新平台,不符合平台类型跳过的资产" -#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:111 +#: assets/serializers/asset/common.py:124 assets/serializers/platform.py:118 #: authentication/serializers/connect_token_secret.py:29 #: authentication/serializers/connect_token_secret.py:72 #: perms/serializers/user_permission.py:25 xpack/plugins/cloud/models.py:99 @@ -1639,8 +1639,8 @@ msgstr "协议是必填的: {}" msgid "Default database" msgstr "默认数据库" -#: assets/serializers/asset/database.py:28 common/db/fields.py:557 -#: common/db/fields.py:562 common/serializers/fields.py:104 +#: assets/serializers/asset/database.py:28 common/db/fields.py:564 +#: common/db/fields.py:569 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -1742,27 +1742,27 @@ msgstr "启用账号收集" msgid "Gather accounts method" msgstr "收集账号方式" -#: assets/serializers/platform.py:96 +#: assets/serializers/platform.py:103 msgid "Help text" msgstr "帮助" -#: assets/serializers/platform.py:97 +#: assets/serializers/platform.py:104 msgid "Choices" msgstr "" -#: assets/serializers/platform.py:112 +#: assets/serializers/platform.py:119 msgid "Automation" msgstr "自动化" -#: assets/serializers/platform.py:137 +#: assets/serializers/platform.py:144 msgid "Default Domain" msgstr "默认网域" -#: assets/serializers/platform.py:146 +#: assets/serializers/platform.py:153 msgid "type is required" msgstr "类型 该字段是必填项。" -#: assets/serializers/platform.py:169 +#: assets/serializers/platform.py:176 msgid "Protocols is required" msgstr "协议是必填的" @@ -1904,7 +1904,7 @@ msgstr "改密" #: audits/const.py:35 settings/serializers/terminal.py:6 #: terminal/models/applet/host.py:25 terminal/models/component/terminal.py:163 -#: terminal/serializers/session.py:48 +#: terminal/serializers/session.py:49 terminal/serializers/session.py:58 msgid "Terminal" msgstr "终端" @@ -1929,11 +1929,11 @@ msgstr "任务" msgid "-" msgstr "-" -#: audits/handler.py:112 +#: audits/handler.py:117 msgid "Yes" msgstr "是" -#: audits/handler.py:112 +#: audits/handler.py:117 msgid "No" msgstr "否" @@ -1954,6 +1954,10 @@ msgstr "操作" msgid "Filename" msgstr "文件名" +#: audits/models.py:61 common/serializers/common.py:98 +msgid "File" +msgstr "文件" + #: audits/models.py:62 terminal/backends/command/models.py:24 #: terminal/models/session/replay.py:9 terminal/models/session/sharing.py:18 #: terminal/models/session/sharing.py:81 @@ -2136,7 +2140,7 @@ msgstr "ACL 动作是复核" msgid "Current user not support mfa type: {}" msgstr "当前用户不支持 MFA 类型: {}" -#: authentication/api/password.py:31 terminal/api/session/session.py:249 +#: authentication/api/password.py:31 terminal/api/session/session.py:259 #: users/views/profile/reset.py:44 msgid "User does not exist: {}" msgstr "用户不存在: {}" @@ -3080,26 +3084,26 @@ msgstr "编码数据为 text" msgid "Encrypt field using Secret Key" msgstr "加密的字段" -#: common/db/fields.py:545 +#: common/db/fields.py:552 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" -#: common/db/fields.py:552 +#: common/db/fields.py:559 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "无效类型,应为 all、ids 或 attrs" -#: common/db/fields.py:555 +#: common/db/fields.py:562 msgid "Invalid ids for ids, should be a list" msgstr "无效的ID,应为列表" -#: common/db/fields.py:560 common/db/fields.py:565 +#: common/db/fields.py:567 common/db/fields.py:572 msgid "Invalid attrs, should be a list of dict" msgstr "无效的属性,应为dict列表" -#: common/db/fields.py:567 +#: common/db/fields.py:574 msgid "Invalid attrs, should be has name and value" msgstr "无效属性,应具有名称和值" @@ -3242,10 +3246,6 @@ msgstr "请在 {} 秒后发送" msgid "Children" msgstr "节点" -#: common/serializers/common.py:98 -msgid "File" -msgstr "文件" - #: common/serializers/fields.py:105 #, python-brace-format msgid "Invalid pk \"{pk_value}\" - object does not exist." @@ -3660,7 +3660,7 @@ msgstr "保存后执行" msgid "Job type" msgstr "任务类型" -#: ops/serializers/job.py:57 terminal/serializers/session.py:49 +#: ops/serializers/job.py:57 terminal/serializers/session.py:50 msgid "Is finished" msgstr "是否完成" @@ -4074,7 +4074,7 @@ msgid "My assets" msgstr "我的资产" #: rbac/tree.py:56 terminal/models/applet/applet.py:51 -#: terminal/models/applet/applet.py:239 terminal/models/applet/host.py:28 +#: terminal/models/applet/applet.py:240 terminal/models/applet/host.py:28 #: terminal/serializers/applet.py:15 msgid "Applet" msgstr "远程应用" @@ -5166,11 +5166,13 @@ msgid "" msgstr "提示:在Luna 页面中连接图形化资产时默认使用的分辨率" #: settings/tasks/ldap.py:25 -msgid "Import ldap user" -msgstr "导入 LDAP 用户" +msgid "Periodic import ldap user" +msgstr "周期导入 LDAP 用户" #: settings/tasks/ldap.py:47 -msgid "Periodic import ldap user" +#, fuzzy +#| msgid "Periodic import ldap user" +msgid "Registration periodic import ldap user task" msgstr "周期导入 LDAP 用户" #: settings/utils/ldap.py:472 @@ -5506,15 +5508,15 @@ msgstr "测试失败: 账号无效" msgid "Have online sessions" msgstr "有在线会话" -#: terminal/api/session/session.py:241 +#: terminal/api/session/session.py:251 msgid "Session does not exist: {}" msgstr "会话不存在: {}" -#: terminal/api/session/session.py:244 +#: terminal/api/session/session.py:254 msgid "Session is finished or the protocol not supported" msgstr "会话已经完成或协议不支持" -#: terminal/api/session/session.py:257 +#: terminal/api/session/session.py:267 msgid "User does not have permission" msgstr "用户没有权限" @@ -5635,7 +5637,7 @@ msgstr "" msgid "Missing type in platform.yml" msgstr "" -#: terminal/models/applet/applet.py:241 terminal/models/applet/host.py:34 +#: terminal/models/applet/applet.py:242 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "宿主机" @@ -5960,7 +5962,7 @@ msgstr "RDS 最大断开时间" msgid "RDS Remote App Logoff Time Limit" msgstr "RDS 远程应用注销时间限制" -#: terminal/serializers/applet_host.py:55 terminal/serializers/terminal.py:41 +#: terminal/serializers/applet_host.py:55 terminal/serializers/terminal.py:47 msgid "Load status" msgstr "负载状态" @@ -6016,35 +6018,35 @@ msgstr "如果不同端点下的资产 IP 有冲突,使用资产标签实现" msgid "Asset IP" msgstr "资产 IP" -#: terminal/serializers/session.py:24 terminal/serializers/session.py:46 +#: terminal/serializers/session.py:25 terminal/serializers/session.py:47 msgid "Can replay" msgstr "是否可重放" -#: terminal/serializers/session.py:25 terminal/serializers/session.py:47 +#: terminal/serializers/session.py:26 terminal/serializers/session.py:48 msgid "Can join" msgstr "是否可加入" -#: terminal/serializers/session.py:26 terminal/serializers/session.py:50 +#: terminal/serializers/session.py:27 terminal/serializers/session.py:51 msgid "Can terminate" msgstr "是否可中断" -#: terminal/serializers/session.py:42 +#: terminal/serializers/session.py:43 msgid "User ID" msgstr "用户 ID" -#: terminal/serializers/session.py:43 +#: terminal/serializers/session.py:44 msgid "Asset ID" msgstr "资产 ID" -#: terminal/serializers/session.py:44 +#: terminal/serializers/session.py:45 msgid "Login from display" msgstr "登录来源名称" -#: terminal/serializers/session.py:51 +#: terminal/serializers/session.py:52 msgid "Terminal display" msgstr "终端显示" -#: terminal/serializers/session.py:56 +#: terminal/serializers/session.py:57 msgid "Command amount" msgstr "命令数量" @@ -6110,7 +6112,7 @@ msgstr "索引" msgid "Doc type" msgstr "文档类型" -#: terminal/serializers/terminal.py:77 terminal/serializers/terminal.py:85 +#: terminal/serializers/terminal.py:83 terminal/serializers/terminal.py:91 msgid "Not found" msgstr "没有发现" @@ -7624,5 +7626,8 @@ msgstr "旗舰版" msgid "Community edition" msgstr "社区版" +#~ msgid "Import ldap user" +#~ msgstr "导入 LDAP 用户" + #~ msgid "Reviewers amount" #~ msgstr "审批人数量" diff --git a/apps/settings/tasks/ldap.py b/apps/settings/tasks/ldap.py index b165d1015..fa2f4287c 100644 --- a/apps/settings/tasks/ldap.py +++ b/apps/settings/tasks/ldap.py @@ -22,7 +22,7 @@ def sync_ldap_user(): LDAPSyncUtil().perform_sync() -@shared_task(verbose_name=_('Import ldap user')) +@shared_task(verbose_name=_('Periodic import ldap user')) @transaction.atomic def import_ldap_user(): logger.info("Start import ldap user task") @@ -44,7 +44,7 @@ def import_ldap_user(): logger.info('Imported {} users successfully'.format(len(users))) -@shared_task(verbose_name=_('Periodic import ldap user')) +@shared_task(verbose_name=_('Registration periodic import ldap user task')) @after_app_ready_start def import_ldap_user_periodic(): if not settings.AUTH_LDAP: From 120f0dd3adb5897b38ea1f71a50ccf033b6018f2 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 14 Jun 2023 14:42:53 +0800 Subject: [PATCH 130/153] =?UTF-8?q?perf:=20asset=20web=20autofill=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0LabeledChoiceField=20(#10706)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/assets/serializers/asset/info/spec.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/assets/serializers/asset/info/spec.py b/apps/assets/serializers/asset/info/spec.py index 5d3de54c3..72be7edec 100644 --- a/apps/assets/serializers/asset/info/spec.py +++ b/apps/assets/serializers/asset/info/spec.py @@ -1,6 +1,9 @@ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers +from assets.const.web import FillType from assets.models import Database, Web +from common.serializers.fields import LabeledChoiceField class DatabaseSpecSerializer(serializers.ModelSerializer): @@ -10,6 +13,7 @@ class DatabaseSpecSerializer(serializers.ModelSerializer): class WebSpecSerializer(serializers.ModelSerializer): + autofill = LabeledChoiceField(choices=FillType.choices, label=_('Autofill')) class Meta: model = Web fields = [ From 96a66e555fbb091d3fe6a922ca56339a39678146 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 14 Jun 2023 14:48:50 +0800 Subject: [PATCH 131/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/serializers/command_acl.py | 5 +---- apps/locale/zh/LC_MESSAGES/django.po | 2 +- apps/terminal/connect_methods.py | 14 +++++++++++--- apps/users/serializers/group.py | 4 +--- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/acls/serializers/command_acl.py b/apps/acls/serializers/command_acl.py index 16cb615a8..a34ea4cc4 100644 --- a/apps/acls/serializers/command_acl.py +++ b/apps/acls/serializers/command_acl.py @@ -27,13 +27,10 @@ class CommandFilterACLSerializer(BaseSerializer, BulkOrgResourceModelSerializer) command_groups = ObjectRelatedField( queryset=CommandGroup.objects, many=True, required=False, label=_('Command group') ) - command_groups_amount = serializers.IntegerField( - source='command_groups.count', read_only=True, label=_('Command group amount') - ) class Meta(BaseSerializer.Meta): model = CommandFilterACL - fields = BaseSerializer.Meta.fields + ['command_groups', 'command_groups_amount'] + fields = BaseSerializer.Meta.fields + ['command_groups'] class CommandReviewSerializer(serializers.Serializer): diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 7540ebf5d..cb24af05d 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -686,7 +686,7 @@ msgstr "特殊信息" #: accounts/serializers/account/base.py:81 msgid "Tip: If no username is required for authentication, fill in `null`" -msgstr "提示: 如果认证时不需要用户名,则填写为 null" +msgstr "提示: 如果认证时不需要用户名,可填写为 null" #: accounts/serializers/automations/base.py:23 #: assets/models/asset/common.py:155 assets/models/automations/base.py:18 diff --git a/apps/terminal/connect_methods.py b/apps/terminal/connect_methods.py index 0d1571489..1ed9e14f1 100644 --- a/apps/terminal/connect_methods.py +++ b/apps/terminal/connect_methods.py @@ -69,10 +69,11 @@ class NativeClient(TextChoices): Protocol.rdp: [cls.mstsc], Protocol.mysql: [cls.db_client], Protocol.mariadb: [cls.db_client], - Protocol.oracle: [cls.db_client], - Protocol.postgresql: [cls.db_client], Protocol.redis: [cls.db_client], Protocol.mongodb: [cls.db_client], + + Protocol.oracle: [cls.db_client], + Protocol.postgresql: [cls.db_client], } return clients @@ -90,12 +91,17 @@ class NativeClient(TextChoices): @classmethod def xpack_methods(cls): - return [cls.sqlplus, cls.mstsc] + return [cls.mstsc] + + @classmethod + def xpack_protocols(cls): + return [Protocol.rdp, Protocol.oracle, Protocol.clickhouse, Protocol.sqlserver] @classmethod def get_methods(cls, os='windows'): clients_map = cls.get_native_clients() methods = defaultdict(list) + xpack_protocols = cls.xpack_protocols() for protocol, _clients in clients_map.items(): if isinstance(_clients, dict): @@ -103,6 +109,8 @@ class NativeClient(TextChoices): _clients = list(itertools.chain(*_clients.values())) else: _clients = _clients.get(os, _clients['default']) + if protocol in xpack_protocols: + continue for client in _clients: if not settings.XPACK_ENABLED and client in cls.xpack_methods(): continue diff --git a/apps/users/serializers/group.py b/apps/users/serializers/group.py index 90228d681..dc61eee21 100644 --- a/apps/users/serializers/group.py +++ b/apps/users/serializers/group.py @@ -24,9 +24,7 @@ class UserGroupSerializer(BulkOrgResourceModelSerializer): fields_small = fields_mini + [ 'comment', 'date_created', 'created_by' ] - fields = fields_mini + fields_small + [ - 'users', 'users_amount', - ] + fields = fields_mini + fields_small + ['users'] extra_kwargs = { 'created_by': {'label': _('Created by'), 'read_only': True}, 'users_amount': {'label': _('Users amount')}, From e762a5d8aed1d913d4bbfa1be83e56b70a62ef2e Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 14 Jun 2023 16:37:30 +0800 Subject: [PATCH 132/153] =?UTF-8?q?perf:=20=E6=9B=B4=E6=96=B0=E5=8F=91?= =?UTF-8?q?=E5=B8=83=E6=9C=BA=E7=9A=84=E5=8D=95=E7=94=A8=E6=88=B7=E5=8D=95?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/terminal/models/applet/applet.py | 2 +- apps/terminal/serializers/applet_host.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/terminal/models/applet/applet.py b/apps/terminal/models/applet/applet.py index e9fdc1b9d..ef8eca8bc 100644 --- a/apps/terminal/models/applet/applet.py +++ b/apps/terminal/models/applet/applet.py @@ -194,7 +194,7 @@ class Applet(JMSBaseModel): host = self.select_host(user) if not host: return None - host_concurrent = str(host.deploy_options.get('RDS_fSingleSessionPerUser', 0)) == '1' + host_concurrent = str(host.deploy_options.get('RDS_fSingleSessionPerUser', 0)) == '0' can_concurrent = (self.can_concurrent or self.type == 'web') and host_concurrent accounts = host.accounts.all().filter(is_active=True, privileged=False) diff --git a/apps/terminal/serializers/applet_host.py b/apps/terminal/serializers/applet_host.py index f866d6213..392b2e2e3 100644 --- a/apps/terminal/serializers/applet_host.py +++ b/apps/terminal/serializers/applet_host.py @@ -24,6 +24,10 @@ class DeployOptionsSerializer(serializers.Serializer): (4, _('Per Session')), (2, _('Per Device')), ) + + # 单用户单会话, + # 默认值为1,表示启用状态(组策略默认值),此时单用户只能有一个会话连接 + # 如果改为 0 ,表示禁用状态,此时可以单用户多会话连接 SESSION_PER_USER = ( (0, _("Disabled")), (1, _("Enabled")), From e8163167c5cf85183ecf982ed2ea11dbb187b2c8 Mon Sep 17 00:00:00 2001 From: "fangfang.dong" Date: Wed, 14 Jun 2023 16:21:46 +0800 Subject: [PATCH 133/153] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E5=8F=B0=20-=20=E8=B4=A6=E5=8F=B7=20-=20=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E5=88=97=E8=A1=A8=20-=20=E6=9F=A5=E7=9C=8B=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E8=AF=A6=E6=83=85=E6=97=B6=E7=9A=84500=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/views/mixins.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/common/views/mixins.py b/apps/common/views/mixins.py index 562e9ca81..5b723eb2b 100644 --- a/apps/common/views/mixins.py +++ b/apps/common/views/mixins.py @@ -9,6 +9,8 @@ from rest_framework.request import Request from common.exceptions import UserConfirmRequired from common.utils import i18n_fmt +from orgs.utils import current_org +from orgs.models import Organization from audits.handler import create_or_update_operate_log from audits.const import ActionChoices, ActivityChoices from audits.models import ActivityLog @@ -91,7 +93,8 @@ class RecordViewLogMixin: activities = [ ActivityLog( resource_id=getattr(resource_id, 'pk', resource_id), - type=ActivityChoices.operate_log, detail=detail + type=ActivityChoices.operate_log, detail=detail, + org_id=Organization.ROOT_ID if current_org.is_root() else None, ) for resource_id in ids ] From d51323faeff7bc4924f8d0004132985e9c63df9b Mon Sep 17 00:00:00 2001 From: nut Date: Wed, 14 Jun 2023 16:57:32 +0800 Subject: [PATCH 134/153] Update mixins.py --- apps/common/views/mixins.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/common/views/mixins.py b/apps/common/views/mixins.py index 5b723eb2b..c68c224b1 100644 --- a/apps/common/views/mixins.py +++ b/apps/common/views/mixins.py @@ -10,7 +10,6 @@ from rest_framework.request import Request from common.exceptions import UserConfirmRequired from common.utils import i18n_fmt from orgs.utils import current_org -from orgs.models import Organization from audits.handler import create_or_update_operate_log from audits.const import ActionChoices, ActivityChoices from audits.models import ActivityLog @@ -93,8 +92,7 @@ class RecordViewLogMixin: activities = [ ActivityLog( resource_id=getattr(resource_id, 'pk', resource_id), - type=ActivityChoices.operate_log, detail=detail, - org_id=Organization.ROOT_ID if current_org.is_root() else None, + type=ActivityChoices.operate_log, detail=detail, org_id=current_org, ) for resource_id in ids ] From 4bcd47df64176673fdcf3577dea9fea99bd5810d Mon Sep 17 00:00:00 2001 From: nut Date: Wed, 14 Jun 2023 17:09:42 +0800 Subject: [PATCH 135/153] Update mixins.py --- apps/common/views/mixins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/common/views/mixins.py b/apps/common/views/mixins.py index c68c224b1..207888593 100644 --- a/apps/common/views/mixins.py +++ b/apps/common/views/mixins.py @@ -92,7 +92,7 @@ class RecordViewLogMixin: activities = [ ActivityLog( resource_id=getattr(resource_id, 'pk', resource_id), - type=ActivityChoices.operate_log, detail=detail, org_id=current_org, + type=ActivityChoices.operate_log, detail=detail, org_id=current_org.id, ) for resource_id in ids ] From 53c3c90e2d90c768af22d9cb467ec883ed54be05 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 14 Jun 2023 18:17:20 +0800 Subject: [PATCH 136/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=20acls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/models/base.py | 4 +--- .../migrations/0098_auto_20220430_2126.py | 6 ++++-- apps/common/db/fields.py | 19 +++++++++++++------ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index c29fec096..6b7a5af37 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -110,11 +110,11 @@ class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL): @classmethod def filter_queryset(cls, user=None, asset=None, account=None, account_username=None, **kwargs): queryset = cls.objects.all() - org_id = None if user: q = cls.users.get_filter_q(user) queryset = queryset.filter(q) + if asset: org_id = asset.org_id with tmp_to_org(org_id): @@ -127,8 +127,6 @@ class UserAssetAccountBaseACL(OrgModelMixin, UserBaseACL): models.Q(accounts__contains='*') | \ models.Q(accounts__contains='@ALL') queryset = queryset.filter(q) - if org_id: - kwargs['org_id'] = org_id if kwargs: queryset = queryset.filter(**kwargs) return queryset.valid().distinct() diff --git a/apps/assets/migrations/0098_auto_20220430_2126.py b/apps/assets/migrations/0098_auto_20220430_2126.py index 64a85ecb6..f388ca731 100644 --- a/apps/assets/migrations/0098_auto_20220430_2126.py +++ b/apps/assets/migrations/0098_auto_20220430_2126.py @@ -90,8 +90,10 @@ def create_app_nodes(apps, org_id): next_value = max([int(k[1]) for k in node_key_split]) + 1 parent_key = node_key_split[0][0] else: - root_node = node_model.objects.filter(org_id=org_id)\ - .filter(parent_key='', key__regex=r'^[0-9]+$').exclude(key__startswith='-').first() + root_node = node_model.objects.filter(org_id=org_id) \ + .filter(parent_key='', key__regex=r'^[0-9]+$') \ + .exclude(key__startswith='-') \ + .first() if not root_node: return parent_key = root_node.key diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index a84a9de6f..d2228d313 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -295,7 +295,13 @@ class RelatedManager: self.instance.__dict__[self.field.name] = value @classmethod - def get_filter_q(cls, value, to_model): + def _get_filter_q(cls, value, to_model): + """ + 这个是 instance 去查找 to_model 的 queryset 的 Q + :param value: + :param to_model: + :return: + """ if not value or not isinstance(value, dict): return Q() @@ -314,7 +320,7 @@ class RelatedManager: queryset = to_model.get_queryset() else: queryset = to_model.objects.all() - q = cls.get_filter_q(value, to_model) + q = cls._get_filter_q(value, to_model) return queryset.filter(q).distinct() @staticmethod @@ -442,9 +448,7 @@ class JSONManyToManyDescriptor: # 自定义的情况:比如 nodes, category res = True to_model = apps.get_model(self.field.to) - src_model = self.field.model - field_name = self.field.name - custom_attr_filter = getattr(src_model, "get_filter_{}_attr_q".format(field_name), None) + custom_attr_filter = getattr(to_model, "get_json_filter_attr_q", None) custom_q = Q() for rule in attr_rules: @@ -513,7 +517,10 @@ class JSONManyToManyDescriptor: model_cls = self.field.model field_name = self.field.column q = Q(**{f'{field_name}__type': 'all'}) | \ - Q(**{f'{field_name}__type': 'ids', f'{field_name}__ids__contains': [str(instance.id)]}) + Q(**{ + f'{field_name}__type': 'ids', + f'{field_name}__ids__contains': [str(instance.id)] + }) queryset_id_attrs = model_cls.objects \ .filter(**{'{}__type'.format(field_name): 'attrs'}) \ .values_list('id', '{}__attrs'.format(field_name)) From ce5ddf78731d1d4a6f106433a4baad4fb7dbde8f Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 14 Jun 2023 19:10:34 +0800 Subject: [PATCH 137/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20filter=20n?= =?UTF-8?q?ame?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 4 ++-- apps/common/drf/filters.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 3e1b1ac98..b1cdc76d6 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -295,7 +295,7 @@ class RelatedManager: self.instance.__dict__[self.field.name] = value @classmethod - def _get_filter_q(cls, value, to_model): + def get_to_filter_q(cls, value, to_model): """ 这个是 instance 去查找 to_model 的 queryset 的 Q :param value: @@ -320,7 +320,7 @@ class RelatedManager: queryset = to_model.get_queryset() else: queryset = to_model.objects.all() - q = cls._get_filter_q(value, to_model) + q = cls.get_to_filter_q(value, to_model) return queryset.filter(q).distinct() @staticmethod diff --git a/apps/common/drf/filters.py b/apps/common/drf/filters.py index cfdff0a6e..bac14190e 100644 --- a/apps/common/drf/filters.py +++ b/apps/common/drf/filters.py @@ -214,5 +214,5 @@ class AttrRulesFilterBackend(filters.BaseFilterBackend): raise ValidationError({'attr_rules': 'attr_rules should be json'}) logging.debug('attr_rules: %s', attr_rules) - q = RelatedManager.get_filter_q(attr_rules, queryset.model) + q = RelatedManager.get_to_filter_q(attr_rules, queryset.model) return queryset.filter(q).distinct() From 954f86f8a9ef80fc9fa09b1084d973610eb182bd Mon Sep 17 00:00:00 2001 From: Bai Date: Wed, 14 Jun 2023 19:52:54 +0800 Subject: [PATCH 138/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E4=BB=BB=E5=8A=A1=E4=B8=AD=E5=BF=83=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/tasks.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/ops/tasks.py b/apps/ops/tasks.py index 11ad27aa4..1fe0fbe7c 100644 --- a/apps/ops/tasks.py +++ b/apps/ops/tasks.py @@ -64,7 +64,13 @@ def job_execution_task_activity_callback(self, execution_id, *args, **kwargs): activity_callback=job_execution_task_activity_callback ) def run_ops_job_execution(execution_id, **kwargs): - execution = get_object_or_none(JobExecution, id=execution_id) + with tmp_to_root_org(): + execution = get_object_or_none(JobExecution, id=execution_id) + + if not execution: + logger.error("Did not get the execution: {}".format(execution_id)) + return + try: with tmp_to_org(execution.org): execution.start() From 9e31a5064bb609bd11e6407de695eb935a87e849 Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Wed, 14 Jun 2023 19:48:43 +0800 Subject: [PATCH 139/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=BB=91?= =?UTF-8?q?=E5=90=8D=E5=8D=95=E5=91=BD=E4=BB=A4=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/ansible/runner.py | 6 +++++- apps/ops/models/job.py | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/ops/ansible/runner.py b/apps/ops/ansible/runner.py index 3bce64b2a..ac83d0d8e 100644 --- a/apps/ops/ansible/runner.py +++ b/apps/ops/ansible/runner.py @@ -7,6 +7,10 @@ from django.conf import settings from .callback import DefaultCallback +class CommandInBlackListException(Exception): + pass + + class AdHocRunner: cmd_modules_choices = ('shell', 'raw', 'command', 'script', 'win_shell') @@ -28,7 +32,7 @@ class AdHocRunner: if self.module not in self.cmd_modules_choices: return if self.module_args and self.module_args.split()[0] in settings.SECURITY_COMMAND_BLACKLIST: - raise Exception("command not allowed: {}".format(self.module_args[0])) + raise CommandInBlackListException("command not allowed:{}".format(self.module_args.split()[0])) def run(self, verbosity=0, **kwargs): self.check_module() diff --git a/apps/ops/models/job.py b/apps/ops/models/job.py index 193debe31..932a948b0 100644 --- a/apps/ops/models/job.py +++ b/apps/ops/models/job.py @@ -19,7 +19,7 @@ from simple_history.models import HistoricalRecords from accounts.models import Account from acls.models import CommandFilterACL from assets.models import Asset -from ops.ansible import JMSInventory, AdHocRunner, PlaybookRunner +from ops.ansible import JMSInventory, AdHocRunner, PlaybookRunner, CommandInBlackListException from ops.mixin import PeriodTaskModelMixin from ops.variables import * from ops.const import Types, Modules, RunasPolicies, JobStatus @@ -450,6 +450,8 @@ class JobExecution(JMSOrgBaseModel): cb = runner.run(**kwargs) self.set_result(cb) return cb + except CommandInBlackListException as e: + print("command is rejected by black list: {}".format(e)) except Exception as e: logging.error(e, exc_info=True) self.set_error(e) From 2c2334b61863a0e357c0cc471d3f5e6550623aa8 Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Wed, 14 Jun 2023 20:04:20 +0800 Subject: [PATCH 140/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/ansible/runner.py | 3 ++- apps/ops/models/job.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/ops/ansible/runner.py b/apps/ops/ansible/runner.py index ac83d0d8e..03aec1787 100644 --- a/apps/ops/ansible/runner.py +++ b/apps/ops/ansible/runner.py @@ -32,7 +32,8 @@ class AdHocRunner: if self.module not in self.cmd_modules_choices: return if self.module_args and self.module_args.split()[0] in settings.SECURITY_COMMAND_BLACKLIST: - raise CommandInBlackListException("command not allowed:{}".format(self.module_args.split()[0])) + raise CommandInBlackListException( + "Command is rejected by black list: {}".format(self.module_args.split()[0])) def run(self, verbosity=0, **kwargs): self.check_module() diff --git a/apps/ops/models/job.py b/apps/ops/models/job.py index 932a948b0..b655fc095 100644 --- a/apps/ops/models/job.py +++ b/apps/ops/models/job.py @@ -451,7 +451,7 @@ class JobExecution(JMSOrgBaseModel): self.set_result(cb) return cb except CommandInBlackListException as e: - print("command is rejected by black list: {}".format(e)) + print(e) except Exception as e: logging.error(e, exc_info=True) self.set_error(e) From fca3936a79caf1b10b5afce101733678e7418990 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 14 Jun 2023 20:22:41 +0800 Subject: [PATCH 141/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20phone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/serializers/fields.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/common/serializers/fields.py b/apps/common/serializers/fields.py index e41a90944..cf92391e1 100644 --- a/apps/common/serializers/fields.py +++ b/apps/common/serializers/fields.py @@ -214,8 +214,11 @@ class BitChoicesField(TreeChoicesField): class PhoneField(serializers.CharField): def to_representation(self, value): if value: - phone = phonenumbers.parse(value, 'CN') - value = {'code': '+%s' % phone.country_code, 'phone': phone.national_number} + try: + phone = phonenumbers.parse(value, 'CN') + value = {'code': '+%s' % phone.country_code, 'phone': phone.national_number} + except phonenumbers.NumberParseException: + value = {'code': '+86', 'phone': value} return value From d10db0aa62c51b9b90aef9b0db26ec9af161ad3f Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Wed, 14 Jun 2023 20:38:18 +0800 Subject: [PATCH 142/153] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E8=A2=AB=E9=BB=91=E5=90=8D=E5=8D=95=E6=8B=A6=E6=88=AA?= =?UTF-8?q?=E5=90=8E=E6=B2=A1=E6=9C=89=E6=9B=B4=E6=96=B0=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/ops/models/job.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/ops/models/job.py b/apps/ops/models/job.py index b655fc095..7360838d7 100644 --- a/apps/ops/models/job.py +++ b/apps/ops/models/job.py @@ -452,6 +452,7 @@ class JobExecution(JMSOrgBaseModel): return cb except CommandInBlackListException as e: print(e) + self.set_error(e) except Exception as e: logging.error(e, exc_info=True) self.set_error(e) From 25e72499572ac8974243faee5e61213877bf74b7 Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 14 Jun 2023 20:39:03 +0800 Subject: [PATCH 143/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=AD=A3?= =?UTF-8?q?=E5=88=99=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index b1cdc76d6..2cd8edc2b 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -474,7 +474,7 @@ class JSONManyToManyDescriptor: res &= str(value).endswith(str(rule_value)) elif rule_match == 'regex': try: - matched = bool(re.match(rule_value, value)) + matched = bool(re.search(r'{}'.format(rule_value), value)) except Exception as e: logging.error('Error regex match: %s', e) matched = False From 7c31b4ee30501d442cdcfbf3a97e53f947497037 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Wed, 14 Jun 2023 20:42:29 +0800 Subject: [PATCH 144/153] =?UTF-8?q?perf:=20=E4=BF=AE=E6=94=B9=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=20(#10721)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/locale/ja/LC_MESSAGES/django.mo | 4 +- apps/locale/ja/LC_MESSAGES/django.po | 124 ++++++++---------- apps/locale/zh/LC_MESSAGES/django.mo | 4 +- apps/locale/zh/LC_MESSAGES/django.po | 124 ++++++++---------- ...k_command_replay_storage_connectivity.html | 4 +- 5 files changed, 116 insertions(+), 144 deletions(-) diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 09f2ef0d4..3d7539330 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70eb1665cc86e50cf78d3b80730aadf7963b51640b80fde21b4e207b7cbb5d0c -size 144416 +oid sha256:a76aa384867a4732eb7d2365515a1a972502ebadcba4de8236c1dcb3c5c7fdd2 +size 145757 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index 8fa8f8465..aee6c1f8c 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-14 10:57+0800\n" +"POT-Creation-Date: 2023-06-14 20:40+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -631,7 +631,7 @@ msgstr "アカウントはすでに存在しています" #: accounts/serializers/account/account.py:420 #: authentication/serializers/connect_token_secret.py:156 #: authentication/templates/authentication/_access_key_modal.html:30 -#: perms/models/perm_node.py:21 users/serializers/group.py:33 +#: perms/models/perm_node.py:21 users/serializers/group.py:31 msgid "ID" msgstr "ID" @@ -922,10 +922,6 @@ msgstr "組織 '{}'は存在しません" msgid "None of the reviewers belong to Organization `{}`" msgstr "いずれのレビューアも組織 '{}' に属していません" -#: acls/serializers/command_acl.py:31 -msgid "Command group amount" -msgstr "コマンドグループ数" - #: acls/serializers/rules/rules.py:20 #: xpack/plugins/cloud/serializers/task.py:22 msgid "IP address invalid: `{}`" @@ -1087,7 +1083,7 @@ msgstr "私有雲" #: assets/const/cloud.py:9 msgid "Kubernetes" -msgstr "" +msgstr "Kubernetes" #: assets/const/device.py:7 terminal/models/applet/applet.py:25 #: tickets/const.py:8 @@ -1119,7 +1115,7 @@ msgid "Website" msgstr "Webサイト" #: assets/const/web.py:59 audits/const.py:47 -#: terminal/serializers/applet_host.py:28 +#: terminal/serializers/applet_host.py:32 msgid "Disabled" msgstr "無効" @@ -1172,7 +1168,7 @@ msgstr "更新日" #: assets/models/_user.py:30 assets/models/cmd_filter.py:44 #: assets/models/cmd_filter.py:91 assets/models/group.py:21 #: common/db/models.py:32 users/models/user.py:799 -#: users/serializers/group.py:31 +#: users/serializers/group.py:29 msgid "Created by" msgstr "によって作成された" @@ -1328,7 +1324,8 @@ msgstr "クライアントキー" msgid "Allow invalid cert" msgstr "証明書チェックを無視" -#: assets/models/asset/web.py:9 assets/serializers/platform.py:30 +#: assets/models/asset/web.py:9 assets/serializers/asset/info/spec.py:16 +#: assets/serializers/platform.py:30 msgid "Autofill" msgstr "自動充填" @@ -1361,7 +1358,7 @@ msgstr "アセットの自動化タスク" #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 #: terminal/models/applet/applet.py:243 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 -#: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 +#: terminal/serializers/applet_host.py:107 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 #: tickets/serializers/ticket/ticket.py:20 xpack/plugins/cloud/models.py:164 #: xpack/plugins/cloud/models.py:216 @@ -1504,7 +1501,7 @@ msgid "Setting" msgstr "設定" #: assets/models/platform.py:31 audits/const.py:48 settings/models.py:37 -#: terminal/serializers/applet_host.py:29 +#: terminal/serializers/applet_host.py:33 msgid "Enabled" msgstr "有効化" @@ -1648,8 +1645,8 @@ msgstr "プロトコルが必要です: {}" msgid "Default database" msgstr "デフォルト・データベース" -#: assets/serializers/asset/database.py:28 common/db/fields.py:564 -#: common/db/fields.py:569 common/serializers/fields.py:104 +#: assets/serializers/asset/database.py:28 common/db/fields.py:570 +#: common/db/fields.py:575 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -1757,7 +1754,7 @@ msgstr "ヘルプ" #: assets/serializers/platform.py:104 msgid "Choices" -msgstr "" +msgstr "せんたく" #: assets/serializers/platform.py:119 msgid "Automation" @@ -2664,6 +2661,8 @@ msgstr "期限切れです" #: authentication/serializers/connection_token.py:79 msgid "Reusable connection token is not allowed, global setting not enabled" msgstr "" +"再使用可能な接続トークンの使用は許可されていません。グローバル設定は有効に" +"なっていません" #: authentication/serializers/password_mfa.py:16 #: authentication/serializers/password_mfa.py:24 @@ -3117,26 +3116,29 @@ msgstr "テキストフィールドへのマーシャルデータ" msgid "Encrypt field using Secret Key" msgstr "Secret Keyを使用したフィールドの暗号化" -#: common/db/fields.py:552 +#: common/db/fields.py:558 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" +"JSON言語多对多字段无效,应为 #「タイプ」:「すべて」#「すべて」或 " +"{'type':'ids','ids':[]}或 #タイプ:属性、属性:[#名前:ip、照合:正確、" +"値:1.1.1.1}" -#: common/db/fields.py:559 +#: common/db/fields.py:565 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "無効なタイプです。all、ids、またはattrsでなければなりません" -#: common/db/fields.py:562 +#: common/db/fields.py:568 msgid "Invalid ids for ids, should be a list" msgstr "無効なID、リストでなければなりません" -#: common/db/fields.py:567 common/db/fields.py:572 +#: common/db/fields.py:573 common/db/fields.py:578 msgid "Invalid attrs, should be a list of dict" msgstr "無効な属性、dictリストでなければなりません" -#: common/db/fields.py:574 +#: common/db/fields.py:580 msgid "Invalid attrs, should be has name and value" msgstr "名前と値が必要な無効な属性" @@ -3332,20 +3334,20 @@ msgstr "特殊文字を含むべきではない" msgid "The mobile phone number format is incorrect" msgstr "携帯電話番号の形式が正しくありません" -#: common/views/mixins.py:73 +#: common/views/mixins.py:74 msgid "Export all" msgstr "すべてエクスポート" -#: common/views/mixins.py:75 +#: common/views/mixins.py:76 msgid "Export only selected items" msgstr "選択項目のみエクスポート" -#: common/views/mixins.py:80 +#: common/views/mixins.py:81 #, python-format msgid "Export filtered: %s" msgstr "検索のエクスポート: %s" -#: common/views/mixins.py:89 +#: common/views/mixins.py:90 #, python-format msgid "User %s view/export secret" msgstr "ユーザー %s がパスワードを閲覧/導き出しました" @@ -3512,7 +3514,7 @@ msgstr "PowerShell" #: ops/const.py:51 msgid "Python" -msgstr "" +msgstr "Python" #: ops/const.py:57 msgid "Timeout" @@ -3646,13 +3648,13 @@ msgstr "ジョブ#ジョブ#" #: ops/models/job.py:195 msgid "Material" -msgstr "" +msgstr "Material" #: ops/models/job.py:197 msgid "Material Type" -msgstr "" +msgstr "Material を選択してオプションを設定します。" -#: ops/models/job.py:458 +#: ops/models/job.py:460 msgid "Job Execution" msgstr "ジョブ実行" @@ -3662,7 +3664,7 @@ msgstr "创建方式" #: ops/models/playbook.py:29 msgid "VCS URL" -msgstr "" +msgstr "VCS URL" #: ops/notifications.py:18 msgid "Server performance" @@ -3716,19 +3718,19 @@ msgstr "Ansible タスクを実行する" msgid "Run ansible task execution" msgstr "Ansible タスクの実行を開始する" -#: ops/tasks.py:79 +#: ops/tasks.py:85 msgid "Clear celery periodic tasks" msgstr "タスクログを定期的にクリアする" -#: ops/tasks.py:100 +#: ops/tasks.py:106 msgid "Create or update periodic tasks" msgstr "定期的なタスクの作成または更新" -#: ops/tasks.py:108 +#: ops/tasks.py:114 msgid "Periodic check service performance" msgstr "サービスのパフォーマンスを定期的に確認する" -#: ops/tasks.py:114 +#: ops/tasks.py:120 msgid "Clean up unexpected jobs" msgstr "例外ジョブのクリーンアップ" @@ -4047,7 +4049,7 @@ msgstr "システムロールバインディング" msgid "Perms" msgstr "パーマ" -#: rbac/serializers/role.py:27 users/serializers/group.py:32 +#: rbac/serializers/role.py:27 users/serializers/group.py:30 msgid "Users amount" msgstr "ユーザー数" @@ -4604,7 +4606,7 @@ msgstr "署名+テンプレートの長さは65文字以内" #: settings/serializers/auth/sms.py:97 msgid "URL" -msgstr "" +msgstr "URL" #: settings/serializers/auth/sms.py:102 msgid "Request method" @@ -5166,7 +5168,7 @@ msgstr "" #: settings/serializers/settings.py:71 #, python-format msgid "[%s] %s" -msgstr "" +msgstr "[%s] %s" #: settings/serializers/terminal.py:9 msgid "Hostname" @@ -5240,10 +5242,8 @@ msgid "Periodic import ldap user" msgstr "LDAP ユーザーを定期的にインポートする" #: settings/tasks/ldap.py:47 -#, fuzzy -#| msgid "Periodic import ldap user" msgid "Registration periodic import ldap user task" -msgstr "LDAP ユーザーを定期的にインポートする" +msgstr "登録サイクルLDAPユーザータスクのインポート" #: settings/utils/ldap.py:472 msgid "ldap:// or ldaps:// protocol is used." @@ -5707,22 +5707,22 @@ msgstr "無効なアプレット パッケージ、ファイル {} がありま #: terminal/models/applet/applet.py:111 msgid "Load platform.yml failed: {}" -msgstr "" +msgstr "platform.ymlのロードに失敗しました:{}" #: terminal/models/applet/applet.py:114 msgid "Only support custom platform" -msgstr "" +msgstr "カスタムプラットフォームのみをサポート" #: terminal/models/applet/applet.py:119 msgid "Missing type in platform.yml" -msgstr "" +msgstr "platform.ymlにタイプがありません" #: terminal/models/applet/applet.py:242 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "ホスト マシン" -#: terminal/models/applet/host.py:19 terminal/serializers/applet_host.py:53 +#: terminal/models/applet/host.py:19 terminal/serializers/applet_host.py:57 msgid "Deploy options" msgstr "展開パラメーター" @@ -5978,6 +5978,7 @@ msgid "Connectivity alarm" msgstr "接続性アラーム" #: terminal/notifications.py:189 +#: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 msgid "Invalid storage" msgstr "無効なストレージ" @@ -5993,11 +5994,11 @@ msgstr "セッションごと" msgid "Per Device" msgstr "デバイスごと" -#: terminal/serializers/applet_host.py:33 +#: terminal/serializers/applet_host.py:37 msgid "Core API" msgstr "コア サービス アドレス" -#: terminal/serializers/applet_host.py:34 +#: terminal/serializers/applet_host.py:38 msgid "" " \n" " Tips: The application release machine communicates with the Core " @@ -6016,35 +6017,35 @@ msgstr "" "URL を入力します。
例: https://172.16.10.110 または https://dev." "jumpserver.com" -#: terminal/serializers/applet_host.py:42 terminal/serializers/storage.py:168 +#: terminal/serializers/applet_host.py:46 terminal/serializers/storage.py:168 msgid "Ignore Certificate Verification" msgstr "証明書の検証を無視する" -#: terminal/serializers/applet_host.py:43 +#: terminal/serializers/applet_host.py:47 msgid "Existing RDS license" msgstr "既存の RDS 証明書" -#: terminal/serializers/applet_host.py:44 +#: terminal/serializers/applet_host.py:48 msgid "RDS License Server" msgstr "RDS ライセンス サーバー" -#: terminal/serializers/applet_host.py:45 +#: terminal/serializers/applet_host.py:49 msgid "RDS Licensing Mode" msgstr "RDS 認可モード" -#: terminal/serializers/applet_host.py:47 +#: terminal/serializers/applet_host.py:51 msgid "RDS Single Session Per User" msgstr "RDS シングル ユーザー シングル セッション" -#: terminal/serializers/applet_host.py:48 +#: terminal/serializers/applet_host.py:52 msgid "RDS Max Disconnection Time" msgstr "最大切断時間" -#: terminal/serializers/applet_host.py:49 +#: terminal/serializers/applet_host.py:53 msgid "RDS Remote App Logoff Time Limit" msgstr "RDS 远程应用注销时间限制" -#: terminal/serializers/applet_host.py:55 terminal/serializers/terminal.py:47 +#: terminal/serializers/applet_host.py:59 terminal/serializers/terminal.py:47 msgid "Load status" msgstr "ロードステータス" @@ -6229,13 +6230,6 @@ msgstr "リモートアプリケーション上のアカウントを収集する msgid "Check command replay storage connectivity" msgstr "チェックコマンドと録画ストレージの接続性" -#: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 -msgid "" -"\n" -" Invalid storage\n" -" " -msgstr "" - #: terminal/templates/terminal/_msg_command_alert.html:10 msgid "view" msgstr "表示" @@ -6348,7 +6342,7 @@ msgstr "{} {} チケット" #: tickets/models/comment.py:14 msgid "common" -msgstr "" +msgstr "ありふれた" #: tickets/models/comment.py:23 msgid "User display name" @@ -7246,7 +7240,7 @@ msgstr "谷歌雲" #: xpack/plugins/cloud/const.py:26 msgid "Fusion Compute" -msgstr "" +msgstr "融合計算" #: xpack/plugins/cloud/const.py:31 msgid "Private IP" @@ -7732,9 +7726,3 @@ msgstr "究極のエディション" #: xpack/plugins/license/models.py:86 msgid "Community edition" msgstr "コミュニティ版" - -#~ msgid "Import ldap user" -#~ msgstr "LDAP ユーザーのインポート" - -#~ msgid "Reviewers amount" -#~ msgstr "承認者数" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index ad1bb99ae..ef7c79319 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ba7d3f3f44c44ef691d93294e8e0ac61cee48a35cdc32baf45f772b4997520b -size 118115 +oid sha256:f32e327dd50762b76d209f80b7de470df6faf5242af383dd6152b0c7ea5a7974 +size 119261 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 5ee8b41b2..3408c2622 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-06-14 10:57+0800\n" +"POT-Creation-Date: 2023-06-14 20:40+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -627,7 +627,7 @@ msgstr "账号已存在" #: accounts/serializers/account/account.py:420 #: authentication/serializers/connect_token_secret.py:156 #: authentication/templates/authentication/_access_key_modal.html:30 -#: perms/models/perm_node.py:21 users/serializers/group.py:33 +#: perms/models/perm_node.py:21 users/serializers/group.py:31 msgid "ID" msgstr "ID" @@ -917,10 +917,6 @@ msgstr "组织 `{}` 不存在" msgid "None of the reviewers belong to Organization `{}`" msgstr "所有复核人都不属于组织 `{}`" -#: acls/serializers/command_acl.py:31 -msgid "Command group amount" -msgstr "命令组数量" - #: acls/serializers/rules/rules.py:20 #: xpack/plugins/cloud/serializers/task.py:22 msgid "IP address invalid: `{}`" @@ -1080,7 +1076,7 @@ msgstr "私有云" #: assets/const/cloud.py:9 msgid "Kubernetes" -msgstr "" +msgstr "Kubernetes" #: assets/const/device.py:7 terminal/models/applet/applet.py:25 #: tickets/const.py:8 @@ -1112,7 +1108,7 @@ msgid "Website" msgstr "网站" #: assets/const/web.py:59 audits/const.py:47 -#: terminal/serializers/applet_host.py:28 +#: terminal/serializers/applet_host.py:32 msgid "Disabled" msgstr "禁用" @@ -1165,7 +1161,7 @@ msgstr "更新日期" #: assets/models/_user.py:30 assets/models/cmd_filter.py:44 #: assets/models/cmd_filter.py:91 assets/models/group.py:21 #: common/db/models.py:32 users/models/user.py:799 -#: users/serializers/group.py:31 +#: users/serializers/group.py:29 msgid "Created by" msgstr "创建者" @@ -1321,7 +1317,8 @@ msgstr "客户端密钥" msgid "Allow invalid cert" msgstr "忽略证书校验" -#: assets/models/asset/web.py:9 assets/serializers/platform.py:30 +#: assets/models/asset/web.py:9 assets/serializers/asset/info/spec.py:16 +#: assets/serializers/platform.py:30 msgid "Autofill" msgstr "自动代填" @@ -1354,7 +1351,7 @@ msgstr "资产自动化任务" #: audits/serializers.py:49 ops/models/base.py:49 ops/models/job.py:184 #: terminal/models/applet/applet.py:243 terminal/models/applet/host.py:136 #: terminal/models/component/status.py:30 terminal/serializers/applet.py:18 -#: terminal/serializers/applet_host.py:103 tickets/models/ticket/general.py:283 +#: terminal/serializers/applet_host.py:107 tickets/models/ticket/general.py:283 #: tickets/serializers/super_ticket.py:13 #: tickets/serializers/ticket/ticket.py:20 xpack/plugins/cloud/models.py:164 #: xpack/plugins/cloud/models.py:216 @@ -1497,7 +1494,7 @@ msgid "Setting" msgstr "设置" #: assets/models/platform.py:31 audits/const.py:48 settings/models.py:37 -#: terminal/serializers/applet_host.py:29 +#: terminal/serializers/applet_host.py:33 msgid "Enabled" msgstr "启用" @@ -1639,8 +1636,8 @@ msgstr "协议是必填的: {}" msgid "Default database" msgstr "默认数据库" -#: assets/serializers/asset/database.py:28 common/db/fields.py:564 -#: common/db/fields.py:569 common/serializers/fields.py:104 +#: assets/serializers/asset/database.py:28 common/db/fields.py:570 +#: common/db/fields.py:575 common/serializers/fields.py:104 #: tickets/serializers/ticket/common.py:58 #: xpack/plugins/cloud/serializers/account_attrs.py:56 #: xpack/plugins/cloud/serializers/account_attrs.py:79 @@ -1748,7 +1745,7 @@ msgstr "帮助" #: assets/serializers/platform.py:104 msgid "Choices" -msgstr "" +msgstr "选择" #: assets/serializers/platform.py:119 msgid "Automation" @@ -2638,7 +2635,7 @@ msgstr "已过期" #: authentication/serializers/connection_token.py:79 msgid "Reusable connection token is not allowed, global setting not enabled" -msgstr "" +msgstr "不允许使用可重复使用的连接令牌,未启用全局设置" #: authentication/serializers/password_mfa.py:16 #: authentication/serializers/password_mfa.py:24 @@ -3084,26 +3081,29 @@ msgstr "编码数据为 text" msgid "Encrypt field using Secret Key" msgstr "加密的字段" -#: common/db/fields.py:552 +#: common/db/fields.py:558 msgid "" "Invalid JSON data for JSONManyToManyField, should be like {'type': 'all'} or " "{'type': 'ids', 'ids': []} or {'type': 'attrs', 'attrs': [{'name': 'ip', " "'match': 'exact', 'value': '1.1.1.1'}}" msgstr "" +"JSON 多对多字段无效,应为 {'type': 'all'} 或 {'type': 'ids', 'ids': []} 或 " +"{'type': 'attrs', 'attrs': [{'name': 'ip', 'match': 'exact', 'value': " +"'1.1.1.1'}}" -#: common/db/fields.py:559 +#: common/db/fields.py:565 msgid "Invalid type, should be \"all\", \"ids\" or \"attrs\"" msgstr "无效类型,应为 all、ids 或 attrs" -#: common/db/fields.py:562 +#: common/db/fields.py:568 msgid "Invalid ids for ids, should be a list" msgstr "无效的ID,应为列表" -#: common/db/fields.py:567 common/db/fields.py:572 +#: common/db/fields.py:573 common/db/fields.py:578 msgid "Invalid attrs, should be a list of dict" msgstr "无效的属性,应为dict列表" -#: common/db/fields.py:574 +#: common/db/fields.py:580 msgid "Invalid attrs, should be has name and value" msgstr "无效属性,应具有名称和值" @@ -3297,20 +3297,20 @@ msgstr "不能包含特殊字符" msgid "The mobile phone number format is incorrect" msgstr "手机号格式不正确" -#: common/views/mixins.py:73 +#: common/views/mixins.py:74 msgid "Export all" msgstr "导出所有" -#: common/views/mixins.py:75 +#: common/views/mixins.py:76 msgid "Export only selected items" msgstr "仅导出选择项" -#: common/views/mixins.py:80 +#: common/views/mixins.py:81 #, python-format msgid "Export filtered: %s" msgstr "导出搜素: %s" -#: common/views/mixins.py:89 +#: common/views/mixins.py:90 #, python-format msgid "User %s view/export secret" msgstr "用户 %s 查看/导出 了密码" @@ -3472,7 +3472,7 @@ msgstr "PowerShell" #: ops/const.py:51 msgid "Python" -msgstr "" +msgstr "Python" #: ops/const.py:57 msgid "Timeout" @@ -3606,13 +3606,13 @@ msgstr "作业" #: ops/models/job.py:195 msgid "Material" -msgstr "" +msgstr "Material" #: ops/models/job.py:197 msgid "Material Type" -msgstr "" +msgstr "Material 类型" -#: ops/models/job.py:458 +#: ops/models/job.py:460 msgid "Job Execution" msgstr "作业执行" @@ -3622,7 +3622,7 @@ msgstr "创建方式" #: ops/models/playbook.py:29 msgid "VCS URL" -msgstr "" +msgstr "VCS URL" #: ops/notifications.py:18 msgid "Server performance" @@ -3676,19 +3676,19 @@ msgstr "运行 Ansible 任务" msgid "Run ansible task execution" msgstr "开始执行 Ansible 任务" -#: ops/tasks.py:79 +#: ops/tasks.py:85 msgid "Clear celery periodic tasks" msgstr "清理周期任务" -#: ops/tasks.py:100 +#: ops/tasks.py:106 msgid "Create or update periodic tasks" msgstr "创建或更新周期任务" -#: ops/tasks.py:108 +#: ops/tasks.py:114 msgid "Periodic check service performance" msgstr "周期检测服务性能" -#: ops/tasks.py:114 +#: ops/tasks.py:120 msgid "Clean up unexpected jobs" msgstr "清理异常作业" @@ -4005,7 +4005,7 @@ msgstr "系统角色绑定" msgid "Perms" msgstr "权限" -#: rbac/serializers/role.py:27 users/serializers/group.py:32 +#: rbac/serializers/role.py:27 users/serializers/group.py:30 msgid "Users amount" msgstr "用户数量" @@ -4561,7 +4561,7 @@ msgstr "模板+签名不能超过65个字" #: settings/serializers/auth/sms.py:97 msgid "URL" -msgstr "" +msgstr "URL" #: settings/serializers/auth/sms.py:102 msgid "Request method" @@ -5099,7 +5099,7 @@ msgstr "" #: settings/serializers/settings.py:71 #, python-format msgid "[%s] %s" -msgstr "" +msgstr "[%s] %s" #: settings/serializers/terminal.py:9 msgid "Hostname" @@ -5170,10 +5170,8 @@ msgid "Periodic import ldap user" msgstr "周期导入 LDAP 用户" #: settings/tasks/ldap.py:47 -#, fuzzy -#| msgid "Periodic import ldap user" msgid "Registration periodic import ldap user task" -msgstr "周期导入 LDAP 用户" +msgstr "注册周期导入 LDAP 用户 任务" #: settings/utils/ldap.py:472 msgid "ldap:// or ldaps:// protocol is used." @@ -5627,22 +5625,22 @@ msgstr "Applet pkg 无效,缺少文件 {}" #: terminal/models/applet/applet.py:111 msgid "Load platform.yml failed: {}" -msgstr "" +msgstr "加载 platform.yml 失败: {}" #: terminal/models/applet/applet.py:114 msgid "Only support custom platform" -msgstr "" +msgstr "只支持自定义平台" #: terminal/models/applet/applet.py:119 msgid "Missing type in platform.yml" -msgstr "" +msgstr "在 platform.yml 中缺少类型" #: terminal/models/applet/applet.py:242 terminal/models/applet/host.py:34 #: terminal/models/applet/host.py:134 msgid "Hosting" msgstr "宿主机" -#: terminal/models/applet/host.py:19 terminal/serializers/applet_host.py:53 +#: terminal/models/applet/host.py:19 terminal/serializers/applet_host.py:57 msgid "Deploy options" msgstr "部署参数" @@ -5898,6 +5896,7 @@ msgid "Connectivity alarm" msgstr "可连接性告警" #: terminal/notifications.py:189 +#: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 msgid "Invalid storage" msgstr "无效的存储" @@ -5913,11 +5912,11 @@ msgstr "每用户" msgid "Per Device" msgstr "每设备" -#: terminal/serializers/applet_host.py:33 +#: terminal/serializers/applet_host.py:37 msgid "Core API" msgstr "Core 服务地址" -#: terminal/serializers/applet_host.py:34 +#: terminal/serializers/applet_host.py:38 msgid "" " \n" " Tips: The application release machine communicates with the Core " @@ -5934,35 +5933,35 @@ msgstr "" "建议填写内网地址,否则填写当前站点 URL
例如:https://172.16.10.110 or " "https://dev.jumpserver.com" -#: terminal/serializers/applet_host.py:42 terminal/serializers/storage.py:168 +#: terminal/serializers/applet_host.py:46 terminal/serializers/storage.py:168 msgid "Ignore Certificate Verification" msgstr "忽略证书认证" -#: terminal/serializers/applet_host.py:43 +#: terminal/serializers/applet_host.py:47 msgid "Existing RDS license" msgstr "已有 RDS 许可证" -#: terminal/serializers/applet_host.py:44 +#: terminal/serializers/applet_host.py:48 msgid "RDS License Server" msgstr "RDS 许可服务器" -#: terminal/serializers/applet_host.py:45 +#: terminal/serializers/applet_host.py:49 msgid "RDS Licensing Mode" msgstr "RDS 授权模式" -#: terminal/serializers/applet_host.py:47 +#: terminal/serializers/applet_host.py:51 msgid "RDS Single Session Per User" msgstr "RDS 单用户单会话" -#: terminal/serializers/applet_host.py:48 +#: terminal/serializers/applet_host.py:52 msgid "RDS Max Disconnection Time" msgstr "RDS 最大断开时间" -#: terminal/serializers/applet_host.py:49 +#: terminal/serializers/applet_host.py:53 msgid "RDS Remote App Logoff Time Limit" msgstr "RDS 远程应用注销时间限制" -#: terminal/serializers/applet_host.py:55 terminal/serializers/terminal.py:47 +#: terminal/serializers/applet_host.py:59 terminal/serializers/terminal.py:47 msgid "Load status" msgstr "负载状态" @@ -6144,13 +6143,6 @@ msgstr "收集远程应用上的账号" msgid "Check command replay storage connectivity" msgstr "检查命令及录像存储可连接性 " -#: terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html:4 -msgid "" -"\n" -" Invalid storage\n" -" " -msgstr "" - #: terminal/templates/terminal/_msg_command_alert.html:10 msgid "view" msgstr "查看" @@ -6259,7 +6251,7 @@ msgstr "{} {} 工单" #: tickets/models/comment.py:14 msgid "common" -msgstr "" +msgstr "常见的" #: tickets/models/comment.py:23 msgid "User display name" @@ -7142,7 +7134,7 @@ msgstr "谷歌云" #: xpack/plugins/cloud/const.py:26 msgid "Fusion Compute" -msgstr "" +msgstr "融合计算" #: xpack/plugins/cloud/const.py:31 msgid "Private IP" @@ -7625,9 +7617,3 @@ msgstr "旗舰版" #: xpack/plugins/license/models.py:86 msgid "Community edition" msgstr "社区版" - -#~ msgid "Import ldap user" -#~ msgstr "导入 LDAP 用户" - -#~ msgid "Reviewers amount" -#~ msgstr "审批人数量" diff --git a/apps/terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html b/apps/terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html index 366be33cf..cd2753b15 100644 --- a/apps/terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html +++ b/apps/terminal/templates/terminal/_msg_check_command_replay_storage_connectivity.html @@ -1,9 +1,7 @@ {% load i18n %}

- {% blocktranslate %} - Invalid storage - {% endblocktranslate %} + {% blocktranslate %}Invalid storage{% endblocktranslate %}

    From ee15f2d3d7e6c26853a6b6e9375720d8bdf1e31c Mon Sep 17 00:00:00 2001 From: ibuler Date: Wed, 14 Jun 2023 21:10:35 +0800 Subject: [PATCH 145/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20json=20m2m?= =?UTF-8?q?=20filter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 2cd8edc2b..7aa1971d6 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -502,7 +502,7 @@ class JSONManyToManyDescriptor: value = [value.id] value = set(map(str, value)) rule_value = set(map(str, rule_value)) - res &= rule_value.issubset(value) + res &= value.issubset(rule_value) else: logging.error("unknown match: {}".format(rule['match'])) res &= False From 40d8a71bf8219e0a07633d47127da47eabbd296f Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 15 Jun 2023 09:37:00 +0800 Subject: [PATCH 146/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20json=20m2m?= =?UTF-8?q?=20filter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 2 +- apps/terminal/connect_methods.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 7aa1971d6..bd968c734 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -502,7 +502,7 @@ class JSONManyToManyDescriptor: value = [value.id] value = set(map(str, value)) rule_value = set(map(str, rule_value)) - res &= value.issubset(rule_value) + res &= value & rule_value else: logging.error("unknown match: {}".format(rule['match'])) res &= False diff --git a/apps/terminal/connect_methods.py b/apps/terminal/connect_methods.py index 1ed9e14f1..e38a8d123 100644 --- a/apps/terminal/connect_methods.py +++ b/apps/terminal/connect_methods.py @@ -104,13 +104,15 @@ class NativeClient(TextChoices): xpack_protocols = cls.xpack_protocols() for protocol, _clients in clients_map.items(): + if not settings.XPACK_ENABLED and protocol in xpack_protocols: + continue + if isinstance(_clients, dict): if os == 'all': _clients = list(itertools.chain(*_clients.values())) else: _clients = _clients.get(os, _clients['default']) - if protocol in xpack_protocols: - continue + for client in _clients: if not settings.XPACK_ENABLED and client in cls.xpack_methods(): continue From 5bd276b9ce0b02be88c3f6b2469cd1e3ba0cbc36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=B0=8F=E7=99=BD?= <296015668@qq.com> Date: Thu, 15 Jun 2023 10:02:08 +0800 Subject: [PATCH 147/153] =?UTF-8?q?fix:=20=E4=BF=AE=E6=AD=A3=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E9=95=9C=E5=83=8F=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 4 ++-- Dockerfile.loong64 | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index a501e06c6..3dc78a9df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9-slim as stage-build +FROM python:3.9-slim-buster as stage-build ARG TARGETARCH ARG VERSION @@ -8,7 +8,7 @@ WORKDIR /opt/jumpserver ADD . . RUN cd utils && bash -ixeu build.sh -FROM python:3.9-slim +FROM python:3.9-slim-buster ARG TARGETARCH MAINTAINER JumpServer Team diff --git a/Dockerfile.loong64 b/Dockerfile.loong64 index 7e3f4bda2..f5682aec2 100644 --- a/Dockerfile.loong64 +++ b/Dockerfile.loong64 @@ -1,4 +1,4 @@ -FROM python:3.9-slim as stage-build +FROM python:3.9-slim-buster as stage-build ARG TARGETARCH ARG VERSION @@ -8,7 +8,7 @@ WORKDIR /opt/jumpserver ADD . . RUN cd utils && bash -ixeu build.sh -FROM python:3.9-slim +FROM python:3.9-slim-buster ARG TARGETARCH MAINTAINER JumpServer Team From d7121296f2369d3533d6ac7fd3d93667b746ac1f Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 15 Jun 2023 10:14:59 +0800 Subject: [PATCH 148/153] =?UTF-8?q?perf:=20=20=E4=BC=98=E5=8C=96=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=20bool?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index bd968c734..cfa1e829b 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -502,7 +502,7 @@ class JSONManyToManyDescriptor: value = [value.id] value = set(map(str, value)) rule_value = set(map(str, rule_value)) - res &= value & rule_value + res &= bool(value & rule_value) else: logging.error("unknown match: {}".format(rule['match'])) res &= False From 70af478f661864500d8e3995f53d3b8bc856e650 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 15 Jun 2023 10:16:18 +0800 Subject: [PATCH 149/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20rule=20vlaue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index cfa1e829b..4122aafb4 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -500,6 +500,8 @@ class JSONManyToManyDescriptor: value = value.values_list('id', flat=True) elif isinstance(value, models.Model): value = [value.id] + if isinstance(rule_value, (str, int)): + rule_value = [rule_value] value = set(map(str, value)) rule_value = set(map(str, rule_value)) res &= bool(value & rule_value) From 58edf021792783c197e93b8560e9d14c346baef2 Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 15 Jun 2023 10:27:52 +0800 Subject: [PATCH 150/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20json=20fie?= =?UTF-8?q?ld=20re=20=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/db/fields.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/common/db/fields.py b/apps/common/db/fields.py index 4122aafb4..5b7ee7c5f 100644 --- a/apps/common/db/fields.py +++ b/apps/common/db/fields.py @@ -378,9 +378,16 @@ class RelatedManager: if match == 'ip_in': q = cls.get_ip_in_q(name, val) - elif match in ("exact", "contains", "startswith", "endswith", "regex", "gte", "lte", "gt", "lt"): + elif match in ("exact", "contains", "startswith", "endswith", "gte", "lte", "gt", "lt"): lookup = "{}__{}".format(name, match) q = Q(**{lookup: val}) + elif match == 'regex': + try: + re.compile(val) + lookup = "{}__{}".format(name, match) + q = Q(**{lookup: val}) + except re.error: + q = ~Q() elif match == "not": q = ~Q(**{name: val}) elif match in ['m2m', 'in']: From e92c82568db38f0b3268e7d8ab45bf25f7906aec Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 15 Jun 2023 10:45:07 +0800 Subject: [PATCH 151/153] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=20acl=20?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/acls/migrations/0001_initial.py | 4 ++-- apps/acls/migrations/0002_auto_20210926_1047.py | 4 ++-- apps/acls/migrations/0003_auto_20211130_1037.py | 4 ++-- apps/acls/migrations/0006_commandfilteracl_commandgroup.py | 2 +- apps/acls/migrations/0008_commandgroup_comment.py | 6 +++--- apps/acls/migrations/0015_connectmethodacl.py | 2 +- apps/acls/migrations/0017_alter_connectmethodacl_options.py | 3 +-- apps/acls/models/base.py | 2 +- 8 files changed, 13 insertions(+), 14 deletions(-) diff --git a/apps/acls/migrations/0001_initial.py b/apps/acls/migrations/0001_initial.py index 378f33de3..3d314387b 100644 --- a/apps/acls/migrations/0001_initial.py +++ b/apps/acls/migrations/0001_initial.py @@ -38,7 +38,7 @@ class Migration(migrations.Migration): to=settings.AUTH_USER_MODEL, verbose_name='User')), ], options={ - 'ordering': ('priority', 'name'), + 'ordering': ('priority', '-is_active', 'name'), }, ), migrations.CreateModel( @@ -68,7 +68,7 @@ class Migration(migrations.Migration): verbose_name='Reviewers')), ], options={ - 'ordering': ('priority', 'name'), + 'ordering': ('priority', '-is_active', 'name'), 'unique_together': {('name', 'org_id')}, }, ), diff --git a/apps/acls/migrations/0002_auto_20210926_1047.py b/apps/acls/migrations/0002_auto_20210926_1047.py index a4af4bd69..f2019a613 100644 --- a/apps/acls/migrations/0002_auto_20210926_1047.py +++ b/apps/acls/migrations/0002_auto_20210926_1047.py @@ -89,10 +89,10 @@ class Migration(migrations.Migration): ), migrations.AlterModelOptions( name='loginacl', - options={'ordering': ('priority', 'name'), 'verbose_name': 'Login acl'}, + options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'}, ), migrations.AlterModelOptions( name='loginassetacl', - options={'ordering': ('priority', 'name'), 'verbose_name': 'Login asset acl'}, + options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'}, ), ] diff --git a/apps/acls/migrations/0003_auto_20211130_1037.py b/apps/acls/migrations/0003_auto_20211130_1037.py index cf32bca45..9a975c684 100644 --- a/apps/acls/migrations/0003_auto_20211130_1037.py +++ b/apps/acls/migrations/0003_auto_20211130_1037.py @@ -11,10 +11,10 @@ class Migration(migrations.Migration): operations = [ migrations.AlterModelOptions( name='loginacl', - options={'ordering': ('priority', 'name'), 'verbose_name': 'Login acl'}, + options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'}, ), migrations.AlterModelOptions( name='loginassetacl', - options={'ordering': ('priority', 'name'), 'verbose_name': 'Login asset acl'}, + options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'}, ), ] diff --git a/apps/acls/migrations/0006_commandfilteracl_commandgroup.py b/apps/acls/migrations/0006_commandfilteracl_commandgroup.py index 991efe556..3c1bd6793 100644 --- a/apps/acls/migrations/0006_commandfilteracl_commandgroup.py +++ b/apps/acls/migrations/0006_commandfilteracl_commandgroup.py @@ -63,7 +63,7 @@ class Migration(migrations.Migration): ], options={ 'verbose_name': 'Command acl', - 'ordering': ('priority', 'name'), + 'ordering': ('priority', '-is_active', 'name'), 'unique_together': {('name', 'org_id')}, }, ), diff --git a/apps/acls/migrations/0008_commandgroup_comment.py b/apps/acls/migrations/0008_commandgroup_comment.py index 82e44912c..0764daa22 100644 --- a/apps/acls/migrations/0008_commandgroup_comment.py +++ b/apps/acls/migrations/0008_commandgroup_comment.py @@ -20,14 +20,14 @@ class Migration(migrations.Migration): ), migrations.AlterModelOptions( name='commandfilteracl', - options={'ordering': ('priority', 'name'), 'verbose_name': 'Command acl'}, + options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Command acl'}, ), migrations.AlterModelOptions( name='loginacl', - options={'ordering': ('priority', 'name'), 'verbose_name': 'Login acl'}, + options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login acl'}, ), migrations.AlterModelOptions( name='loginassetacl', - options={'ordering': ('priority', 'name'), 'verbose_name': 'Login asset acl'}, + options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Login asset acl'}, ), ] diff --git a/apps/acls/migrations/0015_connectmethodacl.py b/apps/acls/migrations/0015_connectmethodacl.py index a786b87eb..5d5e3ff8c 100644 --- a/apps/acls/migrations/0015_connectmethodacl.py +++ b/apps/acls/migrations/0015_connectmethodacl.py @@ -39,7 +39,7 @@ class Migration(migrations.Migration): models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Reviewers')), ], options={ - 'ordering': ('priority', 'name'), + 'ordering': ('priority', '-is_active', 'name'), 'abstract': False, }, ), diff --git a/apps/acls/migrations/0017_alter_connectmethodacl_options.py b/apps/acls/migrations/0017_alter_connectmethodacl_options.py index 39132b450..6767771d6 100644 --- a/apps/acls/migrations/0017_alter_connectmethodacl_options.py +++ b/apps/acls/migrations/0017_alter_connectmethodacl_options.py @@ -4,7 +4,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ ('acls', '0016_auto_20230606_1857'), ] @@ -12,6 +11,6 @@ class Migration(migrations.Migration): operations = [ migrations.AlterModelOptions( name='connectmethodacl', - options={'ordering': ('priority', 'name'), 'verbose_name': 'Connect method acl'}, + options={'ordering': ('priority', '-is_active', 'name'), 'verbose_name': 'Connect method acl'}, ), ] diff --git a/apps/acls/models/base.py b/apps/acls/models/base.py index 6b7a5af37..cbc5c6e4e 100644 --- a/apps/acls/models/base.py +++ b/apps/acls/models/base.py @@ -51,7 +51,7 @@ class BaseACL(JMSBaseModel): objects = BaseACLQuerySet.as_manager() class Meta: - ordering = ('priority', 'name') + ordering = ('priority', '-is_active', 'name') abstract = True def is_action(self, action): From 852435c7d564cbb65099c9500727f18bf002ddd8 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Thu, 15 Jun 2023 12:15:04 +0800 Subject: [PATCH 152/153] =?UTF-8?q?perf:=20user=20=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E5=8C=96=E6=B7=BB=E5=8A=A0is=5Forg=5Fadmin=20=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=20(#10728)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: feng <1304903146@qq.com> --- apps/users/serializers/user.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index eb8d35cd9..099bddd1d 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- # -import phonenumbers from functools import partial @@ -132,7 +131,7 @@ class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, serializer "last_login", "date_updated" # 日期字段 ] fields_bool = [ - "is_superuser", + "is_superuser", "is_org_admin", "is_service_account", "is_valid", "is_expired", "is_active", # 布尔字段 "is_otp_secret_key_bound", "can_public_key_auth", From a48d0046a99968f0e6824c8559af76964b42810d Mon Sep 17 00:00:00 2001 From: ibuler Date: Thu, 15 Jun 2023 13:14:02 +0800 Subject: [PATCH 153/153] =?UTF-8?q?perf:=20=E8=87=AA=E5=AE=9A=E4=B9=89=20f?= =?UTF-8?q?ield=20=E6=94=AF=E6=8C=81=20required?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/common/serializers/dynamic.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/common/serializers/dynamic.py b/apps/common/serializers/dynamic.py index 2a8ffe0c0..cac9ae0dc 100644 --- a/apps/common/serializers/dynamic.py +++ b/apps/common/serializers/dynamic.py @@ -49,10 +49,15 @@ def create_serializer_class(serializer_name, fields_info): for i, field_info in enumerate(fields_info): data = {k: field_info.get(k) for k in fields_name} field_type = data.pop('type', 'str') + + if data.get('default') is None: + data.pop('default', None) + data['required'] = field_info.get('required', True) data = set_default_by_type(field_type, data, field_info) data = set_default_if_need(data, i) + if data.get('default', None) is not None: + data['required'] = False field_name = data.pop('name') field_class = type_field_map.get(field_type, serializers.CharField) serializer_fields[field_name] = field_class(**data) - return type(serializer_name, (serializers.Serializer,), serializer_fields)