diff --git a/Dockerfile-ee b/Dockerfile-ee
index c59ab222d..1809e321a 100644
--- a/Dockerfile-ee
+++ b/Dockerfile-ee
@@ -21,6 +21,17 @@ WORKDIR /opt/jumpserver
ARG PIP_MIRROR=https://pypi.org/simple
+ARG GMSSL_VERSION=3.1.1
+
RUN set -ex \
&& uv pip install -i${PIP_MIRROR} --group xpack \
- && rm -rf /root/.cache/
\ No newline at end of file
+ && rm -rf /root/.cache/
+
+RUN set -ex \
+ && wget -q -O /tmp/gmssl-install.sh \
+ "https://github.com/guanzhi/GmSSL/releases/download/v${GMSSL_VERSION}/GmSSL-${GMSSL_VERSION}-Linux.sh" \
+ && chmod +x /tmp/gmssl-install.sh \
+ && /tmp/gmssl-install.sh --prefix=/usr/local \
+ && echo "/usr/local/GmSSL-${GMSSL_VERSION}-Linux/lib" > /etc/ld.so.conf.d/gmssl.conf \
+ && ldconfig \
+ && rm -f /tmp/gmssl-install.sh
\ No newline at end of file
diff --git a/apps/authentication/backends/cert/__init__.py b/apps/authentication/backends/cert/__init__.py
new file mode 100644
index 000000000..72f1ead27
--- /dev/null
+++ b/apps/authentication/backends/cert/__init__.py
@@ -0,0 +1 @@
+from .backends import *
\ No newline at end of file
diff --git a/apps/authentication/backends/cert/api.py b/apps/authentication/backends/cert/api.py
new file mode 100644
index 000000000..7e46a9ec5
--- /dev/null
+++ b/apps/authentication/backends/cert/api.py
@@ -0,0 +1,193 @@
+
+import base64
+import os
+import subprocess
+import tempfile
+from django.utils.translation import gettext_lazy as _
+
+import yaml
+from django.conf import settings
+from django.http import FileResponse, Http404
+from django.utils.decorators import method_decorator
+from django.views.decorators.cache import cache_control
+from rest_framework.response import Response
+from rest_framework.views import APIView
+from rest_framework.permissions import AllowAny
+from common.permissions import OnlySuperUser
+from common.utils import get_logger
+from .driver import cert_vd_cfg
+
+
+__all__ = ['VendorDriverFileAPIView', 'CertVendorDriverConfigAPIView']
+
+logger = get_logger(__name__)
+
+
+class VendorDriverFileAPIView(APIView):
+ permission_classes = (AllowAny,)
+
+ @method_decorator(cache_control(public=True, max_age=3600))
+ def get(self, request):
+ js_file = cert_vd_cfg.driver_js_file
+ if not js_file or not os.path.isfile(js_file):
+ raise Http404
+ response = FileResponse(open(js_file, 'rb'), content_type='application/javascript')
+ response['Cache-Control'] = 'public, max-age=3600'
+ return response
+
+
+class CertVendorDriverConfigAPIView(APIView):
+ permission_classes = (AllowAny,)
+
+ def get(self, request):
+ lang = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME) or settings.LANGUAGE_CODE
+ data = cert_vd_cfg.get_vendor_sdk_data(lang=lang)
+ return Response(data)
+
+
+class CertEnrollAPIView(APIView):
+ permission_classes = (OnlySuperUser,)
+
+ # SM2 曲线 OID:1.2.156.10197.1.301
+ # DER 编码:06 08 2a 81 1c cf 55 01 82 2d
+ _SM2_OID_DER = bytes([0x06, 0x08, 0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x82, 0x2d])
+
+ def post(self, request):
+ if not cert_vd_cfg.enroll_enabled:
+ data = {'error': _('Certificate enrollment is not enabled')}
+ return Response(data=data, status=400)
+
+ csr_raw = request.data.get('csr')
+ if not csr_raw:
+ data = {'error': _('CSR is required')}
+ return Response(data=data, status=400)
+
+ try:
+ singed_cert = self.sign_cert(csr_raw)
+ except Exception as e:
+ error = '{}: {}'.format(_('Certificate signing failed'), str(e))
+ logger.error(error, exc_info=True)
+ return Response(data={'error': error}, status=400)
+
+ data = {'signed_cert': singed_cert}
+ return Response(data=data, status=200)
+
+ def sign_cert(self, csr_raw):
+ # 记录输入是否含 PEM 头,用于决定输出格式
+ if isinstance(csr_raw, bytes):
+ has_pem_header = csr_raw.lstrip().startswith(b'-----BEGIN')
+ else:
+ has_pem_header = csr_raw.strip().startswith('-----BEGIN')
+
+ csr_pem = self._normalize_csr_to_pem(csr_raw)
+ if self._is_sm2_csr(csr_pem):
+ singed_cert = self.sign_cert_by_gmssl(csr_pem)
+ else:
+ singed_cert = self.sign_cert_by_other(csr_pem)
+
+ # 输入不含 PEM 头时,返回裸 base64(去掉首尾标识行)
+ if not has_pem_header:
+ lines = singed_cert.strip().splitlines()
+ singed_cert = ''.join(
+ ln for ln in lines if not ln.startswith('-----')
+ )
+ return singed_cert
+
+ def _normalize_csr_to_pem(self, csr_data):
+ """
+ 将 SDK 返回的 CSR 统一转换成标准 PEM 字符串。
+ 支持三种输入格式:
+ 1. 已经是标准 PEM(含 -----BEGIN CERTIFICATE REQUEST----- 头)
+ 2. 裸 base64 字符串(无 PEM 头,国密 USB Key SDK 常见)
+ 3. 原始 DER 二进制 bytes
+ """
+ if isinstance(csr_data, bytes):
+ if csr_data.lstrip().startswith(b'-----BEGIN'):
+ return csr_data.decode('utf-8')
+ b64 = base64.b64encode(csr_data).decode('ascii')
+ else:
+ csr_data = csr_data.strip()
+ if csr_data.startswith('-----BEGIN'):
+ return csr_data
+ # 裸 base64:去除空白后校验并重新分行
+ b64 = ''.join(csr_data.split())
+ base64.b64decode(b64, validate=True)
+
+ lines = [b64[i:i + 64] for i in range(0, len(b64), 64)]
+ return (
+ '-----BEGIN CERTIFICATE REQUEST-----\n'
+ + '\n'.join(lines)
+ + '\n-----END CERTIFICATE REQUEST-----\n'
+ )
+
+ def _is_sm2_csr(self, csr_pem):
+ """
+ 通过查找 SM2 曲线 OID 字节序列判断 CSR 是否使用 SM2 算法,
+ 无需调用外部工具。
+ """
+ pem_lines = csr_pem.strip().splitlines()
+ b64 = ''.join(ln for ln in pem_lines if not ln.startswith('-----'))
+ der = base64.b64decode(b64)
+ return self._SM2_OID_DER in der
+
+ def sign_cert_by_other(self, csr_pem):
+ pass
+
+ def sign_cert_by_gmssl(self, csr_pem):
+ """
+ 使用 gmssl reqsign 签发 SM2 证书。
+ 命令示例:
+ gmssl reqsign -in user.csr -days 365 -cacert root.crt -key root.key -pass 123456 -out user.crt
+ """
+ gmssl_bin = cert_vd_cfg.gmssl_bin
+ ca_key_path = cert_vd_cfg.ca_key_file
+ ca_cert_path = cert_vd_cfg.ca_cert_file
+ ca_key_pass = str(cert_vd_cfg.ca_key_pass)
+ if not ca_key_path or not os.path.isfile(ca_key_path):
+ raise FileNotFoundError('CA_KEY_FILE not configured or not found')
+ if not ca_cert_path or not os.path.isfile(ca_cert_path):
+ raise FileNotFoundError('CA_CERT_FILE not configured or not found')
+
+ validity_days = str(cert_vd_cfg.enroll_validity_days)
+
+ csr_file = cert_file = None
+ try:
+ with tempfile.NamedTemporaryFile(
+ suffix='.csr', mode='w', delete=False, encoding='utf-8'
+ ) as f:
+ f.write(csr_pem)
+ csr_file = f.name
+
+ fd, cert_file = tempfile.mkstemp(suffix='.crt')
+ os.close(fd)
+
+ # https://github.com/GmSSL/GmSSL-Python#sm2数字证书
+ # gmssl_python 只支持SM2证书的解析和验证等功能,不支持SM2证书的签发和生成,
+ # 所以还是需要使用 gmssl bin 来执行 reqsign 命令行工具进行签发。虽然增加了对外部命令的依赖,
+ # 但这是目前最简单可靠的方案。
+ cmd = [
+ gmssl_bin, 'reqsign',
+ '-in', csr_file,
+ '-days', validity_days,
+ '-cacert', ca_cert_path,
+ '-key', ca_key_path,
+ '-out', cert_file,
+ ]
+ if ca_key_pass:
+ cmd += ['-pass', ca_key_pass]
+
+ result = subprocess.run(
+ cmd,
+ capture_output=True,
+ text=True,
+ timeout=30
+ )
+ if result.returncode != 0:
+ raise RuntimeError('gmssl reqsign failed: {}'.format(result.stderr.strip()))
+
+ with open(cert_file, 'r', encoding='utf-8') as f:
+ return f.read()
+ finally:
+ for path in (csr_file, cert_file):
+ if path and os.path.exists(path):
+ os.unlink(path)
diff --git a/apps/authentication/backends/cert/api_urls.py b/apps/authentication/backends/cert/api_urls.py
new file mode 100644
index 000000000..2a7e11cbd
--- /dev/null
+++ b/apps/authentication/backends/cert/api_urls.py
@@ -0,0 +1,10 @@
+
+from django.urls import path
+from . import api
+
+urlpatterns = [
+ # api
+ path('cert/vendor-driver.js/', api.VendorDriverFileAPIView.as_view(), name='cert-vendor-driver-js-file'),
+ path('cert/vendor-driver-config/', api.CertVendorDriverConfigAPIView.as_view(), name='cert-vendor-driver-config'),
+ path('cert/enroll/', api.CertEnrollAPIView.as_view(), name='cert-enroll'),
+]
diff --git a/apps/authentication/backends/cert/backends.py b/apps/authentication/backends/cert/backends.py
new file mode 100644
index 000000000..d203120c1
--- /dev/null
+++ b/apps/authentication/backends/cert/backends.py
@@ -0,0 +1,193 @@
+# -*- coding: utf-8 -*-
+#
+
+import base64
+import os
+import tempfile
+
+from django.conf import settings
+
+from users.models import User
+from common.utils import get_logger
+from ..base import JMSBaseAuthBackend
+
+
+__all__ = ['CertBackend']
+
+logger = get_logger(__name__)
+
+# SM2 曲线 OID DER 字节序列,用于判断证书算法(与 api.py 保持一致)
+_SM2_OID_DER = bytes([0x06, 0x08, 0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x82, 0x2d])
+
+
+class CertBackend(JMSBaseAuthBackend):
+ backend = settings.AUTH_BACKEND_CERT
+
+ @staticmethod
+ def is_enabled():
+ return settings.AUTH_CERT
+
+ def authenticate(self, request, username, cert, signature, challenge):
+ try:
+ cert_pem = self._normalize_cert_to_pem(cert)
+ except Exception as e:
+ logger.warning('CertBackend: cert normalization failed: %s', e)
+ return None
+
+ if self._is_sm2_cert(cert_pem):
+ return self._authenticate_sm2(cert_pem, username, signature, challenge)
+ else:
+ return self._authenticate_other(cert_pem, username, signature, challenge)
+
+ # ── SM2 四步校验 ─────────────────────────────────────────────────────────
+
+ def _authenticate_sm2(self, cert_pem, username, signature, challenge):
+ # 加载证书(写临时文件 → Sm2Certificate)
+ try:
+ sm2_cert = self._load_sm2_cert(cert_pem)
+ except Exception as e:
+ logger.warning('CertBackend: failed to load SM2 cert: %s', e)
+ return None
+
+ # Step 1: 校验证书链,是否由 CA 根证书签发
+ try:
+ self._verify_sm2_cert_chain(sm2_cert)
+ except Exception as e:
+ logger.warning('CertBackend: SM2 cert chain verification failed: %s', e)
+ return None
+
+ # Step 2: 从证书 subject 提取 CN,与传入 username 比对
+ cert_cn = sm2_cert.get_subject().get('commonName')
+ if cert_cn != username:
+ logger.warning(
+ 'CertBackend: cert CN %r does not match username %r', cert_cn, username
+ )
+ return None
+
+ # Step 3: 用证书公钥验证签名
+ public_key = sm2_cert.get_subject_public_key()
+ try:
+ sig_ok = self._verify_sm2_signature(public_key, signature, challenge)
+ except Exception as e:
+ logger.warning('CertBackend: SM2 signature verification failed: %s', e)
+ return None
+ if not sig_ok:
+ logger.warning('CertBackend: SM2 signature mismatch')
+ return None
+
+ # Step 4: 查询并返回用户
+ return User.objects.filter(username=username).first()
+
+ @staticmethod
+ def _load_sm2_cert(cert_pem):
+ """将 PEM 字符串写入临时文件,加载为 Sm2Certificate 对象后立即删除临时文件。"""
+ from common.utils.gmssl_python import Sm2Certificate
+
+ fd, cert_file = tempfile.mkstemp(suffix='.crt')
+ try:
+ os.close(fd)
+ with open(cert_file, 'w', encoding='utf-8') as f:
+ f.write(cert_pem)
+ sm2_cert = Sm2Certificate()
+ sm2_cert.import_pem(cert_file)
+ finally:
+ if os.path.exists(cert_file):
+ os.unlink(cert_file)
+ return sm2_cert
+
+ def _verify_sm2_cert_chain(self, sm2_cert):
+ """调用 Sm2Certificate.verify_by_ca_certificate 验证证书链。"""
+ from common.utils.gmssl_python import SM2_DEFAULT_ID
+
+ ca_cert_path = getattr(settings, 'CA_CERT_FILE', '')
+ if not ca_cert_path or not os.path.isfile(ca_cert_path):
+ raise FileNotFoundError('CA_CERT_FILE not configured or not found')
+
+ from common.utils.gmssl_python import Sm2Certificate
+ ca_cert = Sm2Certificate()
+ ca_cert.import_pem(ca_cert_path)
+
+ if not sm2_cert.verify_by_ca_certificate(ca_cert, SM2_DEFAULT_ID):
+ raise ValueError('SM2 cert chain verification failed')
+
+ @staticmethod
+ def _verify_sm2_signature(sm2_key, signature, challenge):
+ """
+ 使用 gmssl_python 的 Sm2Signature 做 SM2withSM3 验签。
+
+ sm2_key : Sm2Certificate.get_subject_public_key() 返回的 Sm2Key 对象。
+ signature : USB Key 返回的签名(bytes / hex 字符串 / base64 字符串,DER 格式)。
+ challenge : 服务端下发的挑战码字符串;JS 端对 btoa(challenge) 做签名。
+ """
+ from common.utils.gmssl_python import Sm2Signature, DO_VERIFY, SM2_DEFAULT_ID
+
+ sig_bytes = CertBackend._decode_signature(signature)
+
+ # JS 端直接对 challenge 字符串签名,无需 base64 编码
+ if isinstance(challenge, bytes):
+ signed_data = challenge
+ else:
+ signed_data = challenge.encode('utf-8')
+
+ verifier = Sm2Signature(sm2_key, SM2_DEFAULT_ID, DO_VERIFY)
+ verifier.update(signed_data)
+ return bool(verifier.verify(sig_bytes))
+
+ # ── 工具方法 ─────────────────────────────────────────────────────────────
+
+ @staticmethod
+ def _is_sm2_cert(cert_pem):
+ """通过 OID 字节序列判断证书是否使用 SM2 算法。"""
+ pem_lines = cert_pem.strip().splitlines()
+ b64 = ''.join(ln for ln in pem_lines if not ln.startswith('-----'))
+ der = base64.b64decode(b64)
+ return _SM2_OID_DER in der
+
+ @staticmethod
+ def _normalize_cert_to_pem(cert_data):
+ """
+ 将证书统一转换为标准 PEM 格式。
+ 支持:已含头尾的 PEM、裸 base64 字符串、DER bytes。
+ """
+ if isinstance(cert_data, bytes):
+ if cert_data.lstrip().startswith(b'-----BEGIN'):
+ return cert_data.decode('utf-8')
+ b64 = base64.b64encode(cert_data).decode('ascii')
+ else:
+ cert_data = cert_data.strip()
+ if cert_data.startswith('-----BEGIN'):
+ return cert_data
+ b64 = ''.join(cert_data.split())
+ base64.b64decode(b64, validate=True) # 验证是合法 base64
+
+ lines = [b64[i:i + 64] for i in range(0, len(b64), 64)]
+ return (
+ '-----BEGIN CERTIFICATE-----\n'
+ + '\n'.join(lines)
+ + '\n-----END CERTIFICATE-----\n'
+ )
+
+ @staticmethod
+ def _decode_signature(signature):
+ """
+ 将签名值转为 bytes。
+ 依次尝试:已是 bytes → 十六进制字符串 → base64 字符串。
+ """
+ if isinstance(signature, bytes):
+ return signature
+ sig = signature.strip()
+ try:
+ return bytes.fromhex(sig)
+ except ValueError:
+ pass
+ try:
+ return base64.b64decode(sig)
+ except Exception:
+ pass
+ raise ValueError('Cannot decode signature: unknown format')
+
+ # ── 其他算法(预留)────────────────────────────────────────────────────────
+
+ def _authenticate_other(self, cert_pem, username, signature, challenge):
+ logger.warning('CertBackend: non-SM2 cert verification is not yet implemented')
+ return None
\ No newline at end of file
diff --git a/apps/authentication/backends/cert/driver.py b/apps/authentication/backends/cert/driver.py
new file mode 100644
index 000000000..a3f39b103
--- /dev/null
+++ b/apps/authentication/backends/cert/driver.py
@@ -0,0 +1,182 @@
+import os
+import yaml
+import json
+from django.conf import settings
+from common.utils import get_logger
+from common.decorators import Singleton
+from common.const import Language
+
+
+logger = get_logger(__name__)
+
+class Setting:
+ VENDOR = getattr(settings, 'VENDOR', '')
+
+
+@Singleton
+class CertVendorDriverConfig:
+ """
+ 从 YAML 配置文件读取所有证书相关配置。
+
+ CA 相关路径/密码(ca_cert_file / ca_key_file / ca_key_pass)属于系统敏感配置,
+ 只能在系统设置(config.yml / Django settings)中配置,不允许写入此 YAML。
+
+ YAML 结构约定:
+ cert: # 系统级配置段
+ gmssl_bin: gmssl # gmssl 二进制路径
+ challenge_ttl: 300 # Challenge 码 Redis 存活秒数
+ enroll:
+ enabled: true # 是否开启证书签发
+ key_algo: SM2 # 签发密钥算法:SM2 或 RSA
+ subject_cn: username # 用户证书 Subject CN 取自用户的哪个字段
+ subject_o: JumpServer # 用户证书 Subject O(组织名)
+ # 其余 key 为厂商 SDK 方法映射(供前端 API 层使用)
+ newUKeyAPI: ...
+ checkInstall: ...
+ getCertCN: ...
+ ...
+ """
+
+ def __init__(self):
+ if not settings.AUTH_CERT:
+ logger.debug('CertVendorDriverConfig: authentication backend not enabled, skipping config load')
+ return
+ config_file = getattr(settings, 'AUTH_CERT_VENDOR_DRIVER_CONFIG_FILE', None)
+ self._raw = self._load_yaml(config_file)
+ self._cert = self._raw.get('cert') or {}
+ self._enroll = self._cert.get('enroll') or {}
+
+ # ── YAML 加载 ────────────────────────────────────────────────────────────
+
+ @staticmethod
+ def _load_yaml(config_file):
+ if not config_file or not os.path.isfile(config_file):
+ logger.warning('CertVendorDriverConfig: config file not found: %s', config_file)
+ return {}
+ with open(config_file, 'r', encoding='utf-8') as f:
+ return yaml.safe_load(f) or {}
+
+ # ── CA / 证书链(只读系统设置,不允许在 YAML 中配置)────────────────────────
+
+ @property
+ def ca_cert_file(self):
+ """CA 根证书路径,只从系统设置读取。"""
+ return getattr(settings, 'CA_CERT_FILE', None)
+
+ @property
+ def ca_key_file(self):
+ """CA 私钥路径,只从系统设置读取。"""
+ return getattr(settings, 'CA_KEY_FILE', None)
+
+ @property
+ def ca_key_pass(self):
+ """CA 私钥密码,只从系统设置读取。"""
+ return getattr(settings, 'CA_KEY_PASS', '')
+
+ @property
+ def driver_js_file(self):
+ """返回厂商 SDK 驱动文件的 FileResponse,供 API 层使用。"""
+ return getattr(settings, 'AUTH_CERT_VENDOR_DRIVER_JS_FILE', None)
+
+ # ── 工具 ─────────────────────────────────────────────────────────────────
+
+ @property
+ def gmssl_bin(self):
+ """gmssl 二进制路径,默认 'gmssl'(系统 PATH 中查找)。"""
+ return 'gmssl'
+
+ # ── 认证流程 ──────────────────────────────────────────────────────────────
+
+ @property
+ def challenge_ttl(self):
+ """Challenge 码在 Redis 中的存活时间(秒),默认 300。"""
+ v = self._cert.get('challenge_ttl', 300)
+ return int(v)
+
+ # ── 证书签发 ──────────────────────────────────────────────────────────────
+
+ @property
+ def enroll_enabled(self):
+ """是否开启用户证书签发功能。"""
+ v = self._enroll.get('enabled', True)
+ return bool(v)
+
+ @property
+ def enroll_key_algo(self):
+ """签发证书时生成密钥对的算法,SM2 或 RSA。"""
+ return self._enroll.get('key_algo', 'SM2')
+
+ @property
+ def enroll_subject_cn(self):
+ """用户证书 Subject CN 取自用户模型的哪个字段,默认 'username'。"""
+ return self._enroll.get('subject_cn', 'username')
+
+ @property
+ def enroll_subject_o(self):
+ """用户证书 Subject O(组织名)。"""
+ return self._enroll.get('subject_o', Setting.VENDOR)
+
+ @property
+ def enroll_validity_days(self):
+ """签发证书的有效期(天),默认 365。"""
+ v = self._enroll.get('validity_days', 365)
+ return int(v)
+
+ # ── 厂商 SDK 映射(原始数据,供 API 层序列化给前端)───────────────────────
+
+ @staticmethod
+ def _render(data, trans_filter=None):
+ """
+ 渲染 YAML 数据中的 Jinja2 模板表达式。
+ - {{ settings.xxx }} → 系统设置值(任何时候都生效)
+ - {{ user.xxx }} → 原样保留,留给前端 JS 运行时解析
+ - {{ 'text' | trans }} → 按 trans_filter 翻译;不传则原文返回(初始化阶段)
+ """
+ from jinja2 import Undefined, Environment
+
+ class KeepUndefined(Undefined):
+ """未定义变量原样保留占位符,支持任意深度的属性链。"""
+ def __str__(self):
+ return '{{ ' + self._undefined_name + ' }}'
+ def __getattr__(self, name):
+ return KeepUndefined(name=f'{self._undefined_name}.{name}')
+
+ template_str = json.dumps(data, ensure_ascii=False)
+ env = Environment(undefined=KeepUndefined)
+ env.filters['trans'] = trans_filter or (lambda s: s)
+ rendered = env.from_string(template_str).render(settings=Setting)
+ return json.loads(rendered)
+
+ def _build_trans_filter(self, lang):
+ """构建 Jinja2 | trans filter 函数,按 lang 从 YAML i18n 表查找翻译。
+ 未找到翻译时原文返回;语言键自动归一化(zh_hant → zh-hant)。
+ """
+ i18n_raw = self._raw.get('i18n') or {}
+ i18n = {
+ text: {
+ Language.to_internal_code(lk.replace('_', '-')): lv
+ for lk, lv in entries.items()
+ }
+ for text, entries in i18n_raw.items()
+ if isinstance(entries, dict)
+ }
+
+ def trans_filter(s):
+ translations = i18n.get(str(s))
+ if not translations:
+ return s
+ return translations.get(lang) or translations.get('en') or s
+
+ return trans_filter
+
+ def get_vendor_sdk_data(self, lang='en'):
+ """返回去掉 'cert'/'i18n' 顶层 key 后的厂商 SDK 方法映射。
+ YAML 中任意字符串值均可用 {{ 'text' | trans }} 语法标记为可翻译。
+ """
+ lang = Language.to_internal_code(lang)
+ trans_filter = self._build_trans_filter(lang)
+ data = self._render(self._raw, trans_filter)
+ return {k: v for k, v in data.items() if k not in ('i18n',)}
+
+
+cert_vd_cfg = CertVendorDriverConfig()
diff --git a/apps/authentication/backends/cert/driver_config_demo/cert_driver_config.yaml b/apps/authentication/backends/cert/driver_config_demo/cert_driver_config.yaml
new file mode 100644
index 000000000..001182e57
--- /dev/null
+++ b/apps/authentication/backends/cert/driver_config_demo/cert_driver_config.yaml
@@ -0,0 +1,343 @@
+# ── 系统级证书配置 ─────────────────────────────────────────────────────────────
+# 所有与证书认证相关的系统配置均放在 cert: 段,其余 key 为厂商 SDK 方法映射。
+cert:
+ # Challenge 码在 Redis 中的存活时间(秒)
+ challenge_ttl: 300
+ # 证书签发配置
+ enroll:
+ enabled: true
+ key_algo: SM2 # 签发密钥算法:SM2 或 RSA
+ validity_days: 365 # 签发证书的有效期(天)
+ pin:
+ default: "88888888"
+
+showBasicInfo:
+ # 基础加密操作
+ - version:
+ label: "{{ 'Version' | trans }}"
+ method:
+ call: UKey_GetVersion
+ description: "{{ 'Get USB Key driver version' | trans }}"
+ - devSN:
+ label: "{{ 'Device serial number' | trans }}"
+ method:
+ call: UKey_GetDevSN
+ description: "{{ 'Get device serial number' | trans }}"
+ - enrollEnabled:
+ label: "{{ 'Certificate enrollment' | trans }}"
+ value: "{{ 'Enabled' | trans }}"
+ description: "{{ 'Whether certificate enrollment is enabled' | trans }}"
+ only: admin
+ - enrollKeyAlgo:
+ label: "{{ 'Enrollment algorithm' | trans }}"
+ value: "{{ 'SM2' | trans }}"
+ description: "{{ 'Key algorithm used for enrollment' | trans }}"
+ only: admin
+ - enrollValidityDays:
+ label: "{{ 'Certificate validity' | trans }}"
+ value: "{{ '365 days' | trans }}"
+ description: "{{ 'Certificate validity period used for enrollment' | trans }}"
+ only: admin
+
+# ── 厂商 USB Key SDK 方法映射 ──────────────────────────────────────────────────
+# USB Key 厂商 SDK 方法名映射
+
+# Driver 初始化
+newUKeyAPI:
+ description: "{{ 'Initialize USB Key SDK and get SDK instance' | trans }}"
+ method:
+ call: UKeyAPI
+
+# 基本操作
+checkInstall:
+ description: "{{ 'Check if USB Key driver is installed' | trans }}"
+ method:
+ call: UKey_CheckInstall
+
+# 获取用户名
+getCertCN:
+ description: "{{ 'Get built-in username from USB Key' | trans }}"
+ method:
+ call: UKey_GetCertInfo
+ params:
+ - key: CERT_TYPE_SIGN
+ value: 1
+ - key: CERT_SUBJECT_CN
+ value: 9
+
+# 管理员重置 PIN
+adminResetPIN:
+ description: "{{ 'Reset PIN' | trans }}"
+ method:
+ call: UKey_UnblockPIN
+ params:
+ - key: admin_pin
+ value: '{{ input.admin_pin }}'
+ - key: usb_key_pin
+ value: '{{ output.default_pin }}'
+
+# 用户修改 PIN
+userChangePIN:
+ description: "{{ 'User change PIN' | trans }}"
+ method:
+ call: UKey_ChangePIN
+ params:
+ - key: old_pin
+ value: '{{ input.old_pin }}'
+ - key: new_pin1
+ value: '{{ input.new_pin1 }}'
+ result:
+ success: 0
+
+# 清除证书
+deleteCert:
+ description: "{{ 'Delete existing certificate' | trans }}"
+ method:
+ call: UKey_DeleteCons
+
+# 校验 PIN
+checkPIN:
+ description: "{{ 'Verify PIN' | trans }}"
+ method:
+ call: UKey_VerifyPIN
+ params:
+ - key: pin
+ value: '{{ input.login_pin }}'
+ result:
+ success: 0
+
+# 获取公钥
+getCert:
+ description: "{{ 'Get certificate' | trans }}"
+ method:
+ call: UKey_GetCert
+ params:
+ - key: CERT_TYPE_SIGN
+ value: 1
+
+# 签名数据
+signData:
+ description: "{{ 'Sign data using the private key in USB Key' | trans }}"
+ method:
+ call: UKey_SignData
+ params:
+ - key: SM3
+ value: 1
+ - key: challenge_code
+ value: '{{ output.challenge_code }}'
+
+getCertInfo:
+ description: "{{ 'Get certificate list (including certificate information)' | trans }}"
+ method:
+ call: UKey_GetCertInfoList
+ fields:
+ - ID:
+ key: ID
+ label: "{{ 'Certificate ID' | trans }}"
+ - CN:
+ key: CN
+ label: "{{ 'CN (ID)' | trans }}"
+ - DN:
+ key: DN
+ label: "{{ 'DN' | trans }}"
+ - SN:
+ key: SN
+ label: "{{ 'SN' | trans }}"
+ - bef:
+ key: bef
+ label: "{{ 'bef' | trans }}"
+ - aft:
+ key: aft
+ label: "{{ 'aft' | trans }}"
+ - isSM:
+ key: isSM
+ label: "{{ 'SM2 certificate' | trans }}"
+ - DEVSN:
+ key: DEVSN
+ label: "{{ 'Device serial number' | trans }}"
+ showFields: [ID, CN, DN, SN, bef, aft, isSM, DEVSN]
+
+# 制证流程(Enrollment)
+# 步骤顺序:1 → 2 → 3 → 4(服务端签发)→ 5
+enrollSteps:
+ # 制证前清除旧证书,避免容器满
+ - deleteCert:
+ description: "{{ 'Delete existing certificate' | trans }}"
+ method:
+ call: UKey_DeleteCons
+
+ # 在 USB Key 硬件内生成密钥对(私钥永不离开设备)
+ - genKeyPair:
+ description: "{{ 'Generate key pair' | trans }}"
+ method:
+ call: UKey_GenKeyPair
+ params:
+ - key: asymAlg
+ label: "{{ 'Asymmetric algorithm' | trans }}"
+ type: int
+ value: 1 # SM2
+
+ # 用 USB Key 内的私钥生成 CSR(包含公钥 + Subject 信息)
+ - genCSR:
+ description: "{{ 'Generate certificate signing request (CSR)' | trans }}"
+ method:
+ call: UKey_GenCSR
+ params:
+ - key: dn
+ label: "{{ 'Certificate subject (Subject DN)' | trans }}"
+ type: string
+ items:
+ - key: CN
+ label: "{{ 'Name (CN)' | trans }}"
+ value: '{{ user.username }}' # 从配置读取 Subject CN 字段
+ - key: OU
+ label: "{{ 'Other information' | trans }}"
+ value: '{{ settings.VENDOR }}' # 从配置读取 Subject O 字段
+
+ - signCert:
+ description: "{{ 'Certificate issuance' | trans }}"
+
+ # 服务端 CA 签发证书后,将证书写入 USB Key
+ - writeCert:
+ description: "{{ 'Write the certificate' | trans }}"
+ method:
+ call: UKey_ImportCertAndKeyPair
+ params:
+ - key: SignCert
+ type: string
+ value: '{{ output.signed_cert }}' # 从服务端签发结果读取签名证书
+ - key: EncCert
+ value: ''
+ - key: EncKeyPair
+ value: ''
+
+i18n:
+ Version:
+ en: Version
+ zh-hans: 版本
+ zh-hant: 版本
+ Get USB Key driver version:
+ en: Get USB Key driver version
+ zh-hans: 获取 USB Key 驱动版本
+ zh-hant: 取得 USB Key 驅動版本
+ Device serial number:
+ en: Device serial number
+ zh-hans: 设备序列号
+ zh-hant: 裝置序號
+ Get device serial number:
+ en: Get device serial number
+ zh-hans: 获取设备序列号
+ zh-hant: 取得裝置序號
+ Certificate enrollment:
+ en: Certificate enrollment
+ zh-hans: 制证功能
+ zh-hant: 制證功能
+ Enabled:
+ en: Enabled
+ zh-hans: 启用
+ zh-hant: 啟用
+ Whether certificate enrollment is enabled:
+ en: Whether certificate enrollment is enabled
+ zh-hans: 是否启用制证功能
+ zh-hant: 是否啟用制證功能
+ Enrollment algorithm:
+ en: Enrollment algorithm
+ zh-hans: 制证算法
+ zh-hant: 制證演算法
+ Key algorithm used for enrollment:
+ en: Key algorithm used for enrollment
+ zh-hans: 制证使用的密钥算法
+ zh-hant: 制證使用的金鑰演算法
+ Certificate validity:
+ en: Certificate validity
+ zh-hans: 证书期限
+ zh-hant: 證書有效期
+ 365 days:
+ en: 365 days
+ zh-hans: 365 天
+ zh-hant: 365 天
+ Certificate validity period used for enrollment:
+ en: Certificate validity period used for enrollment
+ zh-hans: 制证使用的证书有效期
+ zh-hant: 制證使用的證書有效期
+ Initialize USB Key SDK and get SDK instance:
+ en: Initialize USB Key SDK and get SDK instance
+ zh-hans: 初始化 USB Key SDK,获取 SDK 对象实例
+ zh-hant: 初始化 USB Key SDK 並取得 SDK 物件實例
+ Check if USB Key driver is installed:
+ en: Check if USB Key driver is installed
+ zh-hans: 检查 USB Key 驱动是否安装
+ zh-hant: 檢查 USB Key 驅動是否已安裝
+ Get built-in username from USB Key:
+ en: Get built-in username from USB Key
+ zh-hans: 获取 USB Key 内置用户名
+ zh-hant: 取得 USB Key 內建使用者名稱
+ Reset PIN:
+ en: Reset PIN
+ zh-hans: 重置 PIN
+ zh-hant: 重置 PIN
+ User change PIN:
+ en: User change PIN
+ zh-hans: 用户修改 PIN
+ zh-hant: 使用者修改 PIN
+ Delete existing certificate:
+ en: Delete existing certificate
+ zh-hans: 删除已有证书
+ zh-hant: 刪除已有證書
+ Verify PIN:
+ en: Verify PIN
+ zh-hans: 校验 PIN 是否正确
+ zh-hant: 驗證 PIN 是否正確
+ Get certificate:
+ en: Get certificate
+ zh-hans: 获取证书
+ zh-hant: 取得證書
+ Sign data using the private key in USB Key:
+ en: Sign data using the private key in USB Key
+ zh-hans: 使用 USB Key 内的私钥对数据进行签名
+ zh-hant: 使用 USB Key 內的私鑰對資料進行簽名
+ Get certificate list (including certificate information):
+ en: Get certificate list (including certificate information)
+ zh-hans: 获取证书列表(包含证书信息)
+ zh-hant: 取得證書清單(包含證書資訊)
+ Certificate ID:
+ en: Certificate ID
+ zh-hans: 证书 ID
+ zh-hant: 證書 ID
+ SM2 certificate:
+ en: SM2 certificate
+ zh-hans: 国密证书
+ zh-hant: 國密證書
+ Generate key pair:
+ en: Generate key pair
+ zh-hans: 生成密钥对
+ zh-hant: 產生金鑰對
+ Asymmetric algorithm:
+ en: Asymmetric algorithm
+ zh-hans: 非对称算法
+ zh-hant: 非對稱演算法
+ Generate certificate signing request (CSR):
+ en: Generate certificate signing request (CSR)
+ zh-hans: 生成证书签名请求 (CSR)
+ zh-hant: 產生憑證簽名請求 (CSR)
+ Certificate subject (Subject DN):
+ en: Certificate subject (Subject DN)
+ zh-hans: 证书主题 (Subject DN)
+ zh-hant: 憑證主題 (Subject DN)
+ Name (CN):
+ en: Name (CN)
+ zh-hans: 名称 (CN)
+ zh-hant: 名稱 (CN)
+ Other information:
+ en: Other information
+ zh-hans: 其他信息
+ zh-hant: 其他資訊
+ Certificate issuance:
+ en: Certificate issuance
+ zh-hans: 证书签发
+ zh-hant: 證書簽發
+ Write the certificate:
+ en: Write the certificate
+ zh-hans: 写入证书
+ zh-hant: 寫入證書
+
diff --git a/apps/authentication/backends/cert/forms.py b/apps/authentication/backends/cert/forms.py
new file mode 100644
index 000000000..277d919f2
--- /dev/null
+++ b/apps/authentication/backends/cert/forms.py
@@ -0,0 +1,18 @@
+from django import forms
+from django.utils.translation import gettext_lazy as _
+
+
+class CertLoginForm(forms.Form):
+ username = forms.CharField(
+ label=_('Username'), max_length=100, required=True,
+ widget=forms.HiddenInput(),
+ )
+ cert = forms.CharField(
+ required=True,
+ widget=forms.HiddenInput(),
+ )
+ signature = forms.CharField(
+ required=True,
+ widget=forms.HiddenInput(),
+ )
+
diff --git a/apps/authentication/backends/cert/view_urls.py b/apps/authentication/backends/cert/view_urls.py
new file mode 100644
index 000000000..2faaadf47
--- /dev/null
+++ b/apps/authentication/backends/cert/view_urls.py
@@ -0,0 +1,7 @@
+from . import views
+
+from django.urls import path
+
+urlpatterns = [
+ path('cert/login/', views.CertLoginView.as_view(), name='cert-login')
+]
diff --git a/apps/authentication/backends/cert/views.py b/apps/authentication/backends/cert/views.py
new file mode 100644
index 000000000..1b3b6d64d
--- /dev/null
+++ b/apps/authentication/backends/cert/views.py
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+#
+import secrets
+
+from django.conf import settings
+from django.contrib.auth import authenticate, login as auth_login
+from django.core.cache import cache
+from django.utils.decorators import method_decorator
+from django.utils.translation import gettext as _
+from django.views.decorators.cache import never_cache
+from django.views.decorators.csrf import csrf_protect
+from django.views.decorators.debug import sensitive_post_parameters
+from django.views.generic.edit import FormView
+from django.shortcuts import redirect
+from django.http.response import HttpResponseRedirect
+
+from common.utils import reverse, safe_next_url
+from users.utils import redirect_user_first_login_or_index
+from authentication.mixins import AuthMixin
+from authentication.errors import ACLError
+from authentication.errors import (
+ AuthFailedError, LoginConfirmBaseError, NeedRedirectError
+)
+from .forms import CertLoginForm
+from users.utils import LoginBlockUtil, LoginIpBlockUtil
+
+
+__all__ = ['CertLoginView']
+
+_CHALLENGE_CACHE_KEY_PREFIX = 'cert_login_challenge'
+NEXT_URL = 'next'
+
+@method_decorator(sensitive_post_parameters(), name='dispatch')
+@method_decorator(csrf_protect, name='dispatch')
+@method_decorator(never_cache, name='dispatch')
+class CertLoginView(AuthMixin, FormView):
+ template_name = 'authentication/cert_login.html'
+ form_class = CertLoginForm
+ redirect_field_name = 'next'
+
+ # ------------------------------------------------------------------
+ # Challenge helpers
+ # ------------------------------------------------------------------
+
+ def _ensure_session(self):
+ if not self.request.session.session_key:
+ self.request.session.create()
+
+ def _challenge_cache_key(self):
+ self._ensure_session()
+ return f'{_CHALLENGE_CACHE_KEY_PREFIX}_{self.request.session.session_key}'
+
+ def _generate_and_store_challenge(self):
+ challenge = secrets.token_hex(16)
+ ttl = getattr(settings, 'AUTH_CERT_CHALLENGE_TTL', 300)
+ cache.set(self._challenge_cache_key(), challenge, ttl)
+ return challenge
+
+ def _get_stored_challenge(self):
+ return cache.get(self._challenge_cache_key(), '')
+
+ def _delete_stored_challenge(self):
+ cache.delete(self._challenge_cache_key())
+
+ # ------------------------------------------------------------------
+ # Views
+ # ------------------------------------------------------------------
+
+ def get(self, request, *args, **kwargs):
+ challenge = self._generate_and_store_challenge()
+ context = self.get_context_data(form=self.get_form(), challenge=challenge)
+ return self.render_to_response(context)
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ if 'challenge' not in context:
+ context['challenge'] = self._get_stored_challenge()
+ return context
+
+ def form_valid(self, form):
+ username = form.cleaned_data['username']
+ cert = form.cleaned_data['cert']
+ signature = form.cleaned_data['signature']
+ challenge = self._get_stored_challenge()
+
+ error_msg = None
+ ip = self.get_request_ip()
+
+ try:
+ self._check_is_block(username, True)
+ self._check_only_allow_exists_user_auth(username)
+
+ user = authenticate(
+ self.request, username=username, cert=cert, signature=signature, challenge=challenge
+ )
+ if user is None:
+ error_msg = _('Invalid credentials')
+ return self.get_failed_response(form, username, error_msg)
+
+ username = user.username
+ self._check_login_acl(user, ip)
+
+ LoginIpBlockUtil(ip).clean_block_if_need()
+ LoginBlockUtil(username, ip).clean_failed_count()
+ except AuthFailedError as e:
+ error_msg = e.msg
+ except NeedRedirectError as e:
+ return redirect(e.url)
+ except Exception as e:
+ error_msg = str(e)
+ finally:
+ self._delete_stored_challenge()
+
+ if error_msg:
+ return self.get_failed_response(form, username, error_msg)
+ else:
+ return self.get_success_response(self.request, user)
+
+ def get_failed_response(self, form, username, error_msg):
+ form.add_error(None, error_msg)
+ # Refresh the challenge so it cannot be replayed
+ challenge = self._generate_and_store_challenge()
+ context = self.get_context_data(form=form, challenge=challenge)
+ self.send_auth_signal(success=False, reason=error_msg, username=username)
+ return self.render_to_response(context)
+
+ def get_success_response(self, request, user):
+ self.mark_cert_ok(user, auth_backend=settings.AUTH_BACKEND_CERT)
+ return self.redirect_to_guard_view()
diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py
index b201a1cf8..16599bc48 100644
--- a/apps/authentication/mixins.py
+++ b/apps/authentication/mixins.py
@@ -245,6 +245,12 @@ class CommonMixin:
return user
user_id = self.request.session.get('user_id')
+ auth_cert_ok = self.request.session.get('auth_cert')
+ if auth_cert_ok:
+ user = get_object_or_404(User, pk=user_id)
+ user.backend = self.request.session.get("auth_backend")
+ return user
+
auth_ok = self.request.session.get('auth_password')
auth_expired_at = self.request.session.get('auth_password_expired_at')
auth_expired = auth_expired_at < time.time() if auth_expired_at else False
@@ -669,7 +675,7 @@ class AuthMixin(CommonMixin, AuthPreCheckMixin, AuthACLMixin, AuthFaceMixin, MFA
LoginBlockUtil(user.username, ip).clean_failed_count()
LoginIpBlockUtil(ip).clean_block_if_need()
return user
-
+
def mark_password_ok(self, user, auto_login=False, auth_backend=None):
request = self.request
request.session['auth_password'] = 1
@@ -681,6 +687,12 @@ class AuthMixin(CommonMixin, AuthPreCheckMixin, AuthACLMixin, AuthFaceMixin, MFA
request.session['auth_backend'] = auth_backend
+ def mark_cert_ok(self, user, auth_backend):
+ request = self.request
+ request.session['auth_cert'] = 1
+ request.session['user_id'] = str(user.id)
+ request.session['auth_backend'] = auth_backend
+
def check_oauth2_auth(self, user: User, auth_backend):
ip = self.get_request_ip()
request = self.request
@@ -713,7 +725,8 @@ class AuthMixin(CommonMixin, AuthPreCheckMixin, AuthACLMixin, AuthFaceMixin, MFA
keys = [
'auth_password', 'user_id', 'auth_confirm_required',
'auth_notice_required', 'auth_ticket_id', 'auth_acl_id',
- 'user_session_id', 'user_log_id', 'can_send_notifications'
+ 'user_session_id', 'user_log_id', 'can_send_notifications',
+ 'auth_cert'
]
for k in keys:
self.request.session.pop(k, '')
diff --git a/apps/authentication/templates/authentication/cert_login.html b/apps/authentication/templates/authentication/cert_login.html
new file mode 100644
index 000000000..20627e1fa
--- /dev/null
+++ b/apps/authentication/templates/authentication/cert_login.html
@@ -0,0 +1,492 @@
+{% load i18n %}
+{% load bootstrap3 %}
+{% load static %}
+
+
+
+
+
+ {{ INTERFACE.login_title }}
+
+ {% include '_head_css_js.html' %}
+
+
+
+
+
+
+
+
+
+

+
+
{% trans "Certificate Authentication" %}
+
+
+
+
+ {% trans "Loading USB Key driver..." %}
+
+
+
+
+
+
+
+{% include '_foot_js.html' %}
+
+
+
diff --git a/apps/authentication/urls/api_urls.py b/apps/authentication/urls/api_urls.py
index 1072f4a41..2b7f7b3a3 100644
--- a/apps/authentication/urls/api_urls.py
+++ b/apps/authentication/urls/api_urls.py
@@ -6,6 +6,7 @@ from rest_framework.routers import DefaultRouter
from .. import api
from ..backends.passkey.urls import urlpatterns as passkey_urlpatterns
+from ..backends.cert.api_urls import urlpatterns as cert_api_urlpatterns
app_name = 'authentication'
router = DefaultRouter()
@@ -53,6 +54,7 @@ if settings.AUTH_CUSTOM_SSO:
path('custom-sso/login/', api.CustomSSOLoginAPIView.as_view(), name='custom-sso-login'),
]
-
+if settings.AUTH_CERT:
+ urlpatterns += cert_api_urlpatterns
urlpatterns += router.urls + passkey_urlpatterns
diff --git a/apps/authentication/urls/view_urls.py b/apps/authentication/urls/view_urls.py
index 0ed6621f9..337805acb 100644
--- a/apps/authentication/urls/view_urls.py
+++ b/apps/authentication/urls/view_urls.py
@@ -4,6 +4,7 @@
from django.db.transaction import non_atomic_requests
from django.urls import path, include
+
from users import views as users_view
from .. import views
@@ -81,10 +82,12 @@ urlpatterns = [
path('openid/', include(('authentication.backends.oidc.urls', 'authentication'), namespace='openid')),
path('saml2/', include(('authentication.backends.saml2.urls', 'authentication'), namespace='saml2')),
path('oauth2/', include(('authentication.backends.oauth2.urls', 'authentication'), namespace='oauth2')),
+ path('cert/', include(('authentication.backends.cert.view_urls', 'authentication'), namespace='cert')),
path('captcha/', include('captcha.urls')),
path('oauth2-provider/', include(('authentication.backends.oauth2_provider.urls', 'authentication'), namespace='oauth2-provider')),
path('user-agreement/', views.UserAgreementView.as_view(), name='user-agreement'),
path('privacy-policy/', views.PrivacyPolicyView.as_view(), name='privacy-policy'),
+
]
diff --git a/apps/authentication/utils.py b/apps/authentication/utils.py
index 731cc4493..61d88b2d6 100644
--- a/apps/authentication/utils.py
+++ b/apps/authentication/utils.py
@@ -145,5 +145,11 @@ def get_auth_methods():
'enabled': settings.AUTH_PASSKEY,
'url': reverse('api-auth:passkey-login'),
'logo': static('img/login_passkey.png')
+ },
+ {
+ 'name': _('CERT'),
+ 'enabled': settings.AUTH_CERT,
+ 'url': reverse('authentication:cert:cert-login'),
+ 'logo': static('img/login_cert.png')
}
]
diff --git a/apps/common/utils/gmssl_python.py b/apps/common/utils/gmssl_python.py
new file mode 100644
index 000000000..056d64d83
--- /dev/null
+++ b/apps/common/utils/gmssl_python.py
@@ -0,0 +1,1040 @@
+# Copyright 2023 The GmSSL Project. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# GmSSL-Python - Python binding of the GmSSL library with `ctypes`
+
+
+from ctypes import *
+from ctypes.util import find_library
+import datetime
+import sys
+
+if find_library('gmssl') == None:
+ raise ValueError('Install GmSSL dynamic library from https://github.com/guanzhi/GmSSL')
+gmssl = cdll.LoadLibrary(find_library("gmssl"))
+if gmssl.gmssl_version_num() < 30101:
+ raise ValueError('GmSSL version < 3.1.1')
+
+if sys.platform == 'win32':
+ libc = cdll.LoadLibrary(find_library('msvcrt'))
+else:
+ libc = cdll.LoadLibrary(find_library('c'))
+
+
+class NativeError(Exception):
+ '''
+ GmSSL libraray inner error
+ '''
+
+class StateError(Exception):
+ '''
+ Crypto state error
+ '''
+
+GMSSL_PYTHON_VERSION = "2.2.2"
+
+def gmssl_library_version_num():
+ return gmssl.gmssl_version_num()
+
+def gmssl_library_version_str():
+ gmssl.gmssl_version_str.restype = c_char_p
+ return gmssl.gmssl_version_str().decode('ascii')
+
+GMSSL_LIBRARY_VERSION = gmssl_library_version_str()
+
+
+def rand_bytes(size):
+ buf = create_string_buffer(size)
+ gmssl.rand_bytes(buf, c_size_t(size))
+ return buf.raw
+
+
+
+SM3_DIGEST_SIZE = 32
+_SM3_STATE_WORDS = 8
+_SM3_BLOCK_SIZE = 64
+
+class Sm3(Structure):
+
+ _fields_ = [
+ ("dgst", c_uint32 * _SM3_STATE_WORDS),
+ ("nblocks", c_uint64),
+ ("block", c_uint8 * _SM3_BLOCK_SIZE),
+ ("num", c_size_t)
+ ]
+
+ def __init__(self):
+ gmssl.sm3_init(byref(self))
+
+ def reset(self):
+ gmssl.sm3_init(byref(self))
+
+ def update(self, data):
+ gmssl.sm3_update(byref(self), data, c_size_t(len(data)))
+
+ def digest(self):
+ dgst = create_string_buffer(SM3_DIGEST_SIZE)
+ gmssl.sm3_finish(byref(self), dgst)
+ return dgst.raw
+
+
+SM3_HMAC_MIN_KEY_SIZE = 16
+SM3_HMAC_MAX_KEY_SIZE = 64
+SM3_HMAC_SIZE = SM3_DIGEST_SIZE
+
+class Sm3Hmac(Structure):
+
+ _fields_ = [
+ ("sm3_ctx", Sm3),
+ ("key", c_uint8 * _SM3_BLOCK_SIZE)
+ ]
+
+ def __init__(self, key):
+ if len(key) < SM3_HMAC_MIN_KEY_SIZE or len(key) > SM3_HMAC_MAX_KEY_SIZE:
+ raise ValueError('Invalid SM3 HMAC key length')
+ gmssl.sm3_hmac_init(byref(self), key, c_size_t(len(key)))
+
+ def reset(self, key):
+ if len(key) < SM3_HMAC_MIN_KEY_SIZE or len(key) > SM3_HMAC_MAX_KEY_SIZE:
+ raise ValueError('Invalid SM3 HMAC key length')
+ gmssl.sm3_hmac_init(byref(self), key, c_size_t(len(key)))
+
+ def update(self, data):
+ gmssl.sm3_hmac_update(byref(self), data, c_size_t(len(data)))
+
+ def generate_mac(self):
+ hmac = create_string_buffer(SM3_HMAC_SIZE)
+ gmssl.sm3_hmac_finish(byref(self), hmac)
+ return hmac.raw
+
+
+
+SM3_PBKDF2_MIN_ITER = 10000 # from
+SM3_PBKDF2_MAX_ITER = 16777216 # 2^24
+SM3_PBKDF2_MAX_SALT_SIZE = 64 # from
+SM3_PBKDF2_DEFAULT_SALT_SIZE = 8 # from
+SM3_PBKDF2_MAX_KEY_SIZE = 256 # from gmssljni.c:sm3_pbkdf2():sizeof(keybuf)
+
+def sm3_pbkdf2(passwd, salt, iterator, keylen):
+
+ if len(salt) > SM3_PBKDF2_MAX_SALT_SIZE:
+ raise ValueError('Invalid salt length')
+
+ if iterator < SM3_PBKDF2_MIN_ITER or iterator > SM3_PBKDF2_MAX_ITER:
+ raise ValueError('Invalid iterator value')
+
+ if keylen > SM3_PBKDF2_MAX_KEY_SIZE:
+ raise ValueError('Invalid key length')
+
+ passwd = passwd.encode('utf-8')
+ key = create_string_buffer(keylen)
+
+ if gmssl.pbkdf2_hmac_sm3_genkey(c_char_p(passwd), c_size_t(len(passwd)),
+ salt, c_size_t(len(salt)), c_size_t(iterator), c_size_t(keylen), key) != 1:
+ raise NativeError('libgmssl inner error')
+
+ return key.raw
+
+
+
+SM4_KEY_SIZE = 16
+SM4_BLOCK_SIZE = 16
+_SM4_NUM_ROUNDS = 32
+
+class Sm4(Structure):
+
+ _fields_ = [
+ ("rk", c_uint32 * _SM4_NUM_ROUNDS)
+ ]
+
+ def __init__(self, key, encrypt):
+ if len(key) != SM4_KEY_SIZE:
+ raise ValueError('Invalid key length')
+ if encrypt:
+ gmssl.sm4_set_encrypt_key(byref(self), key)
+ else:
+ gmssl.sm4_set_decrypt_key(byref(self), key)
+
+ def encrypt(self, block):
+ if len(block) != SM4_BLOCK_SIZE:
+ raise ValueError('Invalid block size')
+ outbuf = create_string_buffer(SM4_BLOCK_SIZE)
+ gmssl.sm4_encrypt(byref(self), block, outbuf)
+ return outbuf.raw
+
+
+SM4_CBC_IV_SIZE = SM4_BLOCK_SIZE
+
+
+class Sm4Cbc(Structure):
+
+ _fields_ = [
+ ("sm4_key", Sm4),
+ ("iv", c_uint8 * SM4_BLOCK_SIZE),
+ ("block", c_uint8 * SM4_BLOCK_SIZE),
+ ("block_nbytes", c_size_t)
+ ]
+
+ def __init__(self, key, iv, encrypt):
+ if len(key) != SM4_KEY_SIZE:
+ raise ValueError('Invalid key length')
+ if len(iv) != SM4_BLOCK_SIZE:
+ raise ValueError('Invalid IV size')
+ if encrypt == DO_ENCRYPT:
+ if gmssl.sm4_cbc_encrypt_init(byref(self), key, iv) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm4_cbc_decrypt_init(byref(self), key, iv) != 1:
+ raise NativeError('libgmssl inner error')
+ self._encrypt = encrypt
+
+ def update(self, data):
+ outbuf = create_string_buffer(len(data) + SM4_BLOCK_SIZE)
+ outlen = c_size_t()
+ if self._encrypt == DO_ENCRYPT:
+ if gmssl.sm4_cbc_encrypt_update(byref(self), data, c_size_t(len(data)),
+ outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm4_cbc_decrypt_update(byref(self), data, c_size_t(len(data)),
+ outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[0:outlen.value]
+
+ def finish(self):
+ outbuf = create_string_buffer(SM4_BLOCK_SIZE)
+ outlen = c_size_t()
+ if self._encrypt == True:
+ if gmssl.sm4_cbc_encrypt_finish(byref(self), outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm4_cbc_decrypt_finish(byref(self), outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[:outlen.value]
+
+
+
+SM4_CTR_IV_SIZE = 16
+
+
+class Sm4Ctr(Structure):
+
+ _fields_ = [
+ ("sm4_key", Sm4),
+ ("ctr", c_uint8 * SM4_BLOCK_SIZE),
+ ("block", c_uint8 * SM4_BLOCK_SIZE),
+ ("block_nbytes", c_size_t)
+ ]
+
+ def __init__(self, key, iv):
+ if len(key) != SM4_KEY_SIZE:
+ raise ValueError('Invalid key length')
+ if len(iv) != SM4_BLOCK_SIZE:
+ raise ValueError('Invalid IV size')
+ if gmssl.sm4_ctr_encrypt_init(byref(self), key, iv) != 1:
+ raise NativeError('libgmssl inner error')
+
+ def update(self, data):
+ outbuf = create_string_buffer(len(data) + SM4_BLOCK_SIZE)
+ outlen = c_size_t()
+ if gmssl.sm4_ctr_encrypt_update(byref(self), data, c_size_t(len(data)),
+ outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[0:outlen.value]
+
+ def finish(self):
+ outbuf = create_string_buffer(SM4_BLOCK_SIZE)
+ outlen = c_size_t()
+ if gmssl.sm4_ctr_encrypt_finish(byref(self), outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[:outlen.value]
+
+
+ZUC_KEY_SIZE = 16
+ZUC_IV_SIZE = 16
+
+class ZucState(Structure):
+ _fields_ = [
+ ("LFSR", c_uint32 * 16),
+ ("R1", c_uint32),
+ ("R2", c_uint32)
+ ]
+
+class Zuc(Structure):
+
+ _fields_ = [
+ ("zuc_state", ZucState),
+ ("block", c_uint8 * 4),
+ ("block_nbytes", c_size_t)
+ ]
+
+ def __init__(self, key, iv):
+ if len(key) != ZUC_KEY_SIZE:
+ raise ValueError('Invalid key length')
+ if len(iv) != ZUC_IV_SIZE:
+ raise ValueError('Invalid IV size')
+ if gmssl.zuc_encrypt_init(byref(self), key, iv) != 1:
+ raise NativeError('libgmssl inner error')
+
+ def update(self, data):
+ outbuf = create_string_buffer(len(data) + SM4_BLOCK_SIZE)
+ outlen = c_size_t()
+ if gmssl.zuc_encrypt_update(byref(self), data, c_size_t(len(data)),
+ outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[0:outlen.value]
+
+ def finish(self):
+ outbuf = create_string_buffer(SM4_BLOCK_SIZE)
+ outlen = c_size_t()
+ if gmssl.zuc_encrypt_finish(byref(self), outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[:outlen.value]
+
+
+class gf128_t(Structure):
+ _fields_ = [
+ ("hi", c_uint64),
+ ("lo", c_uint64)
+ ]
+
+
+class Ghash(Structure):
+ _fields_ = [
+ ("H", gf128_t),
+ ("X", gf128_t),
+ ("aadlen", c_size_t),
+ ("clen", c_size_t),
+ ("block", c_uint8 * 16),
+ ("num", c_size_t)
+ ]
+
+
+SM4_GCM_MIN_IV_SIZE = 1
+SM4_GCM_MAX_IV_SIZE = 64
+SM4_GCM_DEFAULT_IV_SIZE = 12
+SM4_GCM_DEFAULT_TAG_SIZE = 16
+SM4_GCM_MAX_TAG_SIZE = 16
+
+class Sm4Gcm(Structure):
+
+ _fields_ = [
+ ("sm4_ctr_ctx", Sm4Ctr),
+ ("mac_ctx", Ghash),
+ ("Y", c_uint8 * 16),
+ ("taglen", c_size_t),
+ ("mac", c_uint8 * 16),
+ ("maclen", c_size_t)
+ ]
+
+ def __init__(self, key, iv, aad, taglen = SM4_GCM_DEFAULT_TAG_SIZE, encrypt = True):
+ if len(key) != SM4_KEY_SIZE:
+ raise ValueError('Invalid key length')
+ if len(iv) < SM4_GCM_MIN_IV_SIZE or len(iv) > SM4_GCM_MAX_IV_SIZE:
+ raise ValueError('Invalid IV size')
+ if taglen < 1 or taglen > SM4_GCM_MAX_TAG_SIZE:
+ raise ValueError('Invalid Tag length')
+ if encrypt == DO_ENCRYPT:
+ if gmssl.sm4_gcm_encrypt_init(byref(self), key, c_size_t(len(key)),
+ iv, c_size_t(len(iv)), aad, c_size_t(len(aad)),
+ c_size_t(taglen)) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm4_gcm_decrypt_init(byref(self), key, c_size_t(len(key)),
+ iv, c_size_t(len(iv)), aad, c_size_t(len(aad)),
+ c_size_t(taglen)) != 1:
+ raise NativeError('libgmssl inner error')
+ self._encrypt = encrypt
+
+ def update(self, data):
+ outbuf = create_string_buffer(len(data) + SM4_BLOCK_SIZE)
+ outlen = c_size_t()
+ if self._encrypt == DO_ENCRYPT:
+ if gmssl.sm4_gcm_encrypt_update(byref(self), data, c_size_t(len(data)),
+ outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm4_gcm_decrypt_update(byref(self), data, c_size_t(len(data)),
+ outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[0:outlen.value]
+
+ def finish(self):
+ outbuf = create_string_buffer(SM4_BLOCK_SIZE + SM4_GCM_MAX_TAG_SIZE)
+ outlen = c_size_t()
+ if self._encrypt == DO_ENCRYPT:
+ if gmssl.sm4_gcm_encrypt_finish(byref(self), outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm4_gcm_decrypt_finish(byref(self), outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[:outlen.value]
+
+
+SM2_DEFAULT_ID = '1234567812345678'
+
+SM2_MAX_SIGNATURE_SIZE = 72
+
+SM2_MIN_PLAINTEXT_SIZE = 1
+SM2_MAX_PLAINTEXT_SIZE = 255
+SM2_MIN_CIPHERTEXT_SIZE = 45
+SM2_MAX_CIPHERTEXT_SIZE = 366
+
+
+class Sm2Point(Structure):
+ _fields_ = [
+ ("x", c_uint8 * 32),
+ ("y", c_uint8 * 32)
+ ]
+
+
+class Sm2Key(Structure):
+
+ _fields_ = [
+ ("public_key", Sm2Point),
+ ("private_key", c_uint8 * 32)
+ ]
+
+ def __init__(self):
+ self._has_public_key = False
+ self._has_private_key = False
+
+ def generate_key(self):
+ if gmssl.sm2_key_generate(byref(self)) != 1:
+ raise NativeError('libgmssl inner error')
+ self._has_public_key = True
+ self._has_private_key = True
+
+ def has_private_key(self):
+ return self._has_private_key
+
+ def has_public_key(self):
+ return self._has_public_key
+
+ def compute_z(self, signer_id = SM2_DEFAULT_ID):
+ if self._has_public_key == False:
+ raise TypeError('has no public key')
+ signer_id = signer_id.encode('utf-8')
+ z = create_string_buffer(SM3_DIGEST_SIZE)
+ gmssl.sm2_compute_z(z, byref(self), c_char_p(signer_id), c_size_t(len(signer_id)))
+ return z.raw
+
+ def export_encrypted_private_key_info_pem(self, path, passwd):
+ if self._has_private_key == False:
+ raise TypeError('has no private key')
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm2_private_key_info_encrypt_to_pem(byref(self), c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+
+ def import_encrypted_private_key_info_pem(self, path, passwd):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'rb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm2_private_key_info_decrypt_from_pem(byref(self), c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+ self._has_public_key = True
+ self._has_private_key = True
+
+ def export_public_key_info_pem(self, path):
+ if self._has_public_key == False:
+ raise TypeError('has no public key')
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ if gmssl.sm2_public_key_info_to_pem(byref(self), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+
+ def import_public_key_info_pem(self, path):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'rb')
+ if gmssl.sm2_public_key_info_from_pem(byref(self), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+ self._has_public_key = True
+ self._has_private_key = False
+
+ def sign(self, dgst):
+ if self._has_private_key == False:
+ raise TypeError('has no private key')
+ if len(dgst) != SM3_DIGEST_SIZE:
+ raise ValueError('Invalid SM3 digest size')
+ sig = create_string_buffer(SM2_MAX_SIGNATURE_SIZE)
+ siglen = c_size_t()
+ if gmssl.sm2_sign(byref(self), dgst, sig, byref(siglen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return sig[:siglen.value]
+
+ def verify(self, dgst, signature):
+ if self._has_public_key == False:
+ raise TypeError('has no public key')
+ if len(dgst) != SM3_DIGEST_SIZE:
+ raise ValueError('Invalid SM3 digest size')
+ if gmssl.sm2_verify(byref(self), dgst, signature, c_size_t(len(signature))) != 1:
+ return False
+ return True
+
+ def encrypt(self, data):
+ if self._has_public_key == False:
+ raise TypeError('has no public key')
+ if len(data) > SM2_MAX_PLAINTEXT_SIZE:
+ raise NativeError('libgmssl inner error')
+ outbuf = create_string_buffer(SM2_MAX_CIPHERTEXT_SIZE)
+ outlen = c_size_t()
+ if gmssl.sm2_encrypt(byref(self), data, c_size_t(len(data)),
+ outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[:outlen.value]
+
+ def decrypt(self, ciphertext):
+ if self._has_private_key == False:
+ raise TypeError('has no private key')
+ outbuf = create_string_buffer(SM2_MAX_PLAINTEXT_SIZE)
+ outlen = c_size_t()
+ if gmssl.sm2_decrypt(byref(self), ciphertext, c_size_t(len(ciphertext))
+ , outbuf, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return outbuf[:outlen.value]
+
+
+DO_ENCRYPT = True
+DO_DECRYPT = False
+DO_SIGN = True
+DO_VERIFY = False
+
+class Sm2Signature(Structure):
+
+ _fields_ = [
+ ("sm3_ctx", Sm3),
+ ("key", Sm2Key)
+ ]
+
+ def __init__(self, sm2_key, signer_id = SM2_DEFAULT_ID, sign = DO_SIGN):
+ signer_id = signer_id.encode('utf-8')
+ if sign == DO_SIGN:
+ if sm2_key.has_private_key() != True:
+ raise NativeError('libgmssl inner error')
+ if gmssl.sm2_sign_init(byref(self), byref(sm2_key),
+ c_char_p(signer_id), c_size_t(len(signer_id))) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if sm2_key.has_public_key() != True:
+ raise NativeError('libgmssl inner error')
+ if gmssl.sm2_verify_init(byref(self), byref(sm2_key),
+ c_char_p(signer_id), c_size_t(len(signer_id))) != 1:
+ raise NativeError('libgmssl inner error')
+ self._sign = sign
+
+ def update(self, data):
+ if self._sign == DO_SIGN:
+ if gmssl.sm2_sign_update(byref(self), data, c_size_t(len(data))) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm2_verify_update(byref(self), data, c_size_t(len(data))) != 1:
+ raise NativeError('libgmssl inner error')
+
+ def sign(self):
+ if self._sign != DO_SIGN:
+ raise StateError('not sign state')
+ sig = create_string_buffer(SM2_MAX_SIGNATURE_SIZE)
+ siglen = c_size_t()
+ if gmssl.sm2_sign_finish(byref(self), sig, byref(siglen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return sig[:siglen.value]
+
+ def verify(self, signature):
+ if self._sign != DO_VERIFY:
+ raise StateError('not verify state')
+ if gmssl.sm2_verify_finish(byref(self), signature, c_size_t(len(signature))) != 1:
+ return False
+ return True
+
+
+class sm9_bn_t(Structure):
+ _fields_ = [
+ ("d", c_uint64 * 8)
+ ]
+
+class sm9_fp2_t(Structure):
+ _fields_ = [
+ ("d", sm9_bn_t * 2)
+ ]
+
+class Sm9Point(Structure):
+ _fields_ = [
+ ("X", sm9_bn_t),
+ ("Y", sm9_bn_t),
+ ("Z", sm9_bn_t)
+ ]
+
+class Sm9TwistPoint(Structure):
+ _fields_ = [
+ ("X", sm9_fp2_t),
+ ("Y", sm9_fp2_t),
+ ("Z", sm9_fp2_t)
+ ]
+
+
+SM9_MAX_ID_SIZE = 63
+SM9_MAX_PLAINTEXT_SIZE = 255
+SM9_MAX_CIPHERTEXT_SIZE = 367
+
+class Sm9EncKey(Structure):
+ _fields_ = [
+ ("Ppube", Sm9Point),
+ ("de", Sm9TwistPoint)
+ ]
+
+ def __init__(self, owner_id):
+ self._id = owner_id.encode('utf-8')
+ self._has_private_key = False
+
+ def get_id(self):
+ return self._id;
+
+ def has_private_key(self):
+ return self._has_private_key
+
+ def import_encrypted_private_key_info_pem(self, path, passwd):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'rb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm9_enc_key_info_decrypt_from_pem(byref(self), c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+ self._has_private_key = True
+
+ def export_encrypted_private_key_info_pem(self, path, passwd):
+ if self._has_private_key != True:
+ raise TypeError('has no private key')
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm9_enc_key_info_encrypt_to_pem(byref(self), c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+
+ def decrypt(self, ciphertext):
+ if self._has_private_key != True:
+ raise TypeError('has no private key')
+ plaintext = create_string_buffer(SM9_MAX_PLAINTEXT_SIZE)
+ outlen = c_size_t()
+ if gmssl.sm9_decrypt(byref(self), c_char_p(self._id), c_size_t(len(self._id)),
+ ciphertext, c_size_t(len(ciphertext)), plaintext, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return plaintext[0:outlen.value]
+
+
+class Sm9EncMasterKey(Structure):
+ _fields_ = [
+ ("Ppube", Sm9Point),
+ ("ke", sm9_bn_t)
+ ]
+
+ def __init__(self):
+ self._has_public_key = False
+ self._has_private_key = False
+
+ def generate_master_key(self):
+ if gmssl.sm9_enc_master_key_generate(byref(self)) != 1:
+ raise NativeError('libgmssl inner error')
+ self._has_public_key = True
+ self._has_private_key = True
+
+ def extract_key(self, identity):
+ if self._has_private_key != True:
+ raise TypeError('has no master key')
+ key = Sm9EncKey(identity)
+ identity = identity.encode('utf-8')
+ if gmssl.sm9_enc_master_key_extract_key(byref(self),
+ c_char_p(identity), c_size_t(len(identity)), byref(key)) != 1:
+ raise NativeError('libgmssl inner error')
+ key._has_public_key = True
+ key._has_private_key = True
+ return key
+
+ def import_encrypted_master_key_info_pem(self, path, passwd):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'rb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm9_enc_master_key_info_decrypt_from_pem(byref(self), c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+ self._has_public_key = True
+ self._has_private_key = True
+
+ def export_encrypted_master_key_info_pem(self, path, passwd):
+ if self._has_private_key != True:
+ raise TypeError('has no master key')
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm9_enc_master_key_info_encrypt_to_pem(byref(self), c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+
+ def export_public_master_key_pem(self, path):
+ if self._has_public_key != True:
+ raise TypeError('has no public master key')
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ if gmssl.sm9_enc_master_public_key_to_pem(byref(self), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+
+ def import_public_master_key_pem(self, path):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'rb')
+ if gmssl.sm9_enc_master_public_key_from_pem(byref(self), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+ self._has_public_key = True
+ self._has_private_key = False
+
+ def encrypt(self, plaintext, to):
+ if self._has_public_key != True:
+ raise TypeError('has no public master key')
+ to = to.encode('utf-8')
+ ciphertext = create_string_buffer(SM9_MAX_CIPHERTEXT_SIZE)
+ outlen = c_size_t()
+ if gmssl.sm9_encrypt(byref(self), c_char_p(to), c_size_t(len(to)),
+ plaintext, c_size_t(len(plaintext)), ciphertext, byref(outlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return ciphertext[0:outlen.value]
+
+
+class Sm9SignKey(Structure):
+ _fields_ = [
+ ("Ppubs", Sm9TwistPoint),
+ ("ds", Sm9Point)
+ ]
+
+ def __init__(self, owner_id):
+ self._id = owner_id.encode('utf-8')
+ self._has_private_key = False
+
+ def get_id(self):
+ return self._id;
+
+ def has_private_key(self):
+ return self._has_private_key
+
+ def import_encrypted_private_key_info_pem(self, path, passwd):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'rb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm9_sign_key_info_decrypt_from_pem(byref(self), c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+ self._has_private_key = True
+
+ def export_encrypted_private_key_info_pem(self, path, passwd):
+ if self._has_private_key == False:
+ raise TypeError('has no master key')
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm9_sign_key_info_encrypt_to_pem(byref(self), c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+
+
+class Sm9SignMasterKey(Structure):
+ _fields_ = [
+ ("Ppubs", Sm9TwistPoint),
+ ("ks", sm9_bn_t)
+ ]
+
+ def __init__(self):
+ self._has_public_key = False
+ self._has_private_key = False
+
+ def generate_master_key(self):
+ if gmssl.sm9_sign_master_key_generate(byref(self)) != 1:
+ raise NativeError('libgmssl inner error')
+ self._has_public_key = True
+ self._has_private_key = True
+
+ def extract_key(self, identity):
+ if self._has_private_key != True:
+ raise TypeError('has no master key')
+ key = Sm9SignKey(identity)
+ identity = identity.encode('utf-8')
+ if gmssl.sm9_sign_master_key_extract_key(byref(self),
+ c_char_p(identity), c_size_t(len(identity)), byref(key)) != 1:
+ raise NativeError('libgmssl inner error')
+ key._has_public_key = True
+ key._has_private_key = True
+ return key
+
+ def import_encrypted_master_key_info_pem(self, path, passwd):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'rb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm9_sign_master_key_info_decrypt_from_pem(byref(self),
+ c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+ self._has_public_key = True
+ self._has_private_key = True
+
+ def export_encrypted_master_key_info_pem(self, path, passwd):
+ if self._has_private_key != True:
+ raise TypeError('has no master key')
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ passwd = passwd.encode('utf-8')
+ if gmssl.sm9_sign_master_key_info_encrypt_to_pem(byref(self),
+ c_char_p(passwd), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+
+ def export_public_master_key_pem(self, path):
+ if self._has_public_key != True:
+ raise TypeError('has no public master key')
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ if gmssl.sm9_sign_master_public_key_to_pem(byref(self), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+
+ def import_public_master_key_pem(self, path):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'rb')
+ if gmssl.sm9_sign_master_public_key_from_pem(byref(self), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+ libc.fclose(c_void_p(fp))
+ self._has_public_key = True
+ self._has_private_key = False
+
+
+SM9_SIGNATURE_SIZE = 104
+
+class Sm9Signature(Structure):
+
+ _fields_ = [
+ ("sm3", Sm3)
+ ]
+
+ def __init__(self, sign = DO_SIGN):
+ if sign == DO_SIGN:
+ if gmssl.sm9_sign_init(byref(self)) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm9_verify_init(byref(self)) != 1:
+ raise NativeError('libgmssl inner error')
+ self._sign = sign
+ self._inited = True
+
+
+ def reset(self):
+ if self._inited != True:
+ raise StateError('not initialized')
+
+ if self._sign == DO_SIGN:
+ if gmssl.sm9_sign_init(byref(self)) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm9_verify_init(byref(self)) != 1:
+ raise NativeError('libgmssl inner error')
+
+ def update(self, data):
+
+ if self._inited != True:
+ raise StateError('not initialized')
+
+ if self._sign == DO_SIGN:
+ if gmssl.sm9_sign_update(byref(self), data, c_size_t(len(data))) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.sm9_verify_update(byref(self), data, c_size_t(len(data))) != 1:
+ raise NativeError('libgmssl inner error')
+
+
+ def sign(self, sign_key):
+ if self._inited != True:
+ raise StateError('not initialized')
+ if self._sign != DO_SIGN:
+ raise StateError('not sign state')
+
+ sig = create_string_buffer(SM9_SIGNATURE_SIZE)
+ siglen = c_size_t()
+ if gmssl.sm9_sign_finish(byref(self), byref(sign_key), sig, byref(siglen)) != 1:
+ raise NativeError('libgmssl inner error')
+ return sig[:siglen.value]
+
+ def verify(self, signature, public_master_key, signer_id):
+ if self._inited != True:
+ raise StateError('not initialized')
+ if self._sign != DO_VERIFY:
+ raise StateError('not verify state')
+
+ signer_id = signer_id.encode('utf-8')
+
+ if gmssl.sm9_verify_finish(byref(self), signature, c_size_t(len(signature)),
+ byref(public_master_key), c_char_p(signer_id), c_size_t(len(signer_id))) != 1:
+ return False
+ return True
+
+
+
+_ASN1_TAG_IA5String = 22
+_ASN1_TAG_SEQUENCE = 0x30
+_ASN1_TAG_SET = 0x31
+
+
+
+def gmssl_parse_attr_type_and_value(name, d, dlen):
+ oid = c_int()
+ tag = c_int()
+ val = c_void_p()
+ vlen = c_size_t()
+
+ if gmssl.x509_name_type_from_der(byref(oid), byref(d), byref(dlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ gmssl.x509_name_type_name.restype = c_char_p
+ oid_name = gmssl.x509_name_type_name(oid).decode('ascii')
+
+ if oid_name == 'emailAddress':
+ if gmssl.asn1_ia5_string_from_der_ex(_ASN1_TAG_IA5String, byref(val), byref(vlen), byref(d), byref(dlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ else:
+ if gmssl.x509_directory_name_from_der(byref(tag), byref(val), byref(vlen), byref(d), byref(dlen)) != 1:
+ raise NativeError('libgmssl inner error')
+
+ if dlen.value != 0:
+ raise ValueError('invalid der encoding')
+
+ value = create_string_buffer(vlen.value)
+ libc.memcpy(value, val, vlen)
+
+ name[oid_name] = value.raw.decode('utf-8')
+ return True
+
+def gmssl_parse_rdn(name, d, dlen):
+ v = c_void_p()
+ vlen = c_size_t()
+
+ while dlen.value > 0:
+ if gmssl.asn1_type_from_der(_ASN1_TAG_SEQUENCE, byref(v), byref(vlen), byref(d), byref(dlen)) != 1:
+ raise NativeError('libgmssl inner error')
+
+ if gmssl_parse_attr_type_and_value(name, v, vlen) != 1:
+ raise NativeError('libgmssl inner error')
+
+ return True
+
+# https://stacktuts.com/how-to-correctly-pass-pointer-to-pointer-into-dll-in-python-and-ctypes#
+def gmssl_parse_name(name, d, dlen):
+ v = c_void_p()
+ vlen = c_size_t()
+
+ while dlen.value > 0:
+ if gmssl.asn1_nonempty_type_from_der(c_int(_ASN1_TAG_SET), byref(v), byref(vlen), byref(d), byref(dlen)) != 1:
+ raise NativeError('libgmssl inner error')
+ gmssl_parse_rdn(name, v, vlen)
+ return True
+
+
+class Validity:
+
+ def __init__(self, not_before, not_after):
+ self.not_before = datetime.datetime.fromtimestamp(not_before)
+ self.not_after = datetime.datetime.fromtimestamp(not_after)
+
+
+class Sm2Certificate:
+
+ def import_pem(self, path):
+
+ cert = c_void_p()
+ certlen = c_size_t()
+ if gmssl.x509_cert_new_from_file(byref(cert), byref(certlen), path.encode('utf-8')) != 1:
+ raise NativeError('libgmssl inner error')
+
+ self._cert = create_string_buffer(certlen.value)
+ libc.memcpy(self._cert, cert, certlen)
+ libc.free(cert)
+
+ def get_raw(self):
+ return self._cert;
+
+ def export_pem(self, path):
+ libc.fopen.restype = c_void_p
+ fp = libc.fopen(path.encode('utf-8'), 'wb')
+ if gmssl.x509_cert_to_pem(self._cert, c_size_t(len(self._cert)), c_void_p(fp)) != 1:
+ raise NativeError('libgmssl inner error')
+
+ def get_serial_number(self):
+
+ serial_ptr = c_void_p()
+ serial_len = c_size_t()
+
+ if gmssl.x509_cert_get_issuer_and_serial_number(self._cert, c_size_t(len(self._cert)),
+ None, None, byref(serial_ptr), byref(serial_len)) != 1:
+ raise NativeError('libgmssl inner error')
+
+ serial = create_string_buffer(serial_len.value)
+ libc.memcpy(serial, serial_ptr, serial_len)
+ return serial.raw
+
+ def get_issuer(self):
+ issuer_ptr = c_void_p()
+ issuer_len = c_size_t()
+ if gmssl.x509_cert_get_issuer(self._cert, c_size_t(len(self._cert)),
+ byref(issuer_ptr), byref(issuer_len)) != 1:
+ raise NativeError('libgmssl inner error')
+ issuer_raw = create_string_buffer(issuer_len.value)
+ libc.memcpy(issuer_raw, issuer_ptr, issuer_len)
+
+ issuer = { "raw_data" : issuer_raw.raw }
+ gmssl_parse_name(issuer, issuer_ptr, issuer_len)
+ return issuer
+
+ def get_subject(self):
+ subject_ptr = c_void_p()
+ subject_len = c_size_t()
+ if gmssl.x509_cert_get_subject(self._cert, c_size_t(len(self._cert)),
+ byref(subject_ptr), byref(subject_len)) != 1:
+ raise NativeError('libgmssl inner error')
+ subject_raw = create_string_buffer(subject_len.value)
+ libc.memcpy(subject_raw, subject_ptr, subject_len)
+
+ subject = { "raw_data" : subject_raw.raw }
+ gmssl_parse_name(subject, subject_ptr, subject_len)
+ return subject
+
+ def get_subject_public_key(self):
+ public_key = Sm2Key()
+ gmssl.x509_cert_get_subject_public_key(self._cert, c_size_t(len(self._cert)), byref(public_key))
+ public_key._has_private_key = False
+ public_key._has_public_key = True
+ return public_key
+
+ def get_validity(self):
+ not_before = c_ulong()
+ not_after = c_ulong()
+ if gmssl.x509_cert_get_details(self._cert, c_size_t(len(self._cert)),
+ None, None, None, None, None, None,
+ byref(not_before), byref(not_after),
+ None, None, None, None, None, None, None, None, None, None, None, None) != 1:
+ raise NativeError('libgmssl inner error')
+ return Validity(not_before.value, not_after.value)
+
+ def verify_by_ca_certificate(self, cacert, sm2_id):
+
+ cacert_raw = cacert.get_raw()
+ sm2_id = sm2_id.encode('utf-8')
+
+ if gmssl.x509_cert_verify_by_ca_cert(self._cert, c_size_t(len(self._cert)),
+ cacert_raw, c_size_t(len(cacert_raw)), c_char_p(sm2_id), c_size_t(len(sm2_id))) != 1:
+ return False
+ return True
+
diff --git a/apps/i18n/core/en/LC_MESSAGES/django.po b/apps/i18n/core/en/LC_MESSAGES/django.po
index 902521979..d685b8712 100644
--- a/apps/i18n/core/en/LC_MESSAGES/django.po
+++ b/apps/i18n/core/en/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-04-21 17:03+0800\n"
+"POT-Creation-Date: 2026-05-25 14:02+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -28,7 +28,7 @@ msgstr ""
msgid "No valid assets found for account creation."
msgstr ""
-#: accounts/api/account/application.py:77
+#: accounts/api/account/application.py:87
#: authentication/api/connection_token.py:463
msgid "Account not found"
msgstr ""
@@ -42,15 +42,15 @@ msgstr ""
msgid "The account key will be split into two parts and sent"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:131
+#: accounts/automations/backup_account/handlers.py:132
msgid "Number of backup accounts"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:152
+#: accounts/automations/backup_account/handlers.py:153
msgid "Generating asset related backup information files"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:177
+#: accounts/automations/backup_account/handlers.py:178
#: accounts/automations/backup_account/manager.py:26
#: accounts/automations/change_secret/manager.py:81
#: accounts/automations/push_account/manager.py:62
@@ -61,31 +61,31 @@ msgstr ""
msgid "Duration"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:178
+#: accounts/automations/backup_account/handlers.py:179
msgid "Backup file creation completed"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:186
+#: accounts/automations/backup_account/handlers.py:187
msgid "Start sending backup emails"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:213
+#: accounts/automations/backup_account/handlers.py:214
msgid "Encrypting files using encryption password"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:223
+#: accounts/automations/backup_account/handlers.py:224
msgid "The backup file will be sent to"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:246
+#: accounts/automations/backup_account/handlers.py:247
msgid "The backup task has no assigned sftp server"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:267
+#: accounts/automations/backup_account/handlers.py:268
msgid "The backup task has no assigned recipient"
msgstr ""
-#: accounts/automations/backup_account/handlers.py:290
+#: accounts/automations/backup_account/handlers.py:291
msgid "Plan start"
msgstr ""
@@ -149,7 +149,7 @@ msgstr ""
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -223,7 +223,7 @@ msgstr ""
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr ""
@@ -345,14 +345,14 @@ msgstr ""
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "Success"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr ""
@@ -360,7 +360,7 @@ msgstr ""
msgid "Queued"
msgstr ""
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr ""
@@ -372,7 +372,7 @@ msgstr ""
msgid "Can login"
msgstr ""
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr ""
@@ -401,7 +401,7 @@ msgid "Default tablespace"
msgstr ""
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr ""
@@ -410,7 +410,7 @@ msgid "Perms"
msgstr ""
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr ""
@@ -783,7 +783,7 @@ msgstr ""
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -798,7 +798,7 @@ msgstr ""
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr ""
@@ -893,8 +893,9 @@ msgstr ""
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1048,7 +1049,7 @@ msgstr ""
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "Active"
@@ -1064,7 +1065,7 @@ msgstr ""
msgid "Push params"
msgstr ""
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr ""
@@ -1148,7 +1149,7 @@ msgstr ""
msgid "Change secret or push account failed information"
msgstr ""
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr ""
@@ -1304,7 +1305,7 @@ msgstr ""
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1312,8 +1313,8 @@ msgstr ""
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr ""
@@ -1346,7 +1347,7 @@ msgstr ""
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1605,7 +1606,7 @@ msgid ""
" Account storage - Record limit"
msgstr ""
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr ""
@@ -1672,7 +1673,7 @@ msgstr ""
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1856,7 +1857,7 @@ msgstr ""
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr ""
@@ -1882,7 +1883,7 @@ msgid "Command"
msgstr ""
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr ""
@@ -1971,7 +1972,7 @@ msgstr ""
msgid "Login acl"
msgstr ""
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr ""
@@ -2089,7 +2090,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr ""
@@ -2148,15 +2149,15 @@ msgstr ""
msgid "User details"
msgstr ""
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr ""
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr ""
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
msgid "The number of assets exceeds the license limit"
msgstr ""
@@ -2173,6 +2174,11 @@ msgstr ""
msgid "Deletion failed and the node contains assets"
msgstr ""
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr ""
@@ -2190,29 +2196,29 @@ msgstr "Assets"
msgid "Task: {} finished"
msgstr ""
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr ""
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr ""
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ""
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ""
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ""
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ""
@@ -2602,7 +2608,7 @@ msgid "Port"
msgstr ""
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr ""
@@ -2610,12 +2616,12 @@ msgstr ""
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr ""
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr ""
@@ -2684,9 +2690,9 @@ msgid "Proxy"
msgstr ""
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr ""
@@ -2710,7 +2716,7 @@ msgstr ""
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr ""
@@ -2799,7 +2805,7 @@ msgstr ""
msgid "System"
msgstr ""
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2814,7 +2820,7 @@ msgstr ""
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr ""
@@ -2830,27 +2836,27 @@ msgstr ""
msgid "My assets"
msgstr ""
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr ""
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr ""
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr ""
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr ""
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr ""
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr ""
@@ -3024,7 +3030,7 @@ msgstr ""
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr ""
@@ -3436,7 +3442,7 @@ msgid "Symlink"
msgstr ""
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr ""
@@ -3465,7 +3471,9 @@ msgstr ""
msgid "Connect"
msgstr ""
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4170,24 +4178,24 @@ msgstr ""
msgid "Current user not support mfa type: {}"
msgstr ""
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr ""
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr ""
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
"password"
msgstr ""
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4197,7 +4205,7 @@ msgstr ""
msgid "Forgot password"
msgstr ""
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr ""
@@ -4210,9 +4218,20 @@ msgstr "Authentication"
msgid "CAS Error"
msgstr ""
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
+#: authentication/backends/cert/api.py:57
+msgid "Certificate enrollment is not enabled"
+msgstr ""
+
+#: authentication/backends/cert/api.py:62
+msgid "CSR is required"
+msgstr ""
+
+#: authentication/backends/cert/api.py:68
+msgid "Certificate signing failed"
+msgstr ""
+
+#: authentication/backends/cert/views.py:97
+msgid "Invalid credentials"
msgstr ""
#: authentication/backends/drf.py:61
@@ -4455,16 +4474,16 @@ msgstr ""
msgid "Please wait for %s seconds before retry"
msgstr ""
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr ""
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr ""
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr ""
@@ -4589,11 +4608,11 @@ msgid ""
"contact the administrator."
msgstr ""
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr ""
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4601,12 +4620,12 @@ msgid ""
"administrator. "
msgstr ""
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr ""
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr ""
@@ -4798,7 +4817,7 @@ msgstr ""
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "Expired"
@@ -4838,13 +4857,13 @@ msgstr ""
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "Is Valid"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr ""
@@ -4936,7 +4955,7 @@ msgstr ""
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5032,6 +5051,73 @@ msgstr ""
msgid "Cancel"
msgstr ""
+#: authentication/templates/authentication/cert_login.html:190
+#, fuzzy
+#| msgid "App Authentication"
+msgid "Certificate Authentication"
+msgstr "Authentication"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:238
+msgid "Other login methods"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:253
+msgid "Please insert USB Key"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:254
+msgid "Driver unavailable"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:257
+msgid "PIN verified"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:258
+msgid "PIN verification failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:260
+msgid "Signing failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:262
+msgid "No certificate detected, please contact administrator"
+msgstr ""
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr ""
@@ -5099,6 +5185,10 @@ msgstr ""
msgid "LAN"
msgstr ""
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5258,47 +5348,47 @@ msgstr ""
msgid "Request file format may be wrong"
msgstr ""
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr ""
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr ""
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr ""
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr ""
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr ""
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr ""
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr ""
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr ""
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr ""
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr ""
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr ""
@@ -5776,24 +5866,24 @@ msgstr ""
msgid "The message code provided is invalid or has expired"
msgstr ""
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr ""
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr ""
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr ""
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "JumpServer"
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -6477,7 +6567,7 @@ msgid "Please save in a org"
msgstr ""
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -6868,25 +6958,25 @@ msgstr ""
msgid "Organization role"
msgstr ""
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr ""
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr ""
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
msgstr ""
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr ""
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr ""
@@ -6951,7 +7041,7 @@ msgid "Storage"
msgstr ""
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr ""
@@ -7010,51 +7100,51 @@ msgstr "Access key id"
msgid "Range days"
msgstr ""
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr ""
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr ""
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr ""
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr ""
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr ""
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr ""
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr ""
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr ""
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr ""
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr ""
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr ""
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr ""
@@ -7326,14 +7416,14 @@ msgstr ""
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
#: settings/serializers/auth/lark.py:13 users/models/user/_source.py:24
@@ -7342,8 +7432,8 @@ msgstr ""
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
#: settings/serializers/auth/ldap.py:42 settings/serializers/auth/ldap.py:108
@@ -7387,8 +7477,8 @@ msgstr ""
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
#: settings/serializers/auth/ldap.py:85 settings/serializers/auth/ldap_ha.py:67
@@ -7486,8 +7576,8 @@ msgstr ""
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
#: settings/serializers/auth/oauth2.py:67 settings/serializers/auth/oidc.py:117
@@ -7521,8 +7611,8 @@ msgstr ""
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
#: settings/serializers/auth/oidc.py:45
@@ -7655,8 +7745,8 @@ msgstr ""
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
#: settings/serializers/auth/sms.py:18
@@ -7691,7 +7781,7 @@ msgid "Template code"
msgstr ""
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr ""
@@ -7745,7 +7835,7 @@ msgid "Enable SSO auth"
msgstr ""
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
+msgid "Other service can using SSO token login to system without password"
msgstr ""
#: settings/serializers/auth/sso.py:20
@@ -7759,8 +7849,8 @@ msgstr ""
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
#: settings/serializers/basic.py:11
@@ -8806,7 +8896,7 @@ msgstr ""
msgid "The verification code has been sent"
msgstr ""
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "Home"
@@ -9067,31 +9157,31 @@ msgstr ""
msgid "Hosts"
msgstr ""
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr ""
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr ""
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr ""
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr ""
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr ""
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr ""
@@ -9181,7 +9271,7 @@ msgstr ""
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -9395,8 +9485,8 @@ msgstr "Storage"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr ""
@@ -9499,7 +9589,8 @@ msgstr ""
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
#: terminal/serializers/applet_host.py:55
@@ -9606,20 +9697,20 @@ msgstr ""
msgid "Timestamp"
msgstr ""
-#: terminal/serializers/endpoint.py:27
+#: terminal/serializers/endpoint.py:28
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:54
+#: terminal/serializers/endpoint.py:64
msgid ""
"The assets within this IP range or Host, the following endpoint will be used "
"for the connection"
msgstr ""
-#: terminal/serializers/endpoint.py:55
+#: terminal/serializers/endpoint.py:65
msgid ""
"If asset IP addresses under different endpoints conflict, use asset labels"
msgstr ""
@@ -9753,7 +9844,7 @@ msgstr "Is alive"
msgid "Stat"
msgstr ""
-#: terminal/serializers/terminal.py:83 terminal/serializers/terminal.py:91
+#: terminal/serializers/terminal.py:79 terminal/serializers/terminal.py:87
msgid "Not found"
msgstr ""
@@ -10315,7 +10406,7 @@ msgstr ""
msgid "Approval Step Distribution"
msgstr ""
-#: tickets/serializers/flow.py:45
+#: tickets/serializers/flow.py:42
msgid "The current organization type already exists"
msgstr ""
@@ -10376,7 +10467,7 @@ msgid "Ticket information"
msgstr ""
#: tickets/templates/tickets/approve_check_password.html:28
-#: tickets/views/approve.py:43 tickets/views/approve.py:80
+#: tickets/views/approve.py:42 tickets/views/approve.py:80
msgid "Ticket approval"
msgstr ""
@@ -10384,12 +10475,12 @@ msgstr ""
msgid "Approval"
msgstr ""
-#: tickets/views/approve.py:44
+#: tickets/views/approve.py:43
msgid ""
"This ticket does not exist, the process has ended, or this link has expired"
msgstr ""
-#: tickets/views/approve.py:72
+#: tickets/views/approve.py:71
msgid "Click the button below to approve or reject"
msgstr ""
@@ -10593,7 +10684,7 @@ msgstr ""
msgid "Email lookup"
msgstr ""
-#: users/models/user/__init__.py:82 users/serializers/user.py:259
+#: users/models/user/__init__.py:82 users/serializers/user.py:264
msgid "Is service account"
msgstr "Is service account"
@@ -10610,7 +10701,7 @@ msgid "OTP secret key"
msgstr ""
#: users/models/user/__init__.py:105 users/serializers/profile.py:86
-#: users/serializers/user.py:256
+#: users/serializers/user.py:261
msgid "Is first login"
msgstr "First login"
@@ -10630,23 +10721,23 @@ msgstr ""
msgid "Date api key used"
msgstr ""
-#: users/models/user/__init__.py:293
+#: users/models/user/__init__.py:298
msgid "Can not delete admin user"
msgstr ""
-#: users/models/user/__init__.py:307
+#: users/models/user/__init__.py:312
msgid "Can invite user"
msgstr ""
-#: users/models/user/__init__.py:308
+#: users/models/user/__init__.py:313
msgid "Can remove user"
msgstr ""
-#: users/models/user/__init__.py:309
+#: users/models/user/__init__.py:314
msgid "Can match user"
msgstr ""
-#: users/models/user/__init__.py:338
+#: users/models/user/__init__.py:343
msgid "User password history"
msgstr ""
@@ -10654,6 +10745,10 @@ msgstr ""
msgid "Force enabled"
msgstr ""
+#: users/models/user/_source.py:27
+msgid "Certificate"
+msgstr ""
+
#: users/notifications.py:23 users/notifications.py:68
msgid "Reset password url"
msgstr ""
@@ -10763,7 +10858,7 @@ msgstr ""
msgid "Connect default open method"
msgstr ""
-#: users/serializers/preference/luna.py:34 xpack/plugins/interface/models.py:42
+#: users/serializers/preference/luna.py:34 xpack/plugins/interface/models.py:44
#: xpack/plugins/interface/serializers/interface.py:35
msgid "Theme"
msgstr ""
@@ -10872,7 +10967,7 @@ msgstr ""
msgid "Login blocked"
msgstr ""
-#: users/serializers/user.py:130 users/serializers/user.py:265
+#: users/serializers/user.py:130 users/serializers/user.py:270
msgid "Is OTP bound"
msgstr "OTP bound"
@@ -10888,59 +10983,65 @@ msgstr ""
msgid "Can public key authentication"
msgstr "Can public key authentication"
-#: users/serializers/user.py:144
+#: users/serializers/user.py:145
+#, fuzzy
+#| msgid "Can public key authentication"
+msgid "Can certificate authentication"
+msgstr "Can public key authentication"
+
+#: users/serializers/user.py:149
msgid "Is face code set"
msgstr ""
-#: users/serializers/user.py:230
+#: users/serializers/user.py:235
msgid "Full name"
msgstr ""
-#: users/serializers/user.py:233
+#: users/serializers/user.py:238
msgid "Login username"
msgstr ""
-#: users/serializers/user.py:236
+#: users/serializers/user.py:241
msgid "Email address"
msgstr ""
-#: users/serializers/user.py:246
+#: users/serializers/user.py:251
msgid "User groups to join"
msgstr ""
-#: users/serializers/user.py:250
+#: users/serializers/user.py:255
msgid ""
"User source identifies where the user was created, which could be AD or "
"other sources.There are security settings that can restrict users to log in "
"to the system only from the sources."
msgstr ""
-#: users/serializers/user.py:260
+#: users/serializers/user.py:265
msgid "Is org admin"
msgstr "Org admin"
-#: users/serializers/user.py:262
+#: users/serializers/user.py:267
msgid "Avatar url"
msgstr ""
-#: users/serializers/user.py:267
+#: users/serializers/user.py:272
msgid "MFA level"
msgstr "MFA"
-#: users/serializers/user.py:268
+#: users/serializers/user.py:273
msgid "Multi-Factor Authentication"
msgstr ""
-#: users/serializers/user.py:398
+#: users/serializers/user.py:403
msgid "Has public keys"
msgstr ""
-#: users/serializers/user.py:426
+#: users/serializers/user.py:431
msgid ""
"* For security, only a partial of users is displayed. You can search for more"
msgstr ""
-#: users/serializers/user.py:462
+#: users/serializers/user.py:467
msgid "name not unique"
msgstr ""
@@ -11411,7 +11512,7 @@ msgstr ""
msgid "Public IP"
msgstr ""
-#: xpack/plugins/cloud/const.py:50 xpack/plugins/cloud/models.py:373
+#: xpack/plugins/cloud/const.py:50 xpack/plugins/cloud/models.py:374
msgid "Instance name"
msgstr ""
@@ -11610,8 +11711,8 @@ msgstr ""
msgid "Date last sync"
msgstr ""
-#: xpack/plugins/cloud/models.py:135 xpack/plugins/cloud/models.py:391
-#: xpack/plugins/cloud/models.py:418
+#: xpack/plugins/cloud/models.py:135 xpack/plugins/cloud/models.py:392
+#: xpack/plugins/cloud/models.py:419
msgid "Strategy"
msgstr ""
@@ -11651,71 +11752,71 @@ msgstr ""
msgid "Task strategy"
msgstr ""
-#: xpack/plugins/cloud/models.py:362
+#: xpack/plugins/cloud/models.py:363
msgid "Equal"
msgstr ""
-#: xpack/plugins/cloud/models.py:363
+#: xpack/plugins/cloud/models.py:364
msgid "Not Equal"
msgstr ""
-#: xpack/plugins/cloud/models.py:364
+#: xpack/plugins/cloud/models.py:365
msgid "In"
msgstr ""
-#: xpack/plugins/cloud/models.py:365
+#: xpack/plugins/cloud/models.py:366
msgid "Contains"
msgstr ""
-#: xpack/plugins/cloud/models.py:366
+#: xpack/plugins/cloud/models.py:367
msgid "Exclude"
msgstr ""
-#: xpack/plugins/cloud/models.py:367
+#: xpack/plugins/cloud/models.py:368
msgid "Startswith"
msgstr ""
-#: xpack/plugins/cloud/models.py:368
+#: xpack/plugins/cloud/models.py:369
msgid "Endswith"
msgstr ""
-#: xpack/plugins/cloud/models.py:374
+#: xpack/plugins/cloud/models.py:375
msgid "Instance platform"
msgstr ""
-#: xpack/plugins/cloud/models.py:375
+#: xpack/plugins/cloud/models.py:376
msgid "Instance address"
msgstr ""
-#: xpack/plugins/cloud/models.py:382
+#: xpack/plugins/cloud/models.py:383
msgid "Rule attr"
msgstr ""
-#: xpack/plugins/cloud/models.py:386
+#: xpack/plugins/cloud/models.py:387
msgid "Rule match"
msgstr ""
-#: xpack/plugins/cloud/models.py:388
+#: xpack/plugins/cloud/models.py:389
msgid "Rule value"
msgstr ""
-#: xpack/plugins/cloud/models.py:395 xpack/plugins/cloud/serializers/task.py:82
+#: xpack/plugins/cloud/models.py:396 xpack/plugins/cloud/serializers/task.py:82
msgid "Strategy rule"
msgstr ""
-#: xpack/plugins/cloud/models.py:406
+#: xpack/plugins/cloud/models.py:407
msgid "Name strategy"
msgstr ""
-#: xpack/plugins/cloud/models.py:413
+#: xpack/plugins/cloud/models.py:414
msgid "Action attr"
msgstr ""
-#: xpack/plugins/cloud/models.py:415
+#: xpack/plugins/cloud/models.py:416
msgid "Action value"
msgstr ""
-#: xpack/plugins/cloud/models.py:422 xpack/plugins/cloud/serializers/task.py:85
+#: xpack/plugins/cloud/models.py:423 xpack/plugins/cloud/serializers/task.py:85
msgid "Strategy action"
msgstr ""
@@ -12066,38 +12167,38 @@ msgstr ""
msgid "Restore default successfully."
msgstr ""
-#: xpack/plugins/interface/meta.py:9 xpack/plugins/interface/models.py:47
-#: xpack/plugins/interface/models.py:91
+#: xpack/plugins/interface/meta.py:9 xpack/plugins/interface/models.py:49
+#: xpack/plugins/interface/models.py:104
msgid "Interface settings"
msgstr ""
-#: xpack/plugins/interface/models.py:24
+#: xpack/plugins/interface/models.py:26
msgid "Login title"
msgstr ""
-#: xpack/plugins/interface/models.py:28
+#: xpack/plugins/interface/models.py:30
msgid "Login image"
msgstr ""
-#: xpack/plugins/interface/models.py:32
+#: xpack/plugins/interface/models.py:34
msgid "Website icon"
msgstr ""
-#: xpack/plugins/interface/models.py:36
+#: xpack/plugins/interface/models.py:38
msgid "Index logo"
msgstr ""
-#: xpack/plugins/interface/models.py:40
+#: xpack/plugins/interface/models.py:42
msgid "Logout logo"
msgstr ""
-#: xpack/plugins/interface/models.py:43
+#: xpack/plugins/interface/models.py:45
msgid "Footer content"
msgstr ""
-#: xpack/plugins/interface/models.py:44
+#: xpack/plugins/interface/models.py:46
#: xpack/plugins/interface/serializers/interface.py:73
-msgid "Extended fields"
+msgid "Extend"
msgstr ""
#: xpack/plugins/interface/serializers/interface.py:48
@@ -12140,7 +12241,7 @@ msgstr ""
#: xpack/plugins/interface/templates/login_i18n.html:22
msgid "More login methods"
-msgstr "Or"
+msgstr ""
#: xpack/plugins/jdmc/i18n.py:4
msgid "AuditAdmin"
diff --git a/apps/i18n/core/es/LC_MESSAGES/django.po b/apps/i18n/core/es/LC_MESSAGES/django.po
index e40f01150..7daa979f2 100644
--- a/apps/i18n/core/es/LC_MESSAGES/django.po
+++ b/apps/i18n/core/es/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-04-21 17:03+0800\n"
+"POT-Creation-Date: 2026-05-25 14:02+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -28,7 +28,7 @@ msgstr "La cuenta ya existe"
msgid "No valid assets found for account creation."
msgstr "No se encontraron activos válidos disponibles para crear una cuenta."
-#: accounts/api/account/application.py:77
+#: accounts/api/account/application.py:87
#: authentication/api/connection_token.py:463
msgid "Account not found"
msgstr "Cuenta no encontrada"
@@ -43,15 +43,15 @@ msgid "The account key will be split into two parts and sent"
msgstr ""
"La clave de la cuenta se enviará en dos partes, la anterior y la posterior"
-#: accounts/automations/backup_account/handlers.py:131
+#: accounts/automations/backup_account/handlers.py:132
msgid "Number of backup accounts"
msgstr "Cantidad de cuentas de respaldo"
-#: accounts/automations/backup_account/handlers.py:152
+#: accounts/automations/backup_account/handlers.py:153
msgid "Generating asset related backup information files"
msgstr "Generar archivo de información de respaldo relacionado con activos"
-#: accounts/automations/backup_account/handlers.py:177
+#: accounts/automations/backup_account/handlers.py:178
#: accounts/automations/backup_account/manager.py:26
#: accounts/automations/change_secret/manager.py:81
#: accounts/automations/push_account/manager.py:62
@@ -62,31 +62,31 @@ msgstr "Generar archivo de información de respaldo relacionado con activos"
msgid "Duration"
msgstr "Tiempo transcurrido"
-#: accounts/automations/backup_account/handlers.py:178
+#: accounts/automations/backup_account/handlers.py:179
msgid "Backup file creation completed"
msgstr "Creación del archivo de respaldo completada"
-#: accounts/automations/backup_account/handlers.py:186
+#: accounts/automations/backup_account/handlers.py:187
msgid "Start sending backup emails"
msgstr "Comenzando el envío del correo electrónico de respaldo"
-#: accounts/automations/backup_account/handlers.py:213
+#: accounts/automations/backup_account/handlers.py:214
msgid "Encrypting files using encryption password"
msgstr "Cifrando el archivo con contraseña encriptada"
-#: accounts/automations/backup_account/handlers.py:223
+#: accounts/automations/backup_account/handlers.py:224
msgid "The backup file will be sent to"
msgstr "El archivo de respaldo será enviado a"
-#: accounts/automations/backup_account/handlers.py:246
+#: accounts/automations/backup_account/handlers.py:247
msgid "The backup task has no assigned sftp server"
msgstr "Esta tarea de respaldo no tiene servidor SFTP asignado"
-#: accounts/automations/backup_account/handlers.py:267
+#: accounts/automations/backup_account/handlers.py:268
msgid "The backup task has no assigned recipient"
msgstr "La tarea de respaldo no tiene destinatario especificado"
-#: accounts/automations/backup_account/handlers.py:290
+#: accounts/automations/backup_account/handlers.py:291
msgid "Plan start"
msgstr "Tarea iniciada"
@@ -179,7 +179,7 @@ msgstr ""
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -253,7 +253,7 @@ msgstr "Actualizar"
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr "Fallido"
@@ -375,14 +375,14 @@ msgstr "SFTP"
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "éxito"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr "pendiente"
@@ -390,7 +390,7 @@ msgstr "pendiente"
msgid "Queued"
msgstr "En cola"
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr "Preparar"
@@ -402,7 +402,7 @@ msgstr "En proceso"
msgid "Can login"
msgstr "se puede iniciar sesión"
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr "superusuario"
@@ -431,7 +431,7 @@ msgid "Default tablespace"
msgstr "espacio de tablas predeterminado"
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr "rol"
@@ -440,7 +440,7 @@ msgid "Perms"
msgstr "Permisos"
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr "Grupo de usuarios"
@@ -815,7 +815,7 @@ msgstr "Fecha de finalización"
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -830,7 +830,7 @@ msgstr "Estado"
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr "Error"
@@ -925,8 +925,9 @@ msgstr "Contraseña duplicada"
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1086,7 +1087,7 @@ msgstr "cuenta privilegiada."
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "Activación"
@@ -1102,7 +1103,7 @@ msgstr "Plataforma"
msgid "Push params"
msgstr "Parámetros de envío de cuentas"
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr "Plantilla de cuentas"
@@ -1203,7 +1204,7 @@ msgid "Change secret or push account failed information"
msgstr ""
"información sobre fallos en el cambio de contraseña o en la cuenta de envío"
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr "Ignorar"
@@ -1359,7 +1360,7 @@ msgstr "ID"
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1367,8 +1368,8 @@ msgstr "ID"
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr "Usuario"
@@ -1403,7 +1404,7 @@ msgstr "Lista blanca de IP"
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1713,7 +1714,7 @@ msgstr ""
"límites establecidos en la configuración del almacenamiento de cuentas a las "
"2 de la mañana todos los días"
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr "Eliminar cuentas históricas que estén fuera de rango."
@@ -1798,7 +1799,7 @@ msgstr "Nombre de la tarea"
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1986,7 +1987,7 @@ msgstr "Persona aprobadora"
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr "Usuario"
@@ -2012,7 +2013,7 @@ msgid "Command"
msgstr "Comando"
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr "Expresión regular"
@@ -2101,7 +2102,7 @@ msgstr "Reglas"
msgid "Login acl"
msgstr "Control de acceso al inicio de sesión"
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr "Revisión de inicio de sesión"
@@ -2224,7 +2225,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr "IP"
@@ -2291,16 +2292,16 @@ msgstr ""
msgid "User details"
msgstr "Detalles del usuario"
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr ""
"No se puede crear activos directamente, debes crear un host u otro activo"
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr "La cantidad de activos ha superado el límite de 5000"
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
#, fuzzy
#| msgid "The number of assets exceeds the limit of 5000"
msgid "The number of assets exceeds the license limit"
@@ -2319,6 +2320,11 @@ msgstr "No se puede eliminar el nodo raíz ({})"
msgid "Deletion failed and the node contains assets"
msgstr "Eliminación fallida, el nodo contiene activos"
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr "Los nombres de los nodos de igual nivel no pueden repetirse"
@@ -2336,30 +2342,30 @@ msgstr "Gestión de activos"
msgid "Task: {} finished"
msgstr "Tarea: {} Completado"
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr ""
"- Plataforma {} Ansible está deshabilitada, no se pueden ejecutar tareas"
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr ">>> Etapa de preparación de tareas"
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ">>> Ejecución de tareas por fases, un total de {runner_count}"
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ">>> Comenzando la ejecución de tareas"
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ">>> No hay tareas que ejecutar"
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ">>> Comenzando a ejecutar el lote de tareas número {index}"
@@ -2771,7 +2777,7 @@ msgid "Port"
msgstr "Puerto"
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr "Dirección"
@@ -2779,12 +2785,12 @@ msgstr "Dirección"
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr "Plataforma"
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr "Dominio"
@@ -2853,9 +2859,9 @@ msgid "Proxy"
msgstr "Proxy"
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr "Nodo"
@@ -2879,7 +2885,7 @@ msgstr "Tareas de automatización de activos"
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr "Fecha de creación"
@@ -2968,7 +2974,7 @@ msgstr "Puerta de enlace"
msgid "System"
msgstr "Sistema"
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2983,7 +2989,7 @@ msgstr "Valor"
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr "Etiqueta"
@@ -2999,27 +3005,27 @@ msgstr "Nota personalizada"
msgid "My assets"
msgstr "Mis activos"
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr "Nodo nuevo"
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr "Vacío"
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr "Clave"
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr "Nombre completo"
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr "ssh clave privada"
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr "puede coincidir con nodo"
@@ -3199,7 +3205,7 @@ msgstr ""
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr "Grupo de protocolos"
@@ -3664,7 +3670,7 @@ msgid "Symlink"
msgstr "Establecer enlace simbólico"
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr "Descargar"
@@ -3693,7 +3699,9 @@ msgstr "Exportar"
msgid "Connect"
msgstr "Conectar"
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4502,17 +4510,17 @@ msgstr "El emparejamiento facial ha fallado."
msgid "Current user not support mfa type: {}"
msgstr "El usuario actual no es compatible con el tipo de MFA: {}"
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr "El usuario no existe: {}"
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr "No se encontró coincidencia con el usuario"
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
@@ -4521,7 +4529,7 @@ msgstr ""
"El usuario proviene de {} por favor, modifica la contraseña en el sistema "
"correspondiente"
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4531,7 +4539,7 @@ msgstr ""
msgid "Forgot password"
msgstr "Olvidé la contraseña"
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr "El código de verificación tiene una validez de {} minuto."
@@ -4544,10 +4552,29 @@ msgstr "Gestión de autenticación"
msgid "CAS Error"
msgstr "Error CAS"
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
-msgstr "Usuario no válido, ha sido desactivado o ha expirado"
+#: authentication/backends/cert/api.py:57
+#, fuzzy
+#| msgid "LDAP authentication is not enabled"
+msgid "Certificate enrollment is not enabled"
+msgstr "La autenticación LDAP no está habilitada"
+
+#: authentication/backends/cert/api.py:62
+#, fuzzy
+#| msgid "type is required"
+msgid "CSR is required"
+msgstr "Tipo Este campo es obligatorio."
+
+#: authentication/backends/cert/api.py:68
+#, fuzzy
+#| msgid "Authentication failed"
+msgid "Certificate signing failed"
+msgstr "Autenticación fallida"
+
+#: authentication/backends/cert/views.py:97
+#, fuzzy
+#| msgid "Invalid data"
+msgid "Invalid credentials"
+msgstr "Datos no válidos"
#: authentication/backends/drf.py:61
msgid "Invalid token header. No credentials provided."
@@ -4802,18 +4829,18 @@ msgstr "Tu contraseña es inválida"
msgid "Please wait for %s seconds before retry"
msgstr "Por favor, inténtalo de nuevo en %s segundos"
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr ""
"Tu contraseña es demasiado simple, por razones de seguridad, modifícala"
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr ""
"Antes de completar el inicio de sesión, por favor, modifique su contraseña."
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr "Su contraseña ha expirado; modifíquela antes de iniciar sesión."
@@ -4950,11 +4977,11 @@ msgstr ""
"existentes', el usuario actual no está en la lista de usuarios, por favor "
"contacta al administrador."
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr "Usuario no válido"
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4965,12 +4992,12 @@ msgstr ""
"fuente de usuarios', la fuente del usuario actual es {}, por favor contacta "
"al administrador."
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr "El método MFA ({}) no está habilitado"
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr "Por favor, modifica la contraseña"
@@ -5162,7 +5189,7 @@ msgstr "Action"
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "Expirado"
@@ -5204,13 +5231,13 @@ msgstr "Clave SSH no válida"
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "¿Es válida?"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr "Rango"
@@ -5313,7 +5340,7 @@ msgstr "Código de error"
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5425,6 +5452,87 @@ msgstr ""
msgid "Cancel"
msgstr "Cancelar"
+#: authentication/templates/authentication/cert_login.html:190
+#, fuzzy
+#| msgid "Multi-Factor Authentication"
+msgid "Certificate Authentication"
+msgstr "Autenticación"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:238
+#, fuzzy
+#| msgid "More login options"
+msgid "Other login methods"
+msgstr "Otras formas de iniciar sesión"
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:253
+#, fuzzy
+#| msgid "Please enter SMS code"
+msgid "Please insert USB Key"
+msgstr "Introduce el código de verificación por SMS"
+
+#: authentication/templates/authentication/cert_login.html:254
+#, fuzzy
+#| msgid "Account unavailable"
+msgid "Driver unavailable"
+msgstr "Cuenta no válida"
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:257
+#, fuzzy
+#| msgid "Date verified"
+msgid "PIN verified"
+msgstr "Fecha de verificación"
+
+#: authentication/templates/authentication/cert_login.html:258
+#, fuzzy
+#| msgid "OTP verification code"
+msgid "PIN verification failed"
+msgstr "Código de verificación MFA virtual"
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:260
+#, fuzzy
+#| msgid "Signing key"
+msgid "Signing failed"
+msgstr "Firma clave"
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:262
+#, fuzzy
+#| msgid "Your account has expired, please contact the administrator."
+msgid "No certificate detected, please contact administrator"
+msgstr "Su cuenta ha expirado, por favor contacte al administrador."
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr "Reintentar"
@@ -5500,6 +5608,10 @@ msgstr "¿Reintentar?"
msgid "LAN"
msgstr "Red local"
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5668,47 +5780,47 @@ msgstr ""
msgid "Request file format may be wrong"
msgstr "Formato de archivo subido incorrecto o archivo de otro tipo de recurso"
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr "China"
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr "Acción manual"
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr "Acción programada"
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr "En ejecución"
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr "Cancelar"
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr "Confirmar"
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr "Versión comunitaria"
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr "Versión básica empresarial"
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr "Versión estándar empresarial"
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr "Versión profesional empresarial"
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr "Versión insignia empresarial"
@@ -6229,24 +6341,24 @@ msgstr "No se encontró el Código"
msgid "The message code provided is invalid or has expired"
msgstr "El código de mensaje proporcionado es inválido o ha expirado"
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr "El código de verificación es: {code}"
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr "Creación de cuenta exitosa"
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr "Tu cuenta ha sido creada con éxito"
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "JumpServer, bastión de código abierto."
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -7033,7 +7145,7 @@ msgid "Please save in a org"
msgstr "Por favor, seleccione una organización antes de guardar."
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -7461,15 +7573,15 @@ msgstr "Rol del sistema"
msgid "Organization role"
msgstr "Rol de la organización"
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr "Vinculación de roles"
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr "Todas las organizaciones"
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
@@ -7477,11 +7589,11 @@ msgstr ""
"El último rol del usuario no se puede eliminar, pero puedes quitar al "
"usuario de la organización"
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr "Rol de organización vinculado"
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr "Rol del sistema vinculado"
@@ -7546,7 +7658,7 @@ msgid "Storage"
msgstr "Almacenamiento"
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr "Aplicación remota"
@@ -7609,51 +7721,51 @@ msgstr "Revocar token de acceso"
msgid "Range days"
msgstr "Modificador"
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr "Informe de inicio de sesión de usuarios"
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr "Informe de cambio de contraseña de usuarios"
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr "Informe de estadísticas de activos"
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr "Informe de actividades de activos"
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr "Informe de estadísticas de cuentas"
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr "Informe de automatización de cuentas"
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr "Tablero de consola"
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr "Tablero de auditoría"
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr "Tablero PAM"
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr "Tablero de cambio de contraseña de cuenta"
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr "Error al enviar el correo electrónico"
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr "Envío de correo electrónico exitoso"
@@ -7962,8 +8074,8 @@ msgstr "Habilitar autenticación de DingTalk"
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
"Mapeo de atributos de usuario, donde `key` es el nombre del atributo de "
"usuario del sistema, y `value` es el nombre del atributo de usuario del "
@@ -7971,8 +8083,8 @@ msgstr ""
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
"Mapeo de atributos de usuario, donde `key` es el nombre del atributo de "
"usuario del sistema, y `value` es el nombre del atributo de usuario del "
@@ -7984,8 +8096,8 @@ msgstr "Lark"
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
"Mapeo de atributos de usuario, donde `key` es el nombre del atributo de "
"usuario del sistema y `value` es el nombre del atributo de usuario del "
@@ -8055,8 +8167,8 @@ msgstr "Las posibles opciones son (cn o uid o sAMAccountName=%(user)s)"
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
"Mapeo de atributos de usuario, donde `key` es el nombre del atributo del "
"usuario del sistema, y `value` es el nombre del atributo del usuario en el "
@@ -8169,8 +8281,8 @@ msgstr ""
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
"Mapeo de atributos del usuario, donde `key` es el nombre del atributo de "
"usuario del sistema y `value` es el nombre del atributo de usuario del "
@@ -8208,8 +8320,8 @@ msgstr "Ignorar la verificación del certificado SSL"
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
"Mapeo de atributos de usuario, donde `key` es el nombre del atributo de "
"usuario del sistema y `value` es el nombre del atributo de usuario del "
@@ -8359,8 +8471,8 @@ msgstr "Al salir, los usuarios también se desconectarán del servidor SAML2"
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
"Mapeo de atributos de usuario, donde `key` es el nombre del atributo de "
"usuario del sistema y `value` es el nombre del atributo de usuario del "
@@ -8398,7 +8510,7 @@ msgid "Template code"
msgstr "Plantilla"
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr "Teléfono móvil"
@@ -8456,7 +8568,10 @@ msgid "Enable SSO auth"
msgstr "Habilitar autenticación con token SSO"
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
+#, fuzzy
+#| msgid ""
+#| "Other service can using SSO token login to JumpServer without password"
+msgid "Other service can using SSO token login to system without password"
msgstr ""
"Otros sistemas pueden integrarse con JumpServer utilizando el Token SSO, "
"eliminando el proceso de inicio de sesión"
@@ -8472,8 +8587,8 @@ msgstr "Unidad: segundos"
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
"Mapeo de atributos de usuario, donde `key` es el nombre del atributo del "
"usuario del sistema y `value` es el nombre del atributo del usuario del "
@@ -9731,7 +9846,7 @@ msgstr "El código de verificación ha sido enviado"
msgid "The verification code has been sent"
msgstr "Página principal"
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "Cliente"
@@ -10000,31 +10115,31 @@ msgstr "puede ejecutarse en paralelo"
msgid "Hosts"
msgstr "host"
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr "Paquete Applet inválido, falta el archivo {}"
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr "Error al cargar platform.yml: {}"
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr "Solo se admite plataforma personalizada"
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr "Falta tipo en el platform.yml"
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "Máquina anfitriona"
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr "Lanzamiento de la aplicación"
@@ -10128,7 +10243,7 @@ msgstr "Puerto de VNC"
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -10342,8 +10457,8 @@ msgstr "Almacenamiento de comandos y grabaciones"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr "Prueba fallida: cuenta no válida"
@@ -10465,11 +10580,13 @@ msgstr "Licencia RDS ya existente"
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
"Si no existe, RDS estará en modo de prueba, con un período de prueba de 120 "
"días. Más detalles"
+"remote-desktop-services/rds-client-access-license' target='_blank'>Más "
+"detalles"
#: terminal/serializers/applet_host.py:55
msgid "RDS License Server"
@@ -10598,7 +10715,7 @@ msgstr "ID de sesión no válido"
msgid "Timestamp"
msgstr "Marca de tiempo"
-#: terminal/serializers/endpoint.py:27
+#: terminal/serializers/endpoint.py:28
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 "
@@ -10608,7 +10725,7 @@ msgstr ""
"utilizará la dirección de acceso del navegador actual (el punto final por "
"defecto no permite modificar el host)"
-#: terminal/serializers/endpoint.py:54
+#: terminal/serializers/endpoint.py:64
msgid ""
"The assets within this IP range or Host, the following endpoint will be used "
"for the connection"
@@ -10616,7 +10733,7 @@ msgstr ""
"Los activos dentro de este rango de IP o de este host se conectarán "
"utilizando el siguiente punto final."
-#: terminal/serializers/endpoint.py:55
+#: terminal/serializers/endpoint.py:65
msgid ""
"If asset IP addresses under different endpoints conflict, use asset labels"
msgstr ""
@@ -10757,7 +10874,7 @@ msgstr "En línea"
msgid "Stat"
msgstr "Estado"
-#: terminal/serializers/terminal.py:83 terminal/serializers/terminal.py:91
+#: terminal/serializers/terminal.py:79 terminal/serializers/terminal.py:87
msgid "Not found"
msgstr "No se encontró"
@@ -11360,7 +11477,7 @@ msgstr "Solicitante"
msgid "Approval Step Distribution"
msgstr "Aprobación sin inicio de sesión"
-#: tickets/serializers/flow.py:45
+#: tickets/serializers/flow.py:42
msgid "The current organization type already exists"
msgstr "El tipo ya existe en la organización actual"
@@ -11421,7 +11538,7 @@ msgid "Ticket information"
msgstr "Información de la orden de trabajo"
#: tickets/templates/tickets/approve_check_password.html:28
-#: tickets/views/approve.py:43 tickets/views/approve.py:80
+#: tickets/views/approve.py:42 tickets/views/approve.py:80
msgid "Ticket approval"
msgstr "Aprobación de la orden de trabajo"
@@ -11429,14 +11546,14 @@ msgstr "Aprobación de la orden de trabajo"
msgid "Approval"
msgstr "Aceptar"
-#: tickets/views/approve.py:44
+#: tickets/views/approve.py:43
msgid ""
"This ticket does not exist, the process has ended, or this link has expired"
msgstr ""
"La orden de trabajo no existe, o el proceso de la orden de trabajo ha "
"finalizado, o este enlace ha expirado"
-#: tickets/views/approve.py:72
+#: tickets/views/approve.py:71
msgid "Click the button below to approve or reject"
msgstr "Haga clic en el botón de abajo para aceptar o rechazar"
@@ -11657,7 +11774,7 @@ msgstr "Configuración del usuario"
msgid "Email lookup"
msgstr "Cuenta de correo electrónico"
-#: users/models/user/__init__.py:82 users/serializers/user.py:259
+#: users/models/user/__init__.py:82 users/serializers/user.py:264
msgid "Is service account"
msgstr "Cuenta de servicio"
@@ -11674,7 +11791,7 @@ msgid "OTP secret key"
msgstr "Clave OTP"
#: users/models/user/__init__.py:105 users/serializers/profile.py:86
-#: users/serializers/user.py:256
+#: users/serializers/user.py:261
msgid "Is first login"
msgstr "Primer inicio de sesión"
@@ -11694,23 +11811,23 @@ msgstr "Vector facial"
msgid "Date api key used"
msgstr "Fecha de último uso de la API key"
-#: users/models/user/__init__.py:293
+#: users/models/user/__init__.py:298
msgid "Can not delete admin user"
msgstr "No se puede eliminar al usuario administrador"
-#: users/models/user/__init__.py:307
+#: users/models/user/__init__.py:312
msgid "Can invite user"
msgstr "Se puede invitar a usuarios"
-#: users/models/user/__init__.py:308
+#: users/models/user/__init__.py:313
msgid "Can remove user"
msgstr "Se puede eliminar a usuarios"
-#: users/models/user/__init__.py:309
+#: users/models/user/__init__.py:314
msgid "Can match user"
msgstr "Se puede hacer coincidir a usuarios"
-#: users/models/user/__init__.py:338
+#: users/models/user/__init__.py:343
msgid "User password history"
msgstr "Historial de contraseñas de usuarios"
@@ -11718,6 +11835,12 @@ msgstr "Historial de contraseñas de usuarios"
msgid "Force enabled"
msgstr "Activación forzada"
+#: users/models/user/_source.py:27
+#, fuzzy
+#| msgid "Authenticate"
+msgid "Certificate"
+msgstr "Verificar identidad"
+
#: users/notifications.py:23 users/notifications.py:68
msgid "Reset password url"
msgstr "URL de reinicio de contraseña"
@@ -11831,7 +11954,7 @@ msgstr "Carga asíncrona del árbol de activos"
msgid "Connect default open method"
msgstr "Forma predeterminada de apertura de conexión"
-#: users/serializers/preference/luna.py:34 xpack/plugins/interface/models.py:42
+#: users/serializers/preference/luna.py:34 xpack/plugins/interface/models.py:44
#: xpack/plugins/interface/serializers/interface.py:35
msgid "Theme"
msgstr "Tema"
@@ -11947,7 +12070,7 @@ msgstr "Forzar MFA"
msgid "Login blocked"
msgstr "Inicio de sesión bloqueado"
-#: users/serializers/user.py:130 users/serializers/user.py:265
+#: users/serializers/user.py:130 users/serializers/user.py:270
msgid "Is OTP bound"
msgstr "¿Está vinculado a un MFA virtual?"
@@ -11963,27 +12086,33 @@ msgstr "Administrador de la organización"
msgid "Can public key authentication"
msgstr "Pueden usar autenticación de clave pública"
-#: users/serializers/user.py:144
+#: users/serializers/user.py:145
+#, fuzzy
+#| msgid "Can public key authentication"
+msgid "Can certificate authentication"
+msgstr "Pueden usar autenticación de clave pública"
+
+#: users/serializers/user.py:149
msgid "Is face code set"
msgstr "¿Existen características faciales?"
-#: users/serializers/user.py:230
+#: users/serializers/user.py:235
msgid "Full name"
msgstr "Nombre completo"
-#: users/serializers/user.py:233
+#: users/serializers/user.py:238
msgid "Login username"
msgstr "Usuario que inicia sesión"
-#: users/serializers/user.py:236
+#: users/serializers/user.py:241
msgid "Email address"
msgstr "Dirección de correo electrónico"
-#: users/serializers/user.py:246
+#: users/serializers/user.py:251
msgid "User groups to join"
msgstr "Cantidad de grupos de usuarios"
-#: users/serializers/user.py:250
+#: users/serializers/user.py:255
msgid ""
"User source identifies where the user was created, which could be AD or "
"other sources.There are security settings that can restrict users to log in "
@@ -11994,34 +12123,34 @@ msgstr ""
"usuarios para que solo inicien sesión en el sistema desde fuentes "
"específicas."
-#: users/serializers/user.py:260
+#: users/serializers/user.py:265
msgid "Is org admin"
msgstr "Administrador de la organización"
-#: users/serializers/user.py:262
+#: users/serializers/user.py:267
msgid "Avatar url"
msgstr "Ruta del avatar"
-#: users/serializers/user.py:267
+#: users/serializers/user.py:272
msgid "MFA level"
msgstr "MFA"
-#: users/serializers/user.py:268
+#: users/serializers/user.py:273
msgid "Multi-Factor Authentication"
msgstr "Autenticación"
-#: users/serializers/user.py:398
+#: users/serializers/user.py:403
msgid "Has public keys"
msgstr "Hay clave pública"
-#: users/serializers/user.py:426
+#: users/serializers/user.py:431
msgid ""
"* For security, only a partial of users is displayed. You can search for more"
msgstr ""
"* Por razones de seguridad, solo se muestran algunos usuarios. Puedes buscar "
"más"
-#: users/serializers/user.py:462
+#: users/serializers/user.py:467
msgid "name not unique"
msgstr "Nombres duplicados"
@@ -12545,7 +12674,7 @@ msgstr "IP Privada"
msgid "Public IP"
msgstr "IP público"
-#: xpack/plugins/cloud/const.py:50 xpack/plugins/cloud/models.py:373
+#: xpack/plugins/cloud/const.py:50 xpack/plugins/cloud/models.py:374
msgid "Instance name"
msgstr "Nombre de la instancia"
@@ -12746,8 +12875,8 @@ msgstr "Publicar activo"
msgid "Date last sync"
msgstr "Fecha de Última Sincronización"
-#: xpack/plugins/cloud/models.py:135 xpack/plugins/cloud/models.py:391
-#: xpack/plugins/cloud/models.py:418
+#: xpack/plugins/cloud/models.py:135 xpack/plugins/cloud/models.py:392
+#: xpack/plugins/cloud/models.py:419
msgid "Strategy"
msgstr "Estrategia"
@@ -12787,71 +12916,71 @@ msgstr "Relación de condiciones"
msgid "Task strategy"
msgstr "Estrategia de tareas"
-#: xpack/plugins/cloud/models.py:362
+#: xpack/plugins/cloud/models.py:363
msgid "Equal"
msgstr "Igual a"
-#: xpack/plugins/cloud/models.py:363
+#: xpack/plugins/cloud/models.py:364
msgid "Not Equal"
msgstr "No igual a"
-#: xpack/plugins/cloud/models.py:364
+#: xpack/plugins/cloud/models.py:365
msgid "In"
msgstr "En..."
-#: xpack/plugins/cloud/models.py:365
+#: xpack/plugins/cloud/models.py:366
msgid "Contains"
msgstr "Contener"
-#: xpack/plugins/cloud/models.py:366
+#: xpack/plugins/cloud/models.py:367
msgid "Exclude"
msgstr "Excluir"
-#: xpack/plugins/cloud/models.py:367
+#: xpack/plugins/cloud/models.py:368
msgid "Startswith"
msgstr "Comenzar con..."
-#: xpack/plugins/cloud/models.py:368
+#: xpack/plugins/cloud/models.py:369
msgid "Endswith"
msgstr "Terminar con..."
-#: xpack/plugins/cloud/models.py:374
+#: xpack/plugins/cloud/models.py:375
msgid "Instance platform"
msgstr "Plataforma de instancia"
-#: xpack/plugins/cloud/models.py:375
+#: xpack/plugins/cloud/models.py:376
msgid "Instance address"
msgstr "Dirección de instancia"
-#: xpack/plugins/cloud/models.py:382
+#: xpack/plugins/cloud/models.py:383
msgid "Rule attr"
msgstr "Atributos de regla"
-#: xpack/plugins/cloud/models.py:386
+#: xpack/plugins/cloud/models.py:387
msgid "Rule match"
msgstr "Coincidencia de regla"
-#: xpack/plugins/cloud/models.py:388
+#: xpack/plugins/cloud/models.py:389
msgid "Rule value"
msgstr "Valor de regla"
-#: xpack/plugins/cloud/models.py:395 xpack/plugins/cloud/serializers/task.py:82
+#: xpack/plugins/cloud/models.py:396 xpack/plugins/cloud/serializers/task.py:82
msgid "Strategy rule"
msgstr "Condición"
-#: xpack/plugins/cloud/models.py:406
+#: xpack/plugins/cloud/models.py:407
msgid "Name strategy"
msgstr "Estrategia de nombre de host"
-#: xpack/plugins/cloud/models.py:413
+#: xpack/plugins/cloud/models.py:414
msgid "Action attr"
msgstr "Atributos de acción"
-#: xpack/plugins/cloud/models.py:415
+#: xpack/plugins/cloud/models.py:416
msgid "Action value"
msgstr "Valor de acción"
-#: xpack/plugins/cloud/models.py:422 xpack/plugins/cloud/serializers/task.py:85
+#: xpack/plugins/cloud/models.py:423 xpack/plugins/cloud/serializers/task.py:85
msgid "Strategy action"
msgstr "Acción"
@@ -13231,38 +13360,38 @@ msgstr "La misión aún no ha comenzado."
msgid "Restore default successfully."
msgstr "¡Restauración predeterminada exitosa!"
-#: xpack/plugins/interface/meta.py:9 xpack/plugins/interface/models.py:47
-#: xpack/plugins/interface/models.py:91
+#: xpack/plugins/interface/meta.py:9 xpack/plugins/interface/models.py:49
+#: xpack/plugins/interface/models.py:104
msgid "Interface settings"
msgstr "Configuración de la interfaz"
-#: xpack/plugins/interface/models.py:24
+#: xpack/plugins/interface/models.py:26
msgid "Login title"
msgstr "Título de la página de inicio de sesión"
-#: xpack/plugins/interface/models.py:28
+#: xpack/plugins/interface/models.py:30
msgid "Login image"
msgstr "Imagen de la página de inicio de sesión"
-#: xpack/plugins/interface/models.py:32
+#: xpack/plugins/interface/models.py:34
msgid "Website icon"
msgstr "Ícono del sitio web"
-#: xpack/plugins/interface/models.py:36
+#: xpack/plugins/interface/models.py:38
msgid "Index logo"
msgstr "Logo de la página de gestión"
-#: xpack/plugins/interface/models.py:40
+#: xpack/plugins/interface/models.py:42
msgid "Logout logo"
msgstr "Cerrar sesión"
-#: xpack/plugins/interface/models.py:43
+#: xpack/plugins/interface/models.py:45
msgid "Footer content"
msgstr "Contenido del pie de página"
-#: xpack/plugins/interface/models.py:44
+#: xpack/plugins/interface/models.py:46
#: xpack/plugins/interface/serializers/interface.py:73
-msgid "Extended fields"
+msgid "Extend"
msgstr ""
#: xpack/plugins/interface/serializers/interface.py:48
@@ -13317,6 +13446,18 @@ msgstr ""
msgid "More login methods"
msgstr "Otras formas de iniciar sesión"
+#: xpack/plugins/jdmc/i18n.py:4
+#, fuzzy
+#| msgid "Audit view"
+msgid "AuditAdmin"
+msgstr "Registro de auditoría"
+
+#: xpack/plugins/jdmc/i18n.py:5
+#, fuzzy
+#| msgid "SystemAdmin"
+msgid "SecAdmin"
+msgstr "Administrador del sistema"
+
#: xpack/plugins/jdmc/meta.py:9
msgid "JDMC"
msgstr ""
@@ -13329,6 +13470,9 @@ msgstr "Importación de licencia exitosa"
msgid "Invalid license"
msgstr "Licencia no válida"
+#~ msgid "User invalid, disabled or expired"
+#~ msgstr "Usuario no válido, ha sido desactivado o ha expirado"
+
#~ msgid "Microsoft"
#~ msgstr "Microsoft"
diff --git a/apps/i18n/core/ja/LC_MESSAGES/django.po b/apps/i18n/core/ja/LC_MESSAGES/django.po
index 3519b9357..968f81b91 100644
--- a/apps/i18n/core/ja/LC_MESSAGES/django.po
+++ b/apps/i18n/core/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: 2026-04-21 17:03+0800\n"
+"POT-Creation-Date: 2026-05-25 14:02+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -28,7 +28,7 @@ msgstr "アカウントはすでに存在しています"
msgid "No valid assets found for account creation."
msgstr "アカウント作成に使用できる有効な資産が見つかりませんでした。"
-#: accounts/api/account/application.py:77
+#: accounts/api/account/application.py:87
#: authentication/api/connection_token.py:463
msgid "Account not found"
msgstr "アカウントが見つかりません"
@@ -42,15 +42,15 @@ msgstr "パラメータ 'action' は [{}] でなければなりません。"
msgid "The account key will be split into two parts and sent"
msgstr "アカウントの秘密鍵は、前後二部に分けられて送信されます"
-#: accounts/automations/backup_account/handlers.py:131
+#: accounts/automations/backup_account/handlers.py:132
msgid "Number of backup accounts"
msgstr "バックアップアカウントの数"
-#: accounts/automations/backup_account/handlers.py:152
+#: accounts/automations/backup_account/handlers.py:153
msgid "Generating asset related backup information files"
msgstr "資産関連のバックアップ情報ファイルを生成"
-#: accounts/automations/backup_account/handlers.py:177
+#: accounts/automations/backup_account/handlers.py:178
#: accounts/automations/backup_account/manager.py:26
#: accounts/automations/change_secret/manager.py:81
#: accounts/automations/push_account/manager.py:62
@@ -61,31 +61,31 @@ msgstr "資産関連のバックアップ情報ファイルを生成"
msgid "Duration"
msgstr "時を過ごす"
-#: accounts/automations/backup_account/handlers.py:178
+#: accounts/automations/backup_account/handlers.py:179
msgid "Backup file creation completed"
msgstr "バックアップファイルの作成が完了しました"
-#: accounts/automations/backup_account/handlers.py:186
+#: accounts/automations/backup_account/handlers.py:187
msgid "Start sending backup emails"
msgstr "バックアップメールの送信を開始する"
-#: accounts/automations/backup_account/handlers.py:213
+#: accounts/automations/backup_account/handlers.py:214
msgid "Encrypting files using encryption password"
msgstr "暗号化パスワードを使用してファイルを暗号化中"
-#: accounts/automations/backup_account/handlers.py:223
+#: accounts/automations/backup_account/handlers.py:224
msgid "The backup file will be sent to"
msgstr "バックアップファイルは送信されます"
-#: accounts/automations/backup_account/handlers.py:246
+#: accounts/automations/backup_account/handlers.py:247
msgid "The backup task has no assigned sftp server"
msgstr "このバックアップタスクはsftpサーバーに割り当てられていません"
-#: accounts/automations/backup_account/handlers.py:267
+#: accounts/automations/backup_account/handlers.py:268
msgid "The backup task has no assigned recipient"
msgstr "バックアップタスクは受取人を指定していません"
-#: accounts/automations/backup_account/handlers.py:290
+#: accounts/automations/backup_account/handlers.py:291
msgid "Plan start"
msgstr "計画開始"
@@ -153,7 +153,7 @@ msgstr ">>> ゲートウェイ接続のテストタスクを開始する"
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -227,7 +227,7 @@ msgstr "更新"
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr "失敗しました"
@@ -349,14 +349,14 @@ msgstr "SFTP"
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "成功"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr "未定"
@@ -364,7 +364,7 @@ msgstr "未定"
msgid "Queued"
msgstr "順番待ち"
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr "の準備を"
@@ -376,7 +376,7 @@ msgstr "処理中"
msgid "Can login"
msgstr "ログイン可能"
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr "システムユーザー"
@@ -405,7 +405,7 @@ msgid "Default tablespace"
msgstr "デフォルト表領域"
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr "ロール"
@@ -414,7 +414,7 @@ msgid "Perms"
msgstr "パーマ"
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr "ユーザーグループ"
@@ -804,7 +804,7 @@ msgstr "終了日"
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -819,7 +819,7 @@ msgstr "ステータス"
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr "間違い"
@@ -914,8 +914,9 @@ msgstr "パスワードの重複"
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1074,7 +1075,7 @@ msgstr "特権アカウント"
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "アクティブです。"
@@ -1090,7 +1091,7 @@ msgstr "プラットフォーム"
msgid "Push params"
msgstr "パラメータをプッシュする"
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr "アカウント テンプレート"
@@ -1184,7 +1185,7 @@ msgstr "アカウント変更情報"
msgid "Change secret or push account failed information"
msgstr "パスワード変更またはアカウントプッシュ失敗情報"
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr "無視する"
@@ -1341,7 +1342,7 @@ msgstr "ID"
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1349,8 +1350,8 @@ msgstr "ID"
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr "ユーザー"
@@ -1385,7 +1386,7 @@ msgstr "Access IP"
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1673,7 +1674,7 @@ msgstr ""
"ジ-レコード制限の設定に基づき、毎日午前2時に超過した数量のアカウントレコード"
"をクリーニングします"
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr "範囲外の履歴アカウントを削除する"
@@ -1746,7 +1747,7 @@ msgstr "タスク名"
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1931,7 +1932,7 @@ msgstr "レビュー担当者"
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr "ユーザー"
@@ -1957,7 +1958,7 @@ msgid "Command"
msgstr "コマンド"
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr "正規情報"
@@ -2046,7 +2047,7 @@ msgstr "ルール"
msgid "Login acl"
msgstr "ログインacl"
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr "ログイン確認"
@@ -2169,7 +2170,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr "IP"
@@ -2231,17 +2232,17 @@ msgstr "ユーザーが最近ログインしたことをお知らせいたしま
msgid "User details"
msgstr "ユーザー詳細"
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr ""
"資産を直接作成することはできません。ホストまたはその他を作成する必要がありま"
"す"
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr "資産の数が5000の制限を超えています"
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
#, fuzzy
#| msgid "The number of assets exceeds the limit of 5000"
msgid "The number of assets exceeds the license limit"
@@ -2260,6 +2261,11 @@ msgstr "ルートノード ({}) を削除できません。"
msgid "Deletion failed and the node contains assets"
msgstr "削除に失敗し、ノードにアセットが含まれています。"
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr "同じレベルのノード名を同じにすることはできません。"
@@ -2277,29 +2283,29 @@ msgstr "アプリ資産"
msgid "Task: {} finished"
msgstr "タスク:{} 完了"
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr " - プラットフォーム {} ansible 無効"
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr "タスク準備段階"
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ">>> バッチでタスクを実行、合計 {runner_count}"
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ">>> タスクの実行を開始"
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ">>> 実行する必要があるタスクはありません"
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ">>> 第 {index} バッチのタスクの実行を開始"
@@ -2701,7 +2707,7 @@ msgid "Port"
msgstr "ポート"
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr "アドレス"
@@ -2709,12 +2715,12 @@ msgstr "アドレス"
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr "プラットフォーム"
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr "ゾーン"
@@ -2783,9 +2789,9 @@ msgid "Proxy"
msgstr "プロキシー"
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr "ノード"
@@ -2809,7 +2815,7 @@ msgstr "アセットの自動化タスク"
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr "作成された日付"
@@ -2898,7 +2904,7 @@ msgstr "ゲートウェイ"
msgid "System"
msgstr "システム"
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2913,7 +2919,7 @@ msgstr "値"
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr "ラベル"
@@ -2929,27 +2935,27 @@ msgstr "カスタムメモ"
msgid "My assets"
msgstr "私の資産"
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr "新しいノード"
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr "空"
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr "キー"
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr "フルバリュー"
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr "親キー"
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr "ノードを一致させることができます"
@@ -3129,7 +3135,7 @@ msgstr ""
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr "プロトコル"
@@ -3586,7 +3592,7 @@ msgid "Symlink"
msgstr "Symlink"
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr "ダウンロード"
@@ -3615,7 +3621,9 @@ msgstr "エクスポート"
msgid "Connect"
msgstr "接続"
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4408,17 +4416,17 @@ msgstr "顔認証の照合に失敗"
msgid "Current user not support mfa type: {}"
msgstr "現在のユーザーはmfaタイプをサポートしていません: {}"
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr "ユーザーが存在しない: {}"
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr "ユーザーにマッチしなかった"
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
@@ -4427,7 +4435,7 @@ msgstr ""
"ユーザーは {}からです。対応するシステムにアクセスしてパスワードを変更してくだ"
"さい。"
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4437,7 +4445,7 @@ msgstr ""
msgid "Forgot password"
msgstr "パスワードを忘れた"
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr "認証コードの有効時間は {} 分"
@@ -4450,10 +4458,29 @@ msgstr "認証"
msgid "CAS Error"
msgstr "CAS エラー"
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
-msgstr "ユーザーが無効、無効、または期限切れです"
+#: authentication/backends/cert/api.py:57
+#, fuzzy
+#| msgid "LDAP authentication is not enabled"
+msgid "Certificate enrollment is not enabled"
+msgstr "LDAP 認証が有効になっていない"
+
+#: authentication/backends/cert/api.py:62
+#, fuzzy
+#| msgid "type is required"
+msgid "CSR is required"
+msgstr "タイプ このフィールドは必須です."
+
+#: authentication/backends/cert/api.py:68
+#, fuzzy
+#| msgid "Authentication failed"
+msgid "Certificate signing failed"
+msgstr "認証に失敗しました"
+
+#: authentication/backends/cert/views.py:97
+#, fuzzy
+#| msgid "Invalid data"
+msgid "Invalid credentials"
+msgstr "無効なデータ"
#: authentication/backends/drf.py:61
msgid "Invalid token header. No credentials provided."
@@ -4705,16 +4732,16 @@ msgstr "パスワードが無効です"
msgid "Please wait for %s seconds before retry"
msgstr "%s 秒後に再試行してください"
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr "パスワードがシンプルすぎるので、セキュリティのために変更してください"
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr "ログインする前にパスワードを変更する必要があります"
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr ""
"パスワードの有効期限が切れました。ログインする前にリセットしてください。"
@@ -4845,11 +4872,11 @@ msgstr ""
"管理者は「既存のユーザーのみログインを許可」に設定しています。現在のユーザー"
"はユーザーリストに含まれていません。管理者に連絡してください。"
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr "無効なユーザーです"
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4859,12 +4886,12 @@ msgstr ""
"管理者は「ユーザーソースからのみログインを許可」に設定しています。現在のユー"
"ザーのソースは {} です。管理者に連絡してください。"
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr "MFAタイプ ({}) が有効になっていない"
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr "パスワードを変更してください"
@@ -5056,7 +5083,7 @@ msgstr "アクション"
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "期限切れです"
@@ -5098,13 +5125,13 @@ msgstr "有効なssh公開鍵ではありません"
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "有効です"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr "スコープ"
@@ -5203,7 +5230,7 @@ msgstr "コードエラー"
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5307,6 +5334,87 @@ msgstr ""
msgid "Cancel"
msgstr "キャンセル"
+#: authentication/templates/authentication/cert_login.html:190
+#, fuzzy
+#| msgid "Multi-Factor Authentication"
+msgid "Certificate Authentication"
+msgstr "認証"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:238
+#, fuzzy
+#| msgid "More login options"
+msgid "Other login methods"
+msgstr "その他のログインオプション"
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:253
+#, fuzzy
+#| msgid "Please enter SMS code"
+msgid "Please insert USB Key"
+msgstr "SMSコードを入力してください"
+
+#: authentication/templates/authentication/cert_login.html:254
+#, fuzzy
+#| msgid "Account unavailable"
+msgid "Driver unavailable"
+msgstr "利用できないアカウント"
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:257
+#, fuzzy
+#| msgid "Date verified"
+msgid "PIN verified"
+msgstr "確認済みの日付"
+
+#: authentication/templates/authentication/cert_login.html:258
+#, fuzzy
+#| msgid "OTP verification code"
+msgid "PIN verification failed"
+msgstr "OTP検証コード"
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:260
+#, fuzzy
+#| msgid "Signing key"
+msgid "Signing failed"
+msgstr "プロバイダ署名キー"
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:262
+#, fuzzy
+#| msgid "Your account has expired, please contact the administrator."
+msgid "No certificate detected, please contact administrator"
+msgstr "あなたのアカウントは既に期限切れです。管理者にご連絡ください。"
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr "再試行"
@@ -5378,6 +5486,10 @@ msgstr "再試行しますか?"
msgid "LAN"
msgstr "ローカルエリアネットワーク"
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5541,47 +5653,47 @@ msgstr "パスワードでログインしてからWeComをバインドしてく
msgid "Request file format may be wrong"
msgstr "リクエストファイルの形式が間違っている可能性があります"
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr "中国"
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr "手動トリガー"
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr "定期トリガー"
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr "ランニング"
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr "キャンセル"
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr "確認"
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr "コミュニティ版"
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr "エンタープライズ基本版"
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr "エンタープライズ標準版"
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr "エンタープライズプロフェッショナル版"
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr "エンタープライズ・フラッグシップ・エディション"
@@ -6097,24 +6209,24 @@ msgstr "コードが見つかりません"
msgid "The message code provided is invalid or has expired"
msgstr "提供されたメッセージコードは無効か期限切れです"
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr "認証コードは: {code}"
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr "アカウントを正常に作成"
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr "アカウントが正常に作成されました"
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "JumpServer オープンソースの要塞ホスト"
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -6836,7 +6948,7 @@ msgid "Please save in a org"
msgstr "組織を選択してから保存してください"
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -7261,26 +7373,26 @@ msgstr "システムの役割"
msgid "Organization role"
msgstr "組織の役割"
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr "ロールバインディング"
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr "全ての組織"
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
msgstr ""
"ユーザーの最後のロールは削除できません。ユーザーを組織から削除できます。"
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr "組織の役割バインディング"
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr "システムロールバインディング"
@@ -7345,7 +7457,7 @@ msgid "Storage"
msgstr "ストレージ"
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr "リモートアプリケーション"
@@ -7408,51 +7520,51 @@ msgstr "アクセストークンを取り消す"
msgid "Range days"
msgstr "による変更"
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr "ユーザーログイン報告"
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr "ユーザー変更パスワード報告"
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr "資産統計報告"
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr "資産活動報告"
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr "アカウント統計報告"
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr "アカウント自動化報告"
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr "コンソールダッシュボード"
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr "監査台ダッシュボード"
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr "PAMダッシュボード"
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr "アカウントパスワード変更ダッシュボード"
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr "メール送信失敗"
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr "メール送信成功"
@@ -7735,16 +7847,16 @@ msgstr "ピン認証の有効化"
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
"ユーザー属性のマッピング、ここで `key` はこのシステムのユーザー属性名で、"
"`value` は ディントーク サービスのユーザー属性名です"
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
"ユーザー属性のマッピング、ここで `key` はこのシステムのユーザー属性名で、"
"`value` は フェイシュ サービスのユーザー属性名です"
@@ -7755,8 +7867,8 @@ msgstr "Lark"
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
"ユーザー属性のマッピング、ここで `key` はこのシステムのユーザー属性名で、"
"`value` は Lark サービスのユーザー属性名です"
@@ -7803,8 +7915,8 @@ msgstr "選択は (cnまたはuidまたはsAMAccountName)=%(user)s)"
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
"ユーザー属性のマッピング、ここで `key` はこのシステムのユーザー属性名で、"
"`value` は LDAP サービスのユーザー属性名です"
@@ -7912,8 +8024,8 @@ msgstr "ユーザーがログアウトすると、OAuth2 サーバからもロ
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
"ユーザー属性のマッピング、ここで `key` はこのシステムのユーザー属性名で、"
"`value` は OAuth2 サービスのユーザー属性名です"
@@ -7949,8 +8061,8 @@ msgstr "Ssl検証を無視する"
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
"ユーザー属性のマッピング、ここで `key` はこのシステムのユーザー属性名で、"
"`value` は OIDC サービスのユーザー属性名です"
@@ -8087,8 +8199,8 @@ msgid ""
"User attribute mapping, where the `key` is the SAML2 service user attribute "
"name and the `value` is this system user attribute name"
msgstr ""
-"ユーザー属性マッピング(`key`はSAML2サービスのユーザー属性名、`value`は"
-"このシステムのユーザー属性名)"
+"ユーザー属性マッピング(`key`はSAML2サービスのユーザー属性名、`value`はこのシ"
+"ステムのユーザー属性名)"
#: settings/serializers/auth/saml2.py:43
msgid "When the user signs out, they also be logged out from the SAML2 server"
@@ -8096,8 +8208,8 @@ msgstr "ユーザーがログアウトすると、SAML2サーバーからもロ
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
"ユーザー属性のマッピング、ここで `key` はこのシステムのユーザー属性名で、"
"`value` は Slack サービスのユーザー属性名です"
@@ -8134,7 +8246,7 @@ msgid "Template code"
msgstr "テンプレートコード"
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr "電話"
@@ -8191,7 +8303,10 @@ msgid "Enable SSO auth"
msgstr "SSO Token認証の有効化"
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
+#, fuzzy
+#| msgid ""
+#| "Other service can using SSO token login to JumpServer without password"
+msgid "Other service can using SSO token login to system without password"
msgstr ""
"他のサービスはパスワードなしでJumpServerへのSSOトークンログインを使用できます"
@@ -8206,8 +8321,8 @@ msgstr "単位: 秒"
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
"ユーザー属性のマッピング、ここで `key` はこのシステムのユーザー属性名で、"
"`value` は エンタープライズ WeChat サービスのユーザー属性名です"
@@ -9368,7 +9483,7 @@ msgstr "待つ:"
msgid "The verification code has been sent"
msgstr "確認コードが送信されました"
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "ホームページ"
@@ -9631,31 +9746,31 @@ msgstr "同時実行可能"
msgid "Hosts"
msgstr "ホスト"
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr "無効なアプレット パッケージ、ファイル {} がありません"
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr "platform.ymlのロードに失敗しました:{}"
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr "カスタムプラットフォームのみをサポート"
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr "platform.ymlにタイプがありません"
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "ホスト マシン"
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr "アプリケーションのリリース"
@@ -9745,7 +9860,7 @@ msgstr "VNC ポート"
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -9959,8 +10074,8 @@ msgstr "コマンド及び録画記憶"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr "テスト失敗: アカウントが無効"
@@ -10082,7 +10197,8 @@ msgstr "既存の RDS 証明書"
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
"存在しない場合、RDSは試用モードで、試用期間は120日間です。>> 테스트 게이트웨이 계정 연결성 작업 시작"
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -227,7 +227,7 @@ msgstr "업데이트"
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr "실패"
@@ -349,14 +349,14 @@ msgstr "SFTP"
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "성공"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr "대기 중"
@@ -364,7 +364,7 @@ msgstr "대기 중"
msgid "Queued"
msgstr "대기 중"
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr "준비 중"
@@ -376,7 +376,7 @@ msgstr "처리 중"
msgid "Can login"
msgstr "로그인 가능"
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr "슈퍼 사용자"
@@ -405,7 +405,7 @@ msgid "Default tablespace"
msgstr "기본 테이블 공간"
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr "역할"
@@ -414,7 +414,7 @@ msgid "Perms"
msgstr "권한"
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr "사용자 그룹"
@@ -788,7 +788,7 @@ msgstr "종료 날짜"
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -803,7 +803,7 @@ msgstr "상태"
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr "오류"
@@ -898,8 +898,9 @@ msgstr "중복 비밀번호"
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1056,7 +1057,7 @@ msgstr "권한 계정"
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "활성화"
@@ -1072,7 +1073,7 @@ msgstr "플랫폼"
msgid "Push params"
msgstr "계정 푸시 매개변수"
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr "계정 템플릿"
@@ -1165,7 +1166,7 @@ msgstr "계정 변경 정보"
msgid "Change secret or push account failed information"
msgstr "비밀번호 변경 또는 계정 푸시 실패 정보"
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr "무시"
@@ -1321,7 +1322,7 @@ msgstr "ID"
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1329,8 +1330,8 @@ msgstr "ID"
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr "사용자"
@@ -1365,7 +1366,7 @@ msgstr "IP 화이트리스트"
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1653,7 +1654,7 @@ msgstr ""
"해야 합니다. 시스템은 계정 저장소 - 기록 제한 설정에 따라 매일 새벽 2시에 초"
"과된 수량의 계정 기록을 정리합니다."
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr "범위를 초과한 역사적인 계정을 삭제합니다."
@@ -1725,7 +1726,7 @@ msgstr "작업 이름"
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1911,7 +1912,7 @@ msgstr "승인자"
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr "사용자"
@@ -1937,7 +1938,7 @@ msgid "Command"
msgstr "명령"
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr "정규 표현식"
@@ -2026,7 +2027,7 @@ msgstr "규칙"
msgid "Login acl"
msgstr "로그인 접근 제어"
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr "로그인 재검토"
@@ -2148,7 +2149,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr "IP"
@@ -2210,15 +2211,15 @@ msgstr "최근에 사용자가 로그인했음을 알려드립니다:"
msgid "User details"
msgstr "사용자 세부정보"
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr "직접 자산을 생성할 수 없습니다. 호스트나 다른 자산을 생성해야 합니다."
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr "자산 수가 5000을 초과했습니다."
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
#, fuzzy
#| msgid "The number of assets exceeds the limit of 5000"
msgid "The number of assets exceeds the license limit"
@@ -2237,6 +2238,11 @@ msgstr "루트 노드를 삭제할 수 없습니다 ({})"
msgid "Deletion failed and the node contains assets"
msgstr "삭제 실패, 노드에 자산이 포함되어 있습니다."
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr "동급 노드 이름은 중복될 수 없습니다."
@@ -2254,29 +2260,29 @@ msgstr "자산 관리"
msgid "Task: {} finished"
msgstr "작업: {} 완료"
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr "- 플랫폼 {} Ansible이 비활성화되어 있어 작업을 실행할 수 없습니다."
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr ">>> 작업 준비 단계"
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ">>> 작업을 분할 실행합니다. 총 {runner_count}"
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ">>> 작업 실행 시작"
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ">>> 실행할 작업이 없습니다."
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ">>> {index}번째 배치 작업 실행 시작"
@@ -2676,7 +2682,7 @@ msgid "Port"
msgstr "포트"
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr "주소"
@@ -2684,12 +2690,12 @@ msgstr "주소"
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr "플랫폼"
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr "도메인"
@@ -2758,9 +2764,9 @@ msgid "Proxy"
msgstr "프록시."
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr "노드."
@@ -2784,7 +2790,7 @@ msgstr "자산 자동화 작업"
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr "생성 날짜"
@@ -2873,7 +2879,7 @@ msgstr "게이트웨이"
msgid "System"
msgstr "시스템"
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2888,7 +2894,7 @@ msgstr "값"
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr "태그"
@@ -2904,27 +2910,27 @@ msgstr "사용자 정의 메모"
msgid "My assets"
msgstr "내 자산"
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr "새 노드"
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr "비어 있음"
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr "키"
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr "전체 이름"
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr "ssh 개인 키"
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr "개별 노드와 일치"
@@ -3102,7 +3108,7 @@ msgstr ""
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr "프로토콜 그룹"
@@ -3548,7 +3554,7 @@ msgid "Symlink"
msgstr "심볼릭 링크 생성"
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr "다운로드"
@@ -3577,7 +3583,9 @@ msgstr "내보내기"
msgid "Connect"
msgstr "연결"
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4371,24 +4379,24 @@ msgstr "얼굴 인식 실패"
msgid "Current user not support mfa type: {}"
msgstr "현재 사용자는 MFA 유형을 지원하지 않습니다: {}"
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr "사용자가 존재하지 않습니다: {}"
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr "사용자와 일치하지 않음"
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
"password"
msgstr "사용자가 {}에서 옵니다. 해당 시스템에서 비밀번호를 변경하세요"
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4398,7 +4406,7 @@ msgstr "사용자가 {}에서 옵니다. 해당 시스템에서 비밀번호를
msgid "Forgot password"
msgstr "비밀번호를 잊으셨나요"
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr "인증 코드의 유효 기간은 {} 분입니다."
@@ -4411,10 +4419,29 @@ msgstr "인증 관리"
msgid "CAS Error"
msgstr "CAS 오류"
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
-msgstr "사용자가 유효하지 않거나 비활성 상태이거나 만료되었습니다"
+#: authentication/backends/cert/api.py:57
+#, fuzzy
+#| msgid "LDAP authentication is not enabled"
+msgid "Certificate enrollment is not enabled"
+msgstr "LDAP 인증이 활성화되지 않았습니다"
+
+#: authentication/backends/cert/api.py:62
+#, fuzzy
+#| msgid "type is required"
+msgid "CSR is required"
+msgstr "유형: 이 필드는 필수입니다."
+
+#: authentication/backends/cert/api.py:68
+#, fuzzy
+#| msgid "Authentication failed"
+msgid "Certificate signing failed"
+msgstr "인증 실패"
+
+#: authentication/backends/cert/views.py:97
+#, fuzzy
+#| msgid "Invalid data"
+msgid "Invalid credentials"
+msgstr "유효하지 않은 데이터"
#: authentication/backends/drf.py:61
msgid "Invalid token header. No credentials provided."
@@ -4667,16 +4694,16 @@ msgstr "귀하의 비밀번호가 유효하지 않습니다"
msgid "Please wait for %s seconds before retry"
msgstr "%s 초 후에 다시 시도해주세요."
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr "비밀번호가 너무 간단합니다. 보안을 위해 수정해주세요."
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr "로그인 완료 전에 비밀번호를 먼저 수정해주세요."
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr "당신의 비밀번호가 만료되었습니다. 수정 후 로그인해주세요."
@@ -4805,11 +4832,11 @@ msgstr ""
"관리자가 '존재하는 사용자만 로그인 허용'을 활성화했습니다. 현재 사용자가 사용"
"자 목록에 없습니다. 관리자에게 문의하십시오."
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr "무효한 사용자"
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4819,12 +4846,12 @@ msgstr ""
"관리자가 '사용자 출처에서만 로그인 허용'을 활성화했습니다. 현재 사용자 출처"
"는 {}입니다. 관리자에게 문의하십시오."
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr "해당 MFA ({}) 방식이 활성화되지 않았습니다."
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr "비밀번호를 수정하십시오."
@@ -5016,7 +5043,7 @@ msgstr "Action"
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "이미 만료"
@@ -5058,13 +5085,13 @@ msgstr "SSH 키가 유효하지 않습니다"
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "유효한가요"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr "범위"
@@ -5163,7 +5190,7 @@ msgstr "코드 오류"
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5273,6 +5300,87 @@ msgstr "취소"
msgid "Cancel"
msgstr "재시도"
+#: authentication/templates/authentication/cert_login.html:190
+#, fuzzy
+#| msgid "Multi-Factor Authentication"
+msgid "Certificate Authentication"
+msgstr "인증"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:238
+#, fuzzy
+#| msgid "More login options"
+msgid "Other login methods"
+msgstr "기타 로그인 방법"
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:253
+#, fuzzy
+#| msgid "Please enter SMS code"
+msgid "Please insert USB Key"
+msgstr "문자 메시지 인증 코드를 입력해 주세요"
+
+#: authentication/templates/authentication/cert_login.html:254
+#, fuzzy
+#| msgid "Account unavailable"
+msgid "Driver unavailable"
+msgstr "계정 무효"
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:257
+#, fuzzy
+#| msgid "Date verified"
+msgid "PIN verified"
+msgstr "검증 날짜"
+
+#: authentication/templates/authentication/cert_login.html:258
+#, fuzzy
+#| msgid "OTP verification code"
+msgid "PIN verification failed"
+msgstr "가상 MFA 인증 코드"
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:260
+#, fuzzy
+#| msgid "Signing key"
+msgid "Signing failed"
+msgstr "서명 키"
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:262
+#, fuzzy
+#| msgid "Your account has expired, please contact the administrator."
+msgid "No certificate detected, please contact administrator"
+msgstr "귀하의 계정이 만료되었습니다. 관리자에게 문의하시기 바랍니다."
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr ""
@@ -5344,6 +5452,10 @@ msgstr "재시도 하시겠습니까?"
msgid "LAN"
msgstr "지역 네트워크"
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5508,47 +5620,47 @@ msgstr "密码로 로그인한 후 기업 WeChat을 연결해 주시기 바랍
msgid "Request file format may be wrong"
msgstr "업로드한 파일 형식이 잘못되었거나 다른 유형의 리소스 파일입니다."
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr "중국"
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr "수동으로 트리거"
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr "예약 트리거"
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr "실행 중"
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr "취소"
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr "확인"
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr "커뮤니티 버전"
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr "기업 기본 버전"
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr "기업 표준 버전"
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr "기업 전문 버전"
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr "기업 플래그십 버전"
@@ -6060,24 +6172,24 @@ msgstr "제공된 메시지 코드가 유효하지 않거나 만료되었습니
msgid "The message code provided is invalid or has expired"
msgstr "인증 코드는: {code}"
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr "인증 코드: {code}"
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr "귀하의 계정이 성공적으로 생성되었습니다"
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr "JumpServer 오픈소스 방화벽"
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "Flower 서비스가 사용 불가능합니다, 확인하십시오"
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -6811,7 +6923,7 @@ msgid "Please save in a org"
msgstr "저장하기 전에 조직을 선택해 주십시오"
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -7252,26 +7364,26 @@ msgstr "시스템 역할"
msgid "Organization role"
msgstr "조직 역할"
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr "역할 바인딩"
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr "모든 조직"
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
msgstr ""
"사용자의 마지막 역할은 삭제할 수 없으며, 사용자를 조직에서 제거할 수 있습니다"
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr "조직 역할 바인딩"
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr "시스템 역할 바인딩"
@@ -7336,7 +7448,7 @@ msgid "Storage"
msgstr "저장소"
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr "원격 애플리케이션"
@@ -7399,51 +7511,51 @@ msgstr "접근 토큰 철회"
msgid "Range days"
msgstr "수정자"
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr "사용자 로그인 보고서"
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr "사용자 비밀번호 변경 보고서"
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr "자산 통계 보고서"
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr "자산 활동 보고서"
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr "계정 통계 보고서"
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr "계정 자동화 보고서"
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr "콘솔 대시보드"
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr "감사 대시보드"
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr "PAM 대시보드"
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr "계정 비밀번호 변경 대시보드"
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr "메일 전송 실패"
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr "메일 전송 성공"
@@ -7715,8 +7827,8 @@ msgid ""
"User attribute mapping, where the `key` is the CAS service user attribute "
"name and the `value` is this system user attribute name"
msgstr ""
-"사용자 속성 매핑에서 `key`는 CAS 서비스의 사용자 속성 이름이고, `value`는 "
-"이 시스템 사용자 속성 이름입니다."
+"사용자 속성 매핑에서 `key`는 CAS 서비스의 사용자 속성 이름이고, `value`는 이 "
+"시스템 사용자 속성 이름입니다."
#: settings/serializers/auth/dingtalk.py:16
msgid "Dingtalk"
@@ -7724,16 +7836,16 @@ msgstr "딩딩 인증 활성화"
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
"사용자 속성 매핑에서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 딩딩 "
"서비스의 사용자 속성 이름입니다."
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
"사용자 속성 매핑에서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 페이"
"서 서비스의 사용자 속성 이름입니다."
@@ -7744,8 +7856,8 @@ msgstr "Lark"
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
"사용자 속성 매핑에서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 Lark "
"서비스의 사용자 속성 이름입니다."
@@ -7792,8 +7904,8 @@ msgstr "가능한 옵션은 (cn 또는 uid 또는 sAMAccountName=%(user)s)입니
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
"사용자 속성 매핑에서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 LDAP "
"서비스 사용자 속성 이름입니다."
@@ -7901,8 +8013,8 @@ msgstr "사용자가 로그아웃할 때, 그들은 OAuth2 서버에서도 로
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
"사용자 속성 매핑, 여기서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 "
"OAuth2 서비스 사용자 속성 이름입니다"
@@ -7938,8 +8050,8 @@ msgstr "SSL 인증서 검증 무시"
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
"사용자 속성 매핑, 여기서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 "
"OIDC 서비스 사용자 속성 이름입니다"
@@ -8084,8 +8196,8 @@ msgstr "사용자가 로그아웃하면 SAML2 서버에서도 로그아웃됩니
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
"사용자 속성 매핑, 여기서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 "
"Slack 서비스 사용자 속성 이름입니다."
@@ -8122,7 +8234,7 @@ msgid "Template code"
msgstr "템플릿"
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr "휴대폰"
@@ -8179,7 +8291,10 @@ msgid "Enable SSO auth"
msgstr "SSO 토큰 인증 활성화"
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
+#, fuzzy
+#| msgid ""
+#| "Other service can using SSO token login to JumpServer without password"
+msgid "Other service can using SSO token login to system without password"
msgstr ""
"기타 시스템은 SSO 토큰을 통해 JumpServer에 연동하여 로그인 과정을 생략할 수 "
"있습니다."
@@ -8195,11 +8310,11 @@ msgstr "단위: 초"
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
-"사용자 속성 매핑, 여기서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 "
-"기업 WeChat 서비스 사용자 속성 이름입니다."
+"사용자 속성 매핑, 여기서 `key`는 이 시스템 사용자 속성 이름이고, `value`는 기"
+"업 WeChat 서비스 사용자 속성 이름입니다."
#: settings/serializers/basic.py:11
msgid "Site URL"
@@ -9363,7 +9478,7 @@ msgstr "대기 중:"
msgid "The verification code has been sent"
msgstr "인증 코드가 전송되었습니다."
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "홈페이지"
@@ -9625,31 +9740,31 @@ msgstr "동시 가능"
msgid "Hosts"
msgstr "주최자"
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr "Applet pkg 유효하지 않음, 파일 {}가 없습니다"
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr "platform.yml 로드 실패: {}"
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr "사용자 정의 플랫폼만 지원합니다"
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr "platform.yml에 유형이 누락되었습니다"
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "호스트 머신"
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr "애플리케이션 배포"
@@ -9739,7 +9854,7 @@ msgstr "VNC 포트"
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -9953,8 +10068,8 @@ msgstr "명령 및 녹화 저장"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr "테스트 실패: 계정이 유효하지 않음"
@@ -10075,7 +10190,8 @@ msgstr "이미 RDS 라이센스 보유"
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
"존재하지 않을 경우, RDS는 시험 모드에 있으며, 시험 기간은 120일입니다.\n"
"Language-Team: LANGUAGE \n"
@@ -28,7 +28,7 @@ msgstr "Conta já existente"
msgid "No valid assets found for account creation."
msgstr "Não foi encontrado um ativo válido para a criação da conta."
-#: accounts/api/account/application.py:77
+#: accounts/api/account/application.py:87
#: authentication/api/connection_token.py:463
msgid "Account not found"
msgstr "Conta não encontrada"
@@ -42,15 +42,15 @@ msgstr "O parâmetro 'action' deve ser [{}]"
msgid "The account key will be split into two parts and sent"
msgstr "A chave da conta será dividida e enviada em duas partes"
-#: accounts/automations/backup_account/handlers.py:131
+#: accounts/automations/backup_account/handlers.py:132
msgid "Number of backup accounts"
msgstr "Número de contas de backup"
-#: accounts/automations/backup_account/handlers.py:152
+#: accounts/automations/backup_account/handlers.py:153
msgid "Generating asset related backup information files"
msgstr "Gerar arquivo de informações de backup relacionado ao ativo"
-#: accounts/automations/backup_account/handlers.py:177
+#: accounts/automations/backup_account/handlers.py:178
#: accounts/automations/backup_account/manager.py:26
#: accounts/automations/change_secret/manager.py:81
#: accounts/automations/push_account/manager.py:62
@@ -61,31 +61,31 @@ msgstr "Gerar arquivo de informações de backup relacionado ao ativo"
msgid "Duration"
msgstr "Duração"
-#: accounts/automations/backup_account/handlers.py:178
+#: accounts/automations/backup_account/handlers.py:179
msgid "Backup file creation completed"
msgstr "Criação de arquivo de backup concluída"
-#: accounts/automations/backup_account/handlers.py:186
+#: accounts/automations/backup_account/handlers.py:187
msgid "Start sending backup emails"
msgstr "Comece a enviar e-mails de backup"
-#: accounts/automations/backup_account/handlers.py:213
+#: accounts/automations/backup_account/handlers.py:214
msgid "Encrypting files using encryption password"
msgstr "Usando senha criptografada para criptografar o arquivo"
-#: accounts/automations/backup_account/handlers.py:223
+#: accounts/automations/backup_account/handlers.py:224
msgid "The backup file will be sent to"
msgstr "O arquivo de backup será enviado para"
-#: accounts/automations/backup_account/handlers.py:246
+#: accounts/automations/backup_account/handlers.py:247
msgid "The backup task has no assigned sftp server"
msgstr "A tarefa de backup não foi atribuída a um servidor sftp"
-#: accounts/automations/backup_account/handlers.py:267
+#: accounts/automations/backup_account/handlers.py:268
msgid "The backup task has no assigned recipient"
msgstr "A tarefa de backup não possui destinatário especificado"
-#: accounts/automations/backup_account/handlers.py:290
+#: accounts/automations/backup_account/handlers.py:291
msgid "Plan start"
msgstr "Tarefa iniciada"
@@ -153,7 +153,7 @@ msgstr ">>> Iniciando teste de conectividade da conta do gateway"
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -227,7 +227,7 @@ msgstr "Atualizar"
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr "Falha"
@@ -276,8 +276,7 @@ msgstr "Gerar Aleatoriamente"
#: accounts/const/automation.py:59 ops/const.py:17
msgid "Replace (Replace only keys pushed by system) "
-msgstr ""
-"Substituir (Substituir apenas as chaves impulsionadas pelo sistema) "
+msgstr "Substituir (Substituir apenas as chaves impulsionadas pelo sistema) "
#: accounts/const/automation.py:60 ops/const.py:16
msgid "Empty and append SSH KEY"
@@ -350,14 +349,14 @@ msgstr "SFTP"
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "Successo"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr "Pendente"
@@ -365,7 +364,7 @@ msgstr "Pendente"
msgid "Queued"
msgstr "Em fila de espera"
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr "Preparar"
@@ -377,7 +376,7 @@ msgstr "Em processamento"
msgid "Can login"
msgstr "Login Permitido"
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr "Superusuário"
@@ -406,7 +405,7 @@ msgid "Default tablespace"
msgstr "Espaço de Tabela Padrão"
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr "Papel"
@@ -415,7 +414,7 @@ msgid "Perms"
msgstr "Permissões"
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr "Grupos de usuários"
@@ -790,7 +789,7 @@ msgstr "Data de fim"
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -805,7 +804,7 @@ msgstr "Status"
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr "Erro"
@@ -915,8 +914,9 @@ msgstr "Senha repetida"
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1075,7 +1075,7 @@ msgstr "Conta privilegiada"
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "Ativação"
@@ -1091,7 +1091,7 @@ msgstr "Plataforma"
msgid "Push params"
msgstr "Parâmetros de Push de Conta"
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr "Template de Conta"
@@ -1189,7 +1189,7 @@ msgstr "Informações de alterações de conta"
msgid "Change secret or push account failed information"
msgstr "Informações de falha na alteração de senha ou conta de push"
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr "Ignorar"
@@ -1345,7 +1345,7 @@ msgstr "ID"
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1353,8 +1353,8 @@ msgstr "ID"
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr "Usuário"
@@ -1389,7 +1389,7 @@ msgstr "Lista branca de IP"
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1694,7 +1694,7 @@ msgstr ""
"limpar os registros de conta excedentes às 2 da manhã de acordo com a "
"configuração de limite de registro em Armazenamento de Conta "
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr "Deletar contas históricas fora do alcance"
@@ -1767,7 +1767,7 @@ msgstr "Nome da tarefa"
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1954,7 +1954,7 @@ msgstr "Aprovador"
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr "Usuário"
@@ -1980,7 +1980,7 @@ msgid "Command"
msgstr "Comando"
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr "Expressão Regular"
@@ -2069,7 +2069,7 @@ msgstr "Regras"
msgid "Login acl"
msgstr "Controle de acesso de login"
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr "Revisão de login"
@@ -2192,7 +2192,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr "IP"
@@ -2256,17 +2256,17 @@ msgstr "Queremos informá-lo de que recentemente houve logins de usuários:"
msgid "User details"
msgstr "Detalhes do usuário"
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr ""
"Não é possível criar ativos diretamente, você deve criar um host ou outros "
"ativos."
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr "A quantidade de ativos excedeu o limite de 5000"
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
#, fuzzy
#| msgid "The number of assets exceeds the limit of 5000"
msgid "The number of assets exceeds the license limit"
@@ -2285,6 +2285,11 @@ msgstr "Não é possível excluir o nó raiz ({})"
msgid "Deletion failed and the node contains assets"
msgstr "Falha ao excluir, o nó contém ativos"
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr "O nome do nó no mesmo nível não pode ser repetido"
@@ -2302,29 +2307,29 @@ msgstr "Gestão de ativos"
msgid "Task: {} finished"
msgstr "Tarefa: {} concluída"
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr " - Plataforma {} Ansible foi desabilitada, impossível executar tarefas"
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr ">>> Preparando para executar tarefas"
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ">>> Executando tarefas em partes, total de {runner_count}"
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ">>> Começando a executar tarefas"
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ">>> Não há tarefas para executar"
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ">>> Começando a executar o lote {index} de tarefas"
@@ -2729,7 +2734,7 @@ msgid "Port"
msgstr "Porta"
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr "Endereço"
@@ -2737,12 +2742,12 @@ msgstr "Endereço"
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr "Plataforma"
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr "Domínio"
@@ -2811,9 +2816,9 @@ msgid "Proxy"
msgstr "Proxy"
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr "Nó"
@@ -2837,7 +2842,7 @@ msgstr "Tarefas de Automação de Ativos"
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr "Data de criação"
@@ -2926,7 +2931,7 @@ msgstr "Gateway"
msgid "System"
msgstr "Sistema"
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2941,7 +2946,7 @@ msgstr "Valor"
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr "Etiqueta"
@@ -2957,27 +2962,27 @@ msgstr "Nota personalizada"
msgid "My assets"
msgstr "Meus ativos"
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr "Novo nó"
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr "Vazio"
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr "Chave"
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr "Nome completo"
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr "Chave privada ssh"
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr "Pode corresponder ao nó"
@@ -3157,7 +3162,7 @@ msgstr ""
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr "Grupo de Protocolo"
@@ -3611,7 +3616,7 @@ msgid "Symlink"
msgstr "Criar link simbólico"
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr "Baixar"
@@ -3640,7 +3645,9 @@ msgstr "Exportar"
msgid "Connect"
msgstr "Conectar"
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4437,17 +4444,17 @@ msgstr "Falha na comparação facial"
msgid "Current user not support mfa type: {}"
msgstr "O usuário atual não suporta o tipo de MFA: {}"
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr "Usuário não encontrado: {}"
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr "Nenhum usuário correspondente encontrado"
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
@@ -4455,7 +4462,7 @@ msgid ""
msgstr ""
"O usuário vem de {} Por favor, altere a senha no sistema correspondente"
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4465,7 +4472,7 @@ msgstr ""
msgid "Forgot password"
msgstr "Esqueceu a senha"
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr "O código de verificação é válido por {} minuto"
@@ -4478,10 +4485,29 @@ msgstr "gerenciamento de autenticação"
msgid "CAS Error"
msgstr "Erro CAS"
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
-msgstr "O usuário é inválido, desativado ou expirado"
+#: authentication/backends/cert/api.py:57
+#, fuzzy
+#| msgid "LDAP authentication is not enabled"
+msgid "Certificate enrollment is not enabled"
+msgstr "A autenticação LDAP não está ativada"
+
+#: authentication/backends/cert/api.py:62
+#, fuzzy
+#| msgid "type is required"
+msgid "CSR is required"
+msgstr "Tipo Esse campo é obrigatório."
+
+#: authentication/backends/cert/api.py:68
+#, fuzzy
+#| msgid "Authentication failed"
+msgid "Certificate signing failed"
+msgstr "Falha na autenticação"
+
+#: authentication/backends/cert/views.py:97
+#, fuzzy
+#| msgid "Invalid data"
+msgid "Invalid credentials"
+msgstr "Dados inválidos"
#: authentication/backends/drf.py:61
msgid "Invalid token header. No credentials provided."
@@ -4735,16 +4761,16 @@ msgstr "Sua senha é inválida"
msgid "Please wait for %s seconds before retry"
msgstr "Por favor, tente novamente após %s segundos"
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr "Sua senha é muito simples, por segurança, favor alterar"
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr "Antes de finalizar o login, favor alterar a senha"
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr "Sua senha expirou, modifique antes de fazer login"
@@ -4876,11 +4902,11 @@ msgstr ""
"usuário atual não está na lista de usuários; por favor, entre em contato com "
"o administrador."
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr "Usuário inválido"
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4890,12 +4916,12 @@ msgstr ""
"O administrador ativou 'permitir login apenas de fontes de usuário', a fonte "
"atual do usuário é {}, entre em contato com o administrador."
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr "Este método MFA ({}) não está ativado"
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr "Por favor, altere sua senha."
@@ -5087,7 +5113,7 @@ msgstr "Action"
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "Expirado"
@@ -5129,13 +5155,13 @@ msgstr "Chave SSH inválida"
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "Está válido?"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr "Alcance"
@@ -5238,7 +5264,7 @@ msgstr "Erro de código"
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5348,6 +5374,87 @@ msgstr ""
msgid "Cancel"
msgstr "Cancelar"
+#: authentication/templates/authentication/cert_login.html:190
+#, fuzzy
+#| msgid "Multi-Factor Authentication"
+msgid "Certificate Authentication"
+msgstr "Autenticação"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:238
+#, fuzzy
+#| msgid "More login options"
+msgid "Other login methods"
+msgstr "Login por outros métodos"
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:253
+#, fuzzy
+#| msgid "Please enter SMS code"
+msgid "Please insert USB Key"
+msgstr "Por favor insira o código de verificação por SMS"
+
+#: authentication/templates/authentication/cert_login.html:254
+#, fuzzy
+#| msgid "Account unavailable"
+msgid "Driver unavailable"
+msgstr "Conta inválida"
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:257
+#, fuzzy
+#| msgid "Date verified"
+msgid "PIN verified"
+msgstr "Data de validação"
+
+#: authentication/templates/authentication/cert_login.html:258
+#, fuzzy
+#| msgid "OTP verification code"
+msgid "PIN verification failed"
+msgstr "Código de verificação MFA virtual"
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:260
+#, fuzzy
+#| msgid "Signing key"
+msgid "Signing failed"
+msgstr "Chave de assinatura"
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:262
+#, fuzzy
+#| msgid "Your account has expired, please contact the administrator."
+msgid "No certificate detected, please contact administrator"
+msgstr "Sua conta já expirou, por favor, entre em contato com o administrador."
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr "Tentar novamente"
@@ -5423,6 +5530,10 @@ msgstr "Deseja tentar novamente?"
msgid "LAN"
msgstr "Rede Local"
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5591,47 +5702,47 @@ msgstr "Faça login com a senha, e então vincule ao WeChat Corporativo"
msgid "Request file format may be wrong"
msgstr "Formato de arquivo enviado errado ou outro tipo de recurso do arquivo"
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr "China"
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr "AçãoManual"
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr "AçãoProgramada"
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr "Em execução"
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr "Cancelar"
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr "Confirmar"
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr "Versão Comunitária"
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr "Versão Básica Empresarial"
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr "Versão Padrão Empresarial"
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr "Versão Profissional Empresarial"
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr "Versão Premium Empresarial"
@@ -6148,24 +6259,24 @@ msgstr "Código não encontrado"
msgid "The message code provided is invalid or has expired"
msgstr "O código da mensagem fornecido é inválido ou expirou"
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr "O código de verificação é: {code}"
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr "Criação de conta bem sucedida"
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr "Sua conta foi criada com sucesso"
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "JumpServer Open Fortress Machine"
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -6898,7 +7009,7 @@ msgid "Please save in a org"
msgstr "Por favor, selecione uma organização antes de salvar"
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -7325,15 +7436,15 @@ msgstr "Papel do sistema"
msgid "Organization role"
msgstr "Papel da organização"
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr "Vinculação de papel"
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr "Todas as organizações"
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
@@ -7341,11 +7452,11 @@ msgstr ""
"O último papel do usuário não pode ser excluído, você pode remover o usuário "
"da organização"
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr "Associação de papéis da organização"
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr "Associação de papéis do sistema"
@@ -7410,7 +7521,7 @@ msgid "Storage"
msgstr "Armazenamento"
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr "Aplicativo Remoto"
@@ -7473,51 +7584,51 @@ msgstr "Revogar token de acesso"
msgid "Range days"
msgstr "Modificador"
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr "Relatório de Login de Usuário"
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr "Relatório de Mudança de Senha do Usuário"
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr "Relatório de Estatísticas de Ativos"
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr "Relatório de Atividades de Ativos"
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr "Relatório de Estatísticas de Contas"
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr "Relatório de Automação de Contas"
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr "Painel de Console"
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr "Painel de Auditoria"
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr "Painel PAM"
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr "Painel de Alteração de Senha da Conta"
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr "Envio de e-mail falhou"
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr "Envio de e-mail bem-sucedido"
@@ -7800,8 +7911,8 @@ msgstr "Habilitar autenticação DingTalk"
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
"Mapeamento de atributos do usuário, onde `key` é o nome do atributo do "
"usuário do sistema, e `value` é o nome do atributo do usuário do serviço "
@@ -7809,8 +7920,8 @@ msgstr ""
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
"Mapeamento de atributos do usuário, onde `key` é o nome do atributo do "
"usuário do sistema, e `value` é o nome do atributo do usuário do serviço "
@@ -7822,8 +7933,8 @@ msgstr "Lark"
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
"Mapeamento de atributos do usuário, onde `key` é o nome do atributo do "
"usuário do sistema e `value` é o nome do atributo do usuário do serviço Lark"
@@ -7871,8 +7982,8 @@ msgstr "As opções possíveis são (cn ou uid ou sAMAccountName=%(user)s)"
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
"Mapeamento de atributos do usuário, onde `key` é o nome do atributo do "
"usuário do sistema e `value` é o nome do atributo do usuário do serviço LDAP"
@@ -7982,8 +8093,8 @@ msgstr "Quando os usuários saem, eles também sairão do servidor OAuth2"
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
"Mapeamento de atributos do usuário, onde `key` é o nome do atributo do "
"usuário do sistema, e `value` é o nome do atributo do usuário do serviço "
@@ -8020,8 +8131,8 @@ msgstr "Ignorar validação do certificado SSL"
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
"Mapeamento de atributos do usuário, onde `key` é o nome do atributo do "
"usuário do sistema e `value` é o nome do atributo do usuário do serviço OIDC"
@@ -8170,12 +8281,11 @@ msgstr ""
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
"Mapeamento de atributos do usuário, onde `key` é o nome do atributo do "
-"usuário do sistema, `value` é o nome do atributo do usuário do serviço "
-"Slack"
+"usuário do sistema, `value` é o nome do atributo do usuário do serviço Slack"
#: settings/serializers/auth/sms.py:18
msgid "Enable Short Message Service (SMS)"
@@ -8209,7 +8319,7 @@ msgid "Template code"
msgstr "Modelo"
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr "Celular"
@@ -8267,7 +8377,10 @@ msgid "Enable SSO auth"
msgstr "Ativar autenticação com token SSO"
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
+#, fuzzy
+#| msgid ""
+#| "Other service can using SSO token login to JumpServer without password"
+msgid "Other service can using SSO token login to system without password"
msgstr ""
"Outros sistemas podem se integrar ao JumpServer usando Token SSO, eliminando "
"o processo de login."
@@ -8283,8 +8396,8 @@ msgstr "Unidade: segundos"
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
"Mapeamento de atributos do usuário, onde `key` é o nome do atributo do "
"usuário do sistema e `value` é o nome do atributo do usuário do serviço "
@@ -9476,7 +9589,7 @@ msgstr "Aguardando:"
msgid "The verification code has been sent"
msgstr "O código de verificação foi enviado"
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "Página Inicial"
@@ -9741,31 +9854,31 @@ msgstr "Pode ser Executado Simultaneamente"
msgid "Hosts"
msgstr "Host"
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr "Applet pkg inválido, arquivo ausente {}"
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr "Falha ao carregar platform.yml: {}"
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr "Somente suporte para plataformas personalizadas"
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr "Tipo ausente em platform.yml"
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "Máquina Hospedeira"
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr "Publicação de Aplicativo"
@@ -9855,7 +9968,7 @@ msgstr "Porta VNC"
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -10069,8 +10182,8 @@ msgstr "Armazenamento de comandos e gravações"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr "Teste falhou: Conta inválida"
@@ -10192,11 +10305,13 @@ msgstr "Já existem licenças RDS"
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
"Se não existir, o RDS estará em modo de teste, com um período de teste de "
"120 dias. Detalhes"
+"remote-desktop-services/rds-client-access-license' target='_blank'>Detalhes"
+"a>"
#: terminal/serializers/applet_host.py:55
msgid "RDS License Server"
@@ -10320,7 +10435,7 @@ msgstr "ID de sessão inválida"
msgid "Timestamp"
msgstr "Timestamp"
-#: terminal/serializers/endpoint.py:27
+#: terminal/serializers/endpoint.py:28
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 "
@@ -10329,7 +10444,7 @@ msgstr ""
"Endereço do host acessado ao conectar ao ativo, se estiver vazio, use o "
"endereço de acesso do navegador atual (o host padrão não permite modificação)"
-#: terminal/serializers/endpoint.py:54
+#: terminal/serializers/endpoint.py:64
msgid ""
"The assets within this IP range or Host, the following endpoint will be used "
"for the connection"
@@ -10337,7 +10452,7 @@ msgstr ""
"Os ativos dentro deste intervalo de IP ou host serão conectados utilizando o "
"seguinte endpoint."
-#: terminal/serializers/endpoint.py:55
+#: terminal/serializers/endpoint.py:65
msgid ""
"If asset IP addresses under different endpoints conflict, use asset labels"
msgstr ""
@@ -10477,7 +10592,7 @@ msgstr "Online"
msgid "Stat"
msgstr "Status"
-#: terminal/serializers/terminal.py:83 terminal/serializers/terminal.py:91
+#: terminal/serializers/terminal.py:79 terminal/serializers/terminal.py:87
msgid "Not found"
msgstr "Não encontrado"
@@ -11078,7 +11193,7 @@ msgstr "Solicitante"
msgid "Approval Step Distribution"
msgstr "Aprovação sem Login"
-#: tickets/serializers/flow.py:45
+#: tickets/serializers/flow.py:42
msgid "The current organization type already exists"
msgstr "A organização atual já possui este tipo."
@@ -11139,7 +11254,7 @@ msgid "Ticket information"
msgstr " Informações de ordem de serviço"
#: tickets/templates/tickets/approve_check_password.html:28
-#: tickets/views/approve.py:43 tickets/views/approve.py:80
+#: tickets/views/approve.py:42 tickets/views/approve.py:80
msgid "Ticket approval"
msgstr " Aprovação de ordem de serviço"
@@ -11147,14 +11262,14 @@ msgstr " Aprovação de ordem de serviço"
msgid "Approval"
msgstr " Acordo"
-#: tickets/views/approve.py:44
+#: tickets/views/approve.py:43
msgid ""
"This ticket does not exist, the process has ended, or this link has expired"
msgstr ""
" A ordem de serviço não existe, o processo da ordem de serviço já terminou, "
"ou este link já expirou"
-#: tickets/views/approve.py:72
+#: tickets/views/approve.py:71
msgid "Click the button below to approve or reject"
msgstr "Clique no botão abaixo para aceitar ou recusar"
@@ -11373,7 +11488,7 @@ msgstr "Configurações do usuário"
msgid "Email lookup"
msgstr "Conta de e-mail"
-#: users/models/user/__init__.py:82 users/serializers/user.py:259
+#: users/models/user/__init__.py:82 users/serializers/user.py:264
msgid "Is service account"
msgstr "Conta de serviço"
@@ -11390,7 +11505,7 @@ msgid "OTP secret key"
msgstr "OTP chave"
#: users/models/user/__init__.py:105 users/serializers/profile.py:86
-#: users/serializers/user.py:256
+#: users/serializers/user.py:261
msgid "Is first login"
msgstr "Primeiro login"
@@ -11410,23 +11525,23 @@ msgstr "Vetor facial"
msgid "Date api key used"
msgstr "Data do último uso da API key"
-#: users/models/user/__init__.py:293
+#: users/models/user/__init__.py:298
msgid "Can not delete admin user"
msgstr "Não é possível excluir o usuário administrador"
-#: users/models/user/__init__.py:307
+#: users/models/user/__init__.py:312
msgid "Can invite user"
msgstr "Pode convidar usuários"
-#: users/models/user/__init__.py:308
+#: users/models/user/__init__.py:313
msgid "Can remove user"
msgstr "Pode remover usuários"
-#: users/models/user/__init__.py:309
+#: users/models/user/__init__.py:314
msgid "Can match user"
msgstr "Pode combinar usuários"
-#: users/models/user/__init__.py:338
+#: users/models/user/__init__.py:343
msgid "User password history"
msgstr "Histórico de senhas do usuário"
@@ -11434,6 +11549,12 @@ msgstr "Histórico de senhas do usuário"
msgid "Force enabled"
msgstr "Forçar ativação"
+#: users/models/user/_source.py:27
+#, fuzzy
+#| msgid "Authenticate"
+msgid "Certificate"
+msgstr "Verificar identidade"
+
#: users/notifications.py:23 users/notifications.py:68
msgid "Reset password url"
msgstr "URL para redefinir a senha"
@@ -11547,7 +11668,7 @@ msgstr "Carregamento assíncrono da árvore de ativos"
msgid "Connect default open method"
msgstr "Forma padrão de abertura de conexão"
-#: users/serializers/preference/luna.py:34 xpack/plugins/interface/models.py:42
+#: users/serializers/preference/luna.py:34 xpack/plugins/interface/models.py:44
#: xpack/plugins/interface/serializers/interface.py:35
msgid "Theme"
msgstr "Tema"
@@ -11663,7 +11784,7 @@ msgstr " MFA Obrigatório "
msgid "Login blocked"
msgstr " Login Bloqueado "
-#: users/serializers/user.py:130 users/serializers/user.py:265
+#: users/serializers/user.py:130 users/serializers/user.py:270
msgid "Is OTP bound"
msgstr " MFA Virtual Vinculado "
@@ -11679,27 +11800,33 @@ msgstr " Admin da Organização "
msgid "Can public key authentication"
msgstr " Autenticação por Chave Pública Permitida "
-#: users/serializers/user.py:144
+#: users/serializers/user.py:145
+#, fuzzy
+#| msgid "Can public key authentication"
+msgid "Can certificate authentication"
+msgstr " Autenticação por Chave Pública Permitida "
+
+#: users/serializers/user.py:149
msgid "Is face code set"
msgstr "Existem características faciais?"
-#: users/serializers/user.py:230
+#: users/serializers/user.py:235
msgid "Full name"
msgstr " Nome Completo "
-#: users/serializers/user.py:233
+#: users/serializers/user.py:238
msgid "Login username"
msgstr " Usuário de Login "
-#: users/serializers/user.py:236
+#: users/serializers/user.py:241
msgid "Email address"
msgstr " Endereço de Email "
-#: users/serializers/user.py:246
+#: users/serializers/user.py:251
msgid "User groups to join"
msgstr " Quantidade de Grupos de Usuários "
-#: users/serializers/user.py:250
+#: users/serializers/user.py:255
msgid ""
"User source identifies where the user was created, which could be AD or "
"other sources.There are security settings that can restrict users to log in "
@@ -11709,34 +11836,34 @@ msgstr ""
"pode ser AD ou outra fonte. As configurações de segurança podem limitar os "
"usuários a fazer login somente a partir de uma fonte especificada."
-#: users/serializers/user.py:260
+#: users/serializers/user.py:265
msgid "Is org admin"
msgstr "Administrador da organização"
-#: users/serializers/user.py:262
+#: users/serializers/user.py:267
msgid "Avatar url"
msgstr "Caminho do avatar"
-#: users/serializers/user.py:267
+#: users/serializers/user.py:272
msgid "MFA level"
msgstr "MFA"
-#: users/serializers/user.py:268
+#: users/serializers/user.py:273
msgid "Multi-Factor Authentication"
msgstr "Autenticação"
-#: users/serializers/user.py:398
+#: users/serializers/user.py:403
msgid "Has public keys"
msgstr "Possui chave pública"
-#: users/serializers/user.py:426
+#: users/serializers/user.py:431
msgid ""
"* For security, only a partial of users is displayed. You can search for more"
msgstr ""
"* Para sua segurança, apenas alguns usuários são mostrados. Você pode "
"procurar por mais"
-#: users/serializers/user.py:462
+#: users/serializers/user.py:467
msgid "name not unique"
msgstr "Nome duplicado"
@@ -12254,7 +12381,7 @@ msgstr "IP privado"
msgid "Public IP"
msgstr "IP público"
-#: xpack/plugins/cloud/const.py:50 xpack/plugins/cloud/models.py:373
+#: xpack/plugins/cloud/const.py:50 xpack/plugins/cloud/models.py:374
msgid "Instance name"
msgstr "Nome da instância"
@@ -12455,8 +12582,8 @@ msgstr "Liberar recursos"
msgid "Date last sync"
msgstr "Última data de sincronização"
-#: xpack/plugins/cloud/models.py:135 xpack/plugins/cloud/models.py:391
-#: xpack/plugins/cloud/models.py:418
+#: xpack/plugins/cloud/models.py:135 xpack/plugins/cloud/models.py:392
+#: xpack/plugins/cloud/models.py:419
msgid "Strategy"
msgstr "Estratégia"
@@ -12496,71 +12623,71 @@ msgstr "Relação Condicional"
msgid "Task strategy"
msgstr "Estratégia de Tarefa"
-#: xpack/plugins/cloud/models.py:362
+#: xpack/plugins/cloud/models.py:363
msgid "Equal"
msgstr "Igual a"
-#: xpack/plugins/cloud/models.py:363
+#: xpack/plugins/cloud/models.py:364
msgid "Not Equal"
msgstr "Não é igual a"
-#: xpack/plugins/cloud/models.py:364
+#: xpack/plugins/cloud/models.py:365
msgid "In"
msgstr "Em..."
-#: xpack/plugins/cloud/models.py:365
+#: xpack/plugins/cloud/models.py:366
msgid "Contains"
msgstr "Contém"
-#: xpack/plugins/cloud/models.py:366
+#: xpack/plugins/cloud/models.py:367
msgid "Exclude"
msgstr "Excluir"
-#: xpack/plugins/cloud/models.py:367
+#: xpack/plugins/cloud/models.py:368
msgid "Startswith"
msgstr "Iniciar com..."
-#: xpack/plugins/cloud/models.py:368
+#: xpack/plugins/cloud/models.py:369
msgid "Endswith"
msgstr "Terminar com..."
-#: xpack/plugins/cloud/models.py:374
+#: xpack/plugins/cloud/models.py:375
msgid "Instance platform"
msgstr "Plataforma de instância"
-#: xpack/plugins/cloud/models.py:375
+#: xpack/plugins/cloud/models.py:376
msgid "Instance address"
msgstr "Endereço da instância"
-#: xpack/plugins/cloud/models.py:382
+#: xpack/plugins/cloud/models.py:383
msgid "Rule attr"
msgstr "Atributos de regra"
-#: xpack/plugins/cloud/models.py:386
+#: xpack/plugins/cloud/models.py:387
msgid "Rule match"
msgstr "Correspondência de regra"
-#: xpack/plugins/cloud/models.py:388
+#: xpack/plugins/cloud/models.py:389
msgid "Rule value"
msgstr "Valor da regra"
-#: xpack/plugins/cloud/models.py:395 xpack/plugins/cloud/serializers/task.py:82
+#: xpack/plugins/cloud/models.py:396 xpack/plugins/cloud/serializers/task.py:82
msgid "Strategy rule"
msgstr "Condição"
-#: xpack/plugins/cloud/models.py:406
+#: xpack/plugins/cloud/models.py:407
msgid "Name strategy"
msgstr "Política de nome de host"
-#: xpack/plugins/cloud/models.py:413
+#: xpack/plugins/cloud/models.py:414
msgid "Action attr"
msgstr "Atributos de ação"
-#: xpack/plugins/cloud/models.py:415
+#: xpack/plugins/cloud/models.py:416
msgid "Action value"
msgstr "Valor de ação"
-#: xpack/plugins/cloud/models.py:422 xpack/plugins/cloud/serializers/task.py:85
+#: xpack/plugins/cloud/models.py:423 xpack/plugins/cloud/serializers/task.py:85
msgid "Strategy action"
msgstr "Action"
@@ -12925,38 +13052,38 @@ msgstr "A missão ainda não começou"
msgid "Restore default successfully."
msgstr "Restauração para as configurações padrão bem sucedida!"
-#: xpack/plugins/interface/meta.py:9 xpack/plugins/interface/models.py:47
-#: xpack/plugins/interface/models.py:91
+#: xpack/plugins/interface/meta.py:9 xpack/plugins/interface/models.py:49
+#: xpack/plugins/interface/models.py:104
msgid "Interface settings"
msgstr "Configurações da interface"
-#: xpack/plugins/interface/models.py:24
+#: xpack/plugins/interface/models.py:26
msgid "Login title"
msgstr "Título da página de login"
-#: xpack/plugins/interface/models.py:28
+#: xpack/plugins/interface/models.py:30
msgid "Login image"
msgstr "Imagem da página de login"
-#: xpack/plugins/interface/models.py:32
+#: xpack/plugins/interface/models.py:34
msgid "Website icon"
msgstr "Ícone do site"
-#: xpack/plugins/interface/models.py:36
+#: xpack/plugins/interface/models.py:38
msgid "Index logo"
msgstr "Gerenciar página de logo"
-#: xpack/plugins/interface/models.py:40
+#: xpack/plugins/interface/models.py:42
msgid "Logout logo"
msgstr "Fazer Logout"
-#: xpack/plugins/interface/models.py:43
+#: xpack/plugins/interface/models.py:45
msgid "Footer content"
msgstr "Conteúdo do rodapé"
-#: xpack/plugins/interface/models.py:44
+#: xpack/plugins/interface/models.py:46
#: xpack/plugins/interface/serializers/interface.py:73
-msgid "Extended fields"
+msgid "Extend"
msgstr ""
#: xpack/plugins/interface/serializers/interface.py:48
@@ -13011,6 +13138,12 @@ msgstr ""
msgid "More login methods"
msgstr "Login por outros métodos"
+#: xpack/plugins/jdmc/i18n.py:4
+#, fuzzy
+#| msgid "Audit view"
+msgid "AuditAdmin"
+msgstr "Painel de auditoria"
+
#: xpack/plugins/jdmc/i18n.py:5
#, fuzzy
#| msgid "SystemAdmin"
@@ -13029,6 +13162,9 @@ msgstr "Importação de licença bem-sucedida"
msgid "Invalid license"
msgstr "Licença inválida"
+#~ msgid "User invalid, disabled or expired"
+#~ msgstr "O usuário é inválido, desativado ou expirado"
+
#~ msgid "Microsoft"
#~ msgstr "Microsoft"
diff --git a/apps/i18n/core/ru/LC_MESSAGES/django.po b/apps/i18n/core/ru/LC_MESSAGES/django.po
index fb4b273f9..3d227c7a2 100644
--- a/apps/i18n/core/ru/LC_MESSAGES/django.po
+++ b/apps/i18n/core/ru/LC_MESSAGES/django.po
@@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: jumpserver\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-04-21 17:03+0800\n"
+"POT-Creation-Date: 2026-05-25 14:02+0800\n"
"PO-Revision-Date: 2025-11-13 12:26\n"
"Last-Translator: ibuler \n"
"Language-Team: Russian\n"
@@ -31,7 +31,7 @@ msgstr "Учетная запись уже существует."
msgid "No valid assets found for account creation."
msgstr "Не удалось найти действительные активы для создания учетной записи."
-#: accounts/api/account/application.py:77
+#: accounts/api/account/application.py:87
#: authentication/api/connection_token.py:463
msgid "Account not found"
msgstr "Учетная запись не найдена"
@@ -45,15 +45,15 @@ msgstr "Параметр 'Действие' должен быть [{}]"
msgid "The account key will be split into two parts and sent"
msgstr "Ключ учетной записи будет разделен на две части и отправлен"
-#: accounts/automations/backup_account/handlers.py:131
+#: accounts/automations/backup_account/handlers.py:132
msgid "Number of backup accounts"
msgstr "Количество резервируемых учётных записей"
-#: accounts/automations/backup_account/handlers.py:152
+#: accounts/automations/backup_account/handlers.py:153
msgid "Generating asset related backup information files"
msgstr "Создание файлов резервной копии данных, связанных с активами"
-#: accounts/automations/backup_account/handlers.py:177
+#: accounts/automations/backup_account/handlers.py:178
#: accounts/automations/backup_account/manager.py:26
#: accounts/automations/change_secret/manager.py:81
#: accounts/automations/push_account/manager.py:62
@@ -64,31 +64,31 @@ msgstr "Создание файлов резервной копии данных
msgid "Duration"
msgstr "Продолжительность"
-#: accounts/automations/backup_account/handlers.py:178
+#: accounts/automations/backup_account/handlers.py:179
msgid "Backup file creation completed"
msgstr "Создание файла резервной копии завершено"
-#: accounts/automations/backup_account/handlers.py:186
+#: accounts/automations/backup_account/handlers.py:187
msgid "Start sending backup emails"
msgstr "Начинается отправка резервной копии на почту"
-#: accounts/automations/backup_account/handlers.py:213
+#: accounts/automations/backup_account/handlers.py:214
msgid "Encrypting files using encryption password"
msgstr "Шифрование файлов с использованием пароля шифрования"
-#: accounts/automations/backup_account/handlers.py:223
+#: accounts/automations/backup_account/handlers.py:224
msgid "The backup file will be sent to"
msgstr "Резервный файл будет отправлен"
-#: accounts/automations/backup_account/handlers.py:246
+#: accounts/automations/backup_account/handlers.py:247
msgid "The backup task has no assigned sftp server"
msgstr "В задаче резервирования не указан сервер SFTP"
-#: accounts/automations/backup_account/handlers.py:267
+#: accounts/automations/backup_account/handlers.py:268
msgid "The backup task has no assigned recipient"
msgstr "В задаче резервирования не указан получатель"
-#: accounts/automations/backup_account/handlers.py:290
+#: accounts/automations/backup_account/handlers.py:291
msgid "Plan start"
msgstr "Запуск задачи"
@@ -157,7 +157,7 @@ msgstr ""
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -231,7 +231,7 @@ msgstr "Обновить"
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr "Не удалось"
@@ -353,14 +353,14 @@ msgstr "SFTP"
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "Успех"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr "В ожидании"
@@ -368,7 +368,7 @@ msgstr "В ожидании"
msgid "Queued"
msgstr "В очереди"
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr "Готово"
@@ -380,7 +380,7 @@ msgstr "Обработка"
msgid "Can login"
msgstr "Доступен вход"
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr "Суперпользователь"
@@ -409,7 +409,7 @@ msgid "Default tablespace"
msgstr "Табличное пространство по умолчанию"
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr "Роль"
@@ -418,7 +418,7 @@ msgid "Perms"
msgstr "Права"
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr "Группы"
@@ -793,7 +793,7 @@ msgstr "Дата окончания"
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -808,7 +808,7 @@ msgstr "Статус"
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr "Ошибка"
@@ -903,8 +903,9 @@ msgstr "Повторяющийся пароль"
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1063,7 +1064,7 @@ msgstr "Привилегированный"
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "Активно"
@@ -1079,7 +1080,7 @@ msgstr "Платформа"
msgid "Push params"
msgstr "Параметры публикации аккаунта"
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr "Шаблон УЗ"
@@ -1181,7 +1182,7 @@ msgstr "Сбор информации об изменении УЗ"
msgid "Change secret or push account failed information"
msgstr "Информация о неудачных сменах секретов и публикациях УЗ"
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr "Игнорируется"
@@ -1337,7 +1338,7 @@ msgstr "ID"
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1345,8 +1346,8 @@ msgstr "ID"
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr "Пользователь"
@@ -1381,7 +1382,7 @@ msgstr "Белый список IP"
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1696,7 +1697,7 @@ msgstr ""
" в разделе \"Системные настройки - Функции\" - Хранилище учетной "
"записи - Ограничение записей"
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr "Удаление исторических учетных записей, которые превышают лимит."
@@ -1769,7 +1770,7 @@ msgstr "Название задачи"
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1954,7 +1955,7 @@ msgstr "Утверждающий"
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr "Пользователь"
@@ -1980,7 +1981,7 @@ msgid "Command"
msgstr "Команда"
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr "Регулярное выражение"
@@ -2069,7 +2070,7 @@ msgstr "Правило"
msgid "Login acl"
msgstr "Правила входа пользователей"
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr "Проверка входа"
@@ -2193,7 +2194,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr "IP"
@@ -2256,16 +2257,16 @@ msgstr "Мы хотим сообщить вам, что недавно воше
msgid "User details"
msgstr "Данные пользователя"
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr ""
"Невозможно создать актив напрямую, вам следует создать хост или другой тип"
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr "Количество активов превышает лимит в 5000"
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
#, fuzzy
#| msgid "The number of assets exceeds the limit of 5000"
msgid "The number of assets exceeds the license limit"
@@ -2284,6 +2285,11 @@ msgstr "Нельзя удалить корневую папку ({})"
msgid "Deletion failed and the node contains assets"
msgstr "Удаление не удалось, папка содержит активы"
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr "Имена папок одного уровня не могут повторяться"
@@ -2301,29 +2307,29 @@ msgstr "Управление активами"
msgid "Task: {} finished"
msgstr "Задача: {} Выполнена"
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr " - Ansible отключена на платформе {}, выполнение задачи невозможно"
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr ">>> Подготовка к выполнению"
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ">>> Пакетное выполнение задач, всего {runner_count}"
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ">>> Начинаем выполнение задач"
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ">>> Нет задач для выполнения"
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ">>> Начинаем выполнение пакета из {index} задач"
@@ -2729,7 +2735,7 @@ msgid "Port"
msgstr "Порт"
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr "Адрес"
@@ -2737,12 +2743,12 @@ msgstr "Адрес"
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr "Платформа"
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr "Зона"
@@ -2811,9 +2817,9 @@ msgid "Proxy"
msgstr "Прокси"
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr "Папка"
@@ -2839,7 +2845,7 @@ msgstr "Автоматизация активов"
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr "Дата создания"
@@ -2928,7 +2934,7 @@ msgstr "Шлюз"
msgid "System"
msgstr "Система"
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2943,7 +2949,7 @@ msgstr "Значение"
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr "Тег"
@@ -2959,27 +2965,27 @@ msgstr "Пользовательская заметка"
msgid "My assets"
msgstr "Мои активы"
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr "Новая папка"
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr "пусто"
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr "Ключ"
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr "Полное значение"
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr "Ключ SSH"
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr "Сопоставление с папкой"
@@ -3159,7 +3165,7 @@ msgstr ""
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr "Протоколы"
@@ -3619,7 +3625,7 @@ msgid "Symlink"
msgstr "Создать символическую ссылку"
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr "Скачать"
@@ -3648,7 +3654,9 @@ msgstr "Экспорт"
msgid "Connect"
msgstr "Подключить"
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4448,17 +4456,17 @@ msgstr "Не удалось сравнить лица"
msgid "Current user not support mfa type: {}"
msgstr "Текущий пользователь не поддерживает тип МФА: {}."
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr "Пользователь не существует: {}"
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr "Нет подходящего пользователя"
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
@@ -4466,7 +4474,7 @@ msgid ""
msgstr ""
"Пользователь из {}, пожалуйста, измените пароль в соответствующей системе"
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4476,7 +4484,7 @@ msgstr ""
msgid "Forgot password"
msgstr "Забыли пароль"
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr "Срок действия кода проверки: {} мин"
@@ -4489,10 +4497,29 @@ msgstr "Управление аутентификацией"
msgid "CAS Error"
msgstr "Ошибка CAS"
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
-msgstr "Пользователь недействителен, отключен или просрочен"
+#: authentication/backends/cert/api.py:57
+#, fuzzy
+#| msgid "LDAP authentication is not enabled"
+msgid "Certificate enrollment is not enabled"
+msgstr "LDAP аутентификация не включена"
+
+#: authentication/backends/cert/api.py:62
+#, fuzzy
+#| msgid "type is required"
+msgid "CSR is required"
+msgstr "тип обязателен"
+
+#: authentication/backends/cert/api.py:68
+#, fuzzy
+#| msgid "Authentication failed"
+msgid "Certificate signing failed"
+msgstr "Ошибка аутентификации"
+
+#: authentication/backends/cert/views.py:97
+#, fuzzy
+#| msgid "Invalid data"
+msgid "Invalid credentials"
+msgstr "Недопустимые данные"
#: authentication/backends/drf.py:61
msgid "Invalid token header. No credentials provided."
@@ -4746,16 +4773,16 @@ msgstr "Ваш пароль недействителен"
msgid "Please wait for %s seconds before retry"
msgstr "Пожалуйста, подождите %s секунд перед повторной попыткой"
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr "Ваш пароль слишком простой, измените его в целях безопасности"
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr "Вам необходимо сменить пароль перед входом в систему"
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr ""
"Срок действия вашего пароля истек, пожалуйста, сбросьте его перед входом в "
@@ -4887,11 +4914,11 @@ msgstr ""
"пользователей', текущий пользователь отсутствует в списке пользователей, "
"пожалуйста, свяжитесь с администратором."
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr "Недействительный пользователь"
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4901,12 +4928,12 @@ msgstr ""
"Администратор включил 'разрешить вход только из источника пользователей', "
"текущий источник пользователя - {}, пожалуйста, свяжитесь с администратором."
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr "Способ МФА ({}) не включен"
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr "Пожалуйста, измените свой пароль"
@@ -5098,7 +5125,7 @@ msgstr "Действия"
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "Истекший?"
@@ -5140,13 +5167,13 @@ msgstr "Недействительный ключ SSH"
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "Действует?"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr "Область"
@@ -5249,7 +5276,7 @@ msgstr "Ошибка кода"
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5362,6 +5389,87 @@ msgstr ""
msgid "Cancel"
msgstr "Отмена"
+#: authentication/templates/authentication/cert_login.html:190
+#, fuzzy
+#| msgid "Multi-Factor Authentication"
+msgid "Certificate Authentication"
+msgstr "Многофакторная аутентификация"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:238
+#, fuzzy
+#| msgid "More login options"
+msgid "Other login methods"
+msgstr "Другие способы входа"
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:253
+#, fuzzy
+#| msgid "Please enter SMS code"
+msgid "Please insert USB Key"
+msgstr "Пожалуйста, введите код из SMS"
+
+#: authentication/templates/authentication/cert_login.html:254
+#, fuzzy
+#| msgid "Account unavailable"
+msgid "Driver unavailable"
+msgstr "Учетная запись недоступна"
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:257
+#, fuzzy
+#| msgid "Date verified"
+msgid "PIN verified"
+msgstr "Дата проверки"
+
+#: authentication/templates/authentication/cert_login.html:258
+#, fuzzy
+#| msgid "OTP verification code"
+msgid "PIN verification failed"
+msgstr "Код подтверждения OTP"
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:260
+#, fuzzy
+#| msgid "Signing key"
+msgid "Signing failed"
+msgstr "Подпись ключа"
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:262
+#, fuzzy
+#| msgid "Your account has expired, please contact the administrator."
+msgid "No certificate detected, please contact administrator"
+msgstr "Ваш аккаунт истек, пожалуйста, свяжитесь с администратором"
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr "Повторить"
@@ -5437,6 +5545,10 @@ msgstr "Хотите попробовать снова?"
msgid "LAN"
msgstr "Локальная сеть"
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5602,47 +5714,47 @@ msgstr "Пожалуйста, войдите с паролем, а затем п
msgid "Request file format may be wrong"
msgstr "Неверный формат загружаемого файла или файл другого типа ресурсов"
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr "Китай"
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr "Ручной триггер"
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr "Триггер по времени"
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr "В процессе"
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr "Отмена"
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr "Подтвержденный"
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr "Редакция Community"
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr "Редакция Basic"
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr "Редакция Standard"
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr "Редакция Professional"
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr "Редакция Ultimate"
@@ -6162,24 +6274,24 @@ msgstr "Код не найден"
msgid "The message code provided is invalid or has expired"
msgstr "Предоставленный код сообщения недействительный или истек"
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr "Код подтверждения: {code}"
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr "Успешное создание учетной записи"
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr "Ваша учетная запись была успешно создана"
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "JumpServer открытая система управления доступом"
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -6917,7 +7029,7 @@ msgid "Please save in a org"
msgstr "Пожалуйста, выберите организацию перед сохранением"
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -7347,15 +7459,15 @@ msgstr "Системная роль"
msgid "Organization role"
msgstr "Организационная роль"
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr "Привязка ролей"
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr "Все организации"
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
@@ -7363,11 +7475,11 @@ msgstr ""
"Последняя роль пользователя не может быть удалена. Вы можете удалить "
"пользователя из организации."
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr "Привязка организационной роли"
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr "Привязка системной роли"
@@ -7432,7 +7544,7 @@ msgid "Storage"
msgstr "Хранилище"
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr "Приложения"
@@ -7495,51 +7607,51 @@ msgstr "Отменить токен доступа"
msgid "Range days"
msgstr "Изменивший"
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr "Отчет о входах пользователей"
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr "Отчет о смене пароля пользователя"
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr "Отчет по статистике активов"
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr "Отчет по действиям с активами"
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr "Отчет по статистике учётных записей"
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr "Отчет по автоматизации учётных записей"
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr "Панель управления"
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr "Панель аудита"
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr "Панель PAM"
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr "Панель смены пароля УЗ"
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr "Не удалось отправить письмо "
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr "Письмо успешно отправлено "
@@ -7823,21 +7935,21 @@ msgstr "Dingtalk"
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
"Сопоставление атрибутов пользователя, где \"ключ\" — это название атрибута "
-"пользователя системы, а \"значение\" — название атрибута пользователя "
-"службы DingTalk"
+"пользователя системы, а \"значение\" — название атрибута пользователя службы "
+"DingTalk"
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
"Сопоставление атрибутов пользователя, где \"ключ\" — это название атрибута "
-"пользователя системы, а \"значение\" — название атрибута пользователя "
-"службы Feishu"
+"пользователя системы, а \"значение\" — название атрибута пользователя службы "
+"Feishu"
#: settings/serializers/auth/lark.py:13 users/models/user/_source.py:24
msgid "Lark"
@@ -7845,12 +7957,12 @@ msgstr "Lark"
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
"Сопоставление атрибутов пользователя, где \"ключ\" — это имя атрибута "
-"пользователя системы, а \"значение\" — это имя атрибута пользователя "
-"службы Lark"
+"пользователя системы, а \"значение\" — это имя атрибута пользователя службы "
+"Lark"
#: settings/serializers/auth/ldap.py:42 settings/serializers/auth/ldap.py:108
msgid "LDAP"
@@ -7896,12 +8008,12 @@ msgstr "Возможные варианты: (cn или uid или sAMAccountNam
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
"Сопоставление атрибутов пользователя, где \"ключ\" — это имя атрибута "
-"пользователя системы, а \"значение\" — это имя атрибута пользователя "
-"службы LDAP"
+"пользователя системы, а \"значение\" — это имя атрибута пользователя службы "
+"LDAP"
#: settings/serializers/auth/ldap.py:85 settings/serializers/auth/ldap_ha.py:67
msgid "Connect timeout (s)"
@@ -8008,8 +8120,8 @@ msgstr "При выходе пользователя из системы он т
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
"Сопоставление атрибутов пользователя, где \"ключ\" - это название атрибута "
"пользователя системы, а \"значение\" - название атрибута пользователя "
@@ -8046,8 +8158,8 @@ msgstr "Игнорировать проверку SSL"
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
"Сопоставление атрибутов пользователя, где \"ключ\" - это имя атрибута "
"пользователя системы, а \"значение\" - это имя атрибута пользователя OIDC "
@@ -8194,8 +8306,8 @@ msgstr "При выходе пользователя из системы он т
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
"Сопоставление атрибутов пользователя, где \"ключ\" — это имя атрибута "
"пользователя системы, а \"значение\" — имя атрибута пользователя Slack "
@@ -8233,7 +8345,7 @@ msgid "Template code"
msgstr "Шаблон"
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr "Телефон"
@@ -8290,7 +8402,10 @@ msgid "Enable SSO auth"
msgstr "Включить аутентификацию по SSO-токену"
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
+#, fuzzy
+#| msgid ""
+#| "Other service can using SSO token login to JumpServer without password"
+msgid "Other service can using SSO token login to system without password"
msgstr ""
"Другие системы могут использовать токен SSO для интеграции с JumpServer, "
"исключая процесс входа в систему"
@@ -8306,8 +8421,8 @@ msgstr "Единицы: секунды"
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
"Сопоставление атрибутов пользователя, где \"ключ\" — это название атрибута "
"пользователя системы, а \"значение\" — это название атрибута пользователя "
@@ -9487,7 +9602,7 @@ msgstr "Ожидание: "
msgid "The verification code has been sent"
msgstr "Код подтверждения был отправлен"
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "Главная страница"
@@ -9752,31 +9867,31 @@ msgstr "Возможен параллельный запуск"
msgid "Hosts"
msgstr "Хосты"
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr "Недопустимый пакет Applet: отсутствует файл {}"
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr "Не удалось загрузить platform.yml: {}"
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr "Поддерживается только пользовательская платформа"
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr "Отсутствует тип в platform.yml"
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "Хост-машина"
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr "Публикация приложения"
@@ -9866,7 +9981,7 @@ msgstr "VNC порт"
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -10080,8 +10195,8 @@ msgstr "Хранение команд и записей сессий"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr "Тест не пройден: учетная запись недействительна"
@@ -10203,11 +10318,13 @@ msgstr "Существующая лицензия RDS"
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
"Если лицензия отсутствует, RDS будет работать в пробном режиме в течение 120 "
"дней. Подробнее"
+"remote-desktop-services/rds-client-access-license' "
+"target='_blank'>Подробнее"
#: terminal/serializers/applet_host.py:55
msgid "RDS License Server"
@@ -10336,7 +10453,7 @@ msgstr "Неверный id сессии"
msgid "Timestamp"
msgstr "Метка времени"
-#: terminal/serializers/endpoint.py:27
+#: terminal/serializers/endpoint.py:28
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 "
@@ -10346,7 +10463,7 @@ msgstr ""
"Если он пустой, используется адрес доступа текущего браузера (в конечной "
"точке по умолчанию нельзя изменить хост)"
-#: terminal/serializers/endpoint.py:54
+#: terminal/serializers/endpoint.py:64
msgid ""
"The assets within this IP range or Host, the following endpoint will be used "
"for the connection"
@@ -10354,7 +10471,7 @@ msgstr ""
"Активы в пределах данного диапазона IP или хоста будут подключены с "
"использованием следующей конечной точки."
-#: terminal/serializers/endpoint.py:55
+#: terminal/serializers/endpoint.py:65
msgid ""
"If asset IP addresses under different endpoints conflict, use asset labels"
msgstr ""
@@ -10495,7 +10612,7 @@ msgstr "Онлайн"
msgid "Stat"
msgstr "Статус"
-#: terminal/serializers/terminal.py:83 terminal/serializers/terminal.py:91
+#: terminal/serializers/terminal.py:79 terminal/serializers/terminal.py:87
msgid "Not found"
msgstr "Отсутствует"
@@ -11099,7 +11216,7 @@ msgstr "Запрашивающий"
msgid "Approval Step Distribution"
msgstr "Одобрение без входа"
-#: tickets/serializers/flow.py:45
+#: tickets/serializers/flow.py:42
msgid "The current organization type already exists"
msgstr "В текущей организации уже существует данный тип"
@@ -11160,7 +11277,7 @@ msgid "Ticket information"
msgstr "Информация о заявке"
#: tickets/templates/tickets/approve_check_password.html:28
-#: tickets/views/approve.py:43 tickets/views/approve.py:80
+#: tickets/views/approve.py:42 tickets/views/approve.py:80
msgid "Ticket approval"
msgstr "Одобрение заявки"
@@ -11168,14 +11285,14 @@ msgstr "Одобрение заявки"
msgid "Approval"
msgstr "Согласен"
-#: tickets/views/approve.py:44
+#: tickets/views/approve.py:43
msgid ""
"This ticket does not exist, the process has ended, or this link has expired"
msgstr ""
"Эта заявка не существует, процесс завершен или срок действия этой ссылки "
"истек"
-#: tickets/views/approve.py:72
+#: tickets/views/approve.py:71
msgid "Click the button below to approve or reject"
msgstr "Нажмите кнопку ниже, чтобы одобрить или отклонить"
@@ -11391,7 +11508,7 @@ msgstr "Настройки пользователя"
msgid "Email lookup"
msgstr "Адрес электронной почты"
-#: users/models/user/__init__.py:82 users/serializers/user.py:259
+#: users/models/user/__init__.py:82 users/serializers/user.py:264
msgid "Is service account"
msgstr "Служебная УЗ"
@@ -11410,7 +11527,7 @@ msgstr "Секретный ключ OTP"
# msgid "Private key"
# msgstr "ssh私钥"
#: users/models/user/__init__.py:105 users/serializers/profile.py:86
-#: users/serializers/user.py:256
+#: users/serializers/user.py:261
msgid "Is first login"
msgstr "Первый вход"
@@ -11430,23 +11547,23 @@ msgstr "Вектор лица"
msgid "Date api key used"
msgstr "Дата использования ключа API"
-#: users/models/user/__init__.py:293
+#: users/models/user/__init__.py:298
msgid "Can not delete admin user"
msgstr "Невозможно удалить администратора"
-#: users/models/user/__init__.py:307
+#: users/models/user/__init__.py:312
msgid "Can invite user"
msgstr "Приглашать пользователя"
-#: users/models/user/__init__.py:308
+#: users/models/user/__init__.py:313
msgid "Can remove user"
msgstr "Удаление пользователя"
-#: users/models/user/__init__.py:309
+#: users/models/user/__init__.py:314
msgid "Can match user"
msgstr "Сопоставление пользователей"
-#: users/models/user/__init__.py:338
+#: users/models/user/__init__.py:343
msgid "User password history"
msgstr "История паролей пользователя"
@@ -11454,6 +11571,12 @@ msgstr "История паролей пользователя"
msgid "Force enabled"
msgstr "Принудительное включение"
+#: users/models/user/_source.py:27
+#, fuzzy
+#| msgid "Authenticate"
+msgid "Certificate"
+msgstr "Аутентификация"
+
#: users/notifications.py:23 users/notifications.py:68
msgid "Reset password url"
msgstr "Ссылка для сброса пароля"
@@ -11567,7 +11690,7 @@ msgstr "Асинхронная загрузка дерева активов"
msgid "Connect default open method"
msgstr "Подключить с настройками по умолчанию"
-#: users/serializers/preference/luna.py:34 xpack/plugins/interface/models.py:42
+#: users/serializers/preference/luna.py:34 xpack/plugins/interface/models.py:44
#: xpack/plugins/interface/serializers/interface.py:35
msgid "Theme"
msgstr "Тема"
@@ -11685,7 +11808,7 @@ msgstr "Обязательная МФА"
msgid "Login blocked"
msgstr "Вход заблокирован"
-#: users/serializers/user.py:130 users/serializers/user.py:265
+#: users/serializers/user.py:130 users/serializers/user.py:270
msgid "Is OTP bound"
msgstr "OTP привязан"
@@ -11701,27 +11824,33 @@ msgstr "Администратор организации"
msgid "Can public key authentication"
msgstr "Может войти с открытым ключем"
-#: users/serializers/user.py:144
+#: users/serializers/user.py:145
+#, fuzzy
+#| msgid "Can public key authentication"
+msgid "Can certificate authentication"
+msgstr "Может войти с открытым ключем"
+
+#: users/serializers/user.py:149
msgid "Is face code set"
msgstr "Есть настройки биометрии"
-#: users/serializers/user.py:230
+#: users/serializers/user.py:235
msgid "Full name"
msgstr "Полное имя"
-#: users/serializers/user.py:233
+#: users/serializers/user.py:238
msgid "Login username"
msgstr "Имя пользователя для входа"
-#: users/serializers/user.py:236
+#: users/serializers/user.py:241
msgid "Email address"
msgstr "Адрес электронной почты"
-#: users/serializers/user.py:246
+#: users/serializers/user.py:251
msgid "User groups to join"
msgstr "Группы пользователей для добавления"
-#: users/serializers/user.py:250
+#: users/serializers/user.py:255
msgid ""
"User source identifies where the user was created, which could be AD or "
"other sources.There are security settings that can restrict users to log in "
@@ -11732,34 +11861,34 @@ msgstr ""
"ограничивать пользователей, чтобы они входили в систему только из указанных "
"источников."
-#: users/serializers/user.py:260
+#: users/serializers/user.py:265
msgid "Is org admin"
msgstr "Администратор организации"
-#: users/serializers/user.py:262
+#: users/serializers/user.py:267
msgid "Avatar url"
msgstr "URL аватара"
-#: users/serializers/user.py:267
+#: users/serializers/user.py:272
msgid "MFA level"
msgstr "Уровень МФА"
-#: users/serializers/user.py:268
+#: users/serializers/user.py:273
msgid "Multi-Factor Authentication"
msgstr "Многофакторная аутентификация"
-#: users/serializers/user.py:398
+#: users/serializers/user.py:403
msgid "Has public keys"
msgstr "Есть открытый ключ"
-#: users/serializers/user.py:426
+#: users/serializers/user.py:431
msgid ""
"* For security, only a partial of users is displayed. You can search for more"
msgstr ""
"* В целях безопасности отображаются только некоторые пользователи. Вы можете "
"выполнить поиск по другим"
-#: users/serializers/user.py:462
+#: users/serializers/user.py:467
msgid "name not unique"
msgstr "имя не уникально"
@@ -12281,7 +12410,7 @@ msgstr "Частный IP"
msgid "Public IP"
msgstr "Публичный IP"
-#: xpack/plugins/cloud/const.py:50 xpack/plugins/cloud/models.py:373
+#: xpack/plugins/cloud/const.py:50 xpack/plugins/cloud/models.py:374
msgid "Instance name"
msgstr "Имя экземпляра"
@@ -12482,8 +12611,8 @@ msgstr "Опубликовать активы"
msgid "Date last sync"
msgstr "Дата последней синхронизации"
-#: xpack/plugins/cloud/models.py:135 xpack/plugins/cloud/models.py:391
-#: xpack/plugins/cloud/models.py:418
+#: xpack/plugins/cloud/models.py:135 xpack/plugins/cloud/models.py:392
+#: xpack/plugins/cloud/models.py:419
msgid "Strategy"
msgstr "Стратегия"
@@ -12523,71 +12652,71 @@ msgstr "Логика правил"
msgid "Task strategy"
msgstr "Стратегия задачи"
-#: xpack/plugins/cloud/models.py:362
+#: xpack/plugins/cloud/models.py:363
msgid "Equal"
msgstr "Равно"
-#: xpack/plugins/cloud/models.py:363
+#: xpack/plugins/cloud/models.py:364
msgid "Not Equal"
msgstr "Не равно"
-#: xpack/plugins/cloud/models.py:364
+#: xpack/plugins/cloud/models.py:365
msgid "In"
msgstr "в"
-#: xpack/plugins/cloud/models.py:365
+#: xpack/plugins/cloud/models.py:366
msgid "Contains"
msgstr "Содержит"
-#: xpack/plugins/cloud/models.py:366
+#: xpack/plugins/cloud/models.py:367
msgid "Exclude"
msgstr "Исключить"
-#: xpack/plugins/cloud/models.py:367
+#: xpack/plugins/cloud/models.py:368
msgid "Startswith"
msgstr "Начинается с"
-#: xpack/plugins/cloud/models.py:368
+#: xpack/plugins/cloud/models.py:369
msgid "Endswith"
msgstr "Заканчивается на"
-#: xpack/plugins/cloud/models.py:374
+#: xpack/plugins/cloud/models.py:375
msgid "Instance platform"
msgstr "Платформа экземпляра"
-#: xpack/plugins/cloud/models.py:375
+#: xpack/plugins/cloud/models.py:376
msgid "Instance address"
msgstr "Адрес экземпляра"
-#: xpack/plugins/cloud/models.py:382
+#: xpack/plugins/cloud/models.py:383
msgid "Rule attr"
msgstr "Атрибуты правила"
-#: xpack/plugins/cloud/models.py:386
+#: xpack/plugins/cloud/models.py:387
msgid "Rule match"
msgstr "Сопоставление правила"
-#: xpack/plugins/cloud/models.py:388
+#: xpack/plugins/cloud/models.py:389
msgid "Rule value"
msgstr "Значение правила"
-#: xpack/plugins/cloud/models.py:395 xpack/plugins/cloud/serializers/task.py:82
+#: xpack/plugins/cloud/models.py:396 xpack/plugins/cloud/serializers/task.py:82
msgid "Strategy rule"
msgstr "Правило стратегии"
-#: xpack/plugins/cloud/models.py:406
+#: xpack/plugins/cloud/models.py:407
msgid "Name strategy"
msgstr "Стратегия имени"
-#: xpack/plugins/cloud/models.py:413
+#: xpack/plugins/cloud/models.py:414
msgid "Action attr"
msgstr "Атрибуты действия"
-#: xpack/plugins/cloud/models.py:415
+#: xpack/plugins/cloud/models.py:416
msgid "Action value"
msgstr "Значение действия"
-#: xpack/plugins/cloud/models.py:422 xpack/plugins/cloud/serializers/task.py:85
+#: xpack/plugins/cloud/models.py:423 xpack/plugins/cloud/serializers/task.py:85
msgid "Strategy action"
msgstr "Действия стратегии"
@@ -12950,38 +13079,38 @@ msgstr "Миссия еще не началась"
msgid "Restore default successfully."
msgstr "Настройки по умолчанию успешно восстановлены."
-#: xpack/plugins/interface/meta.py:9 xpack/plugins/interface/models.py:47
-#: xpack/plugins/interface/models.py:91
+#: xpack/plugins/interface/meta.py:9 xpack/plugins/interface/models.py:49
+#: xpack/plugins/interface/models.py:104
msgid "Interface settings"
msgstr "Настройки интерфейса"
-#: xpack/plugins/interface/models.py:24
+#: xpack/plugins/interface/models.py:26
msgid "Login title"
msgstr "Заголовок страницы входа"
-#: xpack/plugins/interface/models.py:28
+#: xpack/plugins/interface/models.py:30
msgid "Login image"
msgstr "Изображение на странице входа"
-#: xpack/plugins/interface/models.py:32
+#: xpack/plugins/interface/models.py:34
msgid "Website icon"
msgstr "Иконка сайта"
-#: xpack/plugins/interface/models.py:36
+#: xpack/plugins/interface/models.py:38
msgid "Index logo"
msgstr "Логотип страницы"
-#: xpack/plugins/interface/models.py:40
+#: xpack/plugins/interface/models.py:42
msgid "Logout logo"
msgstr "Иконка выхода"
-#: xpack/plugins/interface/models.py:43
+#: xpack/plugins/interface/models.py:45
msgid "Footer content"
msgstr "Содержимое нижнего колонтитула"
-#: xpack/plugins/interface/models.py:44
+#: xpack/plugins/interface/models.py:46
#: xpack/plugins/interface/serializers/interface.py:73
-msgid "Extended fields"
+msgid "Extend"
msgstr ""
#: xpack/plugins/interface/serializers/interface.py:48
@@ -13036,6 +13165,12 @@ msgstr ""
msgid "More login methods"
msgstr "Другие способы входа"
+#: xpack/plugins/jdmc/i18n.py:4
+#, fuzzy
+#| msgid "Audit view"
+msgid "AuditAdmin"
+msgstr "Панель Аудита"
+
#: xpack/plugins/jdmc/i18n.py:5
#, fuzzy
#| msgid "SystemAdmin"
@@ -13054,6 +13189,9 @@ msgstr "Лицензия успешно импортирована"
msgid "Invalid license"
msgstr "Лицензия недействительна"
+#~ msgid "User invalid, disabled or expired"
+#~ msgstr "Пользователь недействителен, отключен или просрочен"
+
#~ msgid "Microsoft"
#~ msgstr "Microsoft"
diff --git a/apps/i18n/core/vi/LC_MESSAGES/django.po b/apps/i18n/core/vi/LC_MESSAGES/django.po
index cd05229d1..872b05540 100644
--- a/apps/i18n/core/vi/LC_MESSAGES/django.po
+++ b/apps/i18n/core/vi/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-04-21 17:03+0800\n"
+"POT-Creation-Date: 2026-05-25 14:02+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -28,7 +28,7 @@ msgstr "Tài khoản đã tồn tại"
msgid "No valid assets found for account creation."
msgstr "Không tìm thấy tài sản hợp lệ để tạo tài khoản."
-#: accounts/api/account/application.py:77
+#: accounts/api/account/application.py:87
#: authentication/api/connection_token.py:463
msgid "Account not found"
msgstr "Tài khoản không tìm thấy"
@@ -42,15 +42,15 @@ msgstr "Tham số 'action' phải là [{}]"
msgid "The account key will be split into two parts and sent"
msgstr "Khóa tài khoản sẽ được chia thành hai phần gửi đi"
-#: accounts/automations/backup_account/handlers.py:131
+#: accounts/automations/backup_account/handlers.py:132
msgid "Number of backup accounts"
msgstr "Số lượng tài khoản sao lưu"
-#: accounts/automations/backup_account/handlers.py:152
+#: accounts/automations/backup_account/handlers.py:153
msgid "Generating asset related backup information files"
msgstr "Tạo tệp thông tin sao lưu liên quan đến tài sản"
-#: accounts/automations/backup_account/handlers.py:177
+#: accounts/automations/backup_account/handlers.py:178
#: accounts/automations/backup_account/manager.py:26
#: accounts/automations/change_secret/manager.py:81
#: accounts/automations/push_account/manager.py:62
@@ -61,31 +61,31 @@ msgstr "Tạo tệp thông tin sao lưu liên quan đến tài sản"
msgid "Duration"
msgstr "Thời gian tiêu tốn"
-#: accounts/automations/backup_account/handlers.py:178
+#: accounts/automations/backup_account/handlers.py:179
msgid "Backup file creation completed"
msgstr "Hoàn thành việc tạo tệp sao lưu"
-#: accounts/automations/backup_account/handlers.py:186
+#: accounts/automations/backup_account/handlers.py:187
msgid "Start sending backup emails"
msgstr "Bắt đầu gửi email sao lưu"
-#: accounts/automations/backup_account/handlers.py:213
+#: accounts/automations/backup_account/handlers.py:214
msgid "Encrypting files using encryption password"
msgstr "Đang mã hóa tệp bằng mật khẩu mã hóa"
-#: accounts/automations/backup_account/handlers.py:223
+#: accounts/automations/backup_account/handlers.py:224
msgid "The backup file will be sent to"
msgstr "Tệp sao lưu sẽ được gửi đến"
-#: accounts/automations/backup_account/handlers.py:246
+#: accounts/automations/backup_account/handlers.py:247
msgid "The backup task has no assigned sftp server"
msgstr "Nhiệm vụ sao lưu này chưa được phân bổ máy chủ sftp"
-#: accounts/automations/backup_account/handlers.py:267
+#: accounts/automations/backup_account/handlers.py:268
msgid "The backup task has no assigned recipient"
msgstr "Nhiệm vụ sao lưu không chỉ định người nhận"
-#: accounts/automations/backup_account/handlers.py:290
+#: accounts/automations/backup_account/handlers.py:291
msgid "Plan start"
msgstr "Nhiệm vụ bắt đầu"
@@ -154,7 +154,7 @@ msgstr ""
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -228,7 +228,7 @@ msgstr "Cập nhật"
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr "Thất bại"
@@ -350,14 +350,14 @@ msgstr "SFTP"
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "Success"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr "Đang chờ xử lý"
@@ -365,7 +365,7 @@ msgstr "Đang chờ xử lý"
msgid "Queued"
msgstr "Sẵn sàng"
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr "Đang xử lý"
@@ -377,7 +377,7 @@ msgstr "Có thể đăng nhập"
msgid "Can login"
msgstr "Siêu người dùng"
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr "Ngày tạo"
@@ -406,7 +406,7 @@ msgid "Default tablespace"
msgstr "Không gian bảng mặc định"
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr "Vai trò"
@@ -415,7 +415,7 @@ msgid "Perms"
msgstr "Quyền hạn"
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr "Nhóm người dùng"
@@ -790,7 +790,7 @@ msgstr "Ngày kết thúc"
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -805,7 +805,7 @@ msgstr "Trạng thái"
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr "Lỗi"
@@ -900,8 +900,9 @@ msgstr "Mật khẩu trùng lặp"
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1072,7 +1073,7 @@ msgstr "Tài khoản đặc quyền"
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "Active"
@@ -1088,7 +1089,7 @@ msgstr "Nền tảng"
msgid "Push params"
msgstr "Tham số đẩy tài khoản"
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr "Mẫu tài khoản"
@@ -1185,7 +1186,7 @@ msgstr "Thông tin thay đổi tài khoản."
msgid "Change secret or push account failed information"
msgstr "Thông báo lỗi khi thay đổi mật khẩu hoặc đẩy tài khoản."
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr "Bỏ qua."
@@ -1341,7 +1342,7 @@ msgstr "ID"
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1349,8 +1350,8 @@ msgstr "ID"
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr "Người dùng"
@@ -1385,7 +1386,7 @@ msgstr "Danh sách trắng IP"
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1684,7 +1685,7 @@ msgstr ""
"hạn ghi chép lưu trữ tài khoản - mỗi ngày vào lúc 2 giờ sáng sẽ dọn dẹp các "
"bản ghi tài khoản vượt quá số lượng quy định"
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr "Xóa các tài khoản lịch sử vượt quá giới hạn."
@@ -1757,7 +1758,7 @@ msgstr "Tên nhiệm vụ"
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1945,7 +1946,7 @@ msgstr "Người phê duyệt"
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr "Người dùng"
@@ -1971,7 +1972,7 @@ msgid "Command"
msgstr "Lệnh"
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr "Biểu thức chính quy"
@@ -2060,7 +2061,7 @@ msgstr "Quy tắc"
msgid "Login acl"
msgstr "Kiểm soát truy cập đăng nhập"
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr "Kiểm tra đăng nhập"
@@ -2182,7 +2183,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr "IP"
@@ -2247,7 +2248,7 @@ msgstr "Chúng tôi xin thông báo rằng, gần đây có người dùng đã
msgid "User details"
msgstr "Thông tin người dùng"
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr ""
"Không thể tạo tài sản trực tiếp, bạn nên tạo máy chủ hoặc các tài sản khác. "
@@ -2261,11 +2262,11 @@ msgstr ""
">>> Không có nhiệm vụ nào cần thực hiện. <–SEP–> >>> Bắt đầu thực hiện đợt "
"nhiệm vụ thứ {index}. <–SEP–> Không có tài khoản."
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr "Số lượng tài sản vượt quá giới hạn 5000"
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
#, fuzzy
#| msgid "The number of assets exceeds the limit of 5000"
msgid "The number of assets exceeds the license limit"
@@ -2284,6 +2285,11 @@ msgstr "Không thể xóa nút gốc ({})"
msgid "Deletion failed and the node contains assets"
msgstr "Xóa không thành công, nút chứa tài sản"
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr "Tên nút cùng cấp không được trùng lặp"
@@ -2301,29 +2307,29 @@ msgstr "Assets"
msgid "Task: {} finished"
msgstr "Nhiệm vụ: {} Hoàn thành"
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr "- Nền tảng {} Ansible đã bị vô hiệu hóa, không thể thực hiện nhiệm vụ"
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr ">>> Giai đoạn chuẩn bị nhiệm vụ"
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ">>> Thực hiện nhiệm vụ theo từng đợt, tổng cộng {runner_count}"
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ">>> Bắt đầu thực hiện nhiệm vụ"
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ">>> Không có nhiệm vụ nào cần thực hiện"
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ">>> Bắt đầu thực hiện đợt nhiệm vụ thứ {index}"
@@ -2728,7 +2734,7 @@ msgid "Port"
msgstr "Cổng"
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr "Địa chỉ"
@@ -2736,12 +2742,12 @@ msgstr "Địa chỉ"
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr "Nền tảng"
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr "Tên miền"
@@ -2810,9 +2816,9 @@ msgid "Proxy"
msgstr "Đại lý"
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr "Nút"
@@ -2836,7 +2842,7 @@ msgstr "Nhiệm vụ tự động hóa tài sản"
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr "Ngày tạo"
@@ -2925,7 +2931,7 @@ msgstr "Cổng"
msgid "System"
msgstr "Hệ thống"
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2940,7 +2946,7 @@ msgstr "Giá trị"
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr "Nhãn"
@@ -2956,27 +2962,27 @@ msgstr "Ghi chú tùy chỉnh"
msgid "My assets"
msgstr "Tài sản của tôi"
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr "Nút mới"
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr "Trống"
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr "Phím"
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr "Tên đầy đủ"
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr "Khóa SSH riêng"
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr "Có thể khớp với nút"
@@ -3156,7 +3162,7 @@ msgstr ""
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr "Nhóm giao thức"
@@ -3640,7 +3646,7 @@ msgid "Symlink"
msgstr "Tạo liên kết mềm"
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr "Tải xuống"
@@ -3669,7 +3675,9 @@ msgstr "Xuất"
msgid "Connect"
msgstr "Kết nối"
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4464,17 +4472,17 @@ msgstr "So sánh khuôn mặt thất bại"
msgid "Current user not support mfa type: {}"
msgstr "Người dùng hiện tại không hỗ trợ loại MFA: {}"
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr "Người dùng không tồn tại: {}"
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr "Không tìm thấy người dùng khớp"
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
@@ -4482,7 +4490,7 @@ msgid ""
msgstr ""
"Người dùng đến từ {} hãy đi tới hệ thống tương ứng để thay đổi mật khẩu"
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4492,7 +4500,7 @@ msgstr ""
msgid "Forgot password"
msgstr "Quên mật khẩu"
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr "Mã xác minh có hiệu lực trong {} phút"
@@ -4505,10 +4513,29 @@ msgstr "Authentication"
msgid "CAS Error"
msgstr "Lỗi CAS"
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
-msgstr "Người dùng không hợp lệ, đã bị vô hiệu hóa hoặc đã hết hạn"
+#: authentication/backends/cert/api.py:57
+#, fuzzy
+#| msgid "LDAP authentication is not enabled"
+msgid "Certificate enrollment is not enabled"
+msgstr "Xác thực LDAP chưa được kích hoạt"
+
+#: authentication/backends/cert/api.py:62
+#, fuzzy
+#| msgid "type is required"
+msgid "CSR is required"
+msgstr "Loại: trường này là bắt buộc."
+
+#: authentication/backends/cert/api.py:68
+#, fuzzy
+#| msgid "Authentication failed"
+msgid "Certificate signing failed"
+msgstr "Xác thực thất bại"
+
+#: authentication/backends/cert/views.py:97
+#, fuzzy
+#| msgid "Invalid data"
+msgid "Invalid credentials"
+msgstr "Dữ liệu không hợp lệ"
#: authentication/backends/drf.py:61
msgid "Invalid token header. No credentials provided."
@@ -4761,16 +4788,16 @@ msgstr "Mật khẩu của bạn không hợp lệ"
msgid "Please wait for %s seconds before retry"
msgstr "Vui lòng thử lại sau %s giây"
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr "Mật khẩu của bạn quá đơn giản, để đảm bảo an toàn, vui lòng thay đổi"
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr "Trước khi hoàn tất đăng nhập, vui lòng thay đổi mật khẩu"
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr "Mật khẩu của bạn đã hết hạn, hãy thay đổi rồi mới đăng nhập"
@@ -4901,11 +4928,11 @@ msgstr ""
"dùng hiện tại không có trong danh sách người dùng, vui lòng liên hệ với quản "
"trị viên."
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr "Người dùng không hợp lệ"
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4915,12 +4942,12 @@ msgstr ""
"Quản trị viên đã bật 'chỉ cho phép đăng nhập từ nguồn người dùng', nguồn "
"người dùng hiện tại là {}, vui lòng liên hệ với quản trị viên."
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr "Phương thức MFA ({}) này chưa được kích hoạt"
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr "Vui lòng thay đổi mật khẩu"
@@ -5114,7 +5141,7 @@ msgstr "Action"
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "Expired"
@@ -5156,13 +5183,13 @@ msgstr "SSH khóa không hợp lệ"
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "Is Valid"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr "Phạm vi"
@@ -5264,7 +5291,7 @@ msgstr "Mã không chính xác"
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5371,6 +5398,87 @@ msgstr ""
msgid "Cancel"
msgstr "Hủy bỏ"
+#: authentication/templates/authentication/cert_login.html:190
+#, fuzzy
+#| msgid "Multi-Factor Authentication"
+msgid "Certificate Authentication"
+msgstr "Xác thực"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:238
+#, fuzzy
+#| msgid "More login options"
+msgid "Other login methods"
+msgstr "Or"
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:253
+#, fuzzy
+#| msgid "Please enter SMS code"
+msgid "Please insert USB Key"
+msgstr "Vui lòng nhập mã xác minh qua tin nhắn"
+
+#: authentication/templates/authentication/cert_login.html:254
+#, fuzzy
+#| msgid "Account unavailable"
+msgid "Driver unavailable"
+msgstr "Tài khoản không hợp lệ"
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:257
+#, fuzzy
+#| msgid "Date verified"
+msgid "PIN verified"
+msgstr "Ngày xác nhận"
+
+#: authentication/templates/authentication/cert_login.html:258
+#, fuzzy
+#| msgid "OTP verification code"
+msgid "PIN verification failed"
+msgstr "Mã xác minh MFA ảo"
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:260
+#, fuzzy
+#| msgid "Signing key"
+msgid "Signing failed"
+msgstr "Khóa ký"
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr ""
+
+#: authentication/templates/authentication/cert_login.html:262
+#, fuzzy
+#| msgid "Your account has expired, please contact the administrator."
+msgid "No certificate detected, please contact administrator"
+msgstr "Tài khoản của bạn đã hết hạn, vui lòng liên hệ với quản lý."
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr "Thử lại"
@@ -5446,6 +5554,10 @@ msgstr "Có muốn thử lại không?"
msgid "LAN"
msgstr "Mạng nội bộ"
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5613,47 +5725,47 @@ msgstr ""
msgid "Request file format may be wrong"
msgstr "Định dạng tệp tải lên sai hoặc tệp thuộc loại tài nguyên khác."
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr "Trung Quốc"
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr "Kích hoạt thủ công"
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr "Kích hoạt theo thời gian"
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr "Đang chạy"
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr "Hủy bỏ"
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr "Xác nhận"
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr "Phiên bản cộng đồng"
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr "Phiên bản cơ bản doanh nghiệp"
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr "Phiên bản tiêu chuẩn doanh nghiệp"
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr "Phiên bản chuyên nghiệp doanh nghiệp"
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr "Phiên bản cao cấp doanh nghiệp"
@@ -6178,24 +6290,24 @@ msgstr "Không tìm thấy mã"
msgid "The message code provided is invalid or has expired"
msgstr "Mã tin nhắn cung cấp không hợp lệ hoặc đã hết hạn"
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr "Mã xác nhận là: {code}"
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr "Tạo tài khoản thành công"
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr "Tài khoản của bạn đã được tạo thành công"
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "JumpServer"
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -6919,7 +7031,7 @@ msgid "Please save in a org"
msgstr "Vui lòng chọn một tổ chức trước khi lưu"
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -7345,15 +7457,15 @@ msgstr "Vai trò hệ thống"
msgid "Organization role"
msgstr "Vai trò tổ chức"
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr "Liên kết vai trò"
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr "Tất cả tổ chức"
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
@@ -7361,11 +7473,11 @@ msgstr ""
"Vai trò cuối cùng của người dùng, không thể xóa, bạn có thể loại bỏ người "
"dùng khỏi tổ chức"
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr "Liên kết vai trò tổ chức"
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr "Liên kết vai trò hệ thống"
@@ -7430,7 +7542,7 @@ msgid "Storage"
msgstr "Lưu trữ"
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr "Ứng dụng từ xa"
@@ -7493,51 +7605,51 @@ msgstr "Thu hồi mã thông báo truy cập"
msgid "Range days"
msgstr "Người chỉnh sửa"
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr "Báo cáo đăng nhập người dùng"
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr "Báo cáo thay đổi mật khẩu người dùng"
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr "Báo cáo thống kê tài sản"
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr "Báo cáo hoạt động tài sản"
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr "Báo cáo thống kê tài khoản"
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr "Báo cáo tự động hóa tài khoản"
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr "Bảng điều khiển Console"
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr "Bảng điều khiển Audit"
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr "Bảng điều khiển PAM"
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr "Bảng điều khiển thay đổi mật khẩu tài khoản"
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr "Gửi thư không thành công"
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr "Gửi thư thành công"
@@ -7819,19 +7931,19 @@ msgstr "Kích hoạt xác thực DingTalk"
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
-"Bản đồ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng "
-"hệ thống, `value` là tên thuộc tính người dùng dịch vụ DingTalk"
+"Bản đồ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng hệ "
+"thống, `value` là tên thuộc tính người dùng dịch vụ DingTalk"
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
-"Bản đồ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng "
-"hệ thống, `value` là tên thuộc tính người dùng dịch vụ FeiShu"
+"Bản đồ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng hệ "
+"thống, `value` là tên thuộc tính người dùng dịch vụ FeiShu"
#: settings/serializers/auth/lark.py:13 users/models/user/_source.py:24
msgid "Lark"
@@ -7839,11 +7951,11 @@ msgstr "Lark"
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
-"Bản đồ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng "
-"hệ thống, `value` là tên thuộc tính người dùng dịch vụ Lark"
+"Bản đồ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng hệ "
+"thống, `value` là tên thuộc tính người dùng dịch vụ Lark"
#: settings/serializers/auth/ldap.py:42 settings/serializers/auth/ldap.py:108
msgid "LDAP"
@@ -7903,8 +8015,8 @@ msgstr ""
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
"Ánh xạ thuộc tính của người dùng, trong đó `key` là tên thuộc tính người "
"dùng hệ thống, `value` là tên thuộc tính người dùng dịch vụ LDAP"
@@ -8014,8 +8126,8 @@ msgstr "Khi người dùng đăng xuất, họ cũng sẽ thoát khỏi máy ch
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
"Ánh xạ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng "
"của hệ thống, `value` là tên thuộc tính người dùng của dịch vụ OAuth2"
@@ -8051,8 +8163,8 @@ msgstr "Bỏ qua xác thực chứng chỉ SSL"
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
"Ánh xạ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng "
"của hệ thống, `value` là tên thuộc tính người dùng của dịch vụ OIDC"
@@ -8200,11 +8312,11 @@ msgstr "Khi người dùng đăng xuất, họ cũng sẽ bị đăng xuất kh
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
-"Ánh xạ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng "
-"hệ thống, `value` là tên thuộc tính người dùng dịch vụ Slack"
+"Ánh xạ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng hệ "
+"thống, `value` là tên thuộc tính người dùng dịch vụ Slack"
#: settings/serializers/auth/sms.py:18
msgid "Enable Short Message Service (SMS)"
@@ -8238,7 +8350,7 @@ msgid "Template code"
msgstr "Mẫu tin nhắn"
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr "Số điện thoại di động"
@@ -8295,7 +8407,10 @@ msgid "Enable SSO auth"
msgstr "Kích hoạt xác thực token SSO"
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
+#, fuzzy
+#| msgid ""
+#| "Other service can using SSO token login to JumpServer without password"
+msgid "Other service can using SSO token login to system without password"
msgstr ""
"Các hệ thống khác có thể sử dụng SSO Token để kết nối với JumpServer, miễn "
"quá trình đăng nhập"
@@ -8311,11 +8426,11 @@ msgstr "Đơn vị: giây"
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
-"Ánh xạ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng "
-"hệ thống, `value` là tên thuộc tính người dùng dịch vụ WeChat doanh nghiệp"
+"Ánh xạ thuộc tính người dùng, trong đó `key` là tên thuộc tính người dùng hệ "
+"thống, `value` là tên thuộc tính người dùng dịch vụ WeChat doanh nghiệp"
#: settings/serializers/basic.py:11
msgid "Site URL"
@@ -9479,7 +9594,7 @@ msgstr "Đang chờ:"
msgid "The verification code has been sent"
msgstr "Mã xác thực đã được gửi"
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "Home"
@@ -9744,31 +9859,31 @@ msgstr "Có thể đồng thời"
msgid "Hosts"
msgstr "Máy chủ"
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr "Gói Applet không hợp lệ, thiếu tệp {}"
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr "Tải platform.yml thất bại: {}"
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr "Chỉ hỗ trợ nền tảng tùy chỉnh"
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr "Thiếu loại trong platform.yml"
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "Máy chủ chủ"
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr "Phát hành ứng dụng"
@@ -9858,7 +9973,7 @@ msgstr "Cổng VNC"
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -10072,8 +10187,8 @@ msgstr "Storage"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr "Kiểm tra thất bại: Tài khoản không hợp lệ"
@@ -10194,7 +10309,8 @@ msgstr "Đã có giấy phép RDS"
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
"Nếu không có, RDS sẽ ở chế độ dùng thử, thời gian thử nghiệm là 120 ngày. \n"
"Language-Team: JumpServer team\n"
@@ -27,7 +27,7 @@ msgstr "账号已存在"
msgid "No valid assets found for account creation."
msgstr "未找到可用于创建账户的有效资产。"
-#: accounts/api/account/application.py:77
+#: accounts/api/account/application.py:87
#: authentication/api/connection_token.py:463
msgid "Account not found"
msgstr "账号未找到"
@@ -41,15 +41,15 @@ msgstr "参数 'action' 必须是 [{}]"
msgid "The account key will be split into two parts and sent"
msgstr "账号的密钥将被拆分成前后两部分发送"
-#: accounts/automations/backup_account/handlers.py:131
+#: accounts/automations/backup_account/handlers.py:132
msgid "Number of backup accounts"
msgstr "备份账号数量"
-#: accounts/automations/backup_account/handlers.py:152
+#: accounts/automations/backup_account/handlers.py:153
msgid "Generating asset related backup information files"
msgstr "生成资产相关备份信息文件"
-#: accounts/automations/backup_account/handlers.py:177
+#: accounts/automations/backup_account/handlers.py:178
#: accounts/automations/backup_account/manager.py:26
#: accounts/automations/change_secret/manager.py:81
#: accounts/automations/push_account/manager.py:62
@@ -60,31 +60,31 @@ msgstr "生成资产相关备份信息文件"
msgid "Duration"
msgstr "花费时间"
-#: accounts/automations/backup_account/handlers.py:178
+#: accounts/automations/backup_account/handlers.py:179
msgid "Backup file creation completed"
msgstr "创建备份文件完成"
-#: accounts/automations/backup_account/handlers.py:186
+#: accounts/automations/backup_account/handlers.py:187
msgid "Start sending backup emails"
msgstr "开始发送备份电子邮件"
-#: accounts/automations/backup_account/handlers.py:213
+#: accounts/automations/backup_account/handlers.py:214
msgid "Encrypting files using encryption password"
msgstr "使用加密密码对文件进行加密中"
-#: accounts/automations/backup_account/handlers.py:223
+#: accounts/automations/backup_account/handlers.py:224
msgid "The backup file will be sent to"
msgstr "备份文件将被发送至"
-#: accounts/automations/backup_account/handlers.py:246
+#: accounts/automations/backup_account/handlers.py:247
msgid "The backup task has no assigned sftp server"
msgstr "该备份任务未分配sftp服务器"
-#: accounts/automations/backup_account/handlers.py:267
+#: accounts/automations/backup_account/handlers.py:268
msgid "The backup task has no assigned recipient"
msgstr "备份任务没有指定收件人"
-#: accounts/automations/backup_account/handlers.py:290
+#: accounts/automations/backup_account/handlers.py:291
msgid "Plan start"
msgstr "任务开始"
@@ -151,7 +151,7 @@ msgstr ">>> 开始执行测试网关账号可连接性任务"
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -225,7 +225,7 @@ msgstr "更新"
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr "失败"
@@ -347,14 +347,14 @@ msgstr "SFTP"
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "成功"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr "待定的"
@@ -362,7 +362,7 @@ msgstr "待定的"
msgid "Queued"
msgstr "排队中"
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr "准备就绪"
@@ -374,7 +374,7 @@ msgstr "处理中"
msgid "Can login"
msgstr "可登录"
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr "超级用户"
@@ -403,7 +403,7 @@ msgid "Default tablespace"
msgstr "默认表空间"
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr "角色"
@@ -412,7 +412,7 @@ msgid "Perms"
msgstr "权限"
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr "用户组"
@@ -785,7 +785,7 @@ msgstr "结束日期"
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -800,7 +800,7 @@ msgstr "状态"
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr "错误"
@@ -895,8 +895,9 @@ msgstr "重复密码"
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1050,7 +1051,7 @@ msgstr "特权账号"
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "激活"
@@ -1066,7 +1067,7 @@ msgstr "平台"
msgid "Push params"
msgstr "账号推送参数"
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr "账号模板"
@@ -1159,7 +1160,7 @@ msgstr "账号变更信息"
msgid "Change secret or push account failed information"
msgstr "改密或推送账号失败信息"
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr "忽略"
@@ -1315,7 +1316,7 @@ msgstr "ID"
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1323,8 +1324,8 @@ msgstr "ID"
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr "用户"
@@ -1359,7 +1360,7 @@ msgstr "IP 白名单"
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1634,7 +1635,7 @@ msgstr ""
"由于每次更新资产账号,都会生成历史账号,所以需要清理资产账号的历史。系统会根"
"据账号存储-记录限制的配置,每天凌晨2点对于超出的数量的账号记录进行清理"
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr "删除超出范围的历史帐户。"
@@ -1701,7 +1702,7 @@ msgstr "任务名称"
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1885,7 +1886,7 @@ msgstr "审批人"
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr "用户"
@@ -1911,7 +1912,7 @@ msgid "Command"
msgstr "命令"
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr "正则表达式"
@@ -2000,7 +2001,7 @@ msgstr "规则"
msgid "Login acl"
msgstr "登录访问控制"
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr "登录复核"
@@ -2122,7 +2123,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr "IP"
@@ -2183,15 +2184,15 @@ msgstr "我们想通知您,最近有用户登录:"
msgid "User details"
msgstr "用户详情"
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr "不能直接创建资产, 你应该创建主机或其他资产"
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr "资产数量超过了 5000 的限制"
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
msgid "The number of assets exceeds the license limit"
msgstr "资产数量超过许可证限制"
@@ -2208,6 +2209,11 @@ msgstr "不能删除根节点 ({})"
msgid "Deletion failed and the node contains assets"
msgstr "删除失败,节点包含资产"
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr "同级别节点名字不能重复"
@@ -2225,29 +2231,29 @@ msgstr "资产管理"
msgid "Task: {} finished"
msgstr "任务:{} 完成"
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr " - 平台 {} Ansible 已禁用, 无法执行任务"
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr ">>> 任务准备阶段"
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ">>> 分次执行任务,总共 {runner_count}"
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ">>> 开始执行任务"
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ">>> 没有需要执行的任务"
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ">>> 开始执行第 {index} 批任务"
@@ -2642,7 +2648,7 @@ msgid "Port"
msgstr "端口"
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr "地址"
@@ -2650,12 +2656,12 @@ msgstr "地址"
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr "平台"
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr "网域"
@@ -2724,9 +2730,9 @@ msgid "Proxy"
msgstr "代理"
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr "节点"
@@ -2752,7 +2758,7 @@ msgstr "资产自动化任务"
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr "创建日期"
@@ -2841,7 +2847,7 @@ msgstr "网关"
msgid "System"
msgstr "系统"
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2856,7 +2862,7 @@ msgstr "值"
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr "标签"
@@ -2872,27 +2878,27 @@ msgstr "自定义备注"
msgid "My assets"
msgstr "我的资产"
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr "新节点"
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr "空"
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr "键"
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr "全称"
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr "ssh私钥"
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr "可以匹配节点"
@@ -3068,7 +3074,7 @@ msgstr "节点路径,格式为 [\"/组织/节点名\"], 如果节点不存在
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr "协议组"
@@ -3498,7 +3504,7 @@ msgid "Symlink"
msgstr "建立软链接"
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr "下载"
@@ -3527,7 +3533,9 @@ msgstr "导出"
msgid "Connect"
msgstr "连接"
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4222,24 +4230,24 @@ msgstr "人脸比对失败"
msgid "Current user not support mfa type: {}"
msgstr "当前用户不支持 MFA 类型: {}"
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr "用户不存在: {}"
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr "没有匹配到用户"
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
"password"
msgstr "用户来自 {} 请去相应系统修改密码"
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4249,7 +4257,7 @@ msgstr "用户来自 {} 请去相应系统修改密码"
msgid "Forgot password"
msgstr "忘记密码"
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr "验证码有效期为 {} 分钟"
@@ -4262,10 +4270,21 @@ msgstr "认证管理"
msgid "CAS Error"
msgstr "CAS 错误"
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
-msgstr "用户无效,已禁用或已过期"
+#: authentication/backends/cert/api.py:57
+msgid "Certificate enrollment is not enabled"
+msgstr "证书签发未开启"
+
+#: authentication/backends/cert/api.py:62
+msgid "CSR is required"
+msgstr "CSR 是必须的。"
+
+#: authentication/backends/cert/api.py:68
+msgid "Certificate signing failed"
+msgstr "证书签发失败"
+
+#: authentication/backends/cert/views.py:97
+msgid "Invalid credentials"
+msgstr "无效的证书"
#: authentication/backends/drf.py:61
msgid "Invalid token header. No credentials provided."
@@ -4508,16 +4527,16 @@ msgstr "您的密码无效"
msgid "Please wait for %s seconds before retry"
msgstr "请在 %s 秒后重试"
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr "你的密码过于简单,为了安全,请修改"
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr "登录完成前,请先修改密码"
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr "您的密码已过期,先修改再登录"
@@ -4643,11 +4662,11 @@ msgid ""
msgstr ""
"管理员已开启'仅允许已存在用户登录',当前用户不在用户列表中,请联系管理员。"
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr "无效的用户"
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4655,12 +4674,12 @@ msgid ""
"administrator. "
msgstr "管理员已开启'仅允许从用户来源登录',当前用户来源为 {},请联系管理员。"
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr "该 MFA ({}) 方式没有启用"
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr "请修改密码"
@@ -4852,7 +4871,7 @@ msgstr "动作"
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "已过期"
@@ -4892,13 +4911,13 @@ msgstr "SSH密钥不合法"
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "是否有效"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr "范围"
@@ -4993,7 +5012,7 @@ msgstr "代码错误"
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5089,6 +5108,67 @@ msgstr "如果这次公钥更新不是由你发起的,那么你的账号可能
msgid "Cancel"
msgstr "取消"
+#: authentication/templates/authentication/cert_login.html:190
+msgid "Certificate Authentication"
+msgstr "证书认证"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr "正在加载 USB Key 驱动..."
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr "请插入 USB Key 自动获取"
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr "正在检测 USB Key..."
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr "USB Key 已连接"
+
+#: authentication/templates/authentication/cert_login.html:253
+msgid "Please insert USB Key"
+msgstr "请插入 USB Key"
+
+#: authentication/templates/authentication/cert_login.html:254
+msgid "Driver unavailable"
+msgstr "驱动不可用"
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr "USB Key SDK 初始化失败"
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr "PIN 校验中..."
+
+#: authentication/templates/authentication/cert_login.html:257
+msgid "PIN verified"
+msgstr "PIN 校验通过"
+
+#: authentication/templates/authentication/cert_login.html:258
+msgid "PIN verification failed"
+msgstr "校验 PIN 失败"
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr "正在对挑战码签名..."
+
+#: authentication/templates/authentication/cert_login.html:260
+msgid "Signing failed"
+msgstr "签名失败"
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr "获取证书失败"
+
+#: authentication/templates/authentication/cert_login.html:262
+msgid "No certificate detected, please contact administrator"
+msgstr "未检测到证书,请联系管理员制证"
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr "重试"
@@ -5156,6 +5236,10 @@ msgstr "是否重试 ?"
msgid "LAN"
msgstr "局域网"
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5318,47 +5402,47 @@ msgstr "请使用密码登录,然后绑定企业微信"
msgid "Request file format may be wrong"
msgstr "上传的文件格式错误 或 其它类型资源的文件"
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr "中国"
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr "手动触发"
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr "定时触发"
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr "运行中"
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr "取消"
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr "确认"
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr "社区版"
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr "企业基础版"
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr "企业标准版"
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr "企业专业版"
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr "企业旗舰版"
@@ -5841,24 +5925,24 @@ msgstr "未找到 Code"
msgid "The message code provided is invalid or has expired"
msgstr "提供的消息代码无效或已过期"
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr "验证码为: {code}"
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr "创建账号成功"
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr "你的账号已创建成功"
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "JumpServer 开源堡垒机"
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -6557,7 +6641,7 @@ msgid "Please save in a org"
msgstr "请选择一个组织后再保存"
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -6860,10 +6944,8 @@ msgid "Can view file manager"
msgstr "可以查看文件管理"
#: rbac/models/menu.py:21
-#, fuzzy
-#| msgid "Can view console view"
msgid "Can view jdmc console"
-msgstr "可以显示控制台"
+msgstr "可以显示 JDMC 控制台"
#: rbac/models/menu.py:22
msgid "Can view System Tools"
@@ -6957,25 +7039,25 @@ msgstr "系统角色"
msgid "Organization role"
msgstr "组织角色"
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr "角色绑定"
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr "所有组织"
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
msgstr "用户最后一个角色,不能删除,你可以将用户从组织移除"
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr "组织角色绑定"
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr "系统角色绑定"
@@ -7040,7 +7122,7 @@ msgid "Storage"
msgstr "存储"
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr "远程应用"
@@ -7059,10 +7141,8 @@ msgid "Job audit"
msgstr "作业审计"
#: rbac/tree.py:137
-#, fuzzy
-#| msgid "Console"
msgid "JDMC console"
-msgstr "控制台"
+msgstr "JDMC 控制台"
#: rbac/tree.py:201
msgid "App organizations"
@@ -7101,51 +7181,51 @@ msgstr "撤销访问令牌"
msgid "Range days"
msgstr "范围天数"
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr "用户登录报告"
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr "用户改密报告"
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr "资产统计报告"
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr "资产活动报告"
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr "账号统计报告"
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr "账号自动化报告"
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr "控制台仪表板"
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr "审计台仪表板"
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr "PAM 仪表板"
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr "账号改密仪表盘"
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr "发送邮件失败"
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr "发送邮件成功"
@@ -7415,8 +7495,8 @@ msgid ""
"User attribute mapping, where the `key` is the CAS service user attribute "
"name and the `value` is this system user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是 CAS 服务用户属性名称,`value` 是本系统用户"
-"属性名称"
+"用户属性映射,其中 `key` 是 CAS 服务用户属性名称,`value` 是本系统用户属性名"
+"称"
#: settings/serializers/auth/dingtalk.py:16
msgid "Dingtalk"
@@ -7424,19 +7504,17 @@ msgstr "启用钉钉认证"
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是钉钉服务用户属"
-"性名称"
+"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是钉钉服务用户属性名称"
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是飞书服务用户属"
-"性名称"
+"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是飞书服务用户属性名称"
#: settings/serializers/auth/lark.py:13 users/models/user/_source.py:24
msgid "Lark"
@@ -7444,11 +7522,11 @@ msgstr "Lark"
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 Lark 服务用户"
-"属性名称"
+"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 Lark 服务用户属性名"
+"称"
#: settings/serializers/auth/ldap.py:42 settings/serializers/auth/ldap.py:108
msgid "LDAP"
@@ -7491,11 +7569,11 @@ msgstr "可能的选项是(cn或uid或sAMAccountName=%(user)s)"
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 LDAP 服务用户"
-"属性名称"
+"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 LDAP 服务用户属性名"
+"称"
#: settings/serializers/auth/ldap.py:85 settings/serializers/auth/ldap_ha.py:67
msgid "Connect timeout (s)"
@@ -7596,11 +7674,11 @@ msgstr "当用户退出时,他们也会从 OAuth2 服务器退出"
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 OAuth2 服务用"
-"户属性名称"
+"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 OAuth2 服务用户属性"
+"名称"
#: settings/serializers/auth/oauth2.py:67 settings/serializers/auth/oidc.py:117
#: settings/serializers/auth/saml2.py:45
@@ -7633,11 +7711,11 @@ msgstr "忽略 SSL 证书验证"
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 OIDC 服务用户"
-"属性名称"
+"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 OIDC 服务用户属性名"
+"称"
#: settings/serializers/auth/oidc.py:45
msgid "Enable PKCE"
@@ -7767,8 +7845,8 @@ msgid ""
"User attribute mapping, where the `key` is the SAML2 service user attribute "
"name and the `value` is this system user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是 SAML2 服务用户属性名称,`value` 是本系统用"
-"户属性名称"
+"用户属性映射,其中 `key` 是 SAML2 服务用户属性名称,`value` 是本系统用户属性"
+"名称"
#: settings/serializers/auth/saml2.py:43
msgid "When the user signs out, they also be logged out from the SAML2 server"
@@ -7776,11 +7854,11 @@ msgstr "当用户退出时,他们也会从 SAML2 服务器注销"
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 Slack 服务用"
-"户属性名称"
+"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是 Slack 服务用户属性"
+"名称"
#: settings/serializers/auth/sms.py:18
msgid "Enable Short Message Service (SMS)"
@@ -7814,7 +7892,7 @@ msgid "Template code"
msgstr "模板"
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr "手机"
@@ -7870,8 +7948,8 @@ msgid "Enable SSO auth"
msgstr "启用 SSO 令牌认证"
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
-msgstr "其它系统可以使用 SSO Token 对接 JumpServer, 免去登录的过程"
+msgid "Other service can using SSO token login to system without password"
+msgstr "其它系统可以使用 SSO Token 对接系统,免去登录的过程"
#: settings/serializers/auth/sso.py:20
msgid "SSO auth key TTL"
@@ -7884,11 +7962,11 @@ msgstr "单位: 秒"
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
-"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是企业微信服务用"
-"户属性名称"
+"用户属性映射,其中 `key` 是本系统用户属性名称,`value` 是企业微信服务用户属性"
+"名称"
#: settings/serializers/basic.py:11
msgid "Site URL"
@@ -8976,7 +9054,7 @@ msgstr "等待:"
msgid "The verification code has been sent"
msgstr "验证码已发送"
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "首页"
@@ -9237,31 +9315,31 @@ msgstr "可以并发"
msgid "Hosts"
msgstr "主机"
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr "Applet pkg 无效,缺少文件 {}"
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr "加载 platform.yml 失败: {}"
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr "只支持自定义平台"
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr "在 platform.yml 中缺少类型"
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "宿主机"
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr "应用发布"
@@ -9351,7 +9429,7 @@ msgstr "VNC 端口"
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -9556,10 +9634,8 @@ msgid "Level"
msgstr "级别"
#: terminal/notifications.py:172 terminal/notifications.py:239
-#, fuzzy
-#| msgid "Privacy Policy"
msgid "Policy"
-msgstr "隐私协议"
+msgstr "策略"
#: terminal/notifications.py:263
msgid "Command and replay storage"
@@ -9567,8 +9643,8 @@ msgstr "命令及录像存储"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr "测试失败: 账号无效"
@@ -9667,7 +9743,8 @@ msgstr "已有 RDS 许可证"
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
"如果不存在,RDS 将处于试用模式,试用期为 120 天。>> 開始執行測試閘道器帳號可連結性的任務"
#: settings/serializers/auth/ldap.py:53 settings/serializers/auth/ldap_ha.py:35
#: settings/serializers/msg.py:37 settings/serializers/terminal.py:32
#: terminal/serializers/storage.py:123 terminal/serializers/storage.py:142
-#: users/forms/profile.py:22 users/serializers/user.py:148
+#: users/forms/profile.py:22 users/serializers/user.py:153
#: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_password_verify.html:18
#: xpack/plugins/cloud/serializers/account_attrs.py:43
@@ -227,7 +227,7 @@ msgstr "更新"
#: accounts/const/account.py:34 accounts/const/automation.py:115
#: accounts/serializers/automations/change_secret.py:171 audits/const.py:66
-#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:66
+#: audits/signal_handlers/activity_log.py:34 common/const/choices.py:67
#: ops/const.py:77 terminal/const.py:81 xpack/plugins/cloud/const.py:55
msgid "Failed"
msgstr "失敗"
@@ -349,14 +349,14 @@ msgstr "SFTP"
#: accounts/const/automation.py:116
#: accounts/serializers/automations/change_secret.py:170 audits/const.py:65
#: audits/models.py:65 audits/signal_handlers/activity_log.py:34
-#: common/const/choices.py:65 ops/const.py:75 ops/serializers/celery.py:48
+#: common/const/choices.py:66 ops/const.py:75 ops/serializers/celery.py:48
#: terminal/const.py:80 terminal/models/session/sharing.py:119
#: tickets/views/approve.py:128
msgid "Success"
msgstr "成功"
-#: accounts/const/automation.py:117 common/const/choices.py:63
-#: common/const/choices.py:114 terminal/const.py:79
+#: accounts/const/automation.py:117 common/const/choices.py:64
+#: common/const/choices.py:127 terminal/const.py:79
msgid "Pending"
msgstr "待定的"
@@ -364,7 +364,7 @@ msgstr "待定的"
msgid "Queued"
msgstr "排隊中"
-#: accounts/const/automation.py:122 common/const/choices.py:62
+#: accounts/const/automation.py:122 common/const/choices.py:63
msgid "Ready"
msgstr "準備"
@@ -376,7 +376,7 @@ msgstr "處理中"
msgid "Can login"
msgstr "可登入"
-#: accounts/const/automation.py:128 users/serializers/user.py:254
+#: accounts/const/automation.py:128 users/serializers/user.py:259
msgid "Superuser"
msgstr "超級使用者"
@@ -405,7 +405,7 @@ msgid "Default tablespace"
msgstr "默認表空間"
#: accounts/const/automation.py:135 rbac/models/role.py:46
-#: rbac/models/rolebinding.py:52 users/models/user/__init__.py:79
+#: rbac/models/rolebinding.py:53 users/models/user/__init__.py:79
msgid "Role"
msgstr "角色"
@@ -414,7 +414,7 @@ msgid "Perms"
msgstr "權限"
#: accounts/const/automation.py:137 perms/serializers/permission.py:56
-#: users/serializers/user.py:245
+#: users/serializers/user.py:250
msgid "Groups"
msgstr "使用者群組"
@@ -787,7 +787,7 @@ msgstr "結束日期"
#: assets/models/automations/base.py:137
#: assets/serializers/automations/base.py:47 audits/models.py:224
#: audits/reporting.py:607 audits/serializers.py:77 ops/models/base.py:49
-#: ops/models/job.py:233 terminal/models/applet/applet.py:382
+#: ops/models/job.py:233 terminal/models/applet/applet.py:390
#: terminal/models/applet/host.py:140 terminal/models/component/status.py:30
#: terminal/models/virtualapp/virtualapp.py:99
#: terminal/serializers/applet.py:19 terminal/serializers/applet_host.py:163
@@ -802,7 +802,7 @@ msgstr "狀態"
#: accounts/serializers/account/account.py:297 assets/const/automation.py:9
#: authentication/templates/authentication/passkey.html:177
#: authentication/views/base.py:43 authentication/views/base.py:44
-#: authentication/views/base.py:45 common/const/choices.py:67
+#: authentication/views/base.py:45 common/const/choices.py:68
#: settings/templates/ldap/_msg_import_ldap_user.html:26
msgid "Error"
msgstr "錯誤"
@@ -897,8 +897,9 @@ msgstr "重複密碼"
#: accounts/templates/accounts/push_account_report.html:79
#: accounts/templates/accounts/push_account_report.html:119
#: acls/serializers/base.py:19 acls/serializers/base.py:50 audits/models.py:204
-#: audits/reporting.py:241 authentication/forms.py:21
-#: authentication/forms.py:23 authentication/models/temp_token.py:10
+#: audits/reporting.py:241 authentication/backends/cert/forms.py:7
+#: authentication/forms.py:21 authentication/forms.py:23
+#: authentication/models/temp_token.py:10
#: authentication/serializers/connect_token_secret.py:43
#: authentication/serializers/connect_token_secret.py:53
#: authentication/templates/authentication/_msg_different_city.html:9
@@ -1052,7 +1053,7 @@ msgstr "特權帳號"
#: assets/models/cmd_filter.py:39 assets/models/label.py:22
#: authentication/serializers/connect_token_secret.py:129 reports/models.py:18
#: terminal/models/applet/applet.py:41
-#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:257
+#: terminal/models/virtualapp/virtualapp.py:23 users/serializers/user.py:262
msgid "Is active"
msgstr "啟用"
@@ -1068,7 +1069,7 @@ msgstr "系統平台"
msgid "Push params"
msgstr "帳號推送參數"
-#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:403
+#: accounts/models/template.py:26 xpack/plugins/cloud/models.py:404
msgid "Account template"
msgstr "帳號模板"
@@ -1161,7 +1162,7 @@ msgstr "帳號變更資訊"
msgid "Change secret or push account failed information"
msgstr "改密或推送帳號失敗資訊"
-#: accounts/risk_handlers.py:17 common/const/choices.py:116
+#: accounts/risk_handlers.py:17 common/const/choices.py:129
msgid "Ignored"
msgstr "忽略"
@@ -1317,7 +1318,7 @@ msgstr "ID"
#: authentication/notifications.py:16 authentication/notifications.py:55
#: notifications/models/notification.py:12
#: perms/api/user_permission/mixin.py:58 perms/models/asset_permission.py:63
-#: rbac/builtin.py:134 rbac/models/rolebinding.py:49
+#: rbac/builtin.py:134 rbac/models/rolebinding.py:50
#: rbac/serializers/rolebinding.py:17 terminal/backends/command/models.py:16
#: terminal/models/session/session.py:27 terminal/models/session/sharing.py:34
#: terminal/notifications.py:168 terminal/notifications.py:235
@@ -1325,8 +1326,8 @@ msgstr "ID"
#: terminal/templates/terminal/_msg_command_warning.html:9
#: terminal/templates/terminal/_msg_session_sharing.html:6
#: tickets/models/comment.py:21 tickets/serializers/flow.py:15
-#: users/const.py:14 users/models/user/__init__.py:298
-#: users/models/user/__init__.py:325
+#: users/const.py:14 users/models/user/__init__.py:303
+#: users/models/user/__init__.py:330
msgid "User"
msgstr "用戶"
@@ -1361,7 +1362,7 @@ msgstr "IP 白名單"
#: assets/models/cmd_filter.py:88 common/db/models.py:36 ops/models/adhoc.py:25
#: ops/models/job.py:165 ops/models/playbook.py:31 rbac/models/role.py:37
#: settings/models.py:43 terminal/models/applet/applet.py:46
-#: terminal/models/applet/applet.py:383 terminal/models/applet/host.py:143
+#: terminal/models/applet/applet.py:391 terminal/models/applet/host.py:143
#: terminal/models/component/endpoint.py:29
#: terminal/models/component/endpoint.py:117
#: terminal/models/session/session.py:44
@@ -1637,7 +1638,7 @@ msgstr ""
"由於每次更新資產帳號,均會生成歷史帳號,因此需要清理資產帳號的歷史。系統會根"
"據帳號存儲-記錄限制的配置,每天凌晨2點對於超出的數量的帳號記錄進行清理"
-#: accounts/tasks/remove_account.py:89
+#: accounts/tasks/remove_account.py:91
msgid "Remove historical accounts that are out of range."
msgstr "刪除超出範圍的歷史帳戶。"
@@ -1704,7 +1705,7 @@ msgstr "任務名稱"
#: accounts/templates/accounts/push_account_report.html:22
#: assets/models/automations/base.py:143 audits/models.py:66
#: ops/models/base.py:55 ops/models/celery.py:89 ops/models/job.py:241
-#: ops/templates/ops/celery_task_log.html:101
+#: ops/templates/ops/celery_task_log.html:154
#: perms/models/asset_permission.py:78 settings/serializers/feature.py:29
#: settings/templates/ldap/_msg_import_ldap_user.html:5
#: terminal/models/applet/host.py:141 terminal/models/session/session.py:42
@@ -1888,7 +1889,7 @@ msgstr "審批人"
#: acls/models/base.py:81 perms/serializers/permission.py:54
#: tickets/models/flow.py:23 users/models/preference.py:16
-#: users/serializers/group.py:21 users/serializers/user.py:424
+#: users/serializers/group.py:21 users/serializers/user.py:429
msgid "Users"
msgstr "用戶管理"
@@ -1914,7 +1915,7 @@ msgid "Command"
msgstr "命令"
#: acls/models/command_acl.py:17 assets/models/cmd_filter.py:59
-#: xpack/plugins/cloud/models.py:369
+#: xpack/plugins/cloud/models.py:370
msgid "Regex"
msgstr "正則表達式"
@@ -2003,7 +2004,7 @@ msgstr "規則"
msgid "Login acl"
msgstr "登錄訪問控制"
-#: acls/models/login_acl.py:27 tickets/const.py:11
+#: acls/models/login_acl.py:30 tickets/const.py:11
msgid "Login confirm"
msgstr "登錄覆核"
@@ -2125,7 +2126,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
-#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:405
+#: common/drf/renders/base.py:165 xpack/plugins/cloud/models.py:406
msgid "IP"
msgstr "IP"
@@ -2186,15 +2187,15 @@ msgstr "我們想通知您,最近有用戶登入:"
msgid "User details"
msgstr "使用者詳情"
-#: assets/api/asset/asset.py:166
+#: assets/api/asset/asset.py:168
msgid "Cannot create asset directly, you should create a host or other"
msgstr "不能直接創建資產, 你應該創建主機或其他資產"
-#: assets/api/asset/asset.py:173
+#: assets/api/asset/asset.py:175
msgid "The number of assets exceeds the limit of 5000"
msgstr "資產數量超過 5000 的限制"
-#: assets/api/asset/asset.py:179
+#: assets/api/asset/asset.py:181
#, fuzzy
#| msgid "The number of assets exceeds the limit of 5000"
msgid "The number of assets exceeds the license limit"
@@ -2213,6 +2214,11 @@ msgstr "不能刪除根節點 ({})"
msgid "Deletion failed and the node contains assets"
msgstr "刪除失敗,節點包含資產"
+#: assets/api/node.py:99
+#, python-brace-format
+msgid "Node {} is an ancestor of node {}, can't be added as its child"
+msgstr ""
+
#: assets/api/tree.py:48 assets/serializers/node.py:42
msgid "The same level node name cannot be the same"
msgstr "同級別節點名字不能重複"
@@ -2230,29 +2236,29 @@ msgstr "資產管理"
msgid "Task: {} finished"
msgstr "任務:{} 完成"
-#: assets/automations/base/manager.py:340
+#: assets/automations/base/manager.py:341
#, python-brace-format
msgid " - Platform {} ansible disabled"
msgstr " - 平台 {} Ansible 已禁用, 無法執行任務"
-#: assets/automations/base/manager.py:555
+#: assets/automations/base/manager.py:556
msgid ">>> Task preparation phase"
msgstr ">>> 任務準備階段"
-#: assets/automations/base/manager.py:559
+#: assets/automations/base/manager.py:560
#, python-brace-format
msgid ">>> Executing tasks in batches, total {runner_count}"
msgstr ">>> 分次執行任務,總共 {runner_count}"
-#: assets/automations/base/manager.py:564
+#: assets/automations/base/manager.py:565
msgid ">>> Start executing tasks"
msgstr ">>> 開始執行任務"
-#: assets/automations/base/manager.py:566
+#: assets/automations/base/manager.py:567
msgid ">>> No tasks need to be executed"
msgstr ">>> 沒有需要執行的任務"
-#: assets/automations/base/manager.py:570
+#: assets/automations/base/manager.py:571
#, python-brace-format
msgid ">>> Begin executing batch {index} of tasks"
msgstr ">>> 開始執行第 {index} 批任務"
@@ -2647,7 +2653,7 @@ msgid "Port"
msgstr "埠"
#: assets/models/asset/common.py:167 assets/serializers/asset/common.py:175
-#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:59
+#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:69
msgid "Address"
msgstr "地址"
@@ -2655,12 +2661,12 @@ msgstr "地址"
#: assets/serializers/asset/common.py:151
#: authentication/backends/passkey/models.py:12
#: authentication/serializers/connect_token_secret.py:130
-#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:399
+#: perms/serializers/user_permission.py:26 xpack/plugins/cloud/models.py:400
msgid "Platform"
msgstr "系統平台"
#: assets/models/asset/common.py:173 assets/models/zone.py:22
-#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:401
+#: perms/serializers/user_permission.py:29 xpack/plugins/cloud/models.py:402
msgid "Zone"
msgstr "網域"
@@ -2729,9 +2735,9 @@ msgid "Proxy"
msgstr "代理"
#: assets/models/automations/base.py:23 assets/models/cmd_filter.py:32
-#: assets/models/node.py:553 ops/models/job.py:158
+#: assets/models/node.py:560 ops/models/job.py:158
#: perms/models/asset_permission.py:72 tickets/models/ticket/apply_asset.py:15
-#: xpack/plugins/cloud/models.py:400
+#: xpack/plugins/cloud/models.py:401
msgid "Node"
msgstr "節點"
@@ -2757,7 +2763,7 @@ msgstr "資產自動化任務"
#: assets/models/automations/base.py:140 assets/models/cmd_filter.py:41
#: authentication/serializers/token.py:134 common/db/models.py:34
#: ops/models/base.py:54 ops/models/job.py:240
-#: users/models/user/__init__.py:328
+#: users/models/user/__init__.py:333
msgid "Date created"
msgstr "創建日期"
@@ -2846,7 +2852,7 @@ msgstr "網關"
msgid "System"
msgstr "系統"
-#: assets/models/label.py:19 assets/models/node.py:539
+#: assets/models/label.py:19 assets/models/node.py:546
#: assets/serializers/cagegory.py:11 assets/serializers/cagegory.py:18
#: assets/serializers/cagegory.py:24
#: authentication/models/connection_token.py:35
@@ -2861,7 +2867,7 @@ msgstr "值"
#: assets/serializers/platform.py:160
#: authentication/serializers/connect_token_secret.py:136
#: common/serializers/common.py:85 labels/serializers.py:45
-#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:404
+#: settings/serializers/msg.py:91 xpack/plugins/cloud/models.py:405
msgid "Label"
msgstr "標籤"
@@ -2877,27 +2883,27 @@ msgstr "自訂備註"
msgid "My assets"
msgstr "我的資產"
-#: assets/models/node.py:168
+#: assets/models/node.py:172
msgid "New node"
msgstr "新節點"
-#: assets/models/node.py:467 audits/backends/db.py:85 audits/backends/db.py:86
+#: assets/models/node.py:474 audits/backends/db.py:85 audits/backends/db.py:86
msgid "empty"
msgstr "空"
-#: assets/models/node.py:538 perms/models/perm_node.py:28
+#: assets/models/node.py:545 perms/models/perm_node.py:28
msgid "Key"
msgstr "鍵"
-#: assets/models/node.py:540 assets/serializers/node.py:20
+#: assets/models/node.py:547 assets/serializers/node.py:20
msgid "Full value"
msgstr "全稱"
-#: assets/models/node.py:544 perms/models/perm_node.py:30
+#: assets/models/node.py:551 perms/models/perm_node.py:30
msgid "Parent key"
msgstr "ssh私鑰"
-#: assets/models/node.py:556
+#: assets/models/node.py:563
msgid "Can match node"
msgstr "可以匹配節點"
@@ -3073,7 +3079,7 @@ msgstr "節點路徑,格式為 [\"/組織/節點名稱\"], 如果節點不存
#: authentication/serializers/connect_token_secret.py:30
#: authentication/serializers/connect_token_secret.py:77
#: perms/models/asset_permission.py:76 perms/serializers/permission.py:68
-#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:402
+#: perms/serializers/user_permission.py:86 xpack/plugins/cloud/models.py:403
#: xpack/plugins/cloud/serializers/task.py:36
msgid "Protocols"
msgstr "協議組"
@@ -3507,7 +3513,7 @@ msgid "Symlink"
msgstr "建立軟連結"
#: audits/const.py:18 audits/const.py:29
-#: ops/templates/ops/celery_task_log.html:86
+#: ops/templates/ops/celery_task_log.html:139
#: terminal/api/session/session.py:159
msgid "Download"
msgstr "下載"
@@ -3536,7 +3542,9 @@ msgstr "匯出"
msgid "Connect"
msgstr "連接"
-#: audits/const.py:31 authentication/templates/authentication/login.html:334
+#: audits/const.py:31
+#: authentication/templates/authentication/cert_login.html:232
+#: authentication/templates/authentication/login.html:334
#: authentication/templates/authentication/login.html:408
#: templates/_header_bar.html:101
#: xpack/plugins/interface/templates/login_i18n.html:21
@@ -4185,10 +4193,8 @@ msgid "SSO"
msgstr "SSO"
#: audits/signal_handlers/login_log.py:36
-#, fuzzy
-#| msgid "Custom"
msgid "Custom SSO"
-msgstr "自定義"
+msgstr "自定義 SSO"
#: audits/signal_handlers/login_log.py:37
msgid "Auth Token"
@@ -4325,24 +4331,24 @@ msgstr "臉部比對失敗"
msgid "Current user not support mfa type: {}"
msgstr "當前用戶不支持 MFA 類型: {}"
-#: authentication/api/password.py:34 terminal/api/session/session.py:347
+#: authentication/api/password.py:37 terminal/api/session/session.py:347
#: users/views/profile/reset.py:63
#, python-brace-format
msgid "User does not exist: {}"
msgstr "用戶不存在: {}"
-#: authentication/api/password.py:34 users/views/profile/reset.py:166
+#: authentication/api/password.py:37 users/views/profile/reset.py:166
msgid "No user matched"
msgstr "沒有匹配到用戶"
-#: authentication/api/password.py:38
+#: authentication/api/password.py:41
#, python-brace-format
msgid ""
"The user is from {}, please go to the corresponding system to change the "
"password"
msgstr "用戶來自 {} 請去相應系統修改密碼"
-#: authentication/api/password.py:69
+#: authentication/api/password.py:72
#: authentication/templates/authentication/login.html:400
#: users/templates/users/forgot_password.html:41
#: users/templates/users/forgot_password.html:42
@@ -4352,7 +4358,7 @@ msgstr "用戶來自 {} 請去相應系統修改密碼"
msgid "Forgot password"
msgstr "忘記密碼"
-#: authentication/api/password.py:70 authentication/mfa/email.py:42
+#: authentication/api/password.py:73 authentication/mfa/email.py:42
#, python-brace-format
msgid "The validity period of the verification code is {} minute"
msgstr "驗證碼有效期為 {} 分鐘"
@@ -4365,10 +4371,21 @@ msgstr "身份验证管理"
msgid "CAS Error"
msgstr "CAS 錯誤"
-#: authentication/backends/custom.py:60
-#: authentication/backends/oauth2/backends.py:158
-msgid "User invalid, disabled or expired"
-msgstr "用戶無效,已禁用或已過期"
+#: authentication/backends/cert/api.py:57
+msgid "Certificate enrollment is not enabled"
+msgstr "憑證簽發未啟用"
+
+#: authentication/backends/cert/api.py:62
+msgid "CSR is required"
+msgstr "CSR 為必填項。"
+
+#: authentication/backends/cert/api.py:68
+msgid "Certificate signing failed"
+msgstr "憑證簽發失敗"
+
+#: authentication/backends/cert/views.py:97
+msgid "Invalid credentials"
+msgstr "無效的憑證"
#: authentication/backends/drf.py:61
msgid "Invalid token header. No credentials provided."
@@ -4611,16 +4628,16 @@ msgstr "您的密碼無效"
msgid "Please wait for %s seconds before retry"
msgstr "請在 %s 秒後重試"
-#: authentication/errors/redirect.py:85 authentication/mixins.py:436
+#: authentication/errors/redirect.py:85 authentication/mixins.py:445
#: users/views/profile/reset.py:224
msgid "Your password is too simple, please change it for security"
msgstr "你的密碼過於簡單,為了安全,請修改"
-#: authentication/errors/redirect.py:93 authentication/mixins.py:445
+#: authentication/errors/redirect.py:93 authentication/mixins.py:454
msgid "You should to change your password before login"
msgstr "登錄完成前,請先修改密碼"
-#: authentication/errors/redirect.py:101 authentication/mixins.py:454
+#: authentication/errors/redirect.py:101 authentication/mixins.py:463
msgid "Your password has expired, please reset before logging in"
msgstr "您的密碼已過期,先修改再登錄"
@@ -4746,11 +4763,11 @@ msgid ""
msgstr ""
"管理員已開啟 '僅允許已存在用戶登入',當前用戶不在用戶列表中,請聯繫管理員。"
-#: authentication/mixins.py:184
+#: authentication/mixins.py:187
msgid "User is invalid"
msgstr "無效的用戶"
-#: authentication/mixins.py:201
+#: authentication/mixins.py:204
#, python-brace-format
msgid ""
" The administrator has enabled 'Only allow login from user source'. \n"
@@ -4758,12 +4775,12 @@ msgid ""
"administrator. "
msgstr "管理員已開啟 '僅允許從用戶來源登入',當前用戶來源為 {},請聯繫管理員。"
-#: authentication/mixins.py:382
+#: authentication/mixins.py:391
#, python-brace-format
msgid "The MFA type ({}) is not enabled"
msgstr "該 MFA ({}) 方式沒有啟用"
-#: authentication/mixins.py:424
+#: authentication/mixins.py:433
msgid "Please change your password"
msgstr "請修改密碼"
@@ -4955,7 +4972,7 @@ msgstr "動作"
#: authentication/serializers/connection_token.py:46
#: perms/serializers/permission.py:66 perms/serializers/permission.py:87
-#: users/serializers/user.py:127 users/serializers/user.py:261
+#: users/serializers/user.py:127 users/serializers/user.py:266
msgid "Is expired"
msgstr "已過期"
@@ -4995,13 +5012,13 @@ msgstr "SSH金鑰不合法"
#: authentication/serializers/token.py:93 perms/serializers/permission.py:65
#: perms/serializers/permission.py:88 users/serializers/user.py:128
-#: users/serializers/user.py:258
+#: users/serializers/user.py:263
msgid "Is valid"
msgstr "是否有效"
#: authentication/serializers/token.py:131 ops/models/adhoc.py:26
#: ops/models/playbook.py:34 ops/serializers/mixin.py:10 rbac/models/role.py:31
-#: rbac/models/rolebinding.py:46 rbac/serializers/role.py:12
+#: rbac/models/rolebinding.py:47 rbac/serializers/role.py:12
#: settings/serializers/auth/oauth2.py:37
msgid "Scope"
msgstr "範圍"
@@ -5096,7 +5113,7 @@ msgstr "代碼錯誤"
#: authentication/templates/authentication/_msg_oauth_bind.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_reset_password_code.html:9
-#: jumpserver/conf.py:555
+#: jumpserver/conf.py:558
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:32
#: users/templates/users/_msg_account_expire_reminder.html:4
@@ -5192,6 +5209,67 @@ msgstr "如果這次公鑰更新不是由你發起的,那麼你的帳號可能
msgid "Cancel"
msgstr "取消"
+#: authentication/templates/authentication/cert_login.html:190
+msgid "Certificate Authentication"
+msgstr "憑證認證"
+
+#: authentication/templates/authentication/cert_login.html:195
+#: authentication/templates/authentication/cert_login.html:250
+msgid "Loading USB Key driver..."
+msgstr "正在載入 USB Key 驅動程式..."
+
+#: authentication/templates/authentication/cert_login.html:210
+msgid "Insert USB Key to auto-fetch"
+msgstr "請插入 USB Key 自動取得"
+
+#: authentication/templates/authentication/cert_login.html:251
+msgid "Detecting USB Key..."
+msgstr "正在偵測 USB Key..."
+
+#: authentication/templates/authentication/cert_login.html:252
+msgid "USB Key connected"
+msgstr "USB Key 已連接"
+
+#: authentication/templates/authentication/cert_login.html:253
+msgid "Please insert USB Key"
+msgstr "請插入 USB Key"
+
+#: authentication/templates/authentication/cert_login.html:254
+msgid "Driver unavailable"
+msgstr "驅動程式不可用"
+
+#: authentication/templates/authentication/cert_login.html:255
+msgid "USB Key SDK initialization failed"
+msgstr "USB Key SDK 初始化失敗"
+
+#: authentication/templates/authentication/cert_login.html:256
+msgid "Verifying PIN..."
+msgstr "PIN 驗證中..."
+
+#: authentication/templates/authentication/cert_login.html:257
+msgid "PIN verified"
+msgstr "PIN 驗證通過"
+
+#: authentication/templates/authentication/cert_login.html:258
+msgid "PIN verification failed"
+msgstr "驗證 PIN 失敗"
+
+#: authentication/templates/authentication/cert_login.html:259
+msgid "Signing challenge code..."
+msgstr "正在對挑戰碼簽名..."
+
+#: authentication/templates/authentication/cert_login.html:260
+msgid "Signing failed"
+msgstr "簽名失敗"
+
+#: authentication/templates/authentication/cert_login.html:261
+msgid "Failed to retrieve certificate"
+msgstr "取得憑證失敗"
+
+#: authentication/templates/authentication/cert_login.html:262
+msgid "No certificate detected, please contact administrator"
+msgstr "未偵測到憑證,請聯繫管理員製證"
+
#: authentication/templates/authentication/face_capture.html:14
msgid "Retry"
msgstr "重試"
@@ -5259,6 +5337,10 @@ msgstr "是否重試 ?"
msgid "LAN"
msgstr "區域網路"
+#: authentication/utils.py:150
+msgid "CERT"
+msgstr ""
+
#: authentication/views/base.py:71
#: perms/templates/perms/_msg_permed_items_expire.html:18
msgid "If you have any question, please contact the administrator"
@@ -5421,47 +5503,47 @@ msgstr "請使用密碼登錄,然後綁定企業微信"
msgid "Request file format may be wrong"
msgstr "上傳的檔案格式錯誤 或 其它類型資源的文件"
-#: common/const/choices.py:40
+#: common/const/choices.py:41
msgid "China"
msgstr "中國"
-#: common/const/choices.py:57
+#: common/const/choices.py:58
msgid "Manual"
msgstr "手動觸發"
-#: common/const/choices.py:58
+#: common/const/choices.py:59
msgid "Timing"
msgstr "定時觸發"
-#: common/const/choices.py:64 ops/const.py:74
+#: common/const/choices.py:65 ops/const.py:74
msgid "Running"
msgstr "運行中"
-#: common/const/choices.py:68
+#: common/const/choices.py:69
msgid "Canceled"
msgstr "取消"
-#: common/const/choices.py:115
+#: common/const/choices.py:128
msgid "Confirmed"
msgstr "確認"
-#: common/const/choices.py:123 terminal/models/applet/applet.py:31
+#: common/const/choices.py:136 terminal/models/applet/applet.py:31
msgid "Community edition"
msgstr "社區版"
-#: common/const/choices.py:124
+#: common/const/choices.py:137
msgid "Basic edition"
msgstr "企業基礎版"
-#: common/const/choices.py:125
+#: common/const/choices.py:138
msgid "Standard edition"
msgstr "企業標準版"
-#: common/const/choices.py:126
+#: common/const/choices.py:139
msgid "Professional edition"
msgstr "企業專業版"
-#: common/const/choices.py:127
+#: common/const/choices.py:140
msgid "Ultimate edition"
msgstr "企業旗艦版"
@@ -5962,24 +6044,24 @@ msgstr "未找到 Code"
msgid "The message code provided is invalid or has expired"
msgstr "提供的消息代碼無效或已過期"
-#: jumpserver/conf.py:549
+#: jumpserver/conf.py:552
#, python-brace-format
msgid "The verification code is: {code}"
msgstr "驗證碼為: {code}"
-#: jumpserver/conf.py:554
+#: jumpserver/conf.py:557
msgid "Create account successfully"
msgstr "創建帳號成功"
-#: jumpserver/conf.py:556
+#: jumpserver/conf.py:559
msgid "Your account has been created successfully"
msgstr "你的帳號已創建成功"
-#: jumpserver/context_processor.py:17
+#: jumpserver/context_processor.py:16
msgid "JumpServer - An open-source PAM"
msgstr "JumpServer 開源堡壘機"
-#: jumpserver/context_processor.py:37
+#: jumpserver/context_processor.py:31
msgid "FIT2CLOUD"
msgstr ""
@@ -6680,7 +6762,7 @@ msgid "Please save in a org"
msgstr "請選擇一個組織後再保存"
#: orgs/mixins/models.py:58 orgs/mixins/serializers.py:25 orgs/models.py:91
-#: rbac/const.py:7 rbac/models/rolebinding.py:56
+#: rbac/const.py:7 rbac/models/rolebinding.py:57
#: rbac/serializers/rolebinding.py:44 settings/serializers/auth/base.py:53
#: terminal/notifications.py:309
#: terminal/templates/terminal/_msg_command_warning.html:27
@@ -7104,25 +7186,25 @@ msgstr "系統角色"
msgid "Organization role"
msgstr "組織角色"
-#: rbac/models/rolebinding.py:62
+#: rbac/models/rolebinding.py:63
msgid "Role binding"
msgstr "角色綁定"
-#: rbac/models/rolebinding.py:168
+#: rbac/models/rolebinding.py:169
msgid "All organizations"
msgstr "所有組織"
-#: rbac/models/rolebinding.py:200
+#: rbac/models/rolebinding.py:201
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
msgstr "用戶最後一個角色,不能刪除,你可以將用戶從組織移除"
-#: rbac/models/rolebinding.py:207
+#: rbac/models/rolebinding.py:208
msgid "Organization role binding"
msgstr "組織角色綁定"
-#: rbac/models/rolebinding.py:222
+#: rbac/models/rolebinding.py:223
msgid "System role binding"
msgstr "系統角色綁定"
@@ -7187,7 +7269,7 @@ msgid "Storage"
msgstr "儲存"
#: rbac/tree.py:64 terminal/models/applet/applet.py:53
-#: terminal/models/applet/applet.py:379 terminal/models/applet/host.py:30
+#: terminal/models/applet/applet.py:387 terminal/models/applet/host.py:30
#: terminal/serializers/applet.py:16
msgid "Applet"
msgstr "遠程應用"
@@ -7250,51 +7332,51 @@ msgstr "撤銷訪問令牌"
msgid "Range days"
msgstr "修改者"
-#: reports/views.py:20
+#: reports/views.py:19
msgid "User login report"
msgstr "用戶登錄報告"
-#: reports/views.py:24
+#: reports/views.py:23
msgid "User change password report"
msgstr "用戶修改密碼報告"
-#: reports/views.py:28
+#: reports/views.py:27
msgid "Asset statistics report"
msgstr "資產統計報告"
-#: reports/views.py:32
+#: reports/views.py:31
msgid "Asset activity report"
msgstr "資產活動報告"
-#: reports/views.py:36
+#: reports/views.py:35
msgid "Account statistics report"
msgstr "賬號統計報告"
-#: reports/views.py:40
+#: reports/views.py:39
msgid "Account automation report"
msgstr "賬號自動化報告"
-#: reports/views.py:44
+#: reports/views.py:43
msgid "ConsoleDashboard"
msgstr "控制台儀表板"
-#: reports/views.py:48
+#: reports/views.py:47
msgid "AuditsDashboard"
msgstr "審計台儀表板"
-#: reports/views.py:52
+#: reports/views.py:51
msgid "PamDashboard"
msgstr "PAM 儀表板"
-#: reports/views.py:56
+#: reports/views.py:55
msgid "ChangeSecretDashboard"
msgstr "帳號改密儀表盤"
-#: reports/views.py:191
+#: reports/views.py:190
msgid "Failed to send email: "
msgstr "發送郵件失敗"
-#: reports/views.py:192
+#: reports/views.py:191
msgid "Email sent successfully to "
msgstr "發送郵件成功"
@@ -7573,19 +7655,19 @@ msgstr "啟用釘釘認證"
#: settings/serializers/auth/dingtalk.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the DingTalk service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the DingTalk service user attribute name"
msgstr ""
-"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是釘釘服務使"
-"用者屬性名稱"
+"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是釘釘服務使用者屬"
+"性名稱"
#: settings/serializers/auth/feishu.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the FeiShu service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the FeiShu service user attribute name"
msgstr ""
-"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是飛書服務使"
-"用者屬性名稱"
+"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是飛書服務使用者屬"
+"性名稱"
#: settings/serializers/auth/lark.py:13 users/models/user/_source.py:24
msgid "Lark"
@@ -7593,11 +7675,11 @@ msgstr "Lark"
#: settings/serializers/auth/lark.py:19
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Lark service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Lark service user attribute name"
msgstr ""
-"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是 Lark 服務"
-"使用者屬性名稱"
+"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是 Lark 服務使用者"
+"屬性名稱"
#: settings/serializers/auth/ldap.py:42 settings/serializers/auth/ldap.py:108
msgid "LDAP"
@@ -7640,11 +7722,11 @@ msgstr "可能的選項是(cn或uid或sAMAccountName=%(user)s)"
#: settings/serializers/auth/ldap.py:69 settings/serializers/auth/ldap_ha.py:51
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the LDAP service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the LDAP service user attribute name"
msgstr ""
-"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是 LDAP 服務"
-"使用者屬性名稱"
+"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是 LDAP 服務使用者"
+"屬性名稱"
#: settings/serializers/auth/ldap.py:85 settings/serializers/auth/ldap_ha.py:67
msgid "Connect timeout (s)"
@@ -7745,11 +7827,11 @@ msgstr "當使用者退出時,他們也會從 OAuth2 伺服器退出"
#: settings/serializers/auth/oauth2.py:62
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OAuth2 service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OAuth2 service user attribute name"
msgstr ""
-"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是 OAuth2 服"
-"務使用者屬性名稱"
+"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是 OAuth2 服務使用"
+"者屬性名稱"
#: settings/serializers/auth/oauth2.py:67 settings/serializers/auth/oidc.py:117
#: settings/serializers/auth/saml2.py:45
@@ -7782,11 +7864,11 @@ msgstr "Ignore SSL certificate verification"
#: settings/serializers/auth/oidc.py:41
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the OIDC service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the OIDC service user attribute name"
msgstr ""
-"使用者屬性映射,其中 `key` 是本系統使用者屬性名稱,`value` 是 OIDC 服務"
-"使用者屬性名稱"
+"使用者屬性映射,其中 `key` 是本系統使用者屬性名稱,`value` 是 OIDC 服務使用者"
+"屬性名稱"
#: settings/serializers/auth/oidc.py:45
msgid "Enable PKCE"
@@ -7916,8 +7998,8 @@ msgid ""
"User attribute mapping, where the `key` is the SAML2 service user attribute "
"name and the `value` is this system user attribute name"
msgstr ""
-" 使用者屬性映射,其中 `key` 是 SAML2 服務使用者屬性名稱,`value` 是 "
-"本系統使用者屬性名稱"
+" 使用者屬性映射,其中 `key` 是 SAML2 服務使用者屬性名稱,`value` 是 本系統使"
+"用者屬性名稱"
#: settings/serializers/auth/saml2.py:43
msgid "When the user signs out, they also be logged out from the SAML2 server"
@@ -7925,11 +8007,11 @@ msgstr "當使用者登出時,他們也會從 SAML2 伺服器登出"
#: settings/serializers/auth/slack.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the Slack service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the Slack service user attribute name"
msgstr ""
-"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是 Slack 服"
-"務使用者屬性名稱"
+"使用者屬性對照,其中 `key` 是本系統使用者屬性名稱,`value` 是 Slack 服務使用"
+"者屬性名稱"
#: settings/serializers/auth/sms.py:18
msgid "Enable Short Message Service (SMS)"
@@ -7963,7 +8045,7 @@ msgid "Template code"
msgstr "模板"
#: settings/serializers/auth/sms.py:40 users/models/user/__init__.py:89
-#: users/serializers/user.py:159
+#: users/serializers/user.py:164
msgid "Phone"
msgstr "手機"
@@ -8019,8 +8101,8 @@ msgid "Enable SSO auth"
msgstr "啟用 SSO 令牌認證"
#: settings/serializers/auth/sso.py:17
-msgid "Other service can using SSO token login to JumpServer without password"
-msgstr "其它系統可以使用 SSO Token 對接 JumpServer, 免去登錄的過程"
+msgid "Other service can using SSO token login to system without password"
+msgstr "其它系統可以使用 SSO Token 對接系统, 免去登錄的過程"
#: settings/serializers/auth/sso.py:20
msgid "SSO auth key TTL"
@@ -8033,11 +8115,11 @@ msgstr "單位: 秒"
#: settings/serializers/auth/wecom.py:20
msgid ""
-"User attribute mapping, where the `key` is this system user attribute "
-"name and the `value` is the WeCom service user attribute name"
+"User attribute mapping, where the `key` is this system user attribute name "
+"and the `value` is the WeCom service user attribute name"
msgstr ""
-"使用者屬性映射,其中 `key` 是本系統使用者屬性名稱,`value` 是企業微信服"
-"務使用者屬性名稱"
+"使用者屬性映射,其中 `key` 是本系統使用者屬性名稱,`value` 是企業微信服務使用"
+"者屬性名稱"
#: settings/serializers/basic.py:11
msgid "Site URL"
@@ -9134,7 +9216,7 @@ msgstr "等待:"
msgid "The verification code has been sent"
msgstr "驗證碼已發送"
-#: templates/_without_nav_base.html:46
+#: templates/_without_nav_base.html:51
msgid "Home page"
msgstr "首頁"
@@ -9395,31 +9477,31 @@ msgstr "可以並發"
msgid "Hosts"
msgstr "主機"
-#: terminal/models/applet/applet.py:94
+#: terminal/models/applet/applet.py:102
#: terminal/models/virtualapp/virtualapp.py:66
#, python-brace-format
msgid "Applet pkg not valid, Missing file {}"
msgstr "Applet pkg 無效,缺少文件 {}"
-#: terminal/models/applet/applet.py:113
+#: terminal/models/applet/applet.py:121
#, python-brace-format
msgid "Load platform.yml failed: {}"
msgstr "載入 platform.yml 失敗: {}"
-#: terminal/models/applet/applet.py:116
+#: terminal/models/applet/applet.py:124
msgid "Only support custom platform"
msgstr "只支持自訂平台"
-#: terminal/models/applet/applet.py:121
+#: terminal/models/applet/applet.py:129
msgid "Missing type in platform.yml"
msgstr "在 platform.yml 中缺少類型"
-#: terminal/models/applet/applet.py:381 terminal/models/applet/host.py:36
+#: terminal/models/applet/applet.py:389 terminal/models/applet/host.py:36
#: terminal/models/applet/host.py:138
msgid "Hosting"
msgstr "宿主機"
-#: terminal/models/applet/applet.py:387
+#: terminal/models/applet/applet.py:395
msgid "Applet Publication"
msgstr "應用發布"
@@ -9509,7 +9591,7 @@ msgstr "VNC 端口"
#: terminal/models/component/endpoint.py:35
#: terminal/models/component/endpoint.py:115
-#: terminal/serializers/endpoint.py:63 terminal/serializers/storage.py:41
+#: terminal/serializers/endpoint.py:73 terminal/serializers/storage.py:41
#: terminal/serializers/storage.py:53 terminal/serializers/storage.py:83
#: terminal/serializers/storage.py:93 terminal/serializers/storage.py:101
msgid "Endpoint"
@@ -9723,8 +9805,8 @@ msgstr "命令及錄影儲存"
#: terminal/notifications.py:279 terminal/tasks.py:212
#: xpack/plugins/cloud/api.py:182
-#: xpack/plugins/cloud/serializers/account.py:143
-#: xpack/plugins/cloud/serializers/account.py:146
+#: xpack/plugins/cloud/serializers/account.py:148
+#: xpack/plugins/cloud/serializers/account.py:151
msgid "Test failure: Account invalid"
msgstr "測試失敗: 帳號無效"
@@ -9844,7 +9926,8 @@ msgstr "已有 RDS 許可證"
msgid ""
"If not exist, the RDS will be in trial mode, and the trial period is 120 "
"days. Detail"
+"remote-desktop-services/rds-client-access-license\" "
+"target=\"_blank\">Detail"
msgstr ""
"如果不存在,RDS將處於試用模式,試用期為 120 天。