from django.conf import settings from django.db import models from django.utils.translation import gettext_lazy as _ from common.db.models import ChoicesMixin from common.decorators import cached_method from .base import FillType __all__ = ['Protocol'] class Protocol(ChoicesMixin, models.TextChoices): ssh = 'ssh', 'SSH' sftp = 'sftp', 'SFTP' rdp = 'rdp', 'RDP' telnet = 'telnet', 'Telnet' vnc = 'vnc', 'VNC' winrm = 'winrm', 'WinRM' mysql = 'mysql', 'MySQL' mariadb = 'mariadb', 'MariaDB' oracle = 'oracle', 'Oracle' postgresql = 'postgresql', 'PostgreSQL' sqlserver = 'sqlserver', 'SQLServer' db2 = 'db2', 'DB2' dameng = 'dameng', 'Dameng' clickhouse = 'clickhouse', 'ClickHouse' redis = 'redis', 'Redis' mongodb = 'mongodb', 'MongoDB' k8s = 'k8s', 'K8s' http = 'http', 'HTTP(s)' chatgpt = 'chatgpt', 'ChatGPT' @classmethod def device_protocols(cls): return { cls.ssh: { 'port': 22, 'secret_types': ['password', 'ssh_key'], 'setting': { 'old_ssh_version': { 'type': 'bool', 'default': False, 'label': _('Old SSH version'), 'help_text': _('Old SSH version like openssh 5.x or 6.x') }, 'nc': { 'type': 'bool', 'default': False, 'label': 'Netcat (nc)', 'help_text': _('Netcat help text') } } }, cls.sftp: { 'port': 22, 'secret_types': ['password', 'ssh_key'], 'setting': { 'sftp_home': { 'type': 'str', 'default': '/tmp', 'label': _('SFTP root'), 'help_text': _( 'SFTP root directory, Support variable:
' '- ${ACCOUNT} The connected account username
' '- ${HOME} The home directory of the connected account
' '- ${USER} The username of the user' ) } } }, cls.rdp: { 'port': 3389, 'secret_types': ['password'], 'setting': { 'console': { 'type': 'bool', 'default': False, 'label': _('Console'), 'help_text': _("Connect to console session") }, 'security': { 'type': 'choice', 'choices': [('any', _('Any')), ('rdp', 'RDP'), ('tls', 'TLS'), ('nla', 'NLA')], 'default': 'any', 'label': _('Security'), 'help_text': _("Security layer to use for the connection:
" "Any
" "Automatically select the security mode based on the security protocols " "supported by both the client and the server
" "RDP
" "Legacy RDP encryption. This mode is generally only used for older Windows " "servers or in cases where a standard Windows login screen is desired
" "TLS
" "RDP authentication and encryption implemented via TLS.
" "NLA
" "This mode uses TLS encryption and requires the username and password " "to be given in advance") }, 'ad_domain': { 'type': 'str', 'required': False, 'default': '', 'label': _('AD domain') } } }, cls.vnc: { 'port': 5900, 'secret_types': ['password'], }, cls.telnet: { 'port': 23, 'secret_types': ['password'], 'setting': { 'username_prompt': { 'type': 'str', 'default': 'username:|login:', 'label': _('Username prompt'), 'help_text': _('We will send username when we see this prompt') }, 'password_prompt': { 'type': 'str', 'default': 'password:', 'label': _('Password prompt'), 'help_text': _('We will send password when we see this prompt') }, 'success_prompt': { 'type': 'str', 'default': 'success|成功|#|>|\$', 'label': _('Success prompt'), 'help_text': _('We will consider login success when we see this prompt') } } }, cls.winrm: { 'port': 5985, 'secret_types': ['password'], 'setting': { 'use_ssl': { 'type': 'bool', 'default': False, 'label': _('Use SSL') }, } }, } @classmethod def database_protocols(cls): return { cls.mysql: { 'port': 3306, 'setting': {}, 'required': True, 'secret_types': ['password'], }, cls.mariadb: { 'port': 3306, 'required': True, 'secret_types': ['password'], }, cls.postgresql: { 'port': 5432, 'required': True, 'secret_types': ['password'], 'xpack': True }, cls.oracle: { 'port': 1521, 'required': True, 'secret_types': ['password'], 'xpack': True, 'setting': { 'sysdba': { 'type': 'bool', 'default': False, 'label': _('SYSDBA'), 'help_text': _('Connect as SYSDBA') }, } }, cls.sqlserver: { 'port': 1433, 'required': True, 'secret_types': ['password'], 'xpack': True, 'setting': { 'version': { 'type': 'choice', 'choices': [('>=2014', '>= 2014'), ('<2014', '< 2014')], 'default': '>=2014', 'label': _('Version'), 'help_text': _('SQL Server version, Different versions have different connection drivers') } } }, cls.db2: { 'port': 5000, 'required': True, 'secret_types': ['password'], 'xpack': True, }, cls.dameng: { 'port': 5236, 'required': True, 'secret_types': ['password'], 'xpack': True, }, cls.clickhouse: { 'port': 9000, 'required': True, 'secret_types': ['password'], 'xpack': True, }, cls.mongodb: { 'port': 27017, 'required': True, 'secret_types': ['password'], 'setting': { 'auth_source': { 'type': 'str', 'default': 'admin', 'label': _('Auth source'), 'help_text': _('The database to authenticate against') }, 'connection_options': { 'type': 'str', 'default': '', 'label': _('Connect options'), 'help_text': _('The connection specific options eg. retryWrites=false&retryReads=false') } } }, cls.redis: { 'port': 6379, 'required': True, 'secret_types': ['password'], 'setting': { 'auth_username': { 'type': 'bool', 'default': False, 'label': _('Auth username') }, } }, } @classmethod def cloud_protocols(cls): return { cls.k8s: { 'port': 443, 'port_from_addr': True, 'required': True, 'secret_types': ['token'], }, cls.http: { 'port': 80, 'port_from_addr': True, 'secret_types': ['password'], 'setting': { 'safe_mode': { 'type': 'bool', 'default': False, 'label': _('Safe mode'), 'help_text': _( 'When safe mode is enabled, some operations will be disabled, such as: ' 'New tab, right click, visit other website, etc.' ) }, 'autofill': { 'label': _('Autofill'), 'type': 'choice', 'choices': FillType.choices, 'default': 'basic', }, 'username_selector': { 'type': 'str', 'default': 'name=username', 'label': _('Username selector') }, 'password_selector': { 'type': 'str', 'default': 'name=password', 'label': _('Password selector') }, 'submit_selector': { 'type': 'str', 'default': 'type=submit', 'label': _('Submit selector') }, 'script': { 'type': 'text', 'default': [], 'label': _('Script'), } } }, } @classmethod def gpt_protocols(cls): protocols = { cls.chatgpt: { 'port': 443, 'required': True, 'port_from_addr': True, 'secret_types': ['api_key'], 'setting': { 'api_mode': { 'type': 'choice', 'default': 'gpt-4o-mini', 'label': _('API mode'), 'choices': [ ('gpt-4o-mini', 'GPT-4o-mini'), ('gpt-4o', 'GPT-4o'), ('gpt-4-turbo', 'GPT-4 Turbo'), ] } } } } return protocols @classmethod @cached_method(ttl=600) def settings(cls): return { **cls.device_protocols(), **cls.database_protocols(), **cls.cloud_protocols(), **cls.gpt_protocols(), } @classmethod @cached_method(ttl=600) def protocols(cls): protocols = [] xpack_enabled = settings.XPACK_ENABLED for protocol, config in cls.settings().items(): if not xpack_enabled and config.get('xpack', False): continue protocols.append(protocol) return protocols @classmethod @cached_method(ttl=600) def xpack_protocols(cls): return [ protocol for protocol, config in cls.settings().items() if config.get('xpack', False) ] @classmethod def protocol_secret_types(cls): configs = cls.settings() return { protocol: configs[protocol]['secret_types'] or ['password'] for protocol in configs }