mirror of https://github.com/jumpserver/jumpserver
[Update] 修改settings配置 (#2067)
* [Update] 修改settings配置 * [Update] 修改settings * [Update] 修改密码校验规则前后端逻辑 * [Update] 修改用户config机制 * [Update] 修改配置 * [Update] 修改config example增加翻译pull/2043/head
parent
5931c5a032
commit
16cc4a0f4e
|
@ -168,13 +168,16 @@ class DjangoSettingsAPI(APIView):
|
||||||
return Response("Not in debug mode")
|
return Response("Not in debug mode")
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
for k, v in settings.__dict__.items():
|
for i in [settings, getattr(settings, '_wrapped')]:
|
||||||
if k and k.isupper():
|
if not i:
|
||||||
try:
|
continue
|
||||||
json.dumps(v)
|
for k, v in i.__dict__.items():
|
||||||
data[k] = v
|
if k and k.isupper():
|
||||||
except (json.JSONDecodeError, TypeError):
|
try:
|
||||||
data[k] = str(v)
|
json.dumps(v)
|
||||||
|
data[k] = v
|
||||||
|
except (json.JSONDecodeError, TypeError):
|
||||||
|
data[k] = str(v)
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from .models import Setting, common_settings
|
from .models import Setting, settings
|
||||||
from .fields import FormDictField, FormEncryptCharField, \
|
from .fields import FormDictField, FormEncryptCharField, \
|
||||||
FormEncryptMixin
|
FormEncryptMixin
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class BaseForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
for name, field in self.fields.items():
|
for name, field in self.fields.items():
|
||||||
value = getattr(common_settings, name)
|
value = getattr(settings, name, None)
|
||||||
# django_value = getattr(settings, name) if hasattr(settings, name) else None
|
# django_value = getattr(settings, name) if hasattr(settings, name) else None
|
||||||
|
|
||||||
if value is None: # and django_value is None:
|
if value is None: # and django_value is None:
|
||||||
|
@ -43,7 +43,7 @@ class BaseForm(forms.Form):
|
||||||
field = self.fields[name]
|
field = self.fields[name]
|
||||||
if isinstance(field.widget, forms.PasswordInput) and not value:
|
if isinstance(field.widget, forms.PasswordInput) and not value:
|
||||||
continue
|
continue
|
||||||
if value == getattr(common_settings, name):
|
if value == getattr(settings, name):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
encrypted = True if isinstance(field, FormEncryptMixin) else False
|
encrypted = True if isinstance(field, FormEncryptMixin) else False
|
||||||
|
@ -69,7 +69,6 @@ class BasicSettingForm(BaseForm):
|
||||||
)
|
)
|
||||||
EMAIL_SUBJECT_PREFIX = forms.CharField(
|
EMAIL_SUBJECT_PREFIX = forms.CharField(
|
||||||
max_length=1024, label=_("Email Subject Prefix"),
|
max_length=1024, label=_("Email Subject Prefix"),
|
||||||
initial="[Jumpserver] "
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,21 +96,21 @@ class EmailSettingForm(BaseForm):
|
||||||
|
|
||||||
class LDAPSettingForm(BaseForm):
|
class LDAPSettingForm(BaseForm):
|
||||||
AUTH_LDAP_SERVER_URI = forms.CharField(
|
AUTH_LDAP_SERVER_URI = forms.CharField(
|
||||||
label=_("LDAP server"), initial='ldap://localhost:389'
|
label=_("LDAP server"),
|
||||||
)
|
)
|
||||||
AUTH_LDAP_BIND_DN = forms.CharField(
|
AUTH_LDAP_BIND_DN = forms.CharField(
|
||||||
label=_("Bind DN"), initial='cn=admin,dc=jumpserver,dc=org'
|
label=_("Bind DN"),
|
||||||
)
|
)
|
||||||
AUTH_LDAP_BIND_PASSWORD = FormEncryptCharField(
|
AUTH_LDAP_BIND_PASSWORD = FormEncryptCharField(
|
||||||
label=_("Password"), initial='',
|
label=_("Password"),
|
||||||
widget=forms.PasswordInput, required=False
|
widget=forms.PasswordInput, required=False
|
||||||
)
|
)
|
||||||
AUTH_LDAP_SEARCH_OU = forms.CharField(
|
AUTH_LDAP_SEARCH_OU = forms.CharField(
|
||||||
label=_("User OU"), initial='ou=tech,dc=jumpserver,dc=org',
|
label=_("User OU"),
|
||||||
help_text=_("Use | split User OUs")
|
help_text=_("Use | split User OUs")
|
||||||
)
|
)
|
||||||
AUTH_LDAP_SEARCH_FILTER = forms.CharField(
|
AUTH_LDAP_SEARCH_FILTER = forms.CharField(
|
||||||
label=_("User search filter"), initial='(cn=%(user)s)',
|
label=_("User search filter"),
|
||||||
help_text=_("Choice may be (cn|uid|sAMAccountName)=%(user)s)")
|
help_text=_("Choice may be (cn|uid|sAMAccountName)=%(user)s)")
|
||||||
)
|
)
|
||||||
AUTH_LDAP_USER_ATTR_MAP = FormDictField(
|
AUTH_LDAP_USER_ATTR_MAP = FormDictField(
|
||||||
|
@ -119,14 +118,14 @@ class LDAPSettingForm(BaseForm):
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"User attr map present how to map LDAP user attr to jumpserver, "
|
"User attr map present how to map LDAP user attr to jumpserver, "
|
||||||
"username,name,email is jumpserver attr"
|
"username,name,email is jumpserver attr"
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
# AUTH_LDAP_GROUP_SEARCH_OU = CONFIG.AUTH_LDAP_GROUP_SEARCH_OU
|
# AUTH_LDAP_GROUP_SEARCH_OU = CONFIG.AUTH_LDAP_GROUP_SEARCH_OU
|
||||||
# AUTH_LDAP_GROUP_SEARCH_FILTER = CONFIG.AUTH_LDAP_GROUP_SEARCH_FILTER
|
# AUTH_LDAP_GROUP_SEARCH_FILTER = CONFIG.AUTH_LDAP_GROUP_SEARCH_FILTER
|
||||||
AUTH_LDAP_START_TLS = forms.BooleanField(
|
AUTH_LDAP_START_TLS = forms.BooleanField(
|
||||||
label=_("Use SSL"), initial=False, required=False
|
label=_("Use SSL"), required=False
|
||||||
)
|
)
|
||||||
AUTH_LDAP = forms.BooleanField(label=_("Enable LDAP auth"), initial=False, required=False)
|
AUTH_LDAP = forms.BooleanField(label=_("Enable LDAP auth"), required=False)
|
||||||
|
|
||||||
|
|
||||||
class TerminalSettingForm(BaseForm):
|
class TerminalSettingForm(BaseForm):
|
||||||
|
|
|
@ -2,6 +2,7 @@ import json
|
||||||
|
|
||||||
import ldap
|
import ldap
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core.cache import cache
|
||||||
from django.db.utils import ProgrammingError, OperationalError
|
from django.db.utils import ProgrammingError, OperationalError
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -40,15 +41,7 @@ class Setting(models.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
default = getattr(settings, item, None)
|
return cache.get(item)
|
||||||
try:
|
|
||||||
instances = self.__class__.objects.filter(name=item)
|
|
||||||
except Exception:
|
|
||||||
return default
|
|
||||||
if len(instances) == 1:
|
|
||||||
return instances[0].cleaned_value
|
|
||||||
else:
|
|
||||||
return default
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cleaned_value(self):
|
def cleaned_value(self):
|
||||||
|
@ -106,22 +99,15 @@ class Setting(models.Model):
|
||||||
|
|
||||||
def refresh_setting(self):
|
def refresh_setting(self):
|
||||||
setattr(settings, self.name, self.cleaned_value)
|
setattr(settings, self.name, self.cleaned_value)
|
||||||
|
|
||||||
if self.name == "AUTH_LDAP":
|
if self.name == "AUTH_LDAP":
|
||||||
if self.cleaned_value and settings.AUTH_LDAP_BACKEND not in settings.AUTHENTICATION_BACKENDS:
|
if self.cleaned_value and settings.AUTH_LDAP_BACKEND not in settings.AUTHENTICATION_BACKENDS:
|
||||||
settings.AUTHENTICATION_BACKENDS.insert(0, settings.AUTH_LDAP_BACKEND)
|
old_setting = settings.AUTHENTICATION_BACKENDS
|
||||||
|
old_setting.insert(0, settings.AUTH_LDAP_BACKEND)
|
||||||
|
settings.AUTHENTICATION_BACKENDS = old_setting
|
||||||
elif not self.cleaned_value and settings.AUTH_LDAP_BACKEND in settings.AUTHENTICATION_BACKENDS:
|
elif not self.cleaned_value and settings.AUTH_LDAP_BACKEND in settings.AUTHENTICATION_BACKENDS:
|
||||||
settings.AUTHENTICATION_BACKENDS.remove(settings.AUTH_LDAP_BACKEND)
|
old_setting = settings.AUTHENTICATION_BACKENDS
|
||||||
|
old_setting.remove(settings.AUTH_LDAP_BACKEND)
|
||||||
if self.name == "AUTH_LDAP_SEARCH_FILTER":
|
settings.AUTHENTICATION_BACKENDS = old_setting
|
||||||
settings.AUTH_LDAP_USER_SEARCH_UNION = [
|
|
||||||
LDAPSearch(USER_SEARCH, ldap.SCOPE_SUBTREE, settings.AUTH_LDAP_SEARCH_FILTER)
|
|
||||||
for USER_SEARCH in str(settings.AUTH_LDAP_SEARCH_OU).split("|")
|
|
||||||
]
|
|
||||||
settings.AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(*settings.AUTH_LDAP_USER_SEARCH_UNION)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "settings"
|
db_table = "settings"
|
||||||
|
|
||||||
|
|
||||||
common_settings = Setting()
|
|
||||||
|
|
|
@ -4,4 +4,3 @@
|
||||||
from django.dispatch import Signal
|
from django.dispatch import Signal
|
||||||
|
|
||||||
django_ready = Signal()
|
django_ready = Signal()
|
||||||
ldap_auth_enable = Signal(providing_args=["enabled"])
|
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
#
|
#
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.db.models.signals import post_save, pre_save
|
from django.db.models.signals import post_save, pre_save
|
||||||
from django.conf import settings
|
from django.conf import LazySettings, empty
|
||||||
from django.db.utils import ProgrammingError, OperationalError
|
from django.db.utils import ProgrammingError, OperationalError
|
||||||
|
from django.core.cache import cache
|
||||||
|
|
||||||
from jumpserver.utils import current_request
|
from jumpserver.utils import current_request
|
||||||
from .models import Setting
|
from .models import Setting
|
||||||
from .utils import get_logger
|
from .utils import get_logger
|
||||||
from .signals import django_ready, ldap_auth_enable
|
from .signals import django_ready
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
@ -25,25 +26,43 @@ def refresh_settings_on_changed(sender, instance=None, **kwargs):
|
||||||
def refresh_all_settings_on_django_ready(sender, **kwargs):
|
def refresh_all_settings_on_django_ready(sender, **kwargs):
|
||||||
logger.debug("Receive django ready signal")
|
logger.debug("Receive django ready signal")
|
||||||
logger.debug(" - fresh all settings")
|
logger.debug(" - fresh all settings")
|
||||||
|
CACHE_KEY_PREFIX = '_SETTING_'
|
||||||
|
|
||||||
|
def monkey_patch_getattr(self, name):
|
||||||
|
key = CACHE_KEY_PREFIX + name
|
||||||
|
cached = cache.get(key)
|
||||||
|
if cached is not None:
|
||||||
|
return cached
|
||||||
|
if self._wrapped is empty:
|
||||||
|
self._setup(name)
|
||||||
|
val = getattr(self._wrapped, name)
|
||||||
|
# self.__dict__[name] = val # Never set it
|
||||||
|
return val
|
||||||
|
|
||||||
|
def monkey_patch_setattr(self, name, value):
|
||||||
|
key = CACHE_KEY_PREFIX + name
|
||||||
|
cache.set(key, value, None)
|
||||||
|
if name == '_wrapped':
|
||||||
|
self.__dict__.clear()
|
||||||
|
else:
|
||||||
|
self.__dict__.pop(name, None)
|
||||||
|
super(LazySettings, self).__setattr__(name, value)
|
||||||
|
|
||||||
|
def monkey_patch_delattr(self, name):
|
||||||
|
super(LazySettings, self).__delattr__(name)
|
||||||
|
self.__dict__.pop(name, None)
|
||||||
|
key = CACHE_KEY_PREFIX + name
|
||||||
|
cache.delete(key)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
LazySettings.__getattr__ = monkey_patch_getattr
|
||||||
|
LazySettings.__setattr__ = monkey_patch_setattr
|
||||||
|
LazySettings.__delattr__ = monkey_patch_delattr
|
||||||
Setting.refresh_all_settings()
|
Setting.refresh_all_settings()
|
||||||
except (ProgrammingError, OperationalError):
|
except (ProgrammingError, OperationalError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@receiver(ldap_auth_enable, dispatch_uid="my_unique_identifier")
|
|
||||||
def ldap_auth_on_changed(sender, enabled=True, **kwargs):
|
|
||||||
if enabled:
|
|
||||||
logger.debug("Enable LDAP auth")
|
|
||||||
if settings.AUTH_LDAP_BACKEND not in settings.AUTHENTICATION_BACKENDS:
|
|
||||||
settings.AUTHENTICATION_BACKENDS.insert(0, settings.AUTH_LDAP_BACKEND)
|
|
||||||
|
|
||||||
else:
|
|
||||||
logger.debug("Disable LDAP auth")
|
|
||||||
if settings.AUTH_LDAP_BACKEND in settings.AUTHENTICATION_BACKENDS:
|
|
||||||
settings.AUTHENTICATION_BACKENDS.remove(settings.AUTH_LDAP_BACKEND)
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(pre_save, dispatch_uid="my_unique_identifier")
|
@receiver(pre_save, dispatch_uid="my_unique_identifier")
|
||||||
def on_create_set_created_by(sender, instance=None, **kwargs):
|
def on_create_set_created_by(sender, instance=None, **kwargs):
|
||||||
if hasattr(instance, 'created_by') and not instance.created_by:
|
if hasattr(instance, 'created_by') and not instance.created_by:
|
||||||
|
|
|
@ -3,7 +3,6 @@ from django.conf import settings
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from .utils import get_logger
|
from .utils import get_logger
|
||||||
from .models import Setting
|
from .models import Setting
|
||||||
from common.models import common_settings
|
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
@ -23,13 +22,9 @@ def send_mail_async(*args, **kwargs):
|
||||||
Example:
|
Example:
|
||||||
send_mail_sync.delay(subject, message, recipient_list, fail_silently=False, html_message=None)
|
send_mail_sync.delay(subject, message, recipient_list, fail_silently=False, html_message=None)
|
||||||
"""
|
"""
|
||||||
configs = Setting.objects.filter(name__startswith='EMAIL')
|
|
||||||
for config in configs:
|
|
||||||
setattr(settings, config.name, config.cleaned_value)
|
|
||||||
|
|
||||||
if len(args) == 3:
|
if len(args) == 3:
|
||||||
args = list(args)
|
args = list(args)
|
||||||
args[0] = common_settings.EMAIL_SUBJECT_PREFIX + args[0]
|
args[0] = settings.EMAIL_SUBJECT_PREFIX + args[0]
|
||||||
args.insert(2, settings.EMAIL_HOST_USER)
|
args.insert(2, settings.EMAIL_HOST_USER)
|
||||||
args = tuple(args)
|
args = tuple(args)
|
||||||
|
|
||||||
|
|
|
@ -13,5 +13,5 @@ urlpatterns = [
|
||||||
path('terminal/replay-storage/delete/', api.ReplayStorageDeleteAPI.as_view(), name='replay-storage-delete'),
|
path('terminal/replay-storage/delete/', api.ReplayStorageDeleteAPI.as_view(), name='replay-storage-delete'),
|
||||||
path('terminal/command-storage/create/', api.CommandStorageCreateAPI.as_view(), name='command-storage-create'),
|
path('terminal/command-storage/create/', api.CommandStorageCreateAPI.as_view(), name='command-storage-create'),
|
||||||
path('terminal/command-storage/delete/', api.CommandStorageDeleteAPI.as_view(), name='command-storage-delete'),
|
path('terminal/command-storage/delete/', api.CommandStorageDeleteAPI.as_view(), name='command-storage-delete'),
|
||||||
# path('django-settings/', api.DjangoSettingsAPI.as_view(), name='django-settings'),
|
path('django-settings/', api.DjangoSettingsAPI.as_view(), name='django-settings'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -37,8 +37,7 @@ def reverse(view_name, urlconf=None, args=None, kwargs=None,
|
||||||
kwargs=kwargs, current_app=current_app)
|
kwargs=kwargs, current_app=current_app)
|
||||||
|
|
||||||
if external:
|
if external:
|
||||||
from common.models import common_settings
|
site_url = settings.SITE_URL
|
||||||
site_url = common_settings.SITE_URL
|
|
||||||
url = site_url.strip('/') + url
|
url = site_url.strip('/') + url
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
@ -390,17 +389,15 @@ def get_request_ip(request):
|
||||||
|
|
||||||
|
|
||||||
def get_command_storage_setting():
|
def get_command_storage_setting():
|
||||||
from common.models import common_settings
|
default = settings.DEFAULT_TERMINAL_COMMAND_STORAGE
|
||||||
default = settings.TERMINAL_COMMAND_STORAGE
|
value = settings.TERMINAL_COMMAND_STORAGE
|
||||||
value = common_settings.TERMINAL_COMMAND_STORAGE
|
|
||||||
value.update(default)
|
value.update(default)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def get_replay_storage_setting():
|
def get_replay_storage_setting():
|
||||||
from common.models import common_settings
|
default = settings.DEFAULT_TERMINAL_REPLAY_STORAGE
|
||||||
default = settings.TERMINAL_REPLAY_STORAGE
|
value = settings.TERMINAL_REPLAY_STORAGE
|
||||||
value = common_settings.TERMINAL_REPLAY_STORAGE
|
|
||||||
value.update(default)
|
value.update(default)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ from django.utils.translation import ugettext as _
|
||||||
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \
|
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \
|
||||||
TerminalSettingForm, SecuritySettingForm
|
TerminalSettingForm, SecuritySettingForm
|
||||||
from common.permissions import SuperUserRequiredMixin
|
from common.permissions import SuperUserRequiredMixin
|
||||||
from .signals import ldap_auth_enable
|
|
||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,8 +78,6 @@ class LDAPSettingView(SuperUserRequiredMixin, TemplateView):
|
||||||
form = self.form_class(request.POST)
|
form = self.form_class(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
if "AUTH_LDAP" in form.cleaned_data:
|
|
||||||
ldap_auth_enable.send(sender=self.__class__, enabled=form.cleaned_data["AUTH_LDAP"])
|
|
||||||
msg = _("Update setting successfully, please restart program")
|
msg = _("Update setting successfully, please restart program")
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
return redirect('settings:ldap-setting')
|
return redirect('settings:ldap-setting')
|
||||||
|
|
|
@ -0,0 +1,331 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
import errno
|
||||||
|
import json
|
||||||
|
import yaml
|
||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
PROJECT_DIR = os.path.dirname(BASE_DIR)
|
||||||
|
|
||||||
|
|
||||||
|
def import_string(dotted_path):
|
||||||
|
try:
|
||||||
|
module_path, class_name = dotted_path.rsplit('.', 1)
|
||||||
|
except ValueError as err:
|
||||||
|
raise ImportError("%s doesn't look like a module path" % dotted_path) from err
|
||||||
|
|
||||||
|
module = import_module(module_path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return getattr(module, class_name)
|
||||||
|
except AttributeError as err:
|
||||||
|
raise ImportError('Module "%s" does not define a "%s" attribute/class' % (
|
||||||
|
module_path, class_name)
|
||||||
|
) from err
|
||||||
|
|
||||||
|
|
||||||
|
class Config(dict):
|
||||||
|
"""Works exactly like a dict but provides ways to fill it from files
|
||||||
|
or special dictionaries. There are two common patterns to populate the
|
||||||
|
config.
|
||||||
|
|
||||||
|
Either you can fill the config from a config file::
|
||||||
|
|
||||||
|
app.config.from_pyfile('yourconfig.cfg')
|
||||||
|
|
||||||
|
Or alternatively you can define the configuration options in the
|
||||||
|
module that calls :meth:`from_object` or provide an import path to
|
||||||
|
a module that should be loaded. It is also possible to tell it to
|
||||||
|
use the same module and with that provide the configuration values
|
||||||
|
just before the call::
|
||||||
|
|
||||||
|
DEBUG = True
|
||||||
|
SECRET_KEY = 'development key'
|
||||||
|
app.config.from_object(__name__)
|
||||||
|
|
||||||
|
In both cases (loading from any Python file or loading from modules),
|
||||||
|
only uppercase keys are added to the config. This makes it possible to use
|
||||||
|
lowercase values in the config file for temporary values that are not added
|
||||||
|
to the config or to define the config keys in the same file that implements
|
||||||
|
the application.
|
||||||
|
|
||||||
|
Probably the most interesting way to load configurations is from an
|
||||||
|
environment variable pointing to a file::
|
||||||
|
|
||||||
|
app.config.from_envvar('YOURAPPLICATION_SETTINGS')
|
||||||
|
|
||||||
|
In this case before launching the application you have to set this
|
||||||
|
environment variable to the file you want to use. On Linux and OS X
|
||||||
|
use the export statement::
|
||||||
|
|
||||||
|
export YOURAPPLICATION_SETTINGS='/path/to/config/file'
|
||||||
|
|
||||||
|
On windows use `set` instead.
|
||||||
|
|
||||||
|
:param root_path: path to which files are read relative from. When the
|
||||||
|
config object is created by the application, this is
|
||||||
|
the application's :attr:`~flask.Flask.root_path`.
|
||||||
|
:param defaults: an optional dictionary of default values
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, root_path=None, defaults=None):
|
||||||
|
self.defaults = defaults or {}
|
||||||
|
self.root_path = root_path
|
||||||
|
super().__init__({})
|
||||||
|
|
||||||
|
def from_envvar(self, variable_name, silent=False):
|
||||||
|
"""Loads a configuration from an environment variable pointing to
|
||||||
|
a configuration file. This is basically just a shortcut with nicer
|
||||||
|
error messages for this line of code::
|
||||||
|
|
||||||
|
app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
|
||||||
|
|
||||||
|
:param variable_name: name of the environment variable
|
||||||
|
:param silent: set to ``True`` if you want silent failure for missing
|
||||||
|
files.
|
||||||
|
:return: bool. ``True`` if able to load config, ``False`` otherwise.
|
||||||
|
"""
|
||||||
|
rv = os.environ.get(variable_name)
|
||||||
|
if not rv:
|
||||||
|
if silent:
|
||||||
|
return False
|
||||||
|
raise RuntimeError('The environment variable %r is not set '
|
||||||
|
'and as such configuration could not be '
|
||||||
|
'loaded. Set this variable and make it '
|
||||||
|
'point to a configuration file' %
|
||||||
|
variable_name)
|
||||||
|
return self.from_pyfile(rv, silent=silent)
|
||||||
|
|
||||||
|
def from_pyfile(self, filename, silent=False):
|
||||||
|
"""Updates the values in the config from a Python file. This function
|
||||||
|
behaves as if the file was imported as module with the
|
||||||
|
:meth:`from_object` function.
|
||||||
|
|
||||||
|
:param filename: the filename of the config. This can either be an
|
||||||
|
absolute filename or a filename relative to the
|
||||||
|
root path.
|
||||||
|
:param silent: set to ``True`` if you want silent failure for missing
|
||||||
|
files.
|
||||||
|
|
||||||
|
.. versionadded:: 0.7
|
||||||
|
`silent` parameter.
|
||||||
|
"""
|
||||||
|
if self.root_path:
|
||||||
|
filename = os.path.join(self.root_path, filename)
|
||||||
|
d = types.ModuleType('config')
|
||||||
|
d.__file__ = filename
|
||||||
|
try:
|
||||||
|
with open(filename, mode='rb') as config_file:
|
||||||
|
exec(compile(config_file.read(), filename, 'exec'), d.__dict__)
|
||||||
|
except IOError as e:
|
||||||
|
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
|
||||||
|
return False
|
||||||
|
e.strerror = 'Unable to load configuration file (%s)' % e.strerror
|
||||||
|
raise
|
||||||
|
self.from_object(d)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def from_object(self, obj):
|
||||||
|
"""Updates the values from the given object. An object can be of one
|
||||||
|
of the following two types:
|
||||||
|
|
||||||
|
- a string: in this case the object with that name will be imported
|
||||||
|
- an actual object reference: that object is used directly
|
||||||
|
|
||||||
|
Objects are usually either modules or classes. :meth:`from_object`
|
||||||
|
loads only the uppercase attributes of the module/class. A ``dict``
|
||||||
|
object will not work with :meth:`from_object` because the keys of a
|
||||||
|
``dict`` are not attributes of the ``dict`` class.
|
||||||
|
|
||||||
|
Example of module-based configuration::
|
||||||
|
|
||||||
|
app.config.from_object('yourapplication.default_config')
|
||||||
|
from yourapplication import default_config
|
||||||
|
app.config.from_object(default_config)
|
||||||
|
|
||||||
|
You should not use this function to load the actual configuration but
|
||||||
|
rather configuration defaults. The actual config should be loaded
|
||||||
|
with :meth:`from_pyfile` and ideally from a location not within the
|
||||||
|
package because the package might be installed system wide.
|
||||||
|
|
||||||
|
See :ref:`config-dev-prod` for an example of class-based configuration
|
||||||
|
using :meth:`from_object`.
|
||||||
|
|
||||||
|
:param obj: an import name or object
|
||||||
|
"""
|
||||||
|
if isinstance(obj, str):
|
||||||
|
obj = import_string(obj)
|
||||||
|
for key in dir(obj):
|
||||||
|
if key.isupper():
|
||||||
|
self[key] = getattr(obj, key)
|
||||||
|
|
||||||
|
def from_json(self, filename, silent=False):
|
||||||
|
"""Updates the values in the config from a JSON file. This function
|
||||||
|
behaves as if the JSON object was a dictionary and passed to the
|
||||||
|
:meth:`from_mapping` function.
|
||||||
|
|
||||||
|
:param filename: the filename of the JSON file. This can either be an
|
||||||
|
absolute filename or a filename relative to the
|
||||||
|
root path.
|
||||||
|
:param silent: set to ``True`` if you want silent failure for missing
|
||||||
|
files.
|
||||||
|
|
||||||
|
.. versionadded:: 0.11
|
||||||
|
"""
|
||||||
|
if self.root_path:
|
||||||
|
filename = os.path.join(self.root_path, filename)
|
||||||
|
try:
|
||||||
|
with open(filename) as json_file:
|
||||||
|
obj = json.loads(json_file.read())
|
||||||
|
except IOError as e:
|
||||||
|
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
|
||||||
|
return False
|
||||||
|
e.strerror = 'Unable to load configuration file (%s)' % e.strerror
|
||||||
|
raise
|
||||||
|
return self.from_mapping(obj)
|
||||||
|
|
||||||
|
def from_yaml(self, filename, silent=False):
|
||||||
|
if self.root_path:
|
||||||
|
filename = os.path.join(self.root_path, filename)
|
||||||
|
try:
|
||||||
|
with open(filename) as json_file:
|
||||||
|
obj = yaml.load(json_file)
|
||||||
|
except IOError as e:
|
||||||
|
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
|
||||||
|
return False
|
||||||
|
e.strerror = 'Unable to load configuration file (%s)' % e.strerror
|
||||||
|
raise
|
||||||
|
return self.from_mapping(obj)
|
||||||
|
|
||||||
|
def from_mapping(self, *mapping, **kwargs):
|
||||||
|
"""Updates the config like :meth:`update` ignoring items with non-upper
|
||||||
|
keys.
|
||||||
|
|
||||||
|
.. versionadded:: 0.11
|
||||||
|
"""
|
||||||
|
mappings = []
|
||||||
|
if len(mapping) == 1:
|
||||||
|
if hasattr(mapping[0], 'items'):
|
||||||
|
mappings.append(mapping[0].items())
|
||||||
|
else:
|
||||||
|
mappings.append(mapping[0])
|
||||||
|
elif len(mapping) > 1:
|
||||||
|
raise TypeError(
|
||||||
|
'expected at most 1 positional argument, got %d' % len(mapping)
|
||||||
|
)
|
||||||
|
mappings.append(kwargs.items())
|
||||||
|
for mapping in mappings:
|
||||||
|
for (key, value) in mapping:
|
||||||
|
if key.isupper():
|
||||||
|
self[key] = value
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_namespace(self, namespace, lowercase=True, trim_namespace=True):
|
||||||
|
"""Returns a dictionary containing a subset of configuration options
|
||||||
|
that match the specified namespace/prefix. Example usage::
|
||||||
|
|
||||||
|
app.config['IMAGE_STORE_TYPE'] = 'fs'
|
||||||
|
app.config['IMAGE_STORE_PATH'] = '/var/app/images'
|
||||||
|
app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com'
|
||||||
|
image_store_config = app.config.get_namespace('IMAGE_STORE_')
|
||||||
|
|
||||||
|
The resulting dictionary `image_store_config` would look like::
|
||||||
|
|
||||||
|
{
|
||||||
|
'types': 'fs',
|
||||||
|
'path': '/var/app/images',
|
||||||
|
'base_url': 'http://img.website.com'
|
||||||
|
}
|
||||||
|
|
||||||
|
This is often useful when configuration options map directly to
|
||||||
|
keyword arguments in functions or class constructors.
|
||||||
|
|
||||||
|
:param namespace: a configuration namespace
|
||||||
|
:param lowercase: a flag indicating if the keys of the resulting
|
||||||
|
dictionary should be lowercase
|
||||||
|
:param trim_namespace: a flag indicating if the keys of the resulting
|
||||||
|
dictionary should not include the namespace
|
||||||
|
|
||||||
|
.. versionadded:: 0.11
|
||||||
|
"""
|
||||||
|
rv = {}
|
||||||
|
for k, v in self.items():
|
||||||
|
if not k.startswith(namespace):
|
||||||
|
continue
|
||||||
|
if trim_namespace:
|
||||||
|
key = k[len(namespace):]
|
||||||
|
else:
|
||||||
|
key = k
|
||||||
|
if lowercase:
|
||||||
|
key = key.lower()
|
||||||
|
rv[key] = v
|
||||||
|
return rv
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<%s %s>' % (self.__class__.__name__, dict.__repr__(self))
|
||||||
|
|
||||||
|
def __getitem__(self, item):
|
||||||
|
try:
|
||||||
|
value = super().__getitem__(item)
|
||||||
|
except KeyError:
|
||||||
|
value = None
|
||||||
|
if value is not None:
|
||||||
|
return value
|
||||||
|
value = os.environ.get(item, None)
|
||||||
|
if value is not None:
|
||||||
|
return value
|
||||||
|
return self.defaults.get(item)
|
||||||
|
|
||||||
|
def __getattr__(self, item):
|
||||||
|
return self.__getitem__(item)
|
||||||
|
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
'SECRET_KEY': '2vym+ky!997d5kkcc64mnz06y1mmui3lut#(^wd=%s_qj$1%x',
|
||||||
|
'BOOTSTRAP_TOKEN': 'PleaseChangeMe',
|
||||||
|
'DEBUG': True,
|
||||||
|
'SITE_URL': 'http://localhost',
|
||||||
|
'LOG_LEVEL': 'DEBUG',
|
||||||
|
'LOG_DIR': os.path.join(PROJECT_DIR, 'logs'),
|
||||||
|
'DB_ENGINE': 'mysql',
|
||||||
|
'DB_NAME': 'jumpserver',
|
||||||
|
'DB_HOST': '127.0.0.1',
|
||||||
|
'DB_PORT': 3306,
|
||||||
|
'DB_USER': 'root',
|
||||||
|
'DB_PASSWORD': '',
|
||||||
|
'REDIS_HOST': '127.0.0.1',
|
||||||
|
'REDIS_PORT': 6379,
|
||||||
|
'REDIS_PASSWORD': '',
|
||||||
|
'REDIS_DB_CELERY_BROKER': 3,
|
||||||
|
'REDIS_DB_CACHE': 4,
|
||||||
|
'CAPTCHA_TEST_MODE': None,
|
||||||
|
'TOKEN_EXPIRATION': 3600,
|
||||||
|
'DISPLAY_PER_PAGE': 25,
|
||||||
|
'DEFAULT_EXPIRED_YEARS': 70,
|
||||||
|
'SESSION_COOKIE_DOMAIN': None,
|
||||||
|
'CSRF_COOKIE_DOMAIN': None,
|
||||||
|
'SESSION_COOKIE_AGE': 3600 * 24,
|
||||||
|
'AUTH_OPENID': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def load_user_config():
|
||||||
|
sys.path.insert(0, PROJECT_DIR)
|
||||||
|
config = Config(PROJECT_DIR, defaults)
|
||||||
|
try:
|
||||||
|
from config import config as c
|
||||||
|
config.from_object(c)
|
||||||
|
except ImportError:
|
||||||
|
msg = """
|
||||||
|
|
||||||
|
Error: No config file found.
|
||||||
|
|
||||||
|
You can run `cp config_example.py config.py`, and edit it.
|
||||||
|
"""
|
||||||
|
raise ImportError(msg)
|
||||||
|
return config
|
|
@ -17,24 +17,12 @@ import ldap
|
||||||
from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
|
from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
|
||||||
|
from .conf import load_user_config
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
PROJECT_DIR = os.path.dirname(BASE_DIR)
|
PROJECT_DIR = os.path.dirname(BASE_DIR)
|
||||||
|
CONFIG = load_user_config()
|
||||||
sys.path.append(PROJECT_DIR)
|
|
||||||
|
|
||||||
# Import project config setting
|
|
||||||
try:
|
|
||||||
from config import config as CONFIG
|
|
||||||
except ImportError:
|
|
||||||
msg = """
|
|
||||||
|
|
||||||
Error: No config file found.
|
|
||||||
|
|
||||||
You can run `cp config_example.py config.py`, and edit it.
|
|
||||||
"""
|
|
||||||
raise ImportError(msg)
|
|
||||||
# CONFIG = type('_', (), {'__getattr__': lambda arg1, arg2: None})()
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
|
||||||
|
@ -43,15 +31,15 @@ except ImportError:
|
||||||
SECRET_KEY = CONFIG.SECRET_KEY
|
SECRET_KEY = CONFIG.SECRET_KEY
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = CONFIG.DEBUG or False
|
DEBUG = CONFIG.DEBUG
|
||||||
|
|
||||||
# Absolute url for some case, for example email link
|
# Absolute url for some case, for example email link
|
||||||
SITE_URL = CONFIG.SITE_URL or 'http://localhost'
|
SITE_URL = CONFIG.SITE_URL
|
||||||
|
|
||||||
# LOG LEVEL
|
# LOG LEVEL
|
||||||
LOG_LEVEL = 'DEBUG' if DEBUG else CONFIG.LOG_LEVEL or 'WARNING'
|
LOG_LEVEL = CONFIG.LOG_LEVEL
|
||||||
|
|
||||||
ALLOWED_HOSTS = CONFIG.ALLOWED_HOSTS or []
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
|
@ -152,9 +140,9 @@ TEMPLATES = [
|
||||||
LOGIN_REDIRECT_URL = reverse_lazy('index')
|
LOGIN_REDIRECT_URL = reverse_lazy('index')
|
||||||
LOGIN_URL = reverse_lazy('users:login')
|
LOGIN_URL = reverse_lazy('users:login')
|
||||||
|
|
||||||
SESSION_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN or None
|
SESSION_COOKIE_DOMAIN = CONFIG.SESSION_COOKIE_DOMAIN
|
||||||
CSRF_COOKIE_DOMAIN = CONFIG.CSRF_COOKIE_DOMAIN or None
|
CSRF_COOKIE_DOMAIN = CONFIG.CSRF_COOKIE_DOMAIN
|
||||||
SESSION_COOKIE_AGE = CONFIG.SESSION_COOKIE_AGE or 3600 * 24
|
SESSION_COOKIE_AGE = CONFIG.SESSION_COOKIE_AGE
|
||||||
|
|
||||||
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
||||||
# Database
|
# Database
|
||||||
|
@ -317,13 +305,13 @@ MEDIA_ROOT = os.path.join(PROJECT_DIR, 'data', 'media').replace('\\', '/') + '/'
|
||||||
FIXTURE_DIRS = [os.path.join(BASE_DIR, 'fixtures'), ]
|
FIXTURE_DIRS = [os.path.join(BASE_DIR, 'fixtures'), ]
|
||||||
|
|
||||||
# Email config
|
# Email config
|
||||||
EMAIL_HOST = CONFIG.EMAIL_HOST
|
EMAIL_HOST = 'smtp.jumpserver.org'
|
||||||
EMAIL_PORT = CONFIG.EMAIL_PORT
|
EMAIL_PORT = 25
|
||||||
EMAIL_HOST_USER = CONFIG.EMAIL_HOST_USER
|
EMAIL_HOST_USER = 'noreply@jumpserver.org'
|
||||||
EMAIL_HOST_PASSWORD = CONFIG.EMAIL_HOST_PASSWORD
|
EMAIL_HOST_PASSWORD = ''
|
||||||
EMAIL_USE_SSL = CONFIG.EMAIL_USE_SSL
|
EMAIL_USE_SSL = False
|
||||||
EMAIL_USE_TLS = CONFIG.EMAIL_USE_TLS
|
EMAIL_USE_TLS = False
|
||||||
EMAIL_SUBJECT_PREFIX = CONFIG.EMAIL_SUBJECT_PREFIX
|
EMAIL_SUBJECT_PREFIX = '[Jumpserver] '
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
# Use Django's standard `django.contrib.auth` permissions,
|
# Use Django's standard `django.contrib.auth` permissions,
|
||||||
|
@ -363,23 +351,23 @@ FILE_UPLOAD_PERMISSIONS = 0o644
|
||||||
FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755
|
FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755
|
||||||
|
|
||||||
# Auth LDAP settings
|
# Auth LDAP settings
|
||||||
AUTH_LDAP = CONFIG.AUTH_LDAP
|
AUTH_LDAP = False
|
||||||
AUTH_LDAP_SERVER_URI = CONFIG.AUTH_LDAP_SERVER_URI
|
AUTH_LDAP_SERVER_URI = 'ldap://localhost:389'
|
||||||
AUTH_LDAP_BIND_DN = CONFIG.AUTH_LDAP_BIND_DN
|
AUTH_LDAP_BIND_DN = 'cn=admin,dc=jumpserver,dc=org'
|
||||||
AUTH_LDAP_BIND_PASSWORD = CONFIG.AUTH_LDAP_BIND_PASSWORD
|
AUTH_LDAP_BIND_PASSWORD = ''
|
||||||
AUTH_LDAP_SEARCH_OU = CONFIG.AUTH_LDAP_SEARCH_OU
|
AUTH_LDAP_SEARCH_OU = 'ou=tech,dc=jumpserver,dc=org'
|
||||||
AUTH_LDAP_SEARCH_FILTER = CONFIG.AUTH_LDAP_SEARCH_FILTER
|
AUTH_LDAP_SEARCH_FILTER = '(cn=%(user)s)'
|
||||||
AUTH_LDAP_START_TLS = CONFIG.AUTH_LDAP_START_TLS
|
AUTH_LDAP_START_TLS = False
|
||||||
AUTH_LDAP_USER_ATTR_MAP = CONFIG.AUTH_LDAP_USER_ATTR_MAP
|
AUTH_LDAP_USER_ATTR_MAP = {"username": "cn", "name": "sn", "email": "mail"}
|
||||||
AUTH_LDAP_USER_SEARCH_UNION = [
|
AUTH_LDAP_USER_SEARCH_UNION = lambda: [
|
||||||
LDAPSearch(USER_SEARCH, ldap.SCOPE_SUBTREE, AUTH_LDAP_SEARCH_FILTER)
|
LDAPSearch(USER_SEARCH, ldap.SCOPE_SUBTREE, AUTH_LDAP_SEARCH_FILTER)
|
||||||
for USER_SEARCH in str(AUTH_LDAP_SEARCH_OU).split("|")
|
for USER_SEARCH in str(AUTH_LDAP_SEARCH_OU).split("|")
|
||||||
]
|
]
|
||||||
AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(*AUTH_LDAP_USER_SEARCH_UNION)
|
AUTH_LDAP_USER_SEARCH = lambda: LDAPSearchUnion(*AUTH_LDAP_USER_SEARCH_UNION())
|
||||||
AUTH_LDAP_GROUP_SEARCH_OU = CONFIG.AUTH_LDAP_GROUP_SEARCH_OU
|
AUTH_LDAP_GROUP_SEARCH_OU = CONFIG.AUTH_LDAP_GROUP_SEARCH_OU
|
||||||
AUTH_LDAP_GROUP_SEARCH_FILTER = CONFIG.AUTH_LDAP_GROUP_SEARCH_FILTER
|
AUTH_LDAP_GROUP_SEARCH_FILTER = CONFIG.AUTH_LDAP_GROUP_SEARCH_FILTER
|
||||||
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
||||||
AUTH_LDAP_GROUP_SEARCH_OU, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_SEARCH_FILTER
|
AUTH_LDAP_GROUP_SEARCH_OU, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_SEARCH_FILTER
|
||||||
)
|
)
|
||||||
AUTH_LDAP_CONNECTION_OPTIONS = {
|
AUTH_LDAP_CONNECTION_OPTIONS = {
|
||||||
ldap.OPT_TIMEOUT: 5
|
ldap.OPT_TIMEOUT: 5
|
||||||
|
@ -414,7 +402,7 @@ CELERY_BROKER_URL = 'redis://:%(password)s@%(host)s:%(port)s/%(db)s' % {
|
||||||
'password': CONFIG.REDIS_PASSWORD if CONFIG.REDIS_PASSWORD else '',
|
'password': CONFIG.REDIS_PASSWORD if CONFIG.REDIS_PASSWORD else '',
|
||||||
'host': CONFIG.REDIS_HOST or '127.0.0.1',
|
'host': CONFIG.REDIS_HOST or '127.0.0.1',
|
||||||
'port': CONFIG.REDIS_PORT or 6379,
|
'port': CONFIG.REDIS_PORT or 6379,
|
||||||
'db':CONFIG.REDIS_DB_CELERY_BROKER or 3,
|
'db': CONFIG.REDIS_DB_CELERY_BROKER or 3,
|
||||||
}
|
}
|
||||||
CELERY_TASK_SERIALIZER = 'pickle'
|
CELERY_TASK_SERIALIZER = 'pickle'
|
||||||
CELERY_RESULT_SERIALIZER = 'pickle'
|
CELERY_RESULT_SERIALIZER = 'pickle'
|
||||||
|
@ -436,10 +424,10 @@ CACHES = {
|
||||||
'default': {
|
'default': {
|
||||||
'BACKEND': 'redis_cache.RedisCache',
|
'BACKEND': 'redis_cache.RedisCache',
|
||||||
'LOCATION': 'redis://:%(password)s@%(host)s:%(port)s/%(db)s' % {
|
'LOCATION': 'redis://:%(password)s@%(host)s:%(port)s/%(db)s' % {
|
||||||
'password': CONFIG.REDIS_PASSWORD if CONFIG.REDIS_PASSWORD else '',
|
'password': CONFIG.REDIS_PASSWORD,
|
||||||
'host': CONFIG.REDIS_HOST or '127.0.0.1',
|
'host': CONFIG.REDIS_HOST,
|
||||||
'port': CONFIG.REDIS_PORT or 6379,
|
'port': CONFIG.REDIS_PORT,
|
||||||
'db': CONFIG.REDIS_DB_CACHE or 4,
|
'db': CONFIG.REDIS_DB_CACHE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,27 +442,44 @@ COMMAND_STORAGE = {
|
||||||
'ENGINE': 'terminal.backends.command.db',
|
'ENGINE': 'terminal.backends.command.db',
|
||||||
}
|
}
|
||||||
|
|
||||||
TERMINAL_COMMAND_STORAGE = {
|
DEFAULT_TERMINAL_COMMAND_STORAGE = {
|
||||||
"default": {
|
"default": {
|
||||||
"TYPE": "server",
|
"TYPE": "server",
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
TERMINAL_COMMAND_STORAGE = {
|
||||||
# 'ali-es': {
|
# 'ali-es': {
|
||||||
# 'TYPE': 'elasticsearch',
|
# 'TYPE': 'elasticsearch',
|
||||||
# 'HOSTS': ['http://elastic:changeme@localhost:9200'],
|
# 'HOSTS': ['http://elastic:changeme@localhost:9200'],
|
||||||
# },
|
# },
|
||||||
}
|
}
|
||||||
|
|
||||||
TERMINAL_REPLAY_STORAGE = {
|
DEFAULT_TERMINAL_REPLAY_STORAGE = {
|
||||||
"default": {
|
"default": {
|
||||||
"TYPE": "server",
|
"TYPE": "server",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TERMINAL_REPLAY_STORAGE = {
|
||||||
|
}
|
||||||
|
|
||||||
SECURITY_PASSWORD_MIN_LENGTH = 6
|
SECURITY_MFA_AUTH = False
|
||||||
SECURITY_LOGIN_LIMIT_COUNT = 7
|
SECURITY_LOGIN_LIMIT_COUNT = 7
|
||||||
SECURITY_LOGIN_LIMIT_TIME = 30 # Unit: minute
|
SECURITY_LOGIN_LIMIT_TIME = 30 # Unit: minute
|
||||||
SECURITY_MAX_IDLE_TIME = 30 # Unit: minute
|
SECURITY_MAX_IDLE_TIME = 30 # Unit: minute
|
||||||
|
SECURITY_PASSWORD_MIN_LENGTH = 6
|
||||||
|
SECURITY_PASSWORD_UPPER_CASE = False
|
||||||
|
SECURITY_PASSWORD_LOWER_CASE = False
|
||||||
|
SECURITY_PASSWORD_NUMBER = False
|
||||||
|
SECURITY_PASSWORD_SPECIAL_CHAR = False
|
||||||
|
SECURITY_PASSWORD_RULES = [
|
||||||
|
'SECURITY_PASSWORD_MIN_LENGTH',
|
||||||
|
'SECURITY_PASSWORD_UPPER_CASE',
|
||||||
|
'SECURITY_PASSWORD_LOWER_CASE',
|
||||||
|
'SECURITY_PASSWORD_NUMBER',
|
||||||
|
'SECURITY_PASSWORD_SPECIAL_CHAR'
|
||||||
|
]
|
||||||
|
|
||||||
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
|
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
|
||||||
BOOTSTRAP3 = {
|
BOOTSTRAP3 = {
|
||||||
|
@ -486,8 +491,8 @@ BOOTSTRAP3 = {
|
||||||
'success_css_class': '',
|
'success_css_class': '',
|
||||||
}
|
}
|
||||||
|
|
||||||
TOKEN_EXPIRATION = CONFIG.TOKEN_EXPIRATION or 3600
|
TOKEN_EXPIRATION = CONFIG.TOKEN_EXPIRATION
|
||||||
DISPLAY_PER_PAGE = CONFIG.DISPLAY_PER_PAGE or 25
|
DISPLAY_PER_PAGE = CONFIG.DISPLAY_PER_PAGE
|
||||||
DEFAULT_EXPIRED_YEARS = 70
|
DEFAULT_EXPIRED_YEARS = 70
|
||||||
USER_GUIDE_URL = ""
|
USER_GUIDE_URL = ""
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Jumpserver 0.3.3\n"
|
"Project-Id-Version: Jumpserver 0.3.3\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-11-08 19:18+0800\n"
|
"POT-Creation-Date: 2018-11-21 19:06+0800\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||||
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
|
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
|
||||||
|
@ -126,7 +126,7 @@ msgstr "端口"
|
||||||
#: perms/templates/perms/asset_permission_create_update.html:40
|
#: perms/templates/perms/asset_permission_create_update.html:40
|
||||||
#: perms/templates/perms/asset_permission_list.html:56
|
#: perms/templates/perms/asset_permission_list.html:56
|
||||||
#: perms/templates/perms/asset_permission_list.html:148
|
#: perms/templates/perms/asset_permission_list.html:148
|
||||||
#: terminal/backends/command/models.py:13 terminal/models.py:133
|
#: terminal/backends/command/models.py:13 terminal/models.py:134
|
||||||
#: terminal/templates/terminal/command_list.html:40
|
#: terminal/templates/terminal/command_list.html:40
|
||||||
#: terminal/templates/terminal/command_list.html:73
|
#: terminal/templates/terminal/command_list.html:73
|
||||||
#: terminal/templates/terminal/session_list.html:41
|
#: terminal/templates/terminal/session_list.html:41
|
||||||
|
@ -154,7 +154,7 @@ msgstr "不能包含特殊字符"
|
||||||
#: assets/templates/assets/domain_list.html:25
|
#: assets/templates/assets/domain_list.html:25
|
||||||
#: assets/templates/assets/label_list.html:14
|
#: assets/templates/assets/label_list.html:14
|
||||||
#: assets/templates/assets/system_user_detail.html:58
|
#: assets/templates/assets/system_user_detail.html:58
|
||||||
#: assets/templates/assets/system_user_list.html:29 common/models.py:30
|
#: assets/templates/assets/system_user_list.html:29 common/models.py:31
|
||||||
#: common/templates/common/command_storage_create.html:41
|
#: common/templates/common/command_storage_create.html:41
|
||||||
#: common/templates/common/replay_storage_create.html:44
|
#: common/templates/common/replay_storage_create.html:44
|
||||||
#: common/templates/common/terminal_setting.html:80
|
#: common/templates/common/terminal_setting.html:80
|
||||||
|
@ -164,9 +164,9 @@ msgstr "不能包含特殊字符"
|
||||||
#: perms/templates/perms/asset_permission_detail.html:62
|
#: perms/templates/perms/asset_permission_detail.html:62
|
||||||
#: perms/templates/perms/asset_permission_list.html:53
|
#: perms/templates/perms/asset_permission_list.html:53
|
||||||
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:18
|
#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:18
|
||||||
#: terminal/models.py:160 terminal/templates/terminal/terminal_detail.html:43
|
#: terminal/models.py:161 terminal/templates/terminal/terminal_detail.html:43
|
||||||
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
|
#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14
|
||||||
#: users/models/user.py:51 users/templates/users/_select_user_modal.html:13
|
#: users/models/user.py:52 users/templates/users/_select_user_modal.html:13
|
||||||
#: users/templates/users/user_detail.html:63
|
#: users/templates/users/user_detail.html:63
|
||||||
#: users/templates/users/user_group_detail.html:55
|
#: users/templates/users/user_group_detail.html:55
|
||||||
#: users/templates/users/user_group_list.html:12
|
#: users/templates/users/user_group_list.html:12
|
||||||
|
@ -191,7 +191,7 @@ msgstr "名称"
|
||||||
#: assets/templates/assets/system_user_list.html:30
|
#: assets/templates/assets/system_user_list.html:30
|
||||||
#: audits/templates/audits/login_log_list.html:49
|
#: audits/templates/audits/login_log_list.html:49
|
||||||
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:15
|
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:15
|
||||||
#: users/forms.py:33 users/models/authentication.py:72 users/models/user.py:49
|
#: users/forms.py:33 users/models/authentication.py:72 users/models/user.py:50
|
||||||
#: users/templates/users/_select_user_modal.html:14
|
#: users/templates/users/_select_user_modal.html:14
|
||||||
#: users/templates/users/login.html:62
|
#: users/templates/users/login.html:62
|
||||||
#: users/templates/users/user_detail.html:67
|
#: users/templates/users/user_detail.html:67
|
||||||
|
@ -204,7 +204,7 @@ msgstr "用户名"
|
||||||
msgid "Password or private key passphrase"
|
msgid "Password or private key passphrase"
|
||||||
msgstr "密码或密钥密码"
|
msgstr "密码或密钥密码"
|
||||||
|
|
||||||
#: assets/forms/user.py:26 assets/models/base.py:24 common/forms.py:107
|
#: assets/forms/user.py:26 assets/models/base.py:24 common/forms.py:105
|
||||||
#: users/forms.py:17 users/forms.py:35 users/forms.py:47
|
#: users/forms.py:17 users/forms.py:35 users/forms.py:47
|
||||||
#: users/templates/users/login.html:65
|
#: users/templates/users/login.html:65
|
||||||
#: users/templates/users/reset_password.html:53
|
#: users/templates/users/reset_password.html:53
|
||||||
|
@ -216,7 +216,7 @@ msgstr "密码或密钥密码"
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "密码"
|
msgstr "密码"
|
||||||
|
|
||||||
#: assets/forms/user.py:29 users/models/user.py:78
|
#: assets/forms/user.py:29 users/models/user.py:79
|
||||||
msgid "Private key"
|
msgid "Private key"
|
||||||
msgstr "ssh私钥"
|
msgstr "ssh私钥"
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ msgstr "如果选择手动登录模式,用户名和密码可以不填写"
|
||||||
#: assets/templates/assets/system_user_asset.html:51
|
#: assets/templates/assets/system_user_asset.html:51
|
||||||
#: assets/templates/assets/user_asset_list.html:46
|
#: assets/templates/assets/user_asset_list.html:46
|
||||||
#: assets/templates/assets/user_asset_list.html:162
|
#: assets/templates/assets/user_asset_list.html:162
|
||||||
#: audits/templates/audits/login_log_list.html:52 common/forms.py:136
|
#: audits/templates/audits/login_log_list.html:52 common/forms.py:134
|
||||||
#: perms/templates/perms/asset_permission_asset.html:55
|
#: perms/templates/perms/asset_permission_asset.html:55
|
||||||
#: users/templates/users/user_granted_asset.html:45
|
#: users/templates/users/user_granted_asset.html:45
|
||||||
#: users/templates/users/user_group_granted_asset.html:45
|
#: users/templates/users/user_group_granted_asset.html:45
|
||||||
|
@ -278,7 +278,7 @@ msgstr "IP"
|
||||||
#: assets/templates/assets/asset_list.html:92
|
#: assets/templates/assets/asset_list.html:92
|
||||||
#: assets/templates/assets/system_user_asset.html:50
|
#: assets/templates/assets/system_user_asset.html:50
|
||||||
#: assets/templates/assets/user_asset_list.html:45
|
#: assets/templates/assets/user_asset_list.html:45
|
||||||
#: assets/templates/assets/user_asset_list.html:161 common/forms.py:135
|
#: assets/templates/assets/user_asset_list.html:161 common/forms.py:133
|
||||||
#: perms/templates/perms/asset_permission_asset.html:54
|
#: perms/templates/perms/asset_permission_asset.html:54
|
||||||
#: users/templates/users/user_granted_asset.html:44
|
#: users/templates/users/user_granted_asset.html:44
|
||||||
#: users/templates/users/user_group_granted_asset.html:44
|
#: users/templates/users/user_group_granted_asset.html:44
|
||||||
|
@ -388,7 +388,7 @@ msgstr "标签管理"
|
||||||
#: assets/templates/assets/system_user_detail.html:100
|
#: assets/templates/assets/system_user_detail.html:100
|
||||||
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 perms/models.py:37
|
#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 perms/models.py:37
|
||||||
#: perms/models.py:84 perms/templates/perms/asset_permission_detail.html:98
|
#: perms/models.py:84 perms/templates/perms/asset_permission_detail.html:98
|
||||||
#: users/models/user.py:92 users/templates/users/user_detail.html:111
|
#: users/models/user.py:93 users/templates/users/user_detail.html:111
|
||||||
#: xpack/plugins/cloud/models.py:46 xpack/plugins/cloud/models.py:140
|
#: xpack/plugins/cloud/models.py:46 xpack/plugins/cloud/models.py:140
|
||||||
msgid "Created by"
|
msgid "Created by"
|
||||||
msgstr "创建者"
|
msgstr "创建者"
|
||||||
|
@ -426,11 +426,11 @@ msgstr "创建日期"
|
||||||
#: assets/templates/assets/domain_list.html:28
|
#: assets/templates/assets/domain_list.html:28
|
||||||
#: assets/templates/assets/system_user_detail.html:104
|
#: assets/templates/assets/system_user_detail.html:104
|
||||||
#: assets/templates/assets/system_user_list.html:37
|
#: assets/templates/assets/system_user_list.html:37
|
||||||
#: assets/templates/assets/user_asset_list.html:170 common/models.py:35
|
#: assets/templates/assets/user_asset_list.html:170 common/models.py:36
|
||||||
#: ops/models/adhoc.py:43 orgs/models.py:17 perms/models.py:39
|
#: ops/models/adhoc.py:43 orgs/models.py:17 perms/models.py:39
|
||||||
#: perms/models.py:86 perms/templates/perms/asset_permission_detail.html:102
|
#: perms/models.py:86 perms/templates/perms/asset_permission_detail.html:102
|
||||||
#: terminal/models.py:28 terminal/templates/terminal/terminal_detail.html:63
|
#: terminal/models.py:28 terminal/templates/terminal/terminal_detail.html:63
|
||||||
#: users/models/group.py:15 users/models/user.py:84
|
#: users/models/group.py:15 users/models/user.py:85
|
||||||
#: users/templates/users/user_detail.html:123
|
#: users/templates/users/user_detail.html:123
|
||||||
#: users/templates/users/user_group_detail.html:67
|
#: users/templates/users/user_group_detail.html:67
|
||||||
#: users/templates/users/user_group_list.html:14
|
#: users/templates/users/user_group_list.html:14
|
||||||
|
@ -461,7 +461,7 @@ msgstr "带宽"
|
||||||
msgid "Contact"
|
msgid "Contact"
|
||||||
msgstr "联系人"
|
msgstr "联系人"
|
||||||
|
|
||||||
#: assets/models/cluster.py:22 users/models/user.py:70
|
#: assets/models/cluster.py:22 users/models/user.py:71
|
||||||
#: users/templates/users/user_detail.html:76
|
#: users/templates/users/user_detail.html:76
|
||||||
msgid "Phone"
|
msgid "Phone"
|
||||||
msgstr "手机"
|
msgstr "手机"
|
||||||
|
@ -487,7 +487,7 @@ msgid "Default"
|
||||||
msgstr "默认"
|
msgstr "默认"
|
||||||
|
|
||||||
#: assets/models/cluster.py:36 assets/models/label.py:14
|
#: assets/models/cluster.py:36 assets/models/label.py:14
|
||||||
#: users/models/user.py:363
|
#: users/models/user.py:364
|
||||||
msgid "System"
|
msgid "System"
|
||||||
msgstr "系统"
|
msgstr "系统"
|
||||||
|
|
||||||
|
@ -515,7 +515,7 @@ msgstr "BGP全网通"
|
||||||
msgid "Regex"
|
msgid "Regex"
|
||||||
msgstr "正则表达式"
|
msgstr "正则表达式"
|
||||||
|
|
||||||
#: assets/models/cmd_filter.py:35 terminal/models.py:139
|
#: assets/models/cmd_filter.py:35 terminal/models.py:140
|
||||||
#: terminal/templates/terminal/command_list.html:55
|
#: terminal/templates/terminal/command_list.html:55
|
||||||
#: terminal/templates/terminal/command_list.html:71
|
#: terminal/templates/terminal/command_list.html:71
|
||||||
#: terminal/templates/terminal/session_detail.html:48
|
#: terminal/templates/terminal/session_detail.html:48
|
||||||
|
@ -616,14 +616,14 @@ msgstr "默认资产组"
|
||||||
#: perms/templates/perms/asset_permission_create_update.html:36
|
#: perms/templates/perms/asset_permission_create_update.html:36
|
||||||
#: perms/templates/perms/asset_permission_list.html:54
|
#: perms/templates/perms/asset_permission_list.html:54
|
||||||
#: perms/templates/perms/asset_permission_list.html:142 templates/index.html:87
|
#: perms/templates/perms/asset_permission_list.html:142 templates/index.html:87
|
||||||
#: terminal/backends/command/models.py:12 terminal/models.py:132
|
#: terminal/backends/command/models.py:12 terminal/models.py:133
|
||||||
#: terminal/templates/terminal/command_list.html:32
|
#: terminal/templates/terminal/command_list.html:32
|
||||||
#: terminal/templates/terminal/command_list.html:72
|
#: terminal/templates/terminal/command_list.html:72
|
||||||
#: terminal/templates/terminal/session_list.html:33
|
#: terminal/templates/terminal/session_list.html:33
|
||||||
#: terminal/templates/terminal/session_list.html:71 users/forms.py:312
|
#: terminal/templates/terminal/session_list.html:71 users/forms.py:312
|
||||||
#: users/models/user.py:33 users/models/user.py:351
|
#: users/models/user.py:32 users/models/user.py:352
|
||||||
#: users/templates/users/user_group_detail.html:78
|
#: users/templates/users/user_group_detail.html:78
|
||||||
#: users/templates/users/user_group_list.html:13 users/views/user.py:385
|
#: users/templates/users/user_group_list.html:13 users/views/user.py:384
|
||||||
#: xpack/plugins/orgs/forms.py:26
|
#: xpack/plugins/orgs/forms.py:26
|
||||||
#: xpack/plugins/orgs/templates/orgs/org_detail.html:113
|
#: xpack/plugins/orgs/templates/orgs/org_detail.html:113
|
||||||
#: xpack/plugins/orgs/templates/orgs/org_list.html:14
|
#: xpack/plugins/orgs/templates/orgs/org_list.html:14
|
||||||
|
@ -631,7 +631,7 @@ msgid "User"
|
||||||
msgstr "用户"
|
msgstr "用户"
|
||||||
|
|
||||||
#: assets/models/label.py:19 assets/models/node.py:20
|
#: assets/models/label.py:19 assets/models/node.py:20
|
||||||
#: assets/templates/assets/label_list.html:15 common/models.py:31
|
#: assets/templates/assets/label_list.html:15 common/models.py:32
|
||||||
msgid "Value"
|
msgid "Value"
|
||||||
msgstr "值"
|
msgstr "值"
|
||||||
|
|
||||||
|
@ -699,7 +699,7 @@ msgstr "登录模式"
|
||||||
#: perms/templates/perms/asset_permission_detail.html:140
|
#: perms/templates/perms/asset_permission_detail.html:140
|
||||||
#: perms/templates/perms/asset_permission_list.html:58
|
#: perms/templates/perms/asset_permission_list.html:58
|
||||||
#: perms/templates/perms/asset_permission_list.html:154 templates/_nav.html:25
|
#: perms/templates/perms/asset_permission_list.html:154 templates/_nav.html:25
|
||||||
#: terminal/backends/command/models.py:14 terminal/models.py:134
|
#: terminal/backends/command/models.py:14 terminal/models.py:135
|
||||||
#: terminal/templates/terminal/command_list.html:48
|
#: terminal/templates/terminal/command_list.html:48
|
||||||
#: terminal/templates/terminal/command_list.html:74
|
#: terminal/templates/terminal/command_list.html:74
|
||||||
#: terminal/templates/terminal/session_list.html:49
|
#: terminal/templates/terminal/session_list.html:49
|
||||||
|
@ -1060,7 +1060,7 @@ msgstr "选择节点"
|
||||||
#: users/templates/users/user_detail.html:476
|
#: users/templates/users/user_detail.html:476
|
||||||
#: users/templates/users/user_group_create_update.html:32
|
#: users/templates/users/user_group_create_update.html:32
|
||||||
#: users/templates/users/user_group_list.html:88
|
#: users/templates/users/user_group_list.html:88
|
||||||
#: users/templates/users/user_list.html:201
|
#: users/templates/users/user_list.html:205
|
||||||
#: users/templates/users/user_profile.html:232
|
#: users/templates/users/user_profile.html:232
|
||||||
#: xpack/plugins/cloud/templates/cloud/account_create_update.html:34
|
#: xpack/plugins/cloud/templates/cloud/account_create_update.html:34
|
||||||
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:36
|
#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:36
|
||||||
|
@ -1277,7 +1277,7 @@ msgstr "重命名失败,不能更改root节点的名称"
|
||||||
#: users/templates/users/user_detail.html:402
|
#: users/templates/users/user_detail.html:402
|
||||||
#: users/templates/users/user_detail.html:470
|
#: users/templates/users/user_detail.html:470
|
||||||
#: users/templates/users/user_group_list.html:82
|
#: users/templates/users/user_group_list.html:82
|
||||||
#: users/templates/users/user_list.html:195
|
#: users/templates/users/user_list.html:199
|
||||||
msgid "Are you sure?"
|
msgid "Are you sure?"
|
||||||
msgstr "你确认吗?"
|
msgstr "你确认吗?"
|
||||||
|
|
||||||
|
@ -1293,7 +1293,7 @@ msgstr "删除选择资产"
|
||||||
#: users/templates/users/user_detail.html:474
|
#: users/templates/users/user_detail.html:474
|
||||||
#: users/templates/users/user_group_create_update.html:31
|
#: users/templates/users/user_group_create_update.html:31
|
||||||
#: users/templates/users/user_group_list.html:86
|
#: users/templates/users/user_group_list.html:86
|
||||||
#: users/templates/users/user_list.html:199
|
#: users/templates/users/user_list.html:203
|
||||||
#: xpack/plugins/orgs/templates/orgs/org_create_update.html:32
|
#: xpack/plugins/orgs/templates/orgs/org_create_update.html:32
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "取消"
|
msgstr "取消"
|
||||||
|
@ -1624,7 +1624,7 @@ msgstr "系统用户集群资产"
|
||||||
#: audits/templates/audits/ftp_log_list.html:73
|
#: audits/templates/audits/ftp_log_list.html:73
|
||||||
#: audits/templates/audits/operate_log_list.html:70
|
#: audits/templates/audits/operate_log_list.html:70
|
||||||
#: audits/templates/audits/password_change_log_list.html:52
|
#: audits/templates/audits/password_change_log_list.html:52
|
||||||
#: terminal/models.py:136 terminal/templates/terminal/session_list.html:74
|
#: terminal/models.py:137 terminal/templates/terminal/session_list.html:74
|
||||||
#: terminal/templates/terminal/terminal_detail.html:47
|
#: terminal/templates/terminal/terminal_detail.html:47
|
||||||
msgid "Remote addr"
|
msgid "Remote addr"
|
||||||
msgstr "远端地址"
|
msgstr "远端地址"
|
||||||
|
@ -1665,7 +1665,7 @@ msgstr "修改者"
|
||||||
#: ops/templates/ops/adhoc_history.html:52
|
#: ops/templates/ops/adhoc_history.html:52
|
||||||
#: ops/templates/ops/adhoc_history_detail.html:61
|
#: ops/templates/ops/adhoc_history_detail.html:61
|
||||||
#: ops/templates/ops/task_history.html:58 perms/models.py:35
|
#: ops/templates/ops/task_history.html:58 perms/models.py:35
|
||||||
#: perms/templates/perms/asset_permission_detail.html:86 terminal/models.py:143
|
#: perms/templates/perms/asset_permission_detail.html:86 terminal/models.py:144
|
||||||
#: terminal/templates/terminal/session_list.html:78
|
#: terminal/templates/terminal/session_list.html:78
|
||||||
msgid "Date start"
|
msgid "Date start"
|
||||||
msgstr "开始日期"
|
msgstr "开始日期"
|
||||||
|
@ -1707,7 +1707,7 @@ msgid "City"
|
||||||
msgstr "城市"
|
msgstr "城市"
|
||||||
|
|
||||||
#: audits/templates/audits/login_log_list.html:54 users/forms.py:169
|
#: audits/templates/audits/login_log_list.html:54 users/forms.py:169
|
||||||
#: users/models/authentication.py:77 users/models/user.py:73
|
#: users/models/authentication.py:77 users/models/user.py:74
|
||||||
#: users/templates/users/first_login.html:45
|
#: users/templates/users/first_login.html:45
|
||||||
msgid "MFA"
|
msgid "MFA"
|
||||||
msgstr "MFA"
|
msgstr "MFA"
|
||||||
|
@ -1758,9 +1758,9 @@ msgstr "改密日志"
|
||||||
|
|
||||||
#: audits/views.py:187 templates/_nav.html:10 users/views/group.py:28
|
#: audits/views.py:187 templates/_nav.html:10 users/views/group.py:28
|
||||||
#: users/views/group.py:44 users/views/group.py:60 users/views/group.py:76
|
#: users/views/group.py:44 users/views/group.py:60 users/views/group.py:76
|
||||||
#: users/views/group.py:92 users/views/login.py:334 users/views/user.py:68
|
#: users/views/group.py:92 users/views/login.py:332 users/views/user.py:68
|
||||||
#: users/views/user.py:83 users/views/user.py:111 users/views/user.py:193
|
#: users/views/user.py:83 users/views/user.py:111 users/views/user.py:192
|
||||||
#: users/views/user.py:354 users/views/user.py:404 users/views/user.py:439
|
#: users/views/user.py:353 users/views/user.py:403 users/views/user.py:437
|
||||||
msgid "Users"
|
msgid "Users"
|
||||||
msgstr "用户管理"
|
msgstr "用户管理"
|
||||||
|
|
||||||
|
@ -1819,88 +1819,88 @@ msgstr "不是字符类型"
|
||||||
msgid "Encrypt field using Secret Key"
|
msgid "Encrypt field using Secret Key"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: common/forms.py:64
|
#: common/forms.py:63
|
||||||
msgid "Current SITE URL"
|
msgid "Current SITE URL"
|
||||||
msgstr "当前站点URL"
|
msgstr "当前站点URL"
|
||||||
|
|
||||||
#: common/forms.py:68
|
#: common/forms.py:67
|
||||||
msgid "User Guide URL"
|
msgid "User Guide URL"
|
||||||
msgstr "用户向导URL"
|
msgstr "用户向导URL"
|
||||||
|
|
||||||
#: common/forms.py:69
|
#: common/forms.py:68
|
||||||
msgid "User first login update profile done redirect to it"
|
msgid "User first login update profile done redirect to it"
|
||||||
msgstr "用户第一次登录,修改profile后重定向到地址"
|
msgstr "用户第一次登录,修改profile后重定向到地址"
|
||||||
|
|
||||||
#: common/forms.py:72
|
#: common/forms.py:71
|
||||||
msgid "Email Subject Prefix"
|
msgid "Email Subject Prefix"
|
||||||
msgstr "Email主题前缀"
|
msgstr "Email主题前缀"
|
||||||
|
|
||||||
#: common/forms.py:79
|
#: common/forms.py:77
|
||||||
msgid "SMTP host"
|
msgid "SMTP host"
|
||||||
msgstr "SMTP主机"
|
msgstr "SMTP主机"
|
||||||
|
|
||||||
#: common/forms.py:81
|
#: common/forms.py:79
|
||||||
msgid "SMTP port"
|
msgid "SMTP port"
|
||||||
msgstr "SMTP端口"
|
msgstr "SMTP端口"
|
||||||
|
|
||||||
#: common/forms.py:83
|
#: common/forms.py:81
|
||||||
msgid "SMTP user"
|
msgid "SMTP user"
|
||||||
msgstr "SMTP账号"
|
msgstr "SMTP账号"
|
||||||
|
|
||||||
#: common/forms.py:86
|
#: common/forms.py:84
|
||||||
msgid "SMTP password"
|
msgid "SMTP password"
|
||||||
msgstr "SMTP密码"
|
msgstr "SMTP密码"
|
||||||
|
|
||||||
#: common/forms.py:87
|
#: common/forms.py:85
|
||||||
msgid "Some provider use token except password"
|
msgid "Some provider use token except password"
|
||||||
msgstr "一些邮件提供商需要输入的是Token"
|
msgstr "一些邮件提供商需要输入的是Token"
|
||||||
|
|
||||||
#: common/forms.py:90 common/forms.py:128
|
#: common/forms.py:88 common/forms.py:126
|
||||||
msgid "Use SSL"
|
msgid "Use SSL"
|
||||||
msgstr "使用SSL"
|
msgstr "使用SSL"
|
||||||
|
|
||||||
#: common/forms.py:91
|
#: common/forms.py:89
|
||||||
msgid "If SMTP port is 465, may be select"
|
msgid "If SMTP port is 465, may be select"
|
||||||
msgstr "如果SMTP端口是465,通常需要启用SSL"
|
msgstr "如果SMTP端口是465,通常需要启用SSL"
|
||||||
|
|
||||||
#: common/forms.py:94
|
#: common/forms.py:92
|
||||||
msgid "Use TLS"
|
msgid "Use TLS"
|
||||||
msgstr "使用TLS"
|
msgstr "使用TLS"
|
||||||
|
|
||||||
#: common/forms.py:95
|
#: common/forms.py:93
|
||||||
msgid "If SMTP port is 587, may be select"
|
msgid "If SMTP port is 587, may be select"
|
||||||
msgstr "如果SMTP端口是587,通常需要启用TLS"
|
msgstr "如果SMTP端口是587,通常需要启用TLS"
|
||||||
|
|
||||||
#: common/forms.py:101
|
#: common/forms.py:99
|
||||||
msgid "LDAP server"
|
msgid "LDAP server"
|
||||||
msgstr "LDAP地址"
|
msgstr "LDAP地址"
|
||||||
|
|
||||||
#: common/forms.py:104
|
#: common/forms.py:102
|
||||||
msgid "Bind DN"
|
msgid "Bind DN"
|
||||||
msgstr "绑定DN"
|
msgstr "绑定DN"
|
||||||
|
|
||||||
#: common/forms.py:111
|
#: common/forms.py:109
|
||||||
msgid "User OU"
|
msgid "User OU"
|
||||||
msgstr "用户OU"
|
msgstr "用户OU"
|
||||||
|
|
||||||
#: common/forms.py:112
|
#: common/forms.py:110
|
||||||
msgid "Use | split User OUs"
|
msgid "Use | split User OUs"
|
||||||
msgstr "使用|分隔各OU"
|
msgstr "使用|分隔各OU"
|
||||||
|
|
||||||
#: common/forms.py:115
|
#: common/forms.py:113
|
||||||
msgid "User search filter"
|
msgid "User search filter"
|
||||||
msgstr "用户过滤器"
|
msgstr "用户过滤器"
|
||||||
|
|
||||||
#: common/forms.py:116
|
#: common/forms.py:114
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Choice may be (cn|uid|sAMAccountName)=%(user)s)"
|
msgid "Choice may be (cn|uid|sAMAccountName)=%(user)s)"
|
||||||
msgstr "可能的选项是(cn或uid或sAMAccountName=%(user)s)"
|
msgstr "可能的选项是(cn或uid或sAMAccountName=%(user)s)"
|
||||||
|
|
||||||
#: common/forms.py:119
|
#: common/forms.py:117
|
||||||
msgid "User attr map"
|
msgid "User attr map"
|
||||||
msgstr "LDAP属性映射"
|
msgstr "LDAP属性映射"
|
||||||
|
|
||||||
#: common/forms.py:121
|
#: common/forms.py:119
|
||||||
msgid ""
|
msgid ""
|
||||||
"User attr map present how to map LDAP user attr to jumpserver, username,name,"
|
"User attr map present how to map LDAP user attr to jumpserver, username,name,"
|
||||||
"email is jumpserver attr"
|
"email is jumpserver attr"
|
||||||
|
@ -1908,103 +1908,103 @@ msgstr ""
|
||||||
"用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上,username, name,"
|
"用户属性映射代表怎样将LDAP中用户属性映射到jumpserver用户上,username, name,"
|
||||||
"email 是jumpserver的属性"
|
"email 是jumpserver的属性"
|
||||||
|
|
||||||
#: common/forms.py:130
|
#: common/forms.py:128
|
||||||
msgid "Enable LDAP auth"
|
msgid "Enable LDAP auth"
|
||||||
msgstr "启用LDAP认证"
|
msgstr "启用LDAP认证"
|
||||||
|
|
||||||
#: common/forms.py:139
|
#: common/forms.py:137
|
||||||
msgid "Password auth"
|
msgid "Password auth"
|
||||||
msgstr "密码认证"
|
msgstr "密码认证"
|
||||||
|
|
||||||
#: common/forms.py:142
|
#: common/forms.py:140
|
||||||
msgid "Public key auth"
|
msgid "Public key auth"
|
||||||
msgstr "密钥认证"
|
msgstr "密钥认证"
|
||||||
|
|
||||||
#: common/forms.py:145
|
#: common/forms.py:143
|
||||||
msgid "Heartbeat interval"
|
msgid "Heartbeat interval"
|
||||||
msgstr "心跳间隔"
|
msgstr "心跳间隔"
|
||||||
|
|
||||||
#: common/forms.py:145 ops/models/adhoc.py:38
|
#: common/forms.py:143 ops/models/adhoc.py:38
|
||||||
msgid "Units: seconds"
|
msgid "Units: seconds"
|
||||||
msgstr "单位: 秒"
|
msgstr "单位: 秒"
|
||||||
|
|
||||||
#: common/forms.py:148
|
#: common/forms.py:146
|
||||||
msgid "List sort by"
|
msgid "List sort by"
|
||||||
msgstr "资产列表排序"
|
msgstr "资产列表排序"
|
||||||
|
|
||||||
#: common/forms.py:160
|
#: common/forms.py:158
|
||||||
msgid "MFA Secondary certification"
|
msgid "MFA Secondary certification"
|
||||||
msgstr "MFA 二次认证"
|
msgstr "MFA 二次认证"
|
||||||
|
|
||||||
#: common/forms.py:162
|
#: common/forms.py:160
|
||||||
msgid ""
|
msgid ""
|
||||||
"After opening, the user login must use MFA secondary authentication (valid "
|
"After opening, the user login must use MFA secondary authentication (valid "
|
||||||
"for all users, including administrators)"
|
"for all users, including administrators)"
|
||||||
msgstr "开启后,用户登录必须使用MFA二次认证(对所有用户有效,包括管理员)"
|
msgstr "开启后,用户登录必须使用MFA二次认证(对所有用户有效,包括管理员)"
|
||||||
|
|
||||||
#: common/forms.py:169
|
#: common/forms.py:167
|
||||||
msgid "Limit the number of login failures"
|
msgid "Limit the number of login failures"
|
||||||
msgstr "限制登录失败次数"
|
msgstr "限制登录失败次数"
|
||||||
|
|
||||||
#: common/forms.py:174
|
#: common/forms.py:172
|
||||||
msgid "No logon interval"
|
msgid "No logon interval"
|
||||||
msgstr "禁止登录时间间隔"
|
msgstr "禁止登录时间间隔"
|
||||||
|
|
||||||
#: common/forms.py:176
|
#: common/forms.py:174
|
||||||
msgid ""
|
msgid ""
|
||||||
"Tip :(unit/minute) if the user has failed to log in for a limited number of "
|
"Tip :(unit/minute) if the user has failed to log in for a limited number of "
|
||||||
"times, no login is allowed during this time interval."
|
"times, no login is allowed during this time interval."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"提示: (单位: 分钟) 当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录."
|
"提示: (单位: 分钟) 当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录."
|
||||||
|
|
||||||
#: common/forms.py:182
|
#: common/forms.py:180
|
||||||
msgid "Connection max idle time"
|
msgid "Connection max idle time"
|
||||||
msgstr "SSH最大空闲时间"
|
msgstr "SSH最大空闲时间"
|
||||||
|
|
||||||
#: common/forms.py:184
|
#: common/forms.py:182
|
||||||
msgid ""
|
msgid ""
|
||||||
"If idle time more than it, disconnect connection(only ssh now) Unit: minute"
|
"If idle time more than it, disconnect connection(only ssh now) Unit: minute"
|
||||||
msgstr "提示: (单位: 分钟) 如果超过该配置没有操作,连接会被断开(仅ssh) "
|
msgstr "提示: (单位: 分钟) 如果超过该配置没有操作,连接会被断开(仅ssh) "
|
||||||
|
|
||||||
#: common/forms.py:190
|
#: common/forms.py:188
|
||||||
msgid "Password minimum length"
|
msgid "Password minimum length"
|
||||||
msgstr "密码最小长度 "
|
msgstr "密码最小长度 "
|
||||||
|
|
||||||
#: common/forms.py:196
|
#: common/forms.py:194
|
||||||
msgid "Must contain capital letters"
|
msgid "Must contain capital letters"
|
||||||
msgstr "必须包含大写字母"
|
msgstr "必须包含大写字母"
|
||||||
|
|
||||||
#: common/forms.py:198
|
#: common/forms.py:196
|
||||||
msgid ""
|
msgid ""
|
||||||
"After opening, the user password changes and resets must contain uppercase "
|
"After opening, the user password changes and resets must contain uppercase "
|
||||||
"letters"
|
"letters"
|
||||||
msgstr "开启后,用户密码修改、重置必须包含大写字母"
|
msgstr "开启后,用户密码修改、重置必须包含大写字母"
|
||||||
|
|
||||||
#: common/forms.py:204
|
#: common/forms.py:202
|
||||||
msgid "Must contain lowercase letters"
|
msgid "Must contain lowercase letters"
|
||||||
msgstr "必须包含小写字母"
|
msgstr "必须包含小写字母"
|
||||||
|
|
||||||
#: common/forms.py:205
|
#: common/forms.py:203
|
||||||
msgid ""
|
msgid ""
|
||||||
"After opening, the user password changes and resets must contain lowercase "
|
"After opening, the user password changes and resets must contain lowercase "
|
||||||
"letters"
|
"letters"
|
||||||
msgstr "开启后,用户密码修改、重置必须包含小写字母"
|
msgstr "开启后,用户密码修改、重置必须包含小写字母"
|
||||||
|
|
||||||
#: common/forms.py:211
|
#: common/forms.py:209
|
||||||
msgid "Must contain numeric characters"
|
msgid "Must contain numeric characters"
|
||||||
msgstr "必须包含数字字符"
|
msgstr "必须包含数字字符"
|
||||||
|
|
||||||
#: common/forms.py:212
|
#: common/forms.py:210
|
||||||
msgid ""
|
msgid ""
|
||||||
"After opening, the user password changes and resets must contain numeric "
|
"After opening, the user password changes and resets must contain numeric "
|
||||||
"characters"
|
"characters"
|
||||||
msgstr "开启后,用户密码修改、重置必须包含数字字符"
|
msgstr "开启后,用户密码修改、重置必须包含数字字符"
|
||||||
|
|
||||||
#: common/forms.py:218
|
#: common/forms.py:216
|
||||||
msgid "Must contain special characters"
|
msgid "Must contain special characters"
|
||||||
msgstr "必须包含特殊字符"
|
msgstr "必须包含特殊字符"
|
||||||
|
|
||||||
#: common/forms.py:219
|
#: common/forms.py:217
|
||||||
msgid ""
|
msgid ""
|
||||||
"After opening, the user password changes and resets must contain special "
|
"After opening, the user password changes and resets must contain special "
|
||||||
"characters"
|
"characters"
|
||||||
|
@ -2018,7 +2018,7 @@ msgstr ""
|
||||||
msgid "discard time"
|
msgid "discard time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: common/models.py:34 users/models/authentication.py:51
|
#: common/models.py:35 users/models/authentication.py:51
|
||||||
#: users/templates/users/user_detail.html:96
|
#: users/templates/users/user_detail.html:96
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "启用"
|
msgstr "启用"
|
||||||
|
@ -2028,7 +2028,7 @@ msgstr "启用"
|
||||||
#: common/templates/common/ldap_setting.html:15
|
#: common/templates/common/ldap_setting.html:15
|
||||||
#: common/templates/common/security_setting.html:15
|
#: common/templates/common/security_setting.html:15
|
||||||
#: common/templates/common/terminal_setting.html:16
|
#: common/templates/common/terminal_setting.html:16
|
||||||
#: common/templates/common/terminal_setting.html:46 common/views.py:22
|
#: common/templates/common/terminal_setting.html:46 common/views.py:19
|
||||||
msgid "Basic setting"
|
msgid "Basic setting"
|
||||||
msgstr "基本设置"
|
msgstr "基本设置"
|
||||||
|
|
||||||
|
@ -2036,7 +2036,7 @@ msgstr "基本设置"
|
||||||
#: common/templates/common/email_setting.html:18
|
#: common/templates/common/email_setting.html:18
|
||||||
#: common/templates/common/ldap_setting.html:18
|
#: common/templates/common/ldap_setting.html:18
|
||||||
#: common/templates/common/security_setting.html:18
|
#: common/templates/common/security_setting.html:18
|
||||||
#: common/templates/common/terminal_setting.html:20 common/views.py:48
|
#: common/templates/common/terminal_setting.html:20 common/views.py:45
|
||||||
msgid "Email setting"
|
msgid "Email setting"
|
||||||
msgstr "邮件设置"
|
msgstr "邮件设置"
|
||||||
|
|
||||||
|
@ -2044,7 +2044,7 @@ msgstr "邮件设置"
|
||||||
#: common/templates/common/email_setting.html:21
|
#: common/templates/common/email_setting.html:21
|
||||||
#: common/templates/common/ldap_setting.html:21
|
#: common/templates/common/ldap_setting.html:21
|
||||||
#: common/templates/common/security_setting.html:21
|
#: common/templates/common/security_setting.html:21
|
||||||
#: common/templates/common/terminal_setting.html:24 common/views.py:74
|
#: common/templates/common/terminal_setting.html:24 common/views.py:71
|
||||||
msgid "LDAP setting"
|
msgid "LDAP setting"
|
||||||
msgstr "LDAP设置"
|
msgstr "LDAP设置"
|
||||||
|
|
||||||
|
@ -2052,7 +2052,7 @@ msgstr "LDAP设置"
|
||||||
#: common/templates/common/email_setting.html:24
|
#: common/templates/common/email_setting.html:24
|
||||||
#: common/templates/common/ldap_setting.html:24
|
#: common/templates/common/ldap_setting.html:24
|
||||||
#: common/templates/common/security_setting.html:24
|
#: common/templates/common/security_setting.html:24
|
||||||
#: common/templates/common/terminal_setting.html:28 common/views.py:105
|
#: common/templates/common/terminal_setting.html:28 common/views.py:100
|
||||||
msgid "Terminal setting"
|
msgid "Terminal setting"
|
||||||
msgstr "终端设置"
|
msgstr "终端设置"
|
||||||
|
|
||||||
|
@ -2060,7 +2060,7 @@ msgstr "终端设置"
|
||||||
#: common/templates/common/email_setting.html:27
|
#: common/templates/common/email_setting.html:27
|
||||||
#: common/templates/common/ldap_setting.html:27
|
#: common/templates/common/ldap_setting.html:27
|
||||||
#: common/templates/common/security_setting.html:27
|
#: common/templates/common/security_setting.html:27
|
||||||
#: common/templates/common/terminal_setting.html:31 common/views.py:157
|
#: common/templates/common/terminal_setting.html:31 common/views.py:152
|
||||||
msgid "Security setting"
|
msgid "Security setting"
|
||||||
msgstr "安全设置"
|
msgstr "安全设置"
|
||||||
|
|
||||||
|
@ -2168,22 +2168,22 @@ msgstr "您确定删除吗?"
|
||||||
msgid "Special char not allowed"
|
msgid "Special char not allowed"
|
||||||
msgstr "不能包含特殊字符"
|
msgstr "不能包含特殊字符"
|
||||||
|
|
||||||
#: common/views.py:21 common/views.py:47 common/views.py:73 common/views.py:104
|
#: common/views.py:18 common/views.py:44 common/views.py:70 common/views.py:99
|
||||||
#: common/views.py:131 common/views.py:143 common/views.py:156
|
#: common/views.py:126 common/views.py:138 common/views.py:151
|
||||||
#: templates/_nav.html:116
|
#: templates/_nav.html:116
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "系统设置"
|
msgstr "系统设置"
|
||||||
|
|
||||||
#: common/views.py:32 common/views.py:58 common/views.py:86 common/views.py:117
|
#: common/views.py:29 common/views.py:55 common/views.py:81 common/views.py:112
|
||||||
#: common/views.py:167
|
#: common/views.py:162
|
||||||
msgid "Update setting successfully, please restart program"
|
msgid "Update setting successfully, please restart program"
|
||||||
msgstr "更新设置成功, 请手动重启程序"
|
msgstr "更新设置成功, 请手动重启程序"
|
||||||
|
|
||||||
#: common/views.py:132
|
#: common/views.py:127
|
||||||
msgid "Create replay storage"
|
msgid "Create replay storage"
|
||||||
msgstr "创建录像存储"
|
msgstr "创建录像存储"
|
||||||
|
|
||||||
#: common/views.py:144
|
#: common/views.py:139
|
||||||
msgid "Create command storage"
|
msgid "Create command storage"
|
||||||
msgstr "创建命令存储"
|
msgstr "创建命令存储"
|
||||||
|
|
||||||
|
@ -2445,7 +2445,7 @@ msgstr "组织管理"
|
||||||
#: perms/forms.py:31 perms/models.py:30 perms/models.py:80
|
#: perms/forms.py:31 perms/models.py:30 perms/models.py:80
|
||||||
#: perms/templates/perms/asset_permission_list.html:55
|
#: perms/templates/perms/asset_permission_list.html:55
|
||||||
#: perms/templates/perms/asset_permission_list.html:145 templates/_nav.html:14
|
#: perms/templates/perms/asset_permission_list.html:145 templates/_nav.html:14
|
||||||
#: users/forms.py:282 users/models/group.py:26 users/models/user.py:57
|
#: users/forms.py:282 users/models/group.py:26 users/models/user.py:58
|
||||||
#: users/templates/users/_select_user_modal.html:16
|
#: users/templates/users/_select_user_modal.html:16
|
||||||
#: users/templates/users/user_detail.html:207
|
#: users/templates/users/user_detail.html:207
|
||||||
#: users/templates/users/user_list.html:26
|
#: users/templates/users/user_list.html:26
|
||||||
|
@ -2463,7 +2463,7 @@ msgstr "资产和节点至少选一个"
|
||||||
|
|
||||||
#: perms/models.py:36 perms/models.py:83
|
#: perms/models.py:36 perms/models.py:83
|
||||||
#: perms/templates/perms/asset_permission_detail.html:90
|
#: perms/templates/perms/asset_permission_detail.html:90
|
||||||
#: users/models/user.py:89 users/templates/users/user_detail.html:107
|
#: users/models/user.py:90 users/templates/users/user_detail.html:107
|
||||||
#: users/templates/users/user_profile.html:112
|
#: users/templates/users/user_profile.html:112
|
||||||
msgid "Date expired"
|
msgid "Date expired"
|
||||||
msgstr "失效日期"
|
msgstr "失效日期"
|
||||||
|
@ -2594,7 +2594,7 @@ msgstr "商业支持"
|
||||||
#: users/templates/users/user_profile.html:17
|
#: users/templates/users/user_profile.html:17
|
||||||
#: users/templates/users/user_profile_update.html:37
|
#: users/templates/users/user_profile_update.html:37
|
||||||
#: users/templates/users/user_profile_update.html:57
|
#: users/templates/users/user_profile_update.html:57
|
||||||
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:367
|
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:366
|
||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "个人信息"
|
msgstr "个人信息"
|
||||||
|
|
||||||
|
@ -2906,43 +2906,43 @@ msgstr "SSH端口"
|
||||||
msgid "HTTP Port"
|
msgid "HTTP Port"
|
||||||
msgstr "HTTP端口"
|
msgstr "HTTP端口"
|
||||||
|
|
||||||
#: terminal/models.py:104
|
#: terminal/models.py:105
|
||||||
msgid "Session Online"
|
msgid "Session Online"
|
||||||
msgstr "在线会话"
|
msgstr "在线会话"
|
||||||
|
|
||||||
#: terminal/models.py:105
|
#: terminal/models.py:106
|
||||||
msgid "CPU Usage"
|
msgid "CPU Usage"
|
||||||
msgstr "CPU使用"
|
msgstr "CPU使用"
|
||||||
|
|
||||||
#: terminal/models.py:106
|
#: terminal/models.py:107
|
||||||
msgid "Memory Used"
|
msgid "Memory Used"
|
||||||
msgstr "内存使用"
|
msgstr "内存使用"
|
||||||
|
|
||||||
#: terminal/models.py:107
|
#: terminal/models.py:108
|
||||||
msgid "Connections"
|
msgid "Connections"
|
||||||
msgstr "连接数"
|
msgstr "连接数"
|
||||||
|
|
||||||
#: terminal/models.py:108
|
#: terminal/models.py:109
|
||||||
msgid "Threads"
|
msgid "Threads"
|
||||||
msgstr "线程数"
|
msgstr "线程数"
|
||||||
|
|
||||||
#: terminal/models.py:109
|
#: terminal/models.py:110
|
||||||
msgid "Boot Time"
|
msgid "Boot Time"
|
||||||
msgstr "运行时间"
|
msgstr "运行时间"
|
||||||
|
|
||||||
#: terminal/models.py:138 terminal/templates/terminal/session_list.html:104
|
#: terminal/models.py:139 terminal/templates/terminal/session_list.html:104
|
||||||
msgid "Replay"
|
msgid "Replay"
|
||||||
msgstr "回放"
|
msgstr "回放"
|
||||||
|
|
||||||
#: terminal/models.py:142
|
#: terminal/models.py:143
|
||||||
msgid "Date last active"
|
msgid "Date last active"
|
||||||
msgstr "最后活跃日期"
|
msgstr "最后活跃日期"
|
||||||
|
|
||||||
#: terminal/models.py:144
|
#: terminal/models.py:145
|
||||||
msgid "Date end"
|
msgid "Date end"
|
||||||
msgstr "结束日期"
|
msgstr "结束日期"
|
||||||
|
|
||||||
#: terminal/models.py:161
|
#: terminal/models.py:162
|
||||||
msgid "Args"
|
msgid "Args"
|
||||||
msgstr "参数"
|
msgstr "参数"
|
||||||
|
|
||||||
|
@ -3092,11 +3092,11 @@ msgstr "登录频繁, 稍后重试"
|
||||||
msgid "Please carry seed value and conduct MFA secondary certification"
|
msgid "Please carry seed value and conduct MFA secondary certification"
|
||||||
msgstr "请携带seed值, 进行MFA二次认证"
|
msgstr "请携带seed值, 进行MFA二次认证"
|
||||||
|
|
||||||
#: users/api/auth.py:196
|
#: users/api/auth.py:195
|
||||||
msgid "Please verify the user name and password first"
|
msgid "Please verify the user name and password first"
|
||||||
msgstr "请先进行用户名和密码验证"
|
msgstr "请先进行用户名和密码验证"
|
||||||
|
|
||||||
#: users/api/auth.py:208
|
#: users/api/auth.py:207
|
||||||
msgid "MFA certification failed"
|
msgid "MFA certification failed"
|
||||||
msgstr "MFA认证失败"
|
msgstr "MFA认证失败"
|
||||||
|
|
||||||
|
@ -3159,7 +3159,7 @@ msgstr ""
|
||||||
msgid "MFA code"
|
msgid "MFA code"
|
||||||
msgstr "MFA 验证码"
|
msgstr "MFA 验证码"
|
||||||
|
|
||||||
#: users/forms.py:52 users/models/user.py:61
|
#: users/forms.py:52 users/models/user.py:62
|
||||||
#: users/templates/users/_select_user_modal.html:15
|
#: users/templates/users/_select_user_modal.html:15
|
||||||
#: users/templates/users/user_detail.html:87
|
#: users/templates/users/user_detail.html:87
|
||||||
#: users/templates/users/user_list.html:25
|
#: users/templates/users/user_list.html:25
|
||||||
|
@ -3247,7 +3247,7 @@ msgstr "自动配置并下载SSH密钥"
|
||||||
msgid "Paste your id_rsa.pub here."
|
msgid "Paste your id_rsa.pub here."
|
||||||
msgstr "复制你的公钥到这里"
|
msgstr "复制你的公钥到这里"
|
||||||
|
|
||||||
#: users/forms.py:258 users/models/user.py:81
|
#: users/forms.py:258 users/models/user.py:82
|
||||||
#: users/templates/users/first_login.html:42
|
#: users/templates/users/first_login.html:42
|
||||||
#: users/templates/users/user_password_update.html:46
|
#: users/templates/users/user_password_update.html:46
|
||||||
#: users/templates/users/user_profile.html:68
|
#: users/templates/users/user_profile.html:68
|
||||||
|
@ -3310,49 +3310,49 @@ msgstr "Agent"
|
||||||
msgid "Date login"
|
msgid "Date login"
|
||||||
msgstr "登录日期"
|
msgstr "登录日期"
|
||||||
|
|
||||||
#: users/models/user.py:32 users/models/user.py:359
|
#: users/models/user.py:31 users/models/user.py:360
|
||||||
msgid "Administrator"
|
msgid "Administrator"
|
||||||
msgstr "管理员"
|
msgstr "管理员"
|
||||||
|
|
||||||
#: users/models/user.py:34
|
#: users/models/user.py:33
|
||||||
msgid "Application"
|
msgid "Application"
|
||||||
msgstr "应用程序"
|
msgstr "应用程序"
|
||||||
|
|
||||||
#: users/models/user.py:37 users/templates/users/user_profile.html:92
|
#: users/models/user.py:36 users/templates/users/user_profile.html:92
|
||||||
#: users/templates/users/user_profile.html:163
|
#: users/templates/users/user_profile.html:163
|
||||||
#: users/templates/users/user_profile.html:166
|
#: users/templates/users/user_profile.html:166
|
||||||
msgid "Disable"
|
msgid "Disable"
|
||||||
msgstr "禁用"
|
msgstr "禁用"
|
||||||
|
|
||||||
#: users/models/user.py:38 users/templates/users/user_profile.html:90
|
#: users/models/user.py:37 users/templates/users/user_profile.html:90
|
||||||
#: users/templates/users/user_profile.html:170
|
#: users/templates/users/user_profile.html:170
|
||||||
msgid "Enable"
|
msgid "Enable"
|
||||||
msgstr "启用"
|
msgstr "启用"
|
||||||
|
|
||||||
#: users/models/user.py:39 users/templates/users/user_profile.html:88
|
#: users/models/user.py:38 users/templates/users/user_profile.html:88
|
||||||
msgid "Force enable"
|
msgid "Force enable"
|
||||||
msgstr "强制启用"
|
msgstr "强制启用"
|
||||||
|
|
||||||
#: users/models/user.py:53 users/templates/users/user_detail.html:71
|
#: users/models/user.py:54 users/templates/users/user_detail.html:71
|
||||||
#: users/templates/users/user_profile.html:59
|
#: users/templates/users/user_profile.html:59
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "邮件"
|
msgstr "邮件"
|
||||||
|
|
||||||
#: users/models/user.py:64
|
#: users/models/user.py:65
|
||||||
msgid "Avatar"
|
msgid "Avatar"
|
||||||
msgstr "头像"
|
msgstr "头像"
|
||||||
|
|
||||||
#: users/models/user.py:67 users/templates/users/user_detail.html:82
|
#: users/models/user.py:68 users/templates/users/user_detail.html:82
|
||||||
msgid "Wechat"
|
msgid "Wechat"
|
||||||
msgstr "微信"
|
msgstr "微信"
|
||||||
|
|
||||||
#: users/models/user.py:96 users/templates/users/user_detail.html:103
|
#: users/models/user.py:97 users/templates/users/user_detail.html:103
|
||||||
#: users/templates/users/user_list.html:27
|
#: users/templates/users/user_list.html:27
|
||||||
#: users/templates/users/user_profile.html:100
|
#: users/templates/users/user_profile.html:100
|
||||||
msgid "Source"
|
msgid "Source"
|
||||||
msgstr "用户来源"
|
msgstr "用户来源"
|
||||||
|
|
||||||
#: users/models/user.py:362
|
#: users/models/user.py:363
|
||||||
msgid "Administrator is the super user of system"
|
msgid "Administrator is the super user of system"
|
||||||
msgstr "Administrator是初始的超级管理员"
|
msgstr "Administrator是初始的超级管理员"
|
||||||
|
|
||||||
|
@ -3636,7 +3636,7 @@ msgid "Reset link will be generated and sent to the user. "
|
||||||
msgstr "生成重置密码连接,通过邮件发送给用户"
|
msgstr "生成重置密码连接,通过邮件发送给用户"
|
||||||
|
|
||||||
#: users/templates/users/user_detail.html:19
|
#: users/templates/users/user_detail.html:19
|
||||||
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:194
|
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:193
|
||||||
msgid "User detail"
|
msgid "User detail"
|
||||||
msgstr "用户详情"
|
msgstr "用户详情"
|
||||||
|
|
||||||
|
@ -3764,20 +3764,20 @@ msgstr "用户组删除"
|
||||||
msgid "UserGroup Deleting failed."
|
msgid "UserGroup Deleting failed."
|
||||||
msgstr "用户组删除失败"
|
msgstr "用户组删除失败"
|
||||||
|
|
||||||
#: users/templates/users/user_list.html:196
|
#: users/templates/users/user_list.html:200
|
||||||
msgid "This will delete the selected users !!!"
|
msgid "This will delete the selected users !!!"
|
||||||
msgstr "删除选中用户 !!!"
|
msgstr "删除选中用户 !!!"
|
||||||
|
|
||||||
#: users/templates/users/user_list.html:205
|
#: users/templates/users/user_list.html:209
|
||||||
msgid "User Deleted."
|
msgid "User Deleted."
|
||||||
msgstr "已被删除"
|
msgstr "已被删除"
|
||||||
|
|
||||||
#: users/templates/users/user_list.html:206
|
#: users/templates/users/user_list.html:210
|
||||||
#: users/templates/users/user_list.html:211
|
#: users/templates/users/user_list.html:215
|
||||||
msgid "User Delete"
|
msgid "User Delete"
|
||||||
msgstr "删除"
|
msgstr "删除"
|
||||||
|
|
||||||
#: users/templates/users/user_list.html:210
|
#: users/templates/users/user_list.html:214
|
||||||
msgid "User Deleting failed."
|
msgid "User Deleting failed."
|
||||||
msgstr "用户删除失败"
|
msgstr "用户删除失败"
|
||||||
|
|
||||||
|
@ -3826,8 +3826,8 @@ msgstr "安装完成后点击下一步进入绑定页面(如已安装,直接
|
||||||
msgid "Administrator Settings force MFA login"
|
msgid "Administrator Settings force MFA login"
|
||||||
msgstr "管理员设置强制使用MFA登录"
|
msgstr "管理员设置强制使用MFA登录"
|
||||||
|
|
||||||
#: users/templates/users/user_profile.html:116 users/views/user.py:230
|
#: users/templates/users/user_profile.html:116 users/views/user.py:229
|
||||||
#: users/views/user.py:284
|
#: users/views/user.py:283
|
||||||
msgid "User groups"
|
msgid "User groups"
|
||||||
msgstr "用户组"
|
msgstr "用户组"
|
||||||
|
|
||||||
|
@ -4003,22 +4003,18 @@ msgstr ""
|
||||||
" </br>\n"
|
" </br>\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: users/utils.py:162
|
#: users/utils.py:148
|
||||||
msgid "User not exist"
|
msgid "User not exist"
|
||||||
msgstr "用户不存在"
|
msgstr "用户不存在"
|
||||||
|
|
||||||
#: users/utils.py:164
|
#: users/utils.py:150
|
||||||
msgid "Disabled or expired"
|
msgid "Disabled or expired"
|
||||||
msgstr "禁用或失效"
|
msgstr "禁用或失效"
|
||||||
|
|
||||||
#: users/utils.py:177
|
#: users/utils.py:163
|
||||||
msgid "Password or SSH public key invalid"
|
msgid "Password or SSH public key invalid"
|
||||||
msgstr "密码或密钥不合法"
|
msgstr "密码或密钥不合法"
|
||||||
|
|
||||||
#: users/utils.py:300 users/utils.py:310
|
|
||||||
msgid "Bit"
|
|
||||||
msgstr " 位"
|
|
||||||
|
|
||||||
#: users/views/group.py:29
|
#: users/views/group.py:29
|
||||||
msgid "User group list"
|
msgid "User group list"
|
||||||
msgstr "用户组列表"
|
msgstr "用户组列表"
|
||||||
|
@ -4031,11 +4027,11 @@ msgstr "更新用户组"
|
||||||
msgid "User group granted asset"
|
msgid "User group granted asset"
|
||||||
msgstr "用户组授权资产"
|
msgstr "用户组授权资产"
|
||||||
|
|
||||||
#: users/views/login.py:70
|
#: users/views/login.py:69
|
||||||
msgid "Please enable cookies and try again."
|
msgid "Please enable cookies and try again."
|
||||||
msgstr "设置你的浏览器支持cookie"
|
msgstr "设置你的浏览器支持cookie"
|
||||||
|
|
||||||
#: users/views/login.py:180 users/views/user.py:526 users/views/user.py:551
|
#: users/views/login.py:179 users/views/user.py:524 users/views/user.py:549
|
||||||
msgid "MFA code invalid, or ntp sync server time"
|
msgid "MFA code invalid, or ntp sync server time"
|
||||||
msgstr "MFA验证码不正确,或者服务器端时间不对"
|
msgstr "MFA验证码不正确,或者服务器端时间不对"
|
||||||
|
|
||||||
|
@ -4068,67 +4064,67 @@ msgstr "重置密码成功"
|
||||||
msgid "Reset password success, return to login page"
|
msgid "Reset password success, return to login page"
|
||||||
msgstr "重置密码成功,返回到登录页面"
|
msgstr "重置密码成功,返回到登录页面"
|
||||||
|
|
||||||
#: users/views/login.py:277 users/views/login.py:290
|
#: users/views/login.py:272 users/views/login.py:288
|
||||||
msgid "Token invalid or expired"
|
msgid "Token invalid or expired"
|
||||||
msgstr "Token错误或失效"
|
msgstr "Token错误或失效"
|
||||||
|
|
||||||
#: users/views/login.py:286
|
#: users/views/login.py:284
|
||||||
msgid "Password not same"
|
msgid "Password not same"
|
||||||
msgstr "密码不一致"
|
msgstr "密码不一致"
|
||||||
|
|
||||||
#: users/views/login.py:296 users/views/user.py:127 users/views/user.py:422
|
#: users/views/login.py:294 users/views/user.py:126 users/views/user.py:420
|
||||||
msgid "* Your password does not meet the requirements"
|
msgid "* Your password does not meet the requirements"
|
||||||
msgstr "* 您的密码不符合要求"
|
msgstr "* 您的密码不符合要求"
|
||||||
|
|
||||||
#: users/views/login.py:334
|
#: users/views/login.py:332
|
||||||
msgid "First login"
|
msgid "First login"
|
||||||
msgstr "首次登陆"
|
msgstr "首次登陆"
|
||||||
|
|
||||||
#: users/views/user.py:144
|
#: users/views/user.py:143
|
||||||
msgid "Bulk update user success"
|
msgid "Bulk update user success"
|
||||||
msgstr "批量更新用户成功"
|
msgstr "批量更新用户成功"
|
||||||
|
|
||||||
#: users/views/user.py:174
|
#: users/views/user.py:173
|
||||||
msgid "Bulk update user"
|
msgid "Bulk update user"
|
||||||
msgstr "批量更新用户"
|
msgstr "批量更新用户"
|
||||||
|
|
||||||
#: users/views/user.py:259
|
#: users/views/user.py:258
|
||||||
msgid "Invalid file."
|
msgid "Invalid file."
|
||||||
msgstr "文件不合法"
|
msgstr "文件不合法"
|
||||||
|
|
||||||
#: users/views/user.py:355
|
#: users/views/user.py:354
|
||||||
msgid "User granted assets"
|
msgid "User granted assets"
|
||||||
msgstr "用户授权资产"
|
msgstr "用户授权资产"
|
||||||
|
|
||||||
#: users/views/user.py:386
|
#: users/views/user.py:385
|
||||||
msgid "Profile setting"
|
msgid "Profile setting"
|
||||||
msgstr "个人信息设置"
|
msgstr "个人信息设置"
|
||||||
|
|
||||||
#: users/views/user.py:405
|
#: users/views/user.py:404
|
||||||
msgid "Password update"
|
msgid "Password update"
|
||||||
msgstr "密码更新"
|
msgstr "密码更新"
|
||||||
|
|
||||||
#: users/views/user.py:440
|
#: users/views/user.py:438
|
||||||
msgid "Public key update"
|
msgid "Public key update"
|
||||||
msgstr "密钥更新"
|
msgstr "密钥更新"
|
||||||
|
|
||||||
#: users/views/user.py:481
|
#: users/views/user.py:479
|
||||||
msgid "Password invalid"
|
msgid "Password invalid"
|
||||||
msgstr "用户名或密码无效"
|
msgstr "用户名或密码无效"
|
||||||
|
|
||||||
#: users/views/user.py:581
|
#: users/views/user.py:579
|
||||||
msgid "MFA enable success"
|
msgid "MFA enable success"
|
||||||
msgstr "MFA 绑定成功"
|
msgstr "MFA 绑定成功"
|
||||||
|
|
||||||
#: users/views/user.py:582
|
#: users/views/user.py:580
|
||||||
msgid "MFA enable success, return login page"
|
msgid "MFA enable success, return login page"
|
||||||
msgstr "MFA 绑定成功,返回到登录页面"
|
msgstr "MFA 绑定成功,返回到登录页面"
|
||||||
|
|
||||||
#: users/views/user.py:584
|
#: users/views/user.py:582
|
||||||
msgid "MFA disable success"
|
msgid "MFA disable success"
|
||||||
msgstr "MFA 解绑成功"
|
msgstr "MFA 解绑成功"
|
||||||
|
|
||||||
#: users/views/user.py:585
|
#: users/views/user.py:583
|
||||||
msgid "MFA disable success, return login page"
|
msgid "MFA disable success, return login page"
|
||||||
msgstr "MFA 解绑成功,返回登录页面"
|
msgstr "MFA 解绑成功,返回登录页面"
|
||||||
|
|
||||||
|
@ -4439,6 +4435,9 @@ msgstr "创建组织"
|
||||||
msgid "Update org"
|
msgid "Update org"
|
||||||
msgstr "更新组织"
|
msgstr "更新组织"
|
||||||
|
|
||||||
|
#~ msgid "Bit"
|
||||||
|
#~ msgstr " 位"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~| msgid "Delete succeed"
|
#~| msgid "Delete succeed"
|
||||||
#~ msgid "Delete success"
|
#~ msgid "Delete success"
|
||||||
|
|
Binary file not shown.
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-08-08 14:48+0800\n"
|
"POT-Creation-Date: 2018-11-21 19:14+0800\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -17,58 +17,58 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:158
|
#: static/js/jumpserver.js:168
|
||||||
msgid "Update is successful!"
|
msgid "Update is successful!"
|
||||||
msgstr "更新成功"
|
msgstr "更新成功"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:160
|
#: static/js/jumpserver.js:170
|
||||||
msgid "An unknown error occurred while updating.."
|
msgid "An unknown error occurred while updating.."
|
||||||
msgstr "更新时发生未知错误"
|
msgstr "更新时发生未知错误"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:205 static/js/jumpserver.js:247
|
#: static/js/jumpserver.js:236 static/js/jumpserver.js:273
|
||||||
#: static/js/jumpserver.js:252
|
#: static/js/jumpserver.js:276
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "错误"
|
msgstr "错误"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:205
|
#: static/js/jumpserver.js:236
|
||||||
msgid "Being used by the asset, please unbind the asset first."
|
msgid "Being used by the asset, please unbind the asset first."
|
||||||
msgstr "正在被资产使用中,请先解除资产绑定"
|
msgstr "正在被资产使用中,请先解除资产绑定"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:212 static/js/jumpserver.js:260
|
#: static/js/jumpserver.js:242 static/js/jumpserver.js:283
|
||||||
msgid "Delete the success"
|
msgid "Delete the success"
|
||||||
msgstr "删除成功"
|
msgstr "删除成功"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:219
|
#: static/js/jumpserver.js:248
|
||||||
msgid "Are you sure about deleting it?"
|
msgid "Are you sure about deleting it?"
|
||||||
msgstr "你确定删除吗 ?"
|
msgstr "你确定删除吗 ?"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:224 static/js/jumpserver.js:273
|
#: static/js/jumpserver.js:252 static/js/jumpserver.js:293
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "取消"
|
msgstr "取消"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:227 static/js/jumpserver.js:276
|
#: static/js/jumpserver.js:254 static/js/jumpserver.js:295
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "确认"
|
msgstr "确认"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:247
|
#: static/js/jumpserver.js:273
|
||||||
msgid ""
|
msgid ""
|
||||||
"The organization contains undeleted information. Please try again after "
|
"The organization contains undeleted information. Please try again after "
|
||||||
"deleting"
|
"deleting"
|
||||||
msgstr "组织中包含未删除信息,请删除后重试"
|
msgstr "组织中包含未删除信息,请删除后重试"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:252
|
#: static/js/jumpserver.js:276
|
||||||
msgid ""
|
msgid ""
|
||||||
"Do not perform this operation under this organization. Try again after "
|
"Do not perform this operation under this organization. Try again after "
|
||||||
"switching to another organization"
|
"switching to another organization"
|
||||||
msgstr "请勿在此组织下执行此操作,切换到其他组织后重试"
|
msgstr "请勿在此组织下执行此操作,切换到其他组织后重试"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:267
|
#: static/js/jumpserver.js:289
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please ensure that the following information in the organization has been "
|
"Please ensure that the following information in the organization has been "
|
||||||
"deleted"
|
"deleted"
|
||||||
msgstr "请确保组织内的以下信息已删除"
|
msgstr "请确保组织内的以下信息已删除"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:269
|
#: static/js/jumpserver.js:290
|
||||||
msgid ""
|
msgid ""
|
||||||
"User list、User group、Asset list、Domain list、Admin user、System user、"
|
"User list、User group、Asset list、Domain list、Admin user、System user、"
|
||||||
"Labels、Asset permission"
|
"Labels、Asset permission"
|
||||||
|
@ -76,32 +76,52 @@ msgstr ""
|
||||||
"用户列表、用户组、资产列表、网域列表、管理用户、系统用户、标签管理、资产授权"
|
"用户列表、用户组、资产列表、网域列表、管理用户、系统用户、标签管理、资产授权"
|
||||||
"规则"
|
"规则"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:311
|
#: static/js/jumpserver.js:329
|
||||||
msgid "Loading ..."
|
msgid "Loading ..."
|
||||||
msgstr "加载中 ..."
|
msgstr "加载中 ..."
|
||||||
|
|
||||||
#: static/js/jumpserver.js:313
|
#: static/js/jumpserver.js:330
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "搜索"
|
msgstr "搜索"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:317
|
#: static/js/jumpserver.js:333
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Selected item %d"
|
msgid "Selected item %d"
|
||||||
msgstr "选中 %d 项"
|
msgstr "选中 %d 项"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:322
|
#: static/js/jumpserver.js:337
|
||||||
msgid "Per page _MENU_"
|
msgid "Per page _MENU_"
|
||||||
msgstr "每页 _MENU_"
|
msgstr "每页 _MENU_"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:324
|
#: static/js/jumpserver.js:338
|
||||||
msgid ""
|
msgid ""
|
||||||
"Displays the results of items _START_ to _END_; A total of _TOTAL_ entries"
|
"Displays the results of items _START_ to _END_; A total of _TOTAL_ entries"
|
||||||
msgstr "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项"
|
msgstr "显示第 _START_ 至 _END_ 项结果; 总共 _TOTAL_ 项"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:328
|
#: static/js/jumpserver.js:341
|
||||||
msgid "No match"
|
msgid "No match"
|
||||||
msgstr "没有匹配项"
|
msgstr "没有匹配项"
|
||||||
|
|
||||||
#: static/js/jumpserver.js:330
|
#: static/js/jumpserver.js:342
|
||||||
msgid "No record"
|
msgid "No record"
|
||||||
msgstr "没有记录"
|
msgstr "没有记录"
|
||||||
|
|
||||||
|
#: static/js/jumpserver.js:701
|
||||||
|
msgid "Password minimum length {N} bits"
|
||||||
|
msgstr "密码最小长度 {N} 位"
|
||||||
|
|
||||||
|
#: static/js/jumpserver.js:702
|
||||||
|
msgid "Must contain capital letters"
|
||||||
|
msgstr "必须包含大写字母"
|
||||||
|
|
||||||
|
#: static/js/jumpserver.js:703
|
||||||
|
msgid "Must contain lowercase letters"
|
||||||
|
msgstr "必须包含小写字母"
|
||||||
|
|
||||||
|
#: static/js/jumpserver.js:704
|
||||||
|
msgid "Must contain numeric characters"
|
||||||
|
msgstr "必须包含数字字符"
|
||||||
|
|
||||||
|
#: static/js/jumpserver.js:705
|
||||||
|
msgid "Must contain special characters"
|
||||||
|
msgstr "必须包含特殊字符"
|
||||||
|
|
|
@ -101,7 +101,7 @@ class AssetPermissionUserView(AdminUserRequiredMixin,
|
||||||
ListView):
|
ListView):
|
||||||
template_name = 'perms/asset_permission_user.html'
|
template_name = 'perms/asset_permission_user.html'
|
||||||
context_object_name = 'asset_permission'
|
context_object_name = 'asset_permission'
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
object = None
|
object = None
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
@ -133,7 +133,7 @@ class AssetPermissionAssetView(AdminUserRequiredMixin,
|
||||||
ListView):
|
ListView):
|
||||||
template_name = 'perms/asset_permission_asset.html'
|
template_name = 'perms/asset_permission_asset.html'
|
||||||
context_object_name = 'asset_permission'
|
context_object_name = 'asset_permission'
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
object = None
|
object = None
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
|
@ -688,41 +688,69 @@ function setUrlParam(url, name, value) {
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Password check rules
|
||||||
|
var rules_short_map_id = {
|
||||||
|
'min': 'id_security_password_min_length',
|
||||||
|
'upper': 'id_security_password_upper_case',
|
||||||
|
'lower': 'id_security_password_lower_case',
|
||||||
|
'number': 'id_security_password_number',
|
||||||
|
'special': 'id_security_password_special_char'
|
||||||
|
};
|
||||||
|
|
||||||
|
var rules_id_map_label = {
|
||||||
|
'id_security_password_min_length': gettext('Password minimum length {N} bits'),
|
||||||
|
'id_security_password_upper_case': gettext('Must contain capital letters'),
|
||||||
|
'id_security_password_lower_case': gettext('Must contain lowercase letters'),
|
||||||
|
'id_security_password_number': gettext('Must contain numeric characters'),
|
||||||
|
'id_security_password_special_char': gettext('Must contain special characters')
|
||||||
|
};
|
||||||
|
|
||||||
|
function getRuleLabel(rule){
|
||||||
|
var label = '';
|
||||||
|
if (rule.key === rules_short_map_id['min']){
|
||||||
|
label = rules_id_map_label[rule.key].replace('{N}', rule.value)
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
label = rules_id_map_label[rule.key]
|
||||||
|
}
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
|
||||||
// 校验密码-改变规则颜色
|
// 校验密码-改变规则颜色
|
||||||
function checkPasswordRules(password, minLength) {
|
function checkPasswordRules(password, minLength) {
|
||||||
if (wordMinLength(password, minLength)) {
|
if (wordMinLength(password, minLength)) {
|
||||||
$('#rule_SECURITY_PASSWORD_MIN_LENGTH').css('color', 'green')
|
$('#'+rules_short_map_id['min']).css('color', 'green')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#rule_SECURITY_PASSWORD_MIN_LENGTH').css('color', '#908a8a')
|
$('#'+rules_short_map_id['min']).css('color', '#908a8a')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wordUpperCase(password)) {
|
if (wordUpperCase(password)) {
|
||||||
$('#rule_SECURITY_PASSWORD_UPPER_CASE').css('color', 'green');
|
$('#'+rules_short_map_id['upper']).css('color', 'green')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#rule_SECURITY_PASSWORD_UPPER_CASE').css('color', '#908a8a')
|
$('#'+rules_short_map_id['upper']).css('color', '#908a8a')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wordLowerCase(password)) {
|
if (wordLowerCase(password)) {
|
||||||
$('#rule_SECURITY_PASSWORD_LOWER_CASE').css('color', 'green')
|
$('#'+rules_short_map_id['lower']).css('color', 'green')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#rule_SECURITY_PASSWORD_LOWER_CASE').css('color', '#908a8a')
|
$('#'+rules_short_map_id['lower']).css('color', '#908a8a')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wordNumber(password)) {
|
if (wordNumber(password)) {
|
||||||
$('#rule_SECURITY_PASSWORD_NUMBER').css('color', 'green')
|
$('#'+rules_short_map_id['number']).css('color', 'green')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#rule_SECURITY_PASSWORD_NUMBER').css('color', '#908a8a')
|
$('#'+rules_short_map_id['number']).css('color', '#908a8a')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wordSpecialChar(password)) {
|
if (wordSpecialChar(password)) {
|
||||||
$('#rule_SECURITY_PASSWORD_SPECIAL_CHAR').css('color', 'green')
|
$('#'+rules_short_map_id['special']).css('color', 'green')
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#rule_SECURITY_PASSWORD_SPECIAL_CHAR').css('color', '#908a8a')
|
$('#'+rules_short_map_id['special']).css('color', '#908a8a')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,11 +777,12 @@ function wordSpecialChar(word) {
|
||||||
return word.match(/[`,~,!,@,#,\$,%,\^,&,\*,\(,\),\-,_,=,\+,\{,\},\[,\],\|,\\,;,',:,",\,,\.,<,>,\/,\?]+/)
|
return word.match(/[`,~,!,@,#,\$,%,\^,&,\*,\(,\),\-,_,=,\+,\{,\},\[,\],\|,\\,;,',:,",\,,\.,<,>,\/,\?]+/)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 显示弹窗密码规则
|
// 显示弹窗密码规则
|
||||||
function popoverPasswordRules(password_check_rules, $el) {
|
function popoverPasswordRules(password_check_rules, $el) {
|
||||||
var message = "";
|
var message = "";
|
||||||
jQuery.each(password_check_rules, function (idx, rules) {
|
jQuery.each(password_check_rules, function (idx, rule) {
|
||||||
message += "<li id=" + rules.id + " style='list-style-type:none;'> <i class='fa fa-check-circle-o' style='margin-right:10px;' ></i>" + rules.label + "</li>";
|
message += "<li id=" + rule.key + " style='list-style-type:none;'> <i class='fa fa-check-circle-o' style='margin-right:10px;' ></i>" + getRuleLabel(rule) + "</li>";
|
||||||
});
|
});
|
||||||
//$('#id_password_rules').html(message);
|
//$('#id_password_rules').html(message);
|
||||||
$el.html(message)
|
$el.html(message)
|
||||||
|
|
|
@ -9,7 +9,6 @@ from django.conf import settings
|
||||||
|
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from orgs.mixins import OrgModelMixin
|
from orgs.mixins import OrgModelMixin
|
||||||
from common.models import common_settings
|
|
||||||
from common.utils import get_command_storage_setting, get_replay_storage_setting
|
from common.utils import get_command_storage_setting, get_replay_storage_setting
|
||||||
from .backends.command.models import AbstractSessionCommand
|
from .backends.command.models import AbstractSessionCommand
|
||||||
|
|
||||||
|
@ -61,11 +60,11 @@ class Terminal(models.Model):
|
||||||
configs = {}
|
configs = {}
|
||||||
for k in dir(settings):
|
for k in dir(settings):
|
||||||
if k.startswith('TERMINAL'):
|
if k.startswith('TERMINAL'):
|
||||||
configs[k] = getattr(common_settings, k)
|
configs[k] = getattr(settings, k)
|
||||||
configs.update(self.get_common_storage())
|
configs.update(self.get_common_storage())
|
||||||
configs.update(self.get_replay_storage())
|
configs.update(self.get_replay_storage())
|
||||||
configs.update({
|
configs.update({
|
||||||
'SECURITY_MAX_IDLE_TIME': common_settings.SECURITY_MAX_IDLE_TIME
|
'SECURITY_MAX_IDLE_TIME': settings.SECURITY_MAX_IDLE_TIME
|
||||||
})
|
})
|
||||||
return configs
|
return configs
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ from django.utils import timezone
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
|
|
||||||
from common.utils import get_signer, date_expired_default
|
from common.utils import get_signer, date_expired_default
|
||||||
from common.models import common_settings
|
|
||||||
from orgs.mixins import OrgManager
|
from orgs.mixins import OrgManager
|
||||||
from orgs.utils import current_org
|
from orgs.utils import current_org
|
||||||
|
|
||||||
|
@ -284,7 +283,7 @@ class User(AbstractUser):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def otp_force_enabled(self):
|
def otp_force_enabled(self):
|
||||||
if common_settings.SECURITY_MFA_AUTH:
|
if settings.SECURITY_MFA_AUTH:
|
||||||
return True
|
return True
|
||||||
return self.otp_level == 2
|
return self.otp_level == 2
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
container = $('#container'),
|
container = $('#container'),
|
||||||
progress = $('#id_progress'),
|
progress = $('#id_progress'),
|
||||||
password_check_rules = {{ password_check_rules|safe }},
|
password_check_rules = {{ password_check_rules|safe }},
|
||||||
minLength = {{ min_length }},
|
minLength = 6,
|
||||||
top = 146, left = 170,
|
top = 146, left = 170,
|
||||||
i18n_fallback = {
|
i18n_fallback = {
|
||||||
"veryWeak": "{% trans 'Very weak' %}",
|
"veryWeak": "{% trans 'Very weak' %}",
|
||||||
|
@ -110,6 +110,12 @@
|
||||||
"veryStrong": "{% trans 'Very strong' %}"
|
"veryStrong": "{% trans 'Very strong' %}"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jQuery.each(password_check_rules, function (idx, rules) {
|
||||||
|
if(rules.key === 'id_security_password_min_length'){
|
||||||
|
minLength = rules.value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 初始化popover
|
// 初始化popover
|
||||||
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
|
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
container = $('#container'),
|
container = $('#container'),
|
||||||
progress = $('#id_progress'),
|
progress = $('#id_progress'),
|
||||||
password_check_rules = {{ password_check_rules|safe }},
|
password_check_rules = {{ password_check_rules|safe }},
|
||||||
minLength = {{ min_length }},
|
minLength = 6,
|
||||||
top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) - 10 + 34,
|
top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) - 10 + 34,
|
||||||
left = 377,
|
left = 377,
|
||||||
i18n_fallback = {
|
i18n_fallback = {
|
||||||
|
@ -104,6 +104,12 @@
|
||||||
"veryStrong": "{% trans 'Very strong' %}"
|
"veryStrong": "{% trans 'Very strong' %}"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jQuery.each(password_check_rules, function (idx, rules) {
|
||||||
|
if(rules.key === 'id_security_password_min_length'){
|
||||||
|
minLength = rules.value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 初始化popover
|
// 初始化popover
|
||||||
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
|
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
container = $('#container'),
|
container = $('#container'),
|
||||||
progress = $('#id_progress'),
|
progress = $('#id_progress'),
|
||||||
password_check_rules = {{ password_check_rules|safe }},
|
password_check_rules = {{ password_check_rules|safe }},
|
||||||
minLength = {{ min_length }},
|
minLength = 6,
|
||||||
top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) - 10 + 34,
|
top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) - 10 + 34,
|
||||||
left = 377,
|
left = 377,
|
||||||
i18n_fallback = {
|
i18n_fallback = {
|
||||||
|
@ -39,6 +39,12 @@
|
||||||
"veryStrong": "{% trans 'Very strong' %}"
|
"veryStrong": "{% trans 'Very strong' %}"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jQuery.each(password_check_rules, function (idx, rules) {
|
||||||
|
if(rules.key === 'id_security_password_min_length'){
|
||||||
|
minLength = rules.value
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 初始化popover
|
// 初始化popover
|
||||||
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
|
initPopover(container, progress, idPassword, el, password_check_rules, i18n_fallback);
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ from django.core.cache import cache
|
||||||
|
|
||||||
from common.tasks import send_mail_async
|
from common.tasks import send_mail_async
|
||||||
from common.utils import reverse, get_object_or_none
|
from common.utils import reverse, get_object_or_none
|
||||||
from common.models import common_settings, Setting
|
|
||||||
from common.forms import SecuritySettingForm
|
from common.forms import SecuritySettingForm
|
||||||
|
from common.models import Setting
|
||||||
from .models import User, LoginLog
|
from .models import User, LoginLog
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,56 +275,27 @@ def check_otp_code(otp_secret_key, otp_code):
|
||||||
|
|
||||||
def get_password_check_rules():
|
def get_password_check_rules():
|
||||||
check_rules = []
|
check_rules = []
|
||||||
min_length = settings.DEFAULT_PASSWORD_MIN_LENGTH
|
for rule in settings.SECURITY_PASSWORD_RULES:
|
||||||
min_name = 'SECURITY_PASSWORD_MIN_LENGTH'
|
key = "id_{}".format(rule.lower())
|
||||||
base_filed = SecuritySettingForm.base_fields
|
value = getattr(settings, rule)
|
||||||
password_setting = Setting.objects.filter(name__startswith='SECURITY_PASSWORD')
|
if not value:
|
||||||
|
continue
|
||||||
if not password_setting:
|
check_rules.append({'key': key, 'value': int(value)})
|
||||||
# 用户还没有设置过密码校验规则
|
return check_rules
|
||||||
label = base_filed.get(min_name).label
|
|
||||||
label += ' ' + str(min_length) + _('Bit')
|
|
||||||
id = 'rule_' + min_name
|
|
||||||
rules = {'id': id, 'label': label}
|
|
||||||
check_rules.append(rules)
|
|
||||||
|
|
||||||
for setting in password_setting:
|
|
||||||
if setting.cleaned_value:
|
|
||||||
id = 'rule_' + setting.name
|
|
||||||
label = base_filed.get(setting.name).label
|
|
||||||
if setting.name == min_name:
|
|
||||||
label += str(setting.cleaned_value) + _('Bit')
|
|
||||||
min_length = setting.cleaned_value
|
|
||||||
rules = {'id': id, 'label': label}
|
|
||||||
check_rules.append(rules)
|
|
||||||
|
|
||||||
return check_rules, min_length
|
|
||||||
|
|
||||||
|
|
||||||
def check_password_rules(password):
|
def check_password_rules(password):
|
||||||
min_field_name = 'SECURITY_PASSWORD_MIN_LENGTH'
|
pattern = r"^"
|
||||||
upper_field_name = 'SECURITY_PASSWORD_UPPER_CASE'
|
if settings.SECURITY_PASSWORD_UPPER_CASE:
|
||||||
lower_field_name = 'SECURITY_PASSWORD_LOWER_CASE'
|
pattern += '(?=.*[A-Z])'
|
||||||
number_field_name = 'SECURITY_PASSWORD_NUMBER'
|
if settings.SECURITY_PASSWORD_LOWER_CASE:
|
||||||
special_field_name = 'SECURITY_PASSWORD_SPECIAL_CHAR'
|
pattern += '(?=.*[a-z])'
|
||||||
min_length = getattr(common_settings, min_field_name)
|
if settings.SECURITY_PASSWORD_NUMBER:
|
||||||
|
pattern += '(?=.*\d)'
|
||||||
password_setting = Setting.objects.filter(name__startswith='SECURITY_PASSWORD')
|
if settings.SECURITY_PASSWORD_SPECIAL_CHAR:
|
||||||
if not password_setting:
|
pattern += '(?=.*[`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'\",\.<>\/\?])'
|
||||||
pattern = r"^.{" + str(min_length) + ",}$"
|
pattern += '[a-zA-Z\d`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'\",\.<>\/\?]'
|
||||||
else:
|
pattern += '.{' + str(settings.SECURITY_PASSWORD_MIN_LENGTH-1) + ',}$'
|
||||||
pattern = r"^"
|
|
||||||
for setting in password_setting:
|
|
||||||
if setting.cleaned_value and setting.name == upper_field_name:
|
|
||||||
pattern += '(?=.*[A-Z])'
|
|
||||||
elif setting.cleaned_value and setting.name == lower_field_name:
|
|
||||||
pattern += '(?=.*[a-z])'
|
|
||||||
elif setting.cleaned_value and setting.name == number_field_name:
|
|
||||||
pattern += '(?=.*\d)'
|
|
||||||
elif setting.cleaned_value and setting.name == special_field_name:
|
|
||||||
pattern += '(?=.*[`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'",\.<>\/\?])'
|
|
||||||
pattern += '[a-zA-Z\d`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'",\.<>\/\?]'
|
|
||||||
|
|
||||||
match_obj = re.match(pattern, password)
|
match_obj = re.match(pattern, password)
|
||||||
return bool(match_obj)
|
return bool(match_obj)
|
||||||
|
|
||||||
|
@ -339,7 +310,7 @@ def increase_login_failed_count(username, ip):
|
||||||
count = cache.get(key_limit)
|
count = cache.get(key_limit)
|
||||||
count = count + 1 if count else 1
|
count = count + 1 if count else 1
|
||||||
|
|
||||||
limit_time = common_settings.SECURITY_LOGIN_LIMIT_TIME
|
limit_time = settings.SECURITY_LOGIN_LIMIT_TIME
|
||||||
cache.set(key_limit, count, int(limit_time)*60)
|
cache.set(key_limit, count, int(limit_time)*60)
|
||||||
|
|
||||||
|
|
||||||
|
@ -355,8 +326,8 @@ def is_block_login(username, ip):
|
||||||
key_block = key_prefix_block.format(username)
|
key_block = key_prefix_block.format(username)
|
||||||
count = cache.get(key_limit, 0)
|
count = cache.get(key_limit, 0)
|
||||||
|
|
||||||
limit_count = common_settings.SECURITY_LOGIN_LIMIT_COUNT
|
limit_count = settings.SECURITY_LOGIN_LIMIT_COUNT
|
||||||
limit_time = common_settings.SECURITY_LOGIN_LIMIT_TIME
|
limit_time = settings.SECURITY_LOGIN_LIMIT_TIME
|
||||||
|
|
||||||
if count >= limit_count:
|
if count >= limit_count:
|
||||||
cache.set(key_block, 1, int(limit_time)*60)
|
cache.set(key_block, 1, int(limit_time)*60)
|
||||||
|
|
|
@ -17,11 +17,10 @@ from django.views.decorators.csrf import csrf_protect
|
||||||
from django.views.decorators.debug import sensitive_post_parameters
|
from django.views.decorators.debug import sensitive_post_parameters
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
from django.views.generic.edit import FormView
|
from django.views.generic.edit import FormView
|
||||||
from formtools.wizard.views import SessionWizardView
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from formtools.wizard.views import SessionWizardView
|
||||||
|
|
||||||
from common.utils import get_object_or_none, get_request_ip
|
from common.utils import get_object_or_none, get_request_ip
|
||||||
from common.models import common_settings
|
|
||||||
from ..models import User, LoginLog
|
from ..models import User, LoginLog
|
||||||
from ..utils import send_reset_password_mail, check_otp_code, \
|
from ..utils import send_reset_password_mail, check_otp_code, \
|
||||||
redirect_user_first_login_or_index, get_user_or_tmp_user, \
|
redirect_user_first_login_or_index, get_user_or_tmp_user, \
|
||||||
|
@ -269,13 +268,11 @@ class UserResetPasswordView(TemplateView):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
token = request.GET.get('token')
|
token = request.GET.get('token')
|
||||||
user = User.validate_reset_token(token)
|
user = User.validate_reset_token(token)
|
||||||
|
|
||||||
check_rules, min_length = get_password_check_rules()
|
|
||||||
password_rules = {'password_check_rules': check_rules, 'min_length': min_length}
|
|
||||||
kwargs.update(password_rules)
|
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
kwargs.update({'errors': _('Token invalid or expired')})
|
kwargs.update({'errors': _('Token invalid or expired')})
|
||||||
|
else:
|
||||||
|
check_rules = get_password_check_rules()
|
||||||
|
kwargs.update({'password_check_rules': check_rules})
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
@ -326,7 +323,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
|
||||||
user.is_public_key_valid = True
|
user.is_public_key_valid = True
|
||||||
user.save()
|
user.save()
|
||||||
context = {
|
context = {
|
||||||
'user_guide_url': common_settings.USER_GUIDE_URL
|
'user_guide_url': settings.USER_GUIDE_URL
|
||||||
}
|
}
|
||||||
return render(self.request, 'users/first_login_done.html', context)
|
return render(self.request, 'users/first_login_done.html', context)
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth import authenticate, login as auth_login
|
from django.contrib.auth import authenticate, login as auth_login
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
from django.conf import settings
|
||||||
from django.http import HttpResponse, JsonResponse
|
from django.http import HttpResponse, JsonResponse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.urls import reverse_lazy, reverse
|
from django.urls import reverse_lazy, reverse
|
||||||
|
@ -33,7 +34,6 @@ from django.contrib.auth import logout as auth_logout
|
||||||
from common.const import create_success_msg, update_success_msg
|
from common.const import create_success_msg, update_success_msg
|
||||||
from common.mixins import JSONResponseMixin
|
from common.mixins import JSONResponseMixin
|
||||||
from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen
|
from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen
|
||||||
from common.models import Setting, common_settings
|
|
||||||
from common.permissions import AdminUserRequiredMixin
|
from common.permissions import AdminUserRequiredMixin
|
||||||
from orgs.utils import current_org
|
from orgs.utils import current_org
|
||||||
from .. import forms
|
from .. import forms
|
||||||
|
@ -106,12 +106,11 @@ class UserUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView):
|
||||||
success_message = update_success_msg
|
success_message = update_success_msg
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
check_rules, min_length = get_password_check_rules()
|
check_rules = get_password_check_rules()
|
||||||
context = {
|
context = {
|
||||||
'app': _('Users'),
|
'app': _('Users'),
|
||||||
'action': _('Update user'),
|
'action': _('Update user'),
|
||||||
'password_check_rules': check_rules,
|
'password_check_rules': check_rules,
|
||||||
'min_length': min_length
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
@ -362,7 +361,7 @@ class UserProfileView(LoginRequiredMixin, TemplateView):
|
||||||
template_name = 'users/user_profile.html'
|
template_name = 'users/user_profile.html'
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
mfa_setting = common_settings.SECURITY_MFA_AUTH
|
mfa_setting = settings.SECURITY_MFA_AUTH
|
||||||
context = {
|
context = {
|
||||||
'action': _('Profile'),
|
'action': _('Profile'),
|
||||||
'mfa_setting': mfa_setting if mfa_setting is not None else False,
|
'mfa_setting': mfa_setting if mfa_setting is not None else False,
|
||||||
|
@ -399,12 +398,11 @@ class UserPasswordUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
return self.request.user
|
return self.request.user
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
check_rules, min_length = get_password_check_rules()
|
check_rules = get_password_check_rules()
|
||||||
context = {
|
context = {
|
||||||
'app': _('Users'),
|
'app': _('Users'),
|
||||||
'action': _('Password update'),
|
'action': _('Password update'),
|
||||||
'password_check_rules': check_rules,
|
'password_check_rules': check_rules,
|
||||||
'min_length': min_length,
|
|
||||||
}
|
}
|
||||||
kwargs.update(context)
|
kwargs.update(context)
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
jumpserver.config
|
jumpserver.config
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
@ -13,48 +15,63 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
# Use it to encrypt or decrypt data
|
"""
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
Jumpserver Config File
|
||||||
SECRET_KEY = os.environ.get('SECRET_KEY') or '2vym+ky!997d5kkcc64mnz06y1mmui3lut#(^wd=%s_qj$1%x'
|
Jumpserver 配置文件
|
||||||
|
|
||||||
# Django security setting, if your disable debug model, you should setting that
|
Jumpserver use this config for drive django framework running,
|
||||||
ALLOWED_HOSTS = ['*']
|
You can set is value or set the same envirment value,
|
||||||
|
Jumpserver look for config order: file => env => default
|
||||||
|
|
||||||
|
Jumpserver使用配置来驱动Django框架的运行,
|
||||||
|
你可以在该文件中设置,或者设置同样名称的环境变量,
|
||||||
|
Jumpserver使用配置的顺序: 文件 => 环境变量 => 默认值
|
||||||
|
"""
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
# 加密秘钥 生产环境中请修改为随机字符串,请勿外泄
|
||||||
|
SECRET_KEY = '2vym+ky!997d5kkcc64mnz06y1mmui3lut#(^wd=%s_qj$1%x'
|
||||||
|
|
||||||
# Development env open this, when error occur display the full process track, Production disable it
|
# Development env open this, when error occur display the full process track, Production disable it
|
||||||
DEBUG = os.environ.get("DEBUG") or True
|
# DEBUG 模式 开启DEBUG后遇到错误时可以看到更多日志
|
||||||
|
# DEBUG = True
|
||||||
|
|
||||||
# DEBUG, INFO, WARNING, ERROR, CRITICAL can set. See https://docs.djangoproject.com/en/1.10/topics/logging/
|
# DEBUG, INFO, WARNING, ERROR, CRITICAL can set. See https://docs.djangoproject.com/en/1.10/topics/logging/
|
||||||
LOG_LEVEL = os.environ.get("LOG_LEVEL") or 'DEBUG'
|
# 日志级别
|
||||||
LOG_DIR = os.path.join(BASE_DIR, 'logs')
|
# LOG_LEVEL = 'DEBUG'
|
||||||
|
# LOG_DIR = os.path.join(BASE_DIR, 'logs')
|
||||||
|
|
||||||
# Database setting, Support sqlite3, mysql, postgres ....
|
# Database setting, Support sqlite3, mysql, postgres ....
|
||||||
|
# 数据库设置
|
||||||
# See https://docs.djangoproject.com/en/1.10/ref/settings/#databases
|
# See https://docs.djangoproject.com/en/1.10/ref/settings/#databases
|
||||||
|
|
||||||
# SQLite setting:
|
# SQLite setting:
|
||||||
DB_ENGINE = 'sqlite3'
|
# 使用单文件sqlite数据库
|
||||||
DB_NAME = os.path.join(BASE_DIR, 'data', 'db.sqlite3')
|
# DB_ENGINE = 'sqlite3'
|
||||||
|
# DB_NAME = os.path.join(BASE_DIR, 'data', 'db.sqlite3')
|
||||||
|
|
||||||
# MySQL or postgres setting like:
|
# MySQL or postgres setting like:
|
||||||
# DB_ENGINE = os.environ.get("DB_ENGINE") or 'mysql'
|
# 使用Mysql作为数据库
|
||||||
# DB_HOST = os.environ.get("DB_HOST") or '127.0.0.1'
|
DB_ENGINE = 'mysql'
|
||||||
# DB_PORT = os.environ.get("DB_PORT") or 3306
|
DB_HOST = '127.0.0.1'
|
||||||
# DB_USER = os.environ.get("DB_USER") or 'jumpserver'
|
DB_PORT = 3306
|
||||||
# DB_PASSWORD = os.environ.get("DB_PASSWORD") or 'weakPassword'
|
DB_USER = 'jumpserver'
|
||||||
# DB_NAME = os.environ.get("DB_NAME") or 'jumpserver'
|
DB_PASSWORD = ''
|
||||||
|
DB_NAME = 'jumpserver'
|
||||||
|
|
||||||
# When Django start it will bind this host and port
|
# When Django start it will bind this host and port
|
||||||
# ./manage.py runserver 127.0.0.1:8080
|
# ./manage.py runserver 127.0.0.1:8080
|
||||||
|
# 运行时绑定端口
|
||||||
HTTP_BIND_HOST = '0.0.0.0'
|
HTTP_BIND_HOST = '0.0.0.0'
|
||||||
HTTP_LISTEN_PORT = 8080
|
HTTP_LISTEN_PORT = 8080
|
||||||
|
|
||||||
# Use Redis as broker for celery and web socket
|
# Use Redis as broker for celery and web socket
|
||||||
REDIS_HOST = os.environ.get("REDIS_HOST") or '127.0.0.1'
|
# Redis配置
|
||||||
REDIS_PORT = os.environ.get("REDIS_PORT") or 6379
|
REDIS_HOST = '127.0.0.1'
|
||||||
REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD") or ''
|
REDIS_PORT = 6379
|
||||||
REDIS_DB_CELERY = os.environ.get('REDIS_DB') or 3
|
REDIS_PASSWORD = ''
|
||||||
REDIS_DB_CACHE = os.environ.get('REDIS_DB') or 4
|
|
||||||
|
|
||||||
# Use OpenID authorization
|
# Use OpenID authorization
|
||||||
|
# 使用OpenID 来进行认证设置
|
||||||
# BASE_SITE_URL = 'http://localhost:8080'
|
# BASE_SITE_URL = 'http://localhost:8080'
|
||||||
# AUTH_OPENID = False # True or False
|
# AUTH_OPENID = False # True or False
|
||||||
# AUTH_OPENID_SERVER_URL = 'https://openid-auth-server.com/'
|
# AUTH_OPENID_SERVER_URL = 'https://openid-auth-server.com/'
|
||||||
|
|
Loading…
Reference in New Issue