mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-24 13:02:37 +00:00
Compare commits
13 Commits
v3.10.13
...
v3.10.14-l
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6686afcec1 | ||
|
|
0918f5c6f6 | ||
|
|
891e3d5609 | ||
|
|
9fad591545 | ||
|
|
1ed1c3a536 | ||
|
|
63824d3491 | ||
|
|
96eadf060c | ||
|
|
2c9128b0e7 | ||
|
|
7d6fd0f881 | ||
|
|
4e996afd5e | ||
|
|
1ed745d042 | ||
|
|
39ebbfcf10 | ||
|
|
d0ec4f798b |
@@ -28,7 +28,7 @@ from orgs.utils import current_org, tmp_to_root_org
|
||||
from rbac.permissions import RBACPermission
|
||||
from terminal.models import default_storage
|
||||
from users.models import User
|
||||
from .backends import TYPE_ENGINE_MAPPING
|
||||
from .backends import get_operate_log_storage
|
||||
from .const import ActivityChoices
|
||||
from .filters import UserSessionFilterSet, OperateLogFilterSet
|
||||
from .models import (
|
||||
@@ -146,7 +146,9 @@ class MyLoginLogViewSet(UserLoginCommonMixin, OrgReadonlyModelViewSet):
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
qs = qs.filter(username=self.request.user.username)
|
||||
username = self.request.user.username
|
||||
q = Q(username=username) | Q(username__icontains=f'({username})')
|
||||
qs = qs.filter(q)
|
||||
return qs
|
||||
|
||||
|
||||
@@ -222,13 +224,11 @@ class OperateLogViewSet(OrgReadonlyModelViewSet):
|
||||
if self.is_action_detail:
|
||||
with tmp_to_root_org():
|
||||
qs |= OperateLog.objects.filter(org_id=Organization.SYSTEM_ID)
|
||||
es_config = settings.OPERATE_LOG_ELASTICSEARCH_CONFIG
|
||||
if es_config:
|
||||
engine_mod = import_module(TYPE_ENGINE_MAPPING['es'])
|
||||
store = engine_mod.OperateLogStore(es_config)
|
||||
if store.ping(timeout=2):
|
||||
qs = ESQuerySet(store)
|
||||
qs.model = OperateLog
|
||||
|
||||
storage = get_operate_log_storage()
|
||||
if storage.get_type() == 'es':
|
||||
qs = ESQuerySet(storage)
|
||||
qs.model = OperateLog
|
||||
return qs
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,62 @@
|
||||
from importlib import import_module
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.utils import get_logger
|
||||
from .base import BaseOperateStorage
|
||||
from .es import OperateLogStore as ESOperateLogStore
|
||||
from .db import OperateLogStore as DBOperateLogStore
|
||||
|
||||
|
||||
TYPE_ENGINE_MAPPING = {
|
||||
'db': 'audits.backends.db',
|
||||
'es': 'audits.backends.es',
|
||||
logger = get_logger(__file__)
|
||||
|
||||
_global_op_log_storage: None | ESOperateLogStore | DBOperateLogStore = None
|
||||
op_log_type_mapping = {
|
||||
'server': DBOperateLogStore, 'es': ESOperateLogStore
|
||||
}
|
||||
|
||||
|
||||
def get_operate_log_storage(default=False):
|
||||
engine_mod = import_module(TYPE_ENGINE_MAPPING['db'])
|
||||
es_config = settings.OPERATE_LOG_ELASTICSEARCH_CONFIG
|
||||
if not default and es_config:
|
||||
engine_mod = import_module(TYPE_ENGINE_MAPPING['es'])
|
||||
storage = engine_mod.OperateLogStore(es_config)
|
||||
return storage
|
||||
def _send_es_unavailable_alarm_msg():
|
||||
from terminal.notifications import StorageConnectivityMessage
|
||||
from terminal.const import CommandStorageType
|
||||
|
||||
key = 'OPERATE_LOG_ES_UNAVAILABLE_KEY'
|
||||
if cache.get(key):
|
||||
return
|
||||
|
||||
cache.set(key, 1, 60)
|
||||
errors = [{
|
||||
'msg': _("Connect failed"), 'name': f"{_('Operate log')}",
|
||||
'type': CommandStorageType.es.label
|
||||
}]
|
||||
StorageConnectivityMessage(errors).publish_async()
|
||||
|
||||
|
||||
def refresh_log_storage():
|
||||
global _global_op_log_storage
|
||||
_global_op_log_storage = None
|
||||
|
||||
if settings.OPERATE_LOG_ELASTICSEARCH_CONFIG.get('HOSTS'):
|
||||
try:
|
||||
config = settings.OPERATE_LOG_ELASTICSEARCH_CONFIG
|
||||
log_storage = op_log_type_mapping['es'](config)
|
||||
_global_op_log_storage = log_storage
|
||||
except Exception as e:
|
||||
_send_es_unavailable_alarm_msg()
|
||||
logger.warning('Invalid logs storage type: es, error: %s' % str(e))
|
||||
|
||||
if not _global_op_log_storage:
|
||||
_global_op_log_storage = op_log_type_mapping['server']()
|
||||
|
||||
|
||||
def get_operate_log_storage():
|
||||
if _global_op_log_storage is None:
|
||||
refresh_log_storage()
|
||||
|
||||
log_storage = _global_op_log_storage
|
||||
if not log_storage.ping(timeout=3):
|
||||
if log_storage.get_type() == 'es':
|
||||
_send_es_unavailable_alarm_msg()
|
||||
logger.warning('Switch default operate log storage.')
|
||||
log_storage = op_log_type_mapping['server']()
|
||||
return log_storage
|
||||
|
||||
15
apps/audits/backends/base.py
Normal file
15
apps/audits/backends/base.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from perms.const import ActionChoices
|
||||
|
||||
|
||||
class BaseOperateStorage(object):
|
||||
@staticmethod
|
||||
def get_type():
|
||||
return 'base'
|
||||
|
||||
@staticmethod
|
||||
def _get_special_handler(resource_type):
|
||||
# 根据资源类型,处理特殊字段
|
||||
resource_map = {
|
||||
'Asset permission': lambda k, v: ActionChoices.display(int(v)) if k == 'Actions' else v
|
||||
}
|
||||
return resource_map.get(resource_type, lambda k, v: v)
|
||||
@@ -2,14 +2,14 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from audits.models import OperateLog
|
||||
from perms.const import ActionChoices
|
||||
from .base import BaseOperateStorage
|
||||
|
||||
|
||||
class OperateLogStore(object):
|
||||
class OperateLogStore(BaseOperateStorage):
|
||||
# 用不可见字符分割前后数据,节省存储-> diff: {'key': 'before\0after'}
|
||||
SEP = '\0'
|
||||
|
||||
def __init__(self, config):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.model = OperateLog
|
||||
self.max_length = 2048
|
||||
self.max_length_tip_msg = _(
|
||||
@@ -17,9 +17,13 @@ class OperateLogStore(object):
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def ping(timeout=None):
|
||||
def ping(*args, **kwargs):
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def get_type():
|
||||
return 'db'
|
||||
|
||||
@classmethod
|
||||
def convert_before_after_to_diff(cls, before, after):
|
||||
if not isinstance(before, dict):
|
||||
@@ -46,21 +50,13 @@ class OperateLogStore(object):
|
||||
before[k], after[k] = before_value, after_value
|
||||
return before, after
|
||||
|
||||
@staticmethod
|
||||
def _get_special_handler(resource_type):
|
||||
# 根据资源类型,处理特殊字段
|
||||
resource_map = {
|
||||
'Asset permission': lambda k, v: ActionChoices.display(int(v)) if k == 'Actions' else v
|
||||
}
|
||||
return resource_map.get(resource_type, lambda k, v: _(v))
|
||||
|
||||
@classmethod
|
||||
def convert_diff_friendly(cls, op_log):
|
||||
diff_list = list()
|
||||
handler = cls._get_special_handler(op_log.resource_type)
|
||||
# 标记翻译字符串
|
||||
labels = _("labels")
|
||||
operate_log_id = _("operate_log_id")
|
||||
handler = cls._get_special_handler(op_log.resource_type)
|
||||
for k, v in op_log.diff.items():
|
||||
before, after = v.split(cls.SEP, 1)
|
||||
diff_list.append({
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
#
|
||||
import uuid
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.utils.timezone import local_now_display
|
||||
from common.utils import get_logger
|
||||
from common.utils.encode import Singleton
|
||||
from common.plugins.es import ES
|
||||
|
||||
from .base import BaseOperateStorage
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
class OperateLogStore(ES, metaclass=Singleton):
|
||||
class OperateLogStore(BaseOperateStorage, ES):
|
||||
def __init__(self, config):
|
||||
properties = {
|
||||
"id": {
|
||||
@@ -48,7 +49,26 @@ class OperateLogStore(ES, metaclass=Singleton):
|
||||
self.pre_use_check()
|
||||
|
||||
@staticmethod
|
||||
def make_data(data):
|
||||
def get_type():
|
||||
return 'es'
|
||||
|
||||
@classmethod
|
||||
def convert_diff_friendly(cls, op_log):
|
||||
diff_list = []
|
||||
handler = cls._get_special_handler(op_log.get('resource_type'))
|
||||
before = op_log.get('before') or {}
|
||||
after = op_log.get('after') or {}
|
||||
keys = set(before.keys()) | set(after.keys())
|
||||
for key in keys:
|
||||
before_v, after_v = before.get(key), after.get(key)
|
||||
diff_list.append({
|
||||
'field': _(key),
|
||||
'before': handler(key, before_v) if before_v else _('empty'),
|
||||
'after': handler(key, after_v) if after_v else _('empty'),
|
||||
})
|
||||
return diff_list
|
||||
|
||||
def make_data(self, data):
|
||||
op_id = data.get('id', str(uuid.uuid4()))
|
||||
datetime_param = data.get('datetime', local_now_display())
|
||||
data = {
|
||||
|
||||
@@ -7,7 +7,6 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.local import encrypted_field_set
|
||||
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.models import Organization
|
||||
@@ -21,17 +20,9 @@ from .backends import get_operate_log_storage
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class OperatorLogHandler(metaclass=Singleton):
|
||||
class OperatorLogHandler(object):
|
||||
CACHE_KEY = 'OPERATOR_LOG_CACHE_KEY'
|
||||
|
||||
def __init__(self):
|
||||
self.log_client = self.get_storage_client()
|
||||
|
||||
@staticmethod
|
||||
def get_storage_client():
|
||||
client = get_operate_log_storage()
|
||||
return client
|
||||
|
||||
@staticmethod
|
||||
def _consistent_type_to_str(value1, value2):
|
||||
if isinstance(value1, datetime):
|
||||
@@ -164,13 +155,8 @@ class OperatorLogHandler(metaclass=Singleton):
|
||||
'remote_addr': remote_addr, 'before': before, 'after': after,
|
||||
}
|
||||
with transaction.atomic():
|
||||
if self.log_client.ping(timeout=1):
|
||||
client = self.log_client
|
||||
else:
|
||||
logger.info('Switch default operate log storage save.')
|
||||
client = get_operate_log_storage(default=True)
|
||||
|
||||
try:
|
||||
client = get_operate_log_storage()
|
||||
client.save(**data)
|
||||
except Exception as e:
|
||||
error_msg = 'An error occurred saving OperateLog.' \
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from audits.backends.db import OperateLogStore
|
||||
from audits.backends import get_operate_log_storage
|
||||
from common.serializers.fields import LabeledChoiceField, ObjectRelatedField
|
||||
from common.utils import reverse, i18n_trans
|
||||
from common.utils.timezone import as_current_tz
|
||||
@@ -77,7 +77,7 @@ class OperateLogActionDetailSerializer(serializers.ModelSerializer):
|
||||
fields = ('diff',)
|
||||
|
||||
def to_representation(self, instance):
|
||||
return {'diff': OperateLogStore.convert_diff_friendly(instance)}
|
||||
return {'diff': get_operate_log_storage().convert_diff_friendly(instance)}
|
||||
|
||||
|
||||
class OperateLogSerializer(BulkOrgResourceModelSerializer):
|
||||
|
||||
@@ -189,7 +189,7 @@ def on_django_start_set_operate_log_monitor_models(sender, **kwargs):
|
||||
'ApplyCommandTicket', 'ApplyLoginAssetTicket',
|
||||
'FavoriteAsset', 'ChangeSecretRecord'
|
||||
}
|
||||
include_models = {'UserSession'}
|
||||
include_models = set()
|
||||
for i, app in enumerate(apps.get_models(), 1):
|
||||
app_name = app._meta.app_label
|
||||
model_name = app._meta.object_name
|
||||
|
||||
@@ -2,6 +2,7 @@ import base64
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout as auth_logout
|
||||
from django.core.cache import cache
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import redirect, reverse, render
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
@@ -116,23 +117,43 @@ class ThirdPartyLoginMiddleware(mixins.AuthMixin):
|
||||
|
||||
|
||||
class SessionCookieMiddleware(MiddlewareMixin):
|
||||
USER_LOGIN_ENCRYPTION_KEY_PAIR = 'user_login_encryption_key_pair'
|
||||
|
||||
@staticmethod
|
||||
def set_cookie_public_key(request, response):
|
||||
def set_cookie_public_key(self, request, response):
|
||||
if request.path.startswith('/api'):
|
||||
return
|
||||
pub_key_name = settings.SESSION_RSA_PUBLIC_KEY_NAME
|
||||
public_key = request.session.get(pub_key_name)
|
||||
cookie_key = request.COOKIES.get(pub_key_name)
|
||||
if public_key and public_key == cookie_key:
|
||||
|
||||
session_public_key_name = settings.SESSION_RSA_PUBLIC_KEY_NAME
|
||||
session_private_key_name = settings.SESSION_RSA_PRIVATE_KEY_NAME
|
||||
|
||||
session_public_key = request.session.get(session_public_key_name)
|
||||
cookie_public_key = request.COOKIES.get(session_public_key_name)
|
||||
|
||||
if session_public_key and session_public_key == cookie_public_key:
|
||||
return
|
||||
|
||||
pri_key_name = settings.SESSION_RSA_PRIVATE_KEY_NAME
|
||||
private_key, public_key = gen_key_pair()
|
||||
private_key, public_key = self.get_key_pair()
|
||||
|
||||
public_key_decode = base64.b64encode(public_key.encode()).decode()
|
||||
request.session[pub_key_name] = public_key_decode
|
||||
request.session[pri_key_name] = private_key
|
||||
response.set_cookie(pub_key_name, public_key_decode)
|
||||
|
||||
request.session[session_public_key_name] = public_key_decode
|
||||
request.session[session_private_key_name] = private_key
|
||||
response.set_cookie(session_public_key_name, public_key_decode)
|
||||
|
||||
def get_key_pair(self):
|
||||
key_pair = cache.get(self.USER_LOGIN_ENCRYPTION_KEY_PAIR)
|
||||
if key_pair:
|
||||
return key_pair['private_key'], key_pair['public_key']
|
||||
|
||||
private_key, public_key = gen_key_pair()
|
||||
|
||||
key_pair = {
|
||||
'private_key': private_key,
|
||||
'public_key': public_key
|
||||
}
|
||||
cache.set(self.USER_LOGIN_ENCRYPTION_KEY_PAIR, key_pair, None)
|
||||
|
||||
return private_key, public_key
|
||||
|
||||
@staticmethod
|
||||
def set_cookie_session_prefix(request, response):
|
||||
|
||||
@@ -319,20 +319,26 @@ class AuthPostCheckMixin:
|
||||
|
||||
@classmethod
|
||||
def _check_passwd_is_too_simple(cls, user: User, password):
|
||||
if user.is_superuser and password == 'admin':
|
||||
if not user.is_auth_backend_model():
|
||||
return
|
||||
if user.check_passwd_too_simple(password):
|
||||
message = _('Your password is too simple, please change it for security')
|
||||
url = cls.generate_reset_password_url_with_flash_msg(user, message=message)
|
||||
raise errors.PasswordTooSimple(url)
|
||||
|
||||
@classmethod
|
||||
def _check_passwd_need_update(cls, user: User):
|
||||
if user.need_update_password:
|
||||
if not user.is_auth_backend_model():
|
||||
return
|
||||
if user.check_need_update_password():
|
||||
message = _('You should to change your password before login')
|
||||
url = cls.generate_reset_password_url_with_flash_msg(user, message)
|
||||
raise errors.PasswordNeedUpdate(url)
|
||||
|
||||
@classmethod
|
||||
def _check_password_require_reset_or_not(cls, user: User):
|
||||
if not user.is_auth_backend_model():
|
||||
return
|
||||
if user.password_has_expired:
|
||||
message = _('Your password has expired, please reset before logging in')
|
||||
url = cls.generate_reset_password_url_with_flash_msg(user, message)
|
||||
|
||||
@@ -8,10 +8,8 @@
|
||||
<p>
|
||||
<b>{% trans 'Username' %}:</b> {{ username }}<br>
|
||||
<b>{% trans 'Login time' %}:</b> {{ time }}<br>
|
||||
<b>{% trans 'Login city' %}:</b> {{ city }}({{ ip }})
|
||||
<b>{% trans 'Login city' %}:</b> {{ city }}({{ ip }})<br>
|
||||
</p>
|
||||
|
||||
-
|
||||
<p>
|
||||
{% trans 'If you suspect that the login behavior is abnormal, please modify the account password in time.' %}
|
||||
</p>
|
||||
@@ -10,8 +10,7 @@
|
||||
{% trans 'Click here reset password' %}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
-
|
||||
<br>
|
||||
<p>
|
||||
{% trans 'This link is valid for 1 hour. After it expires' %}
|
||||
<a href="{{ forget_password_url }}?email={{ user.email }}">{% trans 'request new one' %}</a>
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
{% trans 'Your password has just been successfully updated' %}
|
||||
</p>
|
||||
<p>
|
||||
<b>{% trans 'IP' %}:</b> {{ ip_address }} <br />
|
||||
<b>{% trans 'Browser' %}:</b> {{ browser }}
|
||||
<b>{% trans 'IP' %}:</b> {{ ip_address }} <br/>
|
||||
<b>{% trans 'Browser' %}:</b> {{ browser }} <br>
|
||||
</p>
|
||||
-
|
||||
<p>
|
||||
{% trans 'If the password update was not initiated by you, your account may have security issues' %} <br />
|
||||
{% trans 'If the password update was not initiated by you, your account may have security issues' %} <br/>
|
||||
{% trans 'If you have any questions, you can contact the administrator' %}
|
||||
</p>
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
{% trans 'Your public key has just been successfully updated' %}
|
||||
</p>
|
||||
<p>
|
||||
<b>{% trans 'IP' %}:</b> {{ ip_address }} <br />
|
||||
<b>{% trans 'Browser' %}:</b> {{ browser }}
|
||||
<b>{% trans 'IP' %}:</b> {{ ip_address }} <br>
|
||||
<b>{% trans 'Browser' %}:</b> {{ browser }}<br>
|
||||
</p>
|
||||
-
|
||||
<p>
|
||||
{% trans 'If the public key update was not initiated by you, your account may have security issues' %} <br />
|
||||
{% trans 'If the public key update was not initiated by you, your account may have security issues' %} <br/>
|
||||
{% trans 'If you have any questions, you can contact the administrator' %}
|
||||
</p>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .utils import gen_key_pair, rsa_decrypt, rsa_encrypt
|
||||
from common.utils import gen_key_pair, rsa_decrypt, rsa_encrypt
|
||||
|
||||
|
||||
def test_rsa_encrypt_decrypt(message='test-password-$%^&*'):
|
||||
|
||||
@@ -600,7 +600,6 @@ class Config(dict):
|
||||
|
||||
# API 分页
|
||||
'MAX_LIMIT_PER_PAGE': 10000,
|
||||
'DEFAULT_PAGE_SIZE': None,
|
||||
|
||||
'LIMIT_SUPER_PRIV': False,
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ SESSION_RSA_PUBLIC_KEY_NAME = 'jms_public_key'
|
||||
OPERATE_LOG_ELASTICSEARCH_CONFIG = CONFIG.OPERATE_LOG_ELASTICSEARCH_CONFIG
|
||||
|
||||
MAX_LIMIT_PER_PAGE = CONFIG.MAX_LIMIT_PER_PAGE
|
||||
DEFAULT_PAGE_SIZE = CONFIG.DEFAULT_PAGE_SIZE
|
||||
DEFAULT_PAGE_SIZE = CONFIG.MAX_LIMIT_PER_PAGE
|
||||
PERM_TREE_REGEN_INTERVAL = CONFIG.PERM_TREE_REGEN_INTERVAL
|
||||
|
||||
# Magnus DB Port
|
||||
|
||||
@@ -8610,7 +8610,7 @@ msgstr ""
|
||||
|
||||
#: xpack/plugins/cloud/models.py:100
|
||||
#: xpack/plugins/cloud/serializers/task.py:167
|
||||
msgid "Sync IP type"
|
||||
msgid "Preferred IP type"
|
||||
msgstr ""
|
||||
|
||||
#: xpack/plugins/cloud/models.py:103
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:607f8df8c6cea454283e0bc371db3be0c81f7cfa981a5f00c20b5be139e16aac
|
||||
size 178618
|
||||
oid sha256:2dd9ffcfe15b130a5b3d7b4fcfe806eaae979973e8bd29ad9a473b9215424c57
|
||||
size 178725
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-08-20 14:54+0800\n"
|
||||
"POT-Creation-Date: 2024-10-22 17:33+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -798,8 +798,8 @@ msgstr "カテゴリ"
|
||||
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:40
|
||||
#: terminal/models/component/storage.py:57
|
||||
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
|
||||
#: terminal/serializers/session.py:23 terminal/serializers/storage.py:271
|
||||
#: terminal/serializers/storage.py:283 tickets/models/comment.py:26
|
||||
#: terminal/serializers/session.py:23 terminal/serializers/storage.py:274
|
||||
#: terminal/serializers/storage.py:286 tickets/models/comment.py:26
|
||||
#: tickets/models/flow.py:56 tickets/models/ticket/apply_application.py:16
|
||||
#: tickets/models/ticket/general.py:276 tickets/serializers/flow.py:53
|
||||
#: tickets/serializers/ticket/ticket.py:19
|
||||
@@ -1425,12 +1425,13 @@ msgid "Unable to connect to port {port} on {address}"
|
||||
msgstr "{port} のポート {address} に接続できません"
|
||||
|
||||
#: assets/automations/ping_gateway/manager.py:58
|
||||
#: authentication/middleware.py:93 xpack/plugins/cloud/providers/fc.py:47
|
||||
#: authentication/middleware.py:94 xpack/plugins/cloud/providers/fc.py:47
|
||||
msgid "Authentication failed"
|
||||
msgstr "認証に失敗しました"
|
||||
|
||||
#: assets/automations/ping_gateway/manager.py:60
|
||||
#: assets/automations/ping_gateway/manager.py:86 terminal/const.py:102
|
||||
#: assets/automations/ping_gateway/manager.py:86 audits/backends/__init__.py:29
|
||||
#: terminal/const.py:102
|
||||
msgid "Connect failed"
|
||||
msgstr "接続に失敗しました"
|
||||
|
||||
@@ -1978,7 +1979,8 @@ msgstr "ラベル"
|
||||
msgid "New node"
|
||||
msgstr "新しいノード"
|
||||
|
||||
#: assets/models/node.py:467 audits/backends/db.py:68 audits/backends/db.py:69
|
||||
#: assets/models/node.py:467 audits/backends/db.py:64 audits/backends/db.py:65
|
||||
#: audits/backends/es.py:66 audits/backends/es.py:67
|
||||
msgid "empty"
|
||||
msgstr "空"
|
||||
|
||||
@@ -2407,15 +2409,15 @@ msgstr "監査"
|
||||
msgid "The text content is too long. Use Elasticsearch to store operation logs"
|
||||
msgstr "文章の内容が長すぎる。Elasticsearchで操作履歴を保存する"
|
||||
|
||||
#: audits/backends/db.py:61
|
||||
#: audits/backends/db.py:58
|
||||
msgid "labels"
|
||||
msgstr "ラベル"
|
||||
msgstr "タグ"
|
||||
|
||||
#: audits/backends/db.py:62
|
||||
#: audits/backends/db.py:59
|
||||
msgid "operate_log_id"
|
||||
msgstr "操作ログID"
|
||||
|
||||
#: audits/backends/db.py:94
|
||||
#: audits/backends/db.py:90
|
||||
msgid "Tips"
|
||||
msgstr "謎々"
|
||||
|
||||
@@ -2498,7 +2500,7 @@ msgstr "終了"
|
||||
#: audits/const.py:46 settings/serializers/terminal.py:6
|
||||
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:175
|
||||
#: terminal/models/virtualapp/provider.py:14 terminal/serializers/session.py:55
|
||||
#: terminal/serializers/session.py:69
|
||||
#: terminal/serializers/session.py:79
|
||||
msgid "Terminal"
|
||||
msgstr "ターミナル"
|
||||
|
||||
@@ -2523,11 +2525,11 @@ msgstr "タスク"
|
||||
msgid "-"
|
||||
msgstr "-"
|
||||
|
||||
#: audits/handler.py:116
|
||||
#: audits/handler.py:107
|
||||
msgid "Yes"
|
||||
msgstr "是"
|
||||
|
||||
#: audits/handler.py:116
|
||||
#: audits/handler.py:107
|
||||
msgid "No"
|
||||
msgstr "否"
|
||||
|
||||
@@ -3140,7 +3142,7 @@ msgstr "電話番号を設定して有効にする"
|
||||
msgid "Clear phone number to disable"
|
||||
msgstr "無効にする電話番号をクリアする"
|
||||
|
||||
#: authentication/middleware.py:94 settings/utils/ldap.py:679
|
||||
#: authentication/middleware.py:95 settings/utils/ldap.py:679
|
||||
msgid "Authentication failed (before login check failed): {}"
|
||||
msgstr "認証に失敗しました (ログインチェックが失敗する前): {}"
|
||||
|
||||
@@ -3421,7 +3423,7 @@ msgstr "アカウントにリモートログイン動作があります。注意
|
||||
msgid "Login time"
|
||||
msgstr "ログイン時間"
|
||||
|
||||
#: authentication/templates/authentication/_msg_different_city.html:16
|
||||
#: authentication/templates/authentication/_msg_different_city.html:14
|
||||
msgid ""
|
||||
"If you suspect that the login behavior is abnormal, please modify the "
|
||||
"account password in time."
|
||||
@@ -3449,13 +3451,13 @@ msgstr ""
|
||||
msgid "Click here reset password"
|
||||
msgstr "ここをクリックしてパスワードをリセット"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:16
|
||||
#: users/templates/users/_msg_user_created.html:22
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:15
|
||||
#: users/templates/users/_msg_user_created.html:20
|
||||
msgid "This link is valid for 1 hour. After it expires"
|
||||
msgstr "このリンクは1時間有効です。有効期限が切れた後"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:17
|
||||
#: users/templates/users/_msg_user_created.html:23
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:16
|
||||
#: users/templates/users/_msg_user_created.html:21
|
||||
msgid "request new one"
|
||||
msgstr "新しいものを要求する"
|
||||
|
||||
@@ -3484,7 +3486,7 @@ msgstr "パスワードが正常に更新されました"
|
||||
msgid "Browser"
|
||||
msgstr "ブラウザ"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:12
|
||||
msgid ""
|
||||
"If the password update was not initiated by you, your account may have "
|
||||
"security issues"
|
||||
@@ -3492,8 +3494,8 @@ msgstr ""
|
||||
"パスワードの更新が開始されなかった場合、アカウントにセキュリティ上の問題があ"
|
||||
"る可能性があります"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:14
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:14
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:13
|
||||
msgid "If you have any questions, you can contact the administrator"
|
||||
msgstr "質問があれば、管理者に連絡できます"
|
||||
|
||||
@@ -3501,7 +3503,7 @@ msgstr "質問があれば、管理者に連絡できます"
|
||||
msgid "Your public key has just been successfully updated"
|
||||
msgstr "公開鍵が正常に更新されました"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:12
|
||||
msgid ""
|
||||
"If the public key update was not initiated by you, your account may have "
|
||||
"security issues"
|
||||
@@ -3580,7 +3582,7 @@ msgid "LAN"
|
||||
msgstr "ローカルエリアネットワーク"
|
||||
|
||||
#: authentication/views/base.py:70
|
||||
#: perms/templates/perms/_msg_permed_items_expire.html:21
|
||||
#: perms/templates/perms/_msg_permed_items_expire.html:20
|
||||
msgid "If you have any question, please contact the administrator"
|
||||
msgstr "質問があったら、管理者に連絡して下さい"
|
||||
|
||||
@@ -4467,7 +4469,7 @@ msgstr "Material"
|
||||
msgid "Material Type"
|
||||
msgstr "Material を選択してオプションを設定します。"
|
||||
|
||||
#: ops/models/job.py:545
|
||||
#: ops/models/job.py:555
|
||||
msgid "Job Execution"
|
||||
msgstr "ジョブ実行"
|
||||
|
||||
@@ -6617,7 +6619,7 @@ msgstr "使用中のストレージを削除できません"
|
||||
msgid "Command storages"
|
||||
msgstr "コマンドストア"
|
||||
|
||||
#: terminal/api/component/storage.py:82
|
||||
#: terminal/api/component/storage.py:82 xpack/plugins/cloud/manager.py:83
|
||||
msgid "Invalid"
|
||||
msgstr "無効"
|
||||
|
||||
@@ -7011,7 +7013,7 @@ msgstr "ログイン元"
|
||||
msgid "Replay"
|
||||
msgstr "リプレイ"
|
||||
|
||||
#: terminal/models/session/session.py:48 terminal/serializers/session.py:68
|
||||
#: terminal/models/session/session.py:48 terminal/serializers/session.py:78
|
||||
msgid "Command amount"
|
||||
msgstr "コマンド量"
|
||||
|
||||
@@ -7396,7 +7398,8 @@ msgstr "アクセスキー"
|
||||
msgid "Access key secret"
|
||||
msgstr "アクセスキーシークレット"
|
||||
|
||||
#: terminal/serializers/storage.py:68 xpack/plugins/cloud/models.py:258
|
||||
#: terminal/serializers/storage.py:68 xpack/plugins/cloud/manager.py:83
|
||||
#: xpack/plugins/cloud/models.py:258
|
||||
msgid "Region"
|
||||
msgstr "リージョン"
|
||||
|
||||
@@ -7453,6 +7456,14 @@ msgstr "インデックス"
|
||||
msgid "Doc type"
|
||||
msgstr "Docタイプ"
|
||||
|
||||
#: terminal/serializers/storage.py:258
|
||||
msgid "Store locally"
|
||||
msgstr "ローカルに保存する"
|
||||
|
||||
#: terminal/serializers/storage.py:259
|
||||
msgid "Do not save"
|
||||
msgstr "保存しない"
|
||||
|
||||
#: terminal/serializers/task.py:9
|
||||
msgid "Session id"
|
||||
msgstr "セッション"
|
||||
@@ -8216,7 +8227,7 @@ msgid "User password history"
|
||||
msgstr "ユーザーパスワード履歴"
|
||||
|
||||
#: users/notifications.py:55
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:17
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:16
|
||||
#: users/templates/users/reset_password.html:5
|
||||
#: users/templates/users/reset_password.html:6
|
||||
msgid "Reset password"
|
||||
@@ -8477,7 +8488,7 @@ msgstr ""
|
||||
msgid "Click here update password"
|
||||
msgstr "ここをクリック更新パスワード"
|
||||
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:16
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:15
|
||||
msgid "If your password has expired, please click the link below to"
|
||||
msgstr ""
|
||||
"パスワードの有効期限が切れている場合は、以下のリンクをクリックしてください"
|
||||
@@ -8861,11 +8872,6 @@ msgstr "そして"
|
||||
msgid "Or"
|
||||
msgstr "または"
|
||||
|
||||
#: xpack/plugins/cloud/manager.py:55 xpack/plugins/cloud/providers/gcp.py:64
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:34
|
||||
msgid "Account unavailable"
|
||||
msgstr "利用できないアカウント"
|
||||
|
||||
#: xpack/plugins/cloud/meta.py:9
|
||||
msgid "Cloud center"
|
||||
msgstr "クラウドセンター"
|
||||
@@ -9161,6 +9167,11 @@ msgstr "華東-上海"
|
||||
msgid "AP-Singapore"
|
||||
msgstr "アジア太平洋-シンガポール"
|
||||
|
||||
#: xpack/plugins/cloud/providers/gcp.py:64
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:34
|
||||
msgid "Account unavailable"
|
||||
msgstr "利用できないアカウント"
|
||||
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:44
|
||||
msgid "CN North-Beijing1"
|
||||
msgstr "華北-北京1"
|
||||
@@ -9412,11 +9423,3 @@ msgstr "エンタープライズプロフェッショナル版"
|
||||
#: xpack/plugins/license/models.py:86
|
||||
msgid "Ultimate edition"
|
||||
msgstr "エンタープライズ・フラッグシップ・エディション"
|
||||
|
||||
#~ msgid "Account history"
|
||||
#~ msgstr "アカウント履歴"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "Operate log"
|
||||
#~ msgid "Operate log id"
|
||||
#~ msgstr "ログの操作"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fb60a2ebb525e5aaa2d2c64fb4956fcc56f1b608a6dfb186513e743e226af261
|
||||
size 146172
|
||||
oid sha256:4517c6a7464c68f949912b97c8a9abcc766ca19e32267a1d1da3f0e012471c1a
|
||||
size 146255
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-08-20 14:54+0800\n"
|
||||
"POT-Creation-Date: 2024-10-22 17:33+0800\n"
|
||||
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||
@@ -796,8 +796,8 @@ msgstr "类别"
|
||||
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:40
|
||||
#: terminal/models/component/storage.py:57
|
||||
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
|
||||
#: terminal/serializers/session.py:23 terminal/serializers/storage.py:271
|
||||
#: terminal/serializers/storage.py:283 tickets/models/comment.py:26
|
||||
#: terminal/serializers/session.py:23 terminal/serializers/storage.py:274
|
||||
#: terminal/serializers/storage.py:286 tickets/models/comment.py:26
|
||||
#: tickets/models/flow.py:56 tickets/models/ticket/apply_application.py:16
|
||||
#: tickets/models/ticket/general.py:276 tickets/serializers/flow.py:53
|
||||
#: tickets/serializers/ticket/ticket.py:19
|
||||
@@ -1415,12 +1415,13 @@ msgid "Unable to connect to port {port} on {address}"
|
||||
msgstr "无法连接到 {port} 上的端口 {address}"
|
||||
|
||||
#: assets/automations/ping_gateway/manager.py:58
|
||||
#: authentication/middleware.py:93 xpack/plugins/cloud/providers/fc.py:47
|
||||
#: authentication/middleware.py:94 xpack/plugins/cloud/providers/fc.py:47
|
||||
msgid "Authentication failed"
|
||||
msgstr "认证失败"
|
||||
|
||||
#: assets/automations/ping_gateway/manager.py:60
|
||||
#: assets/automations/ping_gateway/manager.py:86 terminal/const.py:102
|
||||
#: assets/automations/ping_gateway/manager.py:86 audits/backends/__init__.py:29
|
||||
#: terminal/const.py:102
|
||||
msgid "Connect failed"
|
||||
msgstr "连接失败"
|
||||
|
||||
@@ -1968,7 +1969,8 @@ msgstr "标签"
|
||||
msgid "New node"
|
||||
msgstr "新节点"
|
||||
|
||||
#: assets/models/node.py:467 audits/backends/db.py:68 audits/backends/db.py:69
|
||||
#: assets/models/node.py:467 audits/backends/db.py:64 audits/backends/db.py:65
|
||||
#: audits/backends/es.py:66 audits/backends/es.py:67
|
||||
msgid "empty"
|
||||
msgstr "空"
|
||||
|
||||
@@ -2388,15 +2390,15 @@ msgstr "日志审计"
|
||||
msgid "The text content is too long. Use Elasticsearch to store operation logs"
|
||||
msgstr "文字内容太长。请使用 Elasticsearch 存储操作日志"
|
||||
|
||||
#: audits/backends/db.py:61
|
||||
#: audits/backends/db.py:58
|
||||
msgid "labels"
|
||||
msgstr "标签"
|
||||
|
||||
#: audits/backends/db.py:62
|
||||
#: audits/backends/db.py:59
|
||||
msgid "operate_log_id"
|
||||
msgstr "操作日志ID"
|
||||
|
||||
#: audits/backends/db.py:94
|
||||
#: audits/backends/db.py:90
|
||||
msgid "Tips"
|
||||
msgstr "提示"
|
||||
|
||||
@@ -2479,7 +2481,7 @@ msgstr "结束"
|
||||
#: audits/const.py:46 settings/serializers/terminal.py:6
|
||||
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:175
|
||||
#: terminal/models/virtualapp/provider.py:14 terminal/serializers/session.py:55
|
||||
#: terminal/serializers/session.py:69
|
||||
#: terminal/serializers/session.py:79
|
||||
msgid "Terminal"
|
||||
msgstr "终端"
|
||||
|
||||
@@ -2504,11 +2506,11 @@ msgstr "任务"
|
||||
msgid "-"
|
||||
msgstr "-"
|
||||
|
||||
#: audits/handler.py:116
|
||||
#: audits/handler.py:107
|
||||
msgid "Yes"
|
||||
msgstr "是"
|
||||
|
||||
#: audits/handler.py:116
|
||||
#: audits/handler.py:107
|
||||
msgid "No"
|
||||
msgstr "否"
|
||||
|
||||
@@ -3108,7 +3110,7 @@ msgstr "设置手机号码启用"
|
||||
msgid "Clear phone number to disable"
|
||||
msgstr "清空手机号码禁用"
|
||||
|
||||
#: authentication/middleware.py:94 settings/utils/ldap.py:679
|
||||
#: authentication/middleware.py:95 settings/utils/ldap.py:679
|
||||
msgid "Authentication failed (before login check failed): {}"
|
||||
msgstr "认证失败 (登录前检查失败): {}"
|
||||
|
||||
@@ -3387,7 +3389,7 @@ msgstr "你的账号存在异地登录行为,请关注。"
|
||||
msgid "Login time"
|
||||
msgstr "登录日期"
|
||||
|
||||
#: authentication/templates/authentication/_msg_different_city.html:16
|
||||
#: authentication/templates/authentication/_msg_different_city.html:14
|
||||
msgid ""
|
||||
"If you suspect that the login behavior is abnormal, please modify the "
|
||||
"account password in time."
|
||||
@@ -3411,13 +3413,13 @@ msgstr "请点击下面链接重置密码, 如果不是您申请的,请关
|
||||
msgid "Click here reset password"
|
||||
msgstr "点击这里重置密码"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:16
|
||||
#: users/templates/users/_msg_user_created.html:22
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:15
|
||||
#: users/templates/users/_msg_user_created.html:20
|
||||
msgid "This link is valid for 1 hour. After it expires"
|
||||
msgstr "这个链接有效期1小时, 超过时间您可以"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:17
|
||||
#: users/templates/users/_msg_user_created.html:23
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:16
|
||||
#: users/templates/users/_msg_user_created.html:21
|
||||
msgid "request new one"
|
||||
msgstr "重新申请"
|
||||
|
||||
@@ -3446,14 +3448,14 @@ msgstr "你的密码刚刚成功更新"
|
||||
msgid "Browser"
|
||||
msgstr "浏览器"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:12
|
||||
msgid ""
|
||||
"If the password update was not initiated by you, your account may have "
|
||||
"security issues"
|
||||
msgstr "如果这次密码更新不是由你发起的,那么你的账号可能存在安全问题"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:14
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:14
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:13
|
||||
msgid "If you have any questions, you can contact the administrator"
|
||||
msgstr "如果有疑问或需求,请联系系统管理员"
|
||||
|
||||
@@ -3461,7 +3463,7 @@ msgstr "如果有疑问或需求,请联系系统管理员"
|
||||
msgid "Your public key has just been successfully updated"
|
||||
msgstr "你的公钥刚刚成功更新"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:12
|
||||
msgid ""
|
||||
"If the public key update was not initiated by you, your account may have "
|
||||
"security issues"
|
||||
@@ -3534,7 +3536,7 @@ msgid "LAN"
|
||||
msgstr "局域网"
|
||||
|
||||
#: authentication/views/base.py:70
|
||||
#: perms/templates/perms/_msg_permed_items_expire.html:21
|
||||
#: perms/templates/perms/_msg_permed_items_expire.html:20
|
||||
msgid "If you have any question, please contact the administrator"
|
||||
msgstr "如果有疑问或需求,请联系系统管理员"
|
||||
|
||||
@@ -4408,7 +4410,7 @@ msgstr "Material"
|
||||
msgid "Material Type"
|
||||
msgstr "Material 类型"
|
||||
|
||||
#: ops/models/job.py:545
|
||||
#: ops/models/job.py:555
|
||||
msgid "Job Execution"
|
||||
msgstr "作业执行"
|
||||
|
||||
@@ -6514,7 +6516,7 @@ msgstr "不允许删除正在使用的存储配置"
|
||||
msgid "Command storages"
|
||||
msgstr "命令存储"
|
||||
|
||||
#: terminal/api/component/storage.py:82
|
||||
#: terminal/api/component/storage.py:82 xpack/plugins/cloud/manager.py:83
|
||||
msgid "Invalid"
|
||||
msgstr "无效"
|
||||
|
||||
@@ -6908,7 +6910,7 @@ msgstr "登录来源"
|
||||
msgid "Replay"
|
||||
msgstr "回放"
|
||||
|
||||
#: terminal/models/session/session.py:48 terminal/serializers/session.py:68
|
||||
#: terminal/models/session/session.py:48 terminal/serializers/session.py:78
|
||||
msgid "Command amount"
|
||||
msgstr "命令数量"
|
||||
|
||||
@@ -7286,7 +7288,8 @@ msgstr "Access key ID(AK)"
|
||||
msgid "Access key secret"
|
||||
msgstr "Access key secret(SK)"
|
||||
|
||||
#: terminal/serializers/storage.py:68 xpack/plugins/cloud/models.py:258
|
||||
#: terminal/serializers/storage.py:68 xpack/plugins/cloud/manager.py:83
|
||||
#: xpack/plugins/cloud/models.py:258
|
||||
msgid "Region"
|
||||
msgstr "地域"
|
||||
|
||||
@@ -7343,6 +7346,14 @@ msgstr "索引"
|
||||
msgid "Doc type"
|
||||
msgstr "文档类型"
|
||||
|
||||
#: terminal/serializers/storage.py:258
|
||||
msgid "Store locally"
|
||||
msgstr "本地存储"
|
||||
|
||||
#: terminal/serializers/storage.py:259
|
||||
msgid "Do not save"
|
||||
msgstr "不保存"
|
||||
|
||||
#: terminal/serializers/task.py:9
|
||||
msgid "Session id"
|
||||
msgstr "会话 ID"
|
||||
@@ -8100,7 +8111,7 @@ msgid "User password history"
|
||||
msgstr "用户密码历史"
|
||||
|
||||
#: users/notifications.py:55
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:17
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:16
|
||||
#: users/templates/users/reset_password.html:5
|
||||
#: users/templates/users/reset_password.html:6
|
||||
msgid "Reset password"
|
||||
@@ -8355,7 +8366,7 @@ msgstr "为了您的账号安全,请点击下面的链接及时更新密码"
|
||||
msgid "Click here update password"
|
||||
msgstr "点击这里更新密码"
|
||||
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:16
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:15
|
||||
msgid "If your password has expired, please click the link below to"
|
||||
msgstr "如果你的密码已过期,请点击"
|
||||
|
||||
@@ -8728,11 +8739,6 @@ msgstr "与"
|
||||
msgid "Or"
|
||||
msgstr "或"
|
||||
|
||||
#: xpack/plugins/cloud/manager.py:55 xpack/plugins/cloud/providers/gcp.py:64
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:34
|
||||
msgid "Account unavailable"
|
||||
msgstr "账号无效"
|
||||
|
||||
#: xpack/plugins/cloud/meta.py:9
|
||||
msgid "Cloud center"
|
||||
msgstr "云管中心"
|
||||
@@ -8768,7 +8774,7 @@ msgstr "IP网段组"
|
||||
#: xpack/plugins/cloud/models.py:100
|
||||
#: xpack/plugins/cloud/serializers/task.py:167
|
||||
msgid "Sync IP type"
|
||||
msgstr "同步IP类型"
|
||||
msgstr "同步 IP 类型"
|
||||
|
||||
#: xpack/plugins/cloud/models.py:103
|
||||
#: xpack/plugins/cloud/serializers/task.py:185
|
||||
@@ -9028,6 +9034,11 @@ msgstr "华东-上海"
|
||||
msgid "AP-Singapore"
|
||||
msgstr "亚太-新加坡"
|
||||
|
||||
#: xpack/plugins/cloud/providers/gcp.py:64
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:34
|
||||
msgid "Account unavailable"
|
||||
msgstr "账号无效"
|
||||
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:44
|
||||
msgid "CN North-Beijing1"
|
||||
msgstr "华北-北京1"
|
||||
@@ -9276,6 +9287,3 @@ msgstr "企业专业版"
|
||||
#: xpack/plugins/license/models.py:86
|
||||
msgid "Ultimate edition"
|
||||
msgstr "企业旗舰版"
|
||||
|
||||
#~ msgid "Account history"
|
||||
#~ msgstr "账号历史"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4aaedb4c31b1d11ddf63e5d0a27958ee5d42e78e2ce255746b8134d18ffc990f
|
||||
size 146283
|
||||
oid sha256:7d4d2709e597e055072474f08be2f363d43df239240051024a77213ba48ecfac
|
||||
size 146366
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-08-20 14:54+0800\n"
|
||||
"POT-Creation-Date: 2024-10-22 17:33+0800\n"
|
||||
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||
@@ -798,8 +798,8 @@ msgstr "類別"
|
||||
#: perms/serializers/user_permission.py:27 terminal/models/applet/applet.py:40
|
||||
#: terminal/models/component/storage.py:57
|
||||
#: terminal/models/component/storage.py:146 terminal/serializers/applet.py:29
|
||||
#: terminal/serializers/session.py:23 terminal/serializers/storage.py:271
|
||||
#: terminal/serializers/storage.py:283 tickets/models/comment.py:26
|
||||
#: terminal/serializers/session.py:23 terminal/serializers/storage.py:274
|
||||
#: terminal/serializers/storage.py:286 tickets/models/comment.py:26
|
||||
#: tickets/models/flow.py:56 tickets/models/ticket/apply_application.py:16
|
||||
#: tickets/models/ticket/general.py:276 tickets/serializers/flow.py:53
|
||||
#: tickets/serializers/ticket/ticket.py:19
|
||||
@@ -1417,12 +1417,13 @@ msgid "Unable to connect to port {port} on {address}"
|
||||
msgstr "無法連接到 {port} 上的埠 {address}"
|
||||
|
||||
#: assets/automations/ping_gateway/manager.py:58
|
||||
#: authentication/middleware.py:93 xpack/plugins/cloud/providers/fc.py:47
|
||||
#: authentication/middleware.py:94 xpack/plugins/cloud/providers/fc.py:47
|
||||
msgid "Authentication failed"
|
||||
msgstr "認證失敗"
|
||||
|
||||
#: assets/automations/ping_gateway/manager.py:60
|
||||
#: assets/automations/ping_gateway/manager.py:86 terminal/const.py:102
|
||||
#: assets/automations/ping_gateway/manager.py:86 audits/backends/__init__.py:29
|
||||
#: terminal/const.py:102
|
||||
msgid "Connect failed"
|
||||
msgstr "連接失敗"
|
||||
|
||||
@@ -1970,7 +1971,8 @@ msgstr "標籤"
|
||||
msgid "New node"
|
||||
msgstr "新節點"
|
||||
|
||||
#: assets/models/node.py:467 audits/backends/db.py:68 audits/backends/db.py:69
|
||||
#: assets/models/node.py:467 audits/backends/db.py:64 audits/backends/db.py:65
|
||||
#: audits/backends/es.py:66 audits/backends/es.py:67
|
||||
msgid "empty"
|
||||
msgstr "空"
|
||||
|
||||
@@ -2390,15 +2392,15 @@ msgstr "日誌審計"
|
||||
msgid "The text content is too long. Use Elasticsearch to store operation logs"
|
||||
msgstr "文字內容太長。請使用 Elasticsearch 儲存操作日誌"
|
||||
|
||||
#: audits/backends/db.py:61
|
||||
#: audits/backends/db.py:58
|
||||
msgid "labels"
|
||||
msgstr "標籤"
|
||||
|
||||
#: audits/backends/db.py:62
|
||||
#: audits/backends/db.py:59
|
||||
msgid "operate_log_id"
|
||||
msgstr "操作日誌ID"
|
||||
|
||||
#: audits/backends/db.py:94
|
||||
#: audits/backends/db.py:90
|
||||
msgid "Tips"
|
||||
msgstr "提示"
|
||||
|
||||
@@ -2481,7 +2483,7 @@ msgstr "結束"
|
||||
#: audits/const.py:46 settings/serializers/terminal.py:6
|
||||
#: terminal/models/applet/host.py:26 terminal/models/component/terminal.py:175
|
||||
#: terminal/models/virtualapp/provider.py:14 terminal/serializers/session.py:55
|
||||
#: terminal/serializers/session.py:69
|
||||
#: terminal/serializers/session.py:79
|
||||
msgid "Terminal"
|
||||
msgstr "終端"
|
||||
|
||||
@@ -2506,11 +2508,11 @@ msgstr "任務"
|
||||
msgid "-"
|
||||
msgstr "-"
|
||||
|
||||
#: audits/handler.py:116
|
||||
#: audits/handler.py:107
|
||||
msgid "Yes"
|
||||
msgstr "是"
|
||||
|
||||
#: audits/handler.py:116
|
||||
#: audits/handler.py:107
|
||||
msgid "No"
|
||||
msgstr "否"
|
||||
|
||||
@@ -3110,7 +3112,7 @@ msgstr "設置手機號碼啟用"
|
||||
msgid "Clear phone number to disable"
|
||||
msgstr "清空手機號碼禁用"
|
||||
|
||||
#: authentication/middleware.py:94 settings/utils/ldap.py:679
|
||||
#: authentication/middleware.py:95 settings/utils/ldap.py:679
|
||||
msgid "Authentication failed (before login check failed): {}"
|
||||
msgstr "認證失敗 (登錄前檢查失敗): {}"
|
||||
|
||||
@@ -3389,7 +3391,7 @@ msgstr "你的帳號存在異地登入行為,請關注。"
|
||||
msgid "Login time"
|
||||
msgstr "登錄日期"
|
||||
|
||||
#: authentication/templates/authentication/_msg_different_city.html:16
|
||||
#: authentication/templates/authentication/_msg_different_city.html:14
|
||||
msgid ""
|
||||
"If you suspect that the login behavior is abnormal, please modify the "
|
||||
"account password in time."
|
||||
@@ -3413,13 +3415,13 @@ msgstr "請點擊下面連結重設密碼, 如果不是您申請的,請關
|
||||
msgid "Click here reset password"
|
||||
msgstr "點擊這裡重設密碼"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:16
|
||||
#: users/templates/users/_msg_user_created.html:22
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:15
|
||||
#: users/templates/users/_msg_user_created.html:20
|
||||
msgid "This link is valid for 1 hour. After it expires"
|
||||
msgstr "這個連結有效期1小時, 超過時間您可以"
|
||||
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:17
|
||||
#: users/templates/users/_msg_user_created.html:23
|
||||
#: authentication/templates/authentication/_msg_reset_password.html:16
|
||||
#: users/templates/users/_msg_user_created.html:21
|
||||
msgid "request new one"
|
||||
msgstr "重新申請"
|
||||
|
||||
@@ -3448,14 +3450,14 @@ msgstr "你的密碼剛剛成功更新"
|
||||
msgid "Browser"
|
||||
msgstr "瀏覽器"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:12
|
||||
msgid ""
|
||||
"If the password update was not initiated by you, your account may have "
|
||||
"security issues"
|
||||
msgstr "如果這次密碼更新不是由你發起的,那麼你的帳號可能存在安全問題"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:14
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:14
|
||||
#: authentication/templates/authentication/_msg_rest_password_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:13
|
||||
msgid "If you have any questions, you can contact the administrator"
|
||||
msgstr "如果有疑問或需求,請聯絡系統管理員"
|
||||
|
||||
@@ -3463,7 +3465,7 @@ msgstr "如果有疑問或需求,請聯絡系統管理員"
|
||||
msgid "Your public key has just been successfully updated"
|
||||
msgstr "你的公鑰剛剛成功更新"
|
||||
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:13
|
||||
#: authentication/templates/authentication/_msg_rest_public_key_success.html:12
|
||||
msgid ""
|
||||
"If the public key update was not initiated by you, your account may have "
|
||||
"security issues"
|
||||
@@ -3536,7 +3538,7 @@ msgid "LAN"
|
||||
msgstr "區域網路"
|
||||
|
||||
#: authentication/views/base.py:70
|
||||
#: perms/templates/perms/_msg_permed_items_expire.html:21
|
||||
#: perms/templates/perms/_msg_permed_items_expire.html:20
|
||||
msgid "If you have any question, please contact the administrator"
|
||||
msgstr "如果有疑問或需求,請聯絡系統管理員"
|
||||
|
||||
@@ -4409,7 +4411,7 @@ msgstr "Material"
|
||||
msgid "Material Type"
|
||||
msgstr "Material 類型"
|
||||
|
||||
#: ops/models/job.py:545
|
||||
#: ops/models/job.py:555
|
||||
msgid "Job Execution"
|
||||
msgstr "作業執行"
|
||||
|
||||
@@ -6515,7 +6517,7 @@ msgstr "不允許刪除正在使用的儲存配置"
|
||||
msgid "Command storages"
|
||||
msgstr "命令儲存"
|
||||
|
||||
#: terminal/api/component/storage.py:82
|
||||
#: terminal/api/component/storage.py:82 xpack/plugins/cloud/manager.py:83
|
||||
msgid "Invalid"
|
||||
msgstr "無效"
|
||||
|
||||
@@ -6909,7 +6911,7 @@ msgstr "登錄來源"
|
||||
msgid "Replay"
|
||||
msgstr "重播"
|
||||
|
||||
#: terminal/models/session/session.py:48 terminal/serializers/session.py:68
|
||||
#: terminal/models/session/session.py:48 terminal/serializers/session.py:78
|
||||
msgid "Command amount"
|
||||
msgstr "命令數量"
|
||||
|
||||
@@ -7287,7 +7289,8 @@ msgstr "Access key ID(AK)"
|
||||
msgid "Access key secret"
|
||||
msgstr "Access key secret(SK)"
|
||||
|
||||
#: terminal/serializers/storage.py:68 xpack/plugins/cloud/models.py:258
|
||||
#: terminal/serializers/storage.py:68 xpack/plugins/cloud/manager.py:83
|
||||
#: xpack/plugins/cloud/models.py:258
|
||||
msgid "Region"
|
||||
msgstr "地域"
|
||||
|
||||
@@ -7344,6 +7347,14 @@ msgstr "索引"
|
||||
msgid "Doc type"
|
||||
msgstr "文件類型"
|
||||
|
||||
#: terminal/serializers/storage.py:258
|
||||
msgid "Store locally"
|
||||
msgstr "本地儲存"
|
||||
|
||||
#: terminal/serializers/storage.py:259
|
||||
msgid "Do not save"
|
||||
msgstr "不儲存"
|
||||
|
||||
#: terminal/serializers/task.py:9
|
||||
msgid "Session id"
|
||||
msgstr "會話 ID"
|
||||
@@ -8101,7 +8112,7 @@ msgid "User password history"
|
||||
msgstr "用戶密碼歷史"
|
||||
|
||||
#: users/notifications.py:55
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:17
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:16
|
||||
#: users/templates/users/reset_password.html:5
|
||||
#: users/templates/users/reset_password.html:6
|
||||
msgid "Reset password"
|
||||
@@ -8356,7 +8367,7 @@ msgstr "為了您的帳號安全,請點擊下面的連結及時更新密碼"
|
||||
msgid "Click here update password"
|
||||
msgstr "點擊這裡更新密碼"
|
||||
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:16
|
||||
#: users/templates/users/_msg_password_expire_reminder.html:15
|
||||
msgid "If your password has expired, please click the link below to"
|
||||
msgstr "如果你的密碼已過期,請點擊"
|
||||
|
||||
@@ -8729,11 +8740,6 @@ msgstr "與"
|
||||
msgid "Or"
|
||||
msgstr "或"
|
||||
|
||||
#: xpack/plugins/cloud/manager.py:55 xpack/plugins/cloud/providers/gcp.py:64
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:34
|
||||
msgid "Account unavailable"
|
||||
msgstr "帳號無效"
|
||||
|
||||
#: xpack/plugins/cloud/meta.py:9
|
||||
msgid "Cloud center"
|
||||
msgstr "雲管中心"
|
||||
@@ -8769,7 +8775,7 @@ msgstr "IP網段組"
|
||||
#: xpack/plugins/cloud/models.py:100
|
||||
#: xpack/plugins/cloud/serializers/task.py:167
|
||||
msgid "Sync IP type"
|
||||
msgstr "同步IP類型"
|
||||
msgstr "同步 IP 類型"
|
||||
|
||||
#: xpack/plugins/cloud/models.py:103
|
||||
#: xpack/plugins/cloud/serializers/task.py:185
|
||||
@@ -9029,6 +9035,11 @@ msgstr "華東-上海"
|
||||
msgid "AP-Singapore"
|
||||
msgstr "亞太-新加坡"
|
||||
|
||||
#: xpack/plugins/cloud/providers/gcp.py:64
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:34
|
||||
msgid "Account unavailable"
|
||||
msgstr "帳號無效"
|
||||
|
||||
#: xpack/plugins/cloud/providers/huaweicloud.py:44
|
||||
msgid "CN North-Beijing1"
|
||||
msgstr "華北-北京1"
|
||||
@@ -9277,6 +9288,3 @@ msgstr "企業專業版"
|
||||
#: xpack/plugins/license/models.py:86
|
||||
msgid "Ultimate edition"
|
||||
msgstr "企業旗艦版"
|
||||
|
||||
#~ msgid "Account history"
|
||||
#~ msgstr "帳號歷史"
|
||||
|
||||
@@ -14,7 +14,8 @@ class SiteMessageUtil:
|
||||
def send_msg(cls, subject, message, user_ids=(), group_ids=(),
|
||||
sender=None, is_broadcast=False):
|
||||
if not any((user_ids, group_ids, is_broadcast)):
|
||||
raise ValueError('No recipient is specified')
|
||||
logger.warning(f'No recipient is specified, message subject: {subject}')
|
||||
return
|
||||
|
||||
with transaction.atomic():
|
||||
site_msg = SiteMessageModel.objects.create(
|
||||
|
||||
@@ -39,9 +39,10 @@ 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 settings.SECURITY_COMMAND_BLACKLIST:
|
||||
command = self.module_args
|
||||
if command and set(command.split()).intersection(set(settings.SECURITY_COMMAND_BLACKLIST)):
|
||||
raise CommandInBlackListException(
|
||||
"Command is rejected by black list: {}".format(self.module_args.split()[0]))
|
||||
"Command is rejected by black list: {}".format(self.module_args))
|
||||
|
||||
def set_local_connection(self):
|
||||
if self.job_module in self.need_local_connection_modules_choices:
|
||||
|
||||
@@ -478,6 +478,16 @@ class JobExecution(JMSOrgBaseModel):
|
||||
for acl in acls:
|
||||
if self.match_command_group(acl, asset):
|
||||
break
|
||||
command = self.current_job.args
|
||||
if command and set(command.split()).intersection(set(settings.SECURITY_COMMAND_BLACKLIST)):
|
||||
CommandExecutionAlert({
|
||||
"assets": self.current_job.assets.all(),
|
||||
"input": self.material,
|
||||
"risk_level": RiskLevelChoices.reject,
|
||||
"user": self.creator,
|
||||
}).publish_async()
|
||||
raise CommandInBlackListException(
|
||||
"Command is rejected by black list: {}".format(self.current_job.args))
|
||||
|
||||
def check_danger_keywords(self):
|
||||
lines = self.job.playbook.check_dangerous_keywords()
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<br/>
|
||||
-
|
||||
<br>
|
||||
<p>
|
||||
{% trans 'If you have any question, please contact the administrator' %}
|
||||
</p>
|
||||
|
||||
@@ -58,6 +58,16 @@ class SessionSerializer(BulkOrgResourceModelSerializer):
|
||||
'terminal_display': {'label': _('Terminal display')},
|
||||
}
|
||||
|
||||
def get_fields(self):
|
||||
fields = super().get_fields()
|
||||
self.pop_fields_if_need(fields)
|
||||
return fields
|
||||
|
||||
def pop_fields_if_need(self, fields):
|
||||
request = self.context.get('request')
|
||||
if request and request.method != 'GET':
|
||||
fields.pop("command_amount", None)
|
||||
|
||||
def validate_asset(self, value):
|
||||
max_length = self.Meta.model.asset.field.max_length
|
||||
value = pretty_string(value, max_length=max_length)
|
||||
|
||||
@@ -220,7 +220,6 @@ command_storage_type_serializer_classes_mapping = {
|
||||
class BaseStorageSerializer(serializers.ModelSerializer):
|
||||
storage_type_serializer_classes_mapping = {}
|
||||
meta = MethodSerializer()
|
||||
comment = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = None
|
||||
@@ -253,11 +252,15 @@ class BaseStorageSerializer(serializers.ModelSerializer):
|
||||
serializer = serializer_class
|
||||
return serializer
|
||||
|
||||
@staticmethod
|
||||
def get_comment(obj):
|
||||
need_translate_comments = ['Store locally', 'Do not save']
|
||||
comment = obj.comment
|
||||
return _(comment) if comment in need_translate_comments else comment
|
||||
def to_representation(self, instance):
|
||||
data = super().to_representation(instance)
|
||||
need_translate_comments = {
|
||||
'Store locally': _('Store locally'),
|
||||
'Do not save': _('Do not save')
|
||||
}
|
||||
comment = instance.comment
|
||||
data['comment'] = need_translate_comments.get(comment, comment)
|
||||
return data
|
||||
|
||||
def save(self, **kwargs):
|
||||
instance = super().save(**kwargs)
|
||||
|
||||
@@ -69,7 +69,7 @@ class AuthMixin:
|
||||
if self.username:
|
||||
self.date_password_last_updated = timezone.now()
|
||||
post_user_change_password.send(self.__class__, user=self)
|
||||
super().set_password(raw_password) # noqa
|
||||
super().set_password(raw_password) # noqa
|
||||
|
||||
def set_public_key(self, public_key):
|
||||
if self.can_update_ssh_key():
|
||||
@@ -160,6 +160,22 @@ class AuthMixin:
|
||||
return True
|
||||
return False
|
||||
|
||||
def check_need_update_password(self):
|
||||
if self.is_local and self.need_update_password:
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def check_passwd_too_simple(password):
|
||||
simple_passwords = ['admin', 'ChangeMe']
|
||||
if password in simple_passwords:
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_auth_backend_model(self):
|
||||
backend = getattr(self, 'backend', None)
|
||||
return backend == settings.AUTH_BACKEND_MODEL
|
||||
|
||||
@staticmethod
|
||||
def get_public_key_md5(key):
|
||||
try:
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
<br />
|
||||
<br />
|
||||
<a href="{{ update_password_url }}">{% trans 'Click here update password' %}</a>
|
||||
<br />
|
||||
<br/>
|
||||
</p>
|
||||
-
|
||||
<p>
|
||||
{% trans 'If your password has expired, please click the link below to' %}
|
||||
<a href="{{ forget_password_url }}?email={{ email }}">{% trans 'Reset password' %}</a>
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
{% trans 'click here to set your password' %}
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
-
|
||||
<br>
|
||||
<p>
|
||||
{% trans 'This link is valid for 1 hour. After it expires' %}
|
||||
<a href="{{ forget_password_url }}?email={{ user.email }}">{% trans 'request new one' %}</a>
|
||||
|
||||
@@ -227,7 +227,7 @@ class MFABlockUtils(BlockUtilBase):
|
||||
|
||||
class LoginIpBlockUtil(BlockGlobalIpUtilBase):
|
||||
LIMIT_KEY_TMPL = "_LOGIN_LIMIT_{}"
|
||||
BLOCK_KEY_TMPL = "_LOGIN_BLOCK_{}"
|
||||
BLOCK_KEY_TMPL = "_LOGIN_BLOCK_IP_{}"
|
||||
|
||||
|
||||
def validate_emails(emails):
|
||||
|
||||
Reference in New Issue
Block a user