mirror of https://github.com/huashengdun/webssh
add proxy
parent
1cf19c7186
commit
b60acbaf00
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (webssh)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/webssh.iml" filepath="$PROJECT_DIR$/.idea/webssh.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
9
|
||||||
|
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
9
|
||||||
|
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="SonarLintModuleSettings">
|
||||||
|
<option name="uniqueId" value="3fc80e5d-f723-4353-8cca-79f0f3561461" />
|
||||||
|
</component>
|
||||||
|
</module>
|
|
@ -0,0 +1,113 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AutoImportSettings">
|
||||||
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
|
</component>
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="4c3fa67e-67e3-4d45-a581-de095d94f3ad" name="Changes" comment="">
|
||||||
|
<change beforePath="$PROJECT_DIR$/webssh/handler.py" beforeDir="false" afterPath="$PROJECT_DIR$/webssh/handler.py" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/webssh/static/js/main.js" beforeDir="false" afterPath="$PROJECT_DIR$/webssh/static/js/main.js" afterDir="false" />
|
||||||
|
</list>
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
<component name="MarkdownSettingsMigration">
|
||||||
|
<option name="stateVersion" value="1" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectColorInfo">{
|
||||||
|
"associatedIndex": 7
|
||||||
|
}</component>
|
||||||
|
<component name="ProjectId" id="2W7ocgeQUfLJH8PAp9M4UcIppVE" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
<option name="showModules" value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
|
"keyToString": {
|
||||||
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||||
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
|
"WebServerToolWindowFactoryState": "false",
|
||||||
|
"git-widget-placeholder": "master",
|
||||||
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
|
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable",
|
||||||
|
"vue.rearranger.settings.migration": "true"
|
||||||
|
}
|
||||||
|
}]]></component>
|
||||||
|
<component name="RunManager" selected="Python.main">
|
||||||
|
<configuration name="main" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="webssh" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
|
</envs>
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/webssh" />
|
||||||
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
|
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/webssh/main.py" />
|
||||||
|
<option name="PARAMETERS" value="" />
|
||||||
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
|
<option name="EMULATE_TERMINAL" value="false" />
|
||||||
|
<option name="MODULE_MODE" value="false" />
|
||||||
|
<option name="REDIRECT_INPUT" value="false" />
|
||||||
|
<option name="INPUT_FILE" value="" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<configuration name="run" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="webssh" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="" />
|
||||||
|
<option name="PARENT_ENVS" value="true" />
|
||||||
|
<envs>
|
||||||
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
|
</envs>
|
||||||
|
<option name="SDK_HOME" value="" />
|
||||||
|
<option name="SDK_NAME" value="Python 3.9 (webssh)" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="IS_MODULE_SDK" value="false" />
|
||||||
|
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||||
|
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
|
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/run.py" />
|
||||||
|
<option name="PARAMETERS" value="" />
|
||||||
|
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||||
|
<option name="EMULATE_TERMINAL" value="false" />
|
||||||
|
<option name="MODULE_MODE" value="false" />
|
||||||
|
<option name="REDIRECT_INPUT" value="false" />
|
||||||
|
<option name="INPUT_FILE" value="" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
<recent_temporary>
|
||||||
|
<list>
|
||||||
|
<item itemvalue="Python.main" />
|
||||||
|
<item itemvalue="Python.run" />
|
||||||
|
</list>
|
||||||
|
</recent_temporary>
|
||||||
|
</component>
|
||||||
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="4c3fa67e-67e3-4d45-a581-de095d94f3ad" name="Changes" comment="" />
|
||||||
|
<created>1696093060393</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1696093060393</updated>
|
||||||
|
<workItem from="1696093062322" duration="3000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||||
|
<SUITE FILE_PATH="coverage/webssh$main.coverage" NAME="main Coverage Results" MODIFIED="1696500269853" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/webssh" />
|
||||||
|
<SUITE FILE_PATH="coverage/webssh$run.coverage" NAME="run Coverage Results" MODIFIED="1696093175682" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -6,6 +6,7 @@ import struct
|
||||||
import traceback
|
import traceback
|
||||||
import weakref
|
import weakref
|
||||||
import paramiko
|
import paramiko
|
||||||
|
import socks
|
||||||
import tornado.web
|
import tornado.web
|
||||||
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
@ -29,7 +30,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_PORT = 22
|
DEFAULT_PORT = 22
|
||||||
|
|
||||||
swallow_http_errors = True
|
swallow_http_errors = True
|
||||||
|
@ -101,7 +101,6 @@ class SSHClient(paramiko.SSHClient):
|
||||||
|
|
||||||
|
|
||||||
class PrivateKey(object):
|
class PrivateKey(object):
|
||||||
|
|
||||||
max_length = 16384 # rough number
|
max_length = 16384 # rough number
|
||||||
|
|
||||||
tag_to_name = {
|
tag_to_name = {
|
||||||
|
@ -143,7 +142,7 @@ class PrivateKey(object):
|
||||||
logging.debug('Reset offset to {}.'.format(offset))
|
logging.debug('Reset offset to {}.'.format(offset))
|
||||||
|
|
||||||
logging.debug('Try parsing it as {} type key'.format(name))
|
logging.debug('Try parsing it as {} type key'.format(name))
|
||||||
pkeycls = getattr(paramiko, name+'Key')
|
pkeycls = getattr(paramiko, name + 'Key')
|
||||||
pkey = None
|
pkey = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -184,7 +183,6 @@ class PrivateKey(object):
|
||||||
|
|
||||||
|
|
||||||
class MixinHandler(object):
|
class MixinHandler(object):
|
||||||
|
|
||||||
custom_headers = {
|
custom_headers = {
|
||||||
'Server': 'TornadoServer'
|
'Server': 'TornadoServer'
|
||||||
}
|
}
|
||||||
|
@ -313,8 +311,7 @@ class NotFoundHandler(MixinHandler, tornado.web.ErrorHandler):
|
||||||
|
|
||||||
|
|
||||||
class IndexHandler(MixinHandler, tornado.web.RequestHandler):
|
class IndexHandler(MixinHandler, tornado.web.RequestHandler):
|
||||||
|
executor = ThreadPoolExecutor(max_workers=cpu_count() * 5)
|
||||||
executor = ThreadPoolExecutor(max_workers=cpu_count()*5)
|
|
||||||
|
|
||||||
def initialize(self, loop, policy, host_keys_settings):
|
def initialize(self, loop, policy, host_keys_settings):
|
||||||
super(IndexHandler, self).initialize(loop)
|
super(IndexHandler, self).initialize(loop)
|
||||||
|
@ -396,6 +393,19 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
|
||||||
passphrase = self.get_argument('passphrase', u'')
|
passphrase = self.get_argument('passphrase', u'')
|
||||||
totp = self.get_argument('totp', u'')
|
totp = self.get_argument('totp', u'')
|
||||||
|
|
||||||
|
# proxyType, proxyIp, proxyPort, proxyRdns = true, proxyUser, proxyPass
|
||||||
|
|
||||||
|
proxyType = self.get_argument('proxytype', None)
|
||||||
|
if proxyType is not None and proxyType != '':
|
||||||
|
proxyType = int(proxyType)
|
||||||
|
proxyIp = self.get_argument('proxyip', u'')
|
||||||
|
proxyPort = self.get_argument('proxyport', None)
|
||||||
|
if proxyPort is not None and proxyPort != '':
|
||||||
|
proxyPort = int(proxyPort)
|
||||||
|
proxyRdns = self.get_argument('proxyrdns', u'')
|
||||||
|
proxyUser = self.get_argument('proxyuser', u'')
|
||||||
|
proxyPass = self.get_argument('proxypass', u'')
|
||||||
|
|
||||||
if isinstance(self.policy, paramiko.RejectPolicy):
|
if isinstance(self.policy, paramiko.RejectPolicy):
|
||||||
self.lookup_hostname(hostname, port)
|
self.lookup_hostname(hostname, port)
|
||||||
|
|
||||||
|
@ -405,7 +415,8 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
|
||||||
pkey = None
|
pkey = None
|
||||||
|
|
||||||
self.ssh_client.totp = totp
|
self.ssh_client.totp = totp
|
||||||
args = (hostname, port, username, password, pkey)
|
args = (
|
||||||
|
hostname, port, username, password, pkey, proxyType, proxyIp, proxyPort, proxyRdns, proxyUser, proxyPass)
|
||||||
logging.debug(args)
|
logging.debug(args)
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
@ -446,13 +457,33 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
|
||||||
logging.warning('Could not detect the default encoding.')
|
logging.warning('Could not detect the default encoding.')
|
||||||
return 'utf-8'
|
return 'utf-8'
|
||||||
|
|
||||||
|
def http_proxy_tunnel_connect(self, proxy, target, timeout=None):
|
||||||
|
logging.info('Connecting to proxy {}'.format(proxy))
|
||||||
|
logging.info('Connecting to target {}'.format(target))
|
||||||
|
sock = socks.socksocket()
|
||||||
|
sock.set_proxy(*proxy)
|
||||||
|
sock.connect(target)
|
||||||
|
sock.settimeout(timeout)
|
||||||
|
return sock
|
||||||
|
|
||||||
def ssh_connect(self, args):
|
def ssh_connect(self, args):
|
||||||
ssh = self.ssh_client
|
ssh = self.ssh_client
|
||||||
dst_addr = args[:2]
|
dst_addr = args[:2]
|
||||||
|
logging.info(args)
|
||||||
logging.info('Connecting to {}:{}'.format(*dst_addr))
|
logging.info('Connecting to {}:{}'.format(*dst_addr))
|
||||||
|
|
||||||
|
sock = None
|
||||||
|
if len(args) > 5:
|
||||||
|
if args[6] is not None and args[6] != '':
|
||||||
|
# 从args中获取代理信息
|
||||||
|
sock = self.http_proxy_tunnel_connect(
|
||||||
|
proxy=args[5:],
|
||||||
|
target=dst_addr,
|
||||||
|
timeout=5000
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ssh.connect(*args, timeout=options.timeout)
|
ssh.connect(*args[:5], timeout=options.timeout, sock=sock)
|
||||||
except socket.error:
|
except socket.error:
|
||||||
raise ValueError('Unable to connect to {}:{}'.format(*dst_addr))
|
raise ValueError('Unable to connect to {}:{}'.format(*dst_addr))
|
||||||
except paramiko.BadAuthenticationType:
|
except paramiko.BadAuthenticationType:
|
||||||
|
@ -503,6 +534,7 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
|
||||||
|
|
||||||
self.check_origin()
|
self.check_origin()
|
||||||
|
|
||||||
|
logging.info('Connected from {}'.format(self.get_args()))
|
||||||
try:
|
try:
|
||||||
args = self.get_args()
|
args = self.get_args()
|
||||||
except InvalidValueError as exc:
|
except InvalidValueError as exc:
|
||||||
|
|
|
@ -4,16 +4,14 @@ var jQuery;
|
||||||
var wssh = {};
|
var wssh = {};
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function () {
|
||||||
// For FormData without getter and setter
|
// For FormData without getter and setter
|
||||||
var proto = FormData.prototype,
|
var proto = FormData.prototype, data = {};
|
||||||
data = {};
|
|
||||||
|
|
||||||
if (!proto.get) {
|
if (!proto.get) {
|
||||||
proto.get = function (name) {
|
proto.get = function (name) {
|
||||||
if (data[name] === undefined) {
|
if (data[name] === undefined) {
|
||||||
var input = document.querySelector('input[name="' + name + '"]'),
|
var input = document.querySelector('input[name="' + name + '"]'), value;
|
||||||
value;
|
|
||||||
if (input) {
|
if (input) {
|
||||||
if (input.type === 'file') {
|
if (input.type === 'file') {
|
||||||
value = input.files[0];
|
value = input.files[0];
|
||||||
|
@ -35,32 +33,17 @@ var wssh = {};
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
jQuery(function($){
|
jQuery(function ($) {
|
||||||
var status = $('#status'),
|
var status = $('#status'), button = $('.btn-primary'), form_container = $('.form-container'), waiter = $('#waiter'),
|
||||||
button = $('.btn-primary'),
|
term_type = $('#term'), style = {}, default_title = 'WebSSH', title_element = document.querySelector('title'),
|
||||||
form_container = $('.form-container'),
|
form_id = '#connect', debug = document.querySelector(form_id).noValidate,
|
||||||
waiter = $('#waiter'),
|
custom_font = document.fonts ? document.fonts.values().next().value : undefined, default_fonts,
|
||||||
term_type = $('#term'),
|
DISCONNECTED = 0, CONNECTING = 1, CONNECTED = 2, state = DISCONNECTED,
|
||||||
style = {},
|
messages = {1: 'This client is connecting ...', 2: 'This client is already connnected.'}, key_max_size = 16384,
|
||||||
default_title = 'WebSSH',
|
|
||||||
title_element = document.querySelector('title'),
|
|
||||||
form_id = '#connect',
|
|
||||||
debug = document.querySelector(form_id).noValidate,
|
|
||||||
custom_font = document.fonts ? document.fonts.values().next().value : undefined,
|
|
||||||
default_fonts,
|
|
||||||
DISCONNECTED = 0,
|
|
||||||
CONNECTING = 1,
|
|
||||||
CONNECTED = 2,
|
|
||||||
state = DISCONNECTED,
|
|
||||||
messages = {1: 'This client is connecting ...', 2: 'This client is already connnected.'},
|
|
||||||
key_max_size = 16384,
|
|
||||||
fields = ['hostname', 'port', 'username'],
|
fields = ['hostname', 'port', 'username'],
|
||||||
form_keys = fields.concat(['password', 'totp']),
|
form_keys = fields.concat(['password', 'totp', 'proxytype', 'proxyip', 'proxyport', 'proxyrdns', 'proxyuser', 'proxypass']),
|
||||||
opts_keys = ['bgcolor', 'title', 'encoding', 'command', 'term', 'fontsize', 'fontcolor', 'cursor'],
|
opts_keys = ['bgcolor', 'title', 'encoding', 'command', 'term', 'fontsize', 'fontcolor', 'cursor'],
|
||||||
url_form_data = {},
|
url_form_data = {}, url_opts_data = {}, validated_form_data, event_origin,
|
||||||
url_opts_data = {},
|
|
||||||
validated_form_data,
|
|
||||||
event_origin,
|
|
||||||
hostname_tester = /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))|(^\s*((?=.{1,255}$)(?=.*[A-Za-z].*)[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?)*)\s*$)/;
|
hostname_tester = /((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))|(^\s*((?=.{1,255}$)(?=.*[A-Za-z].*)[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|\b-){0,61}[0-9A-Za-z])?)*)\s*$)/;
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,7 +53,7 @@ jQuery(function($){
|
||||||
for (i = 0; i < names.length; i++) {
|
for (i = 0; i < names.length; i++) {
|
||||||
name = names[i];
|
name = names[i];
|
||||||
value = data.get(name);
|
value = data.get(name);
|
||||||
if (value){
|
if (value) {
|
||||||
window.localStorage.setItem(name, value);
|
window.localStorage.setItem(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,23 +63,22 @@ jQuery(function($){
|
||||||
function restore_items(names) {
|
function restore_items(names) {
|
||||||
var i, name, value;
|
var i, name, value;
|
||||||
|
|
||||||
for (i=0; i < names.length; i++) {
|
for (i = 0; i < names.length; i++) {
|
||||||
name = names[i];
|
name = names[i];
|
||||||
value = window.localStorage.getItem(name);
|
value = window.localStorage.getItem(name);
|
||||||
if (value) {
|
if (value) {
|
||||||
$('#'+name).val(value);
|
$('#' + name).val(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function populate_form(data) {
|
function populate_form(data) {
|
||||||
var names = form_keys.concat(['passphrase']),
|
var names = form_keys.concat(['passphrase']), i, name;
|
||||||
i, name;
|
|
||||||
|
|
||||||
for (i=0; i < names.length; i++) {
|
for (i = 0; i < names.length; i++) {
|
||||||
name = names[i];
|
name = names[i];
|
||||||
$('#'+name).val(data.get(name));
|
$('#' + name).val(data.get(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +91,7 @@ jQuery(function($){
|
||||||
function decode_uri_component(uri) {
|
function decode_uri_component(uri) {
|
||||||
try {
|
try {
|
||||||
return decodeURIComponent(uri);
|
return decodeURIComponent(uri);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
|
@ -127,8 +109,7 @@ jQuery(function($){
|
||||||
|
|
||||||
|
|
||||||
function parse_url_data(string, form_keys, opts_keys, form_map, opts_map) {
|
function parse_url_data(string, form_keys, opts_keys, form_map, opts_map) {
|
||||||
var i, pair, key, val,
|
var i, pair, key, val, arr = string.split('&');
|
||||||
arr = string.split('&');
|
|
||||||
|
|
||||||
for (i = 0; i < arr.length; i++) {
|
for (i = 0; i < arr.length; i++) {
|
||||||
pair = arr[i].split('=');
|
pair = arr[i].split('=');
|
||||||
|
@ -137,7 +118,8 @@ jQuery(function($){
|
||||||
|
|
||||||
if (form_keys.indexOf(key) >= 0) {
|
if (form_keys.indexOf(key) >= 0) {
|
||||||
form_map[key] = val;
|
form_map[key] = val;
|
||||||
} else if (opts_keys.indexOf(key) >=0) {
|
} else if (opts_keys.indexOf(key) >= 0) {
|
||||||
|
console.log(key, val)
|
||||||
opts_map[key] = val;
|
opts_map[key] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,7 +243,7 @@ jQuery(function($){
|
||||||
decoder = new window.TextDecoder('utf-8', {'fatal': true});
|
decoder = new window.TextDecoder('utf-8', {'fatal': true});
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.onload = function() {
|
reader.onload = function () {
|
||||||
var text;
|
var text;
|
||||||
try {
|
try {
|
||||||
text = decoder.decode(reader.result);
|
text = decoder.decode(reader.result);
|
||||||
|
@ -289,7 +271,7 @@ jQuery(function($){
|
||||||
encoding = 'utf-8';
|
encoding = 'utf-8';
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.onload = function() {
|
reader.onload = function () {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(reader.result);
|
callback(reader.result);
|
||||||
}
|
}
|
||||||
|
@ -359,13 +341,10 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
|
|
||||||
var ws_url = window.location.href.split(/\?|#/, 1)[0].replace('http', 'ws'),
|
var ws_url = window.location.href.split(/\?|#/, 1)[0].replace('http', 'ws'),
|
||||||
join = (ws_url[ws_url.length-1] === '/' ? '' : '/'),
|
join = (ws_url[ws_url.length - 1] === '/' ? '' : '/'), url = ws_url + join + 'ws?id=' + msg.id,
|
||||||
url = ws_url + join + 'ws?id=' + msg.id,
|
sock = new window.WebSocket(url), encoding = 'utf-8',
|
||||||
sock = new window.WebSocket(url),
|
|
||||||
encoding = 'utf-8',
|
|
||||||
decoder = window.TextDecoder ? new window.TextDecoder(encoding) : encoding,
|
decoder = window.TextDecoder ? new window.TextDecoder(encoding) : encoding,
|
||||||
terminal = document.getElementById('terminal'),
|
terminal = document.getElementById('terminal'), termOptions = {
|
||||||
termOptions = {
|
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
theme: {
|
theme: {
|
||||||
background: url_opts_data.bgcolor || 'black',
|
background: url_opts_data.bgcolor || 'black',
|
||||||
|
@ -374,6 +353,8 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.sock = sock;
|
||||||
|
|
||||||
if (url_opts_data.fontsize) {
|
if (url_opts_data.fontsize) {
|
||||||
var fontsize = window.parseInt(url_opts_data.fontsize);
|
var fontsize = window.parseInt(url_opts_data.fontsize);
|
||||||
if (fontsize && fontsize > 0) {
|
if (fontsize && fontsize > 0) {
|
||||||
|
@ -397,6 +378,7 @@ jQuery(function($){
|
||||||
function term_write(text) {
|
function term_write(text) {
|
||||||
if (term) {
|
if (term) {
|
||||||
term.write(text);
|
term.write(text);
|
||||||
|
window.parent.postMessage({event: 'command', data: text}, '*')
|
||||||
if (!term.resized) {
|
if (!term.resized) {
|
||||||
resize_terminal(term);
|
resize_terminal(term);
|
||||||
term.resized = true;
|
term.resized = true;
|
||||||
|
@ -438,13 +420,13 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wssh.geometry = function() {
|
wssh.geometry = function () {
|
||||||
// for console use
|
// for console use
|
||||||
var geometry = current_geometry(term);
|
var geometry = current_geometry(term);
|
||||||
console.log('Current window geometry: ' + JSON.stringify(geometry));
|
console.log('Current window geometry: ' + JSON.stringify(geometry));
|
||||||
};
|
};
|
||||||
|
|
||||||
wssh.send = function(data) {
|
wssh.send = function (data) {
|
||||||
// for console use
|
// for console use
|
||||||
if (!sock) {
|
if (!sock) {
|
||||||
console.log('Websocket was already closed');
|
console.log('Websocket was already closed');
|
||||||
|
@ -465,7 +447,7 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
wssh.reset_encoding = function() {
|
wssh.reset_encoding = function () {
|
||||||
// for console use
|
// for console use
|
||||||
if (encoding === msg.encoding) {
|
if (encoding === msg.encoding) {
|
||||||
console.log('Already reset to ' + msg.encoding);
|
console.log('Already reset to ' + msg.encoding);
|
||||||
|
@ -474,7 +456,7 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
wssh.resize = function(cols, rows) {
|
wssh.resize = function (cols, rows) {
|
||||||
// for console use
|
// for console use
|
||||||
if (term === undefined) {
|
if (term === undefined) {
|
||||||
console.log('Terminal was already destroryed');
|
console.log('Terminal was already destroryed');
|
||||||
|
@ -497,23 +479,23 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
wssh.set_bgcolor = function(color) {
|
wssh.set_bgcolor = function (color) {
|
||||||
set_backgound_color(term, color);
|
set_backgound_color(term, color);
|
||||||
};
|
};
|
||||||
|
|
||||||
wssh.set_fontcolor = function(color) {
|
wssh.set_fontcolor = function (color) {
|
||||||
set_font_color(term, color);
|
set_font_color(term, color);
|
||||||
};
|
};
|
||||||
|
|
||||||
wssh.custom_font = function() {
|
wssh.custom_font = function () {
|
||||||
update_font_family(term);
|
update_font_family(term);
|
||||||
};
|
};
|
||||||
|
|
||||||
wssh.default_font = function() {
|
wssh.default_font = function () {
|
||||||
reset_font_family(term);
|
reset_font_family(term);
|
||||||
};
|
};
|
||||||
|
|
||||||
term.on_resize = function(cols, rows) {
|
term.on_resize = function (cols, rows) {
|
||||||
if (cols !== this.cols || rows !== this.rows) {
|
if (cols !== this.cols || rows !== this.rows) {
|
||||||
console.log('Resizing terminal to geometry: ' + format_geometry(cols, rows));
|
console.log('Resizing terminal to geometry: ' + format_geometry(cols, rows));
|
||||||
this.resize(cols, rows);
|
this.resize(cols, rows);
|
||||||
|
@ -521,12 +503,12 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
term.onData(function(data) {
|
term.onData(function (data) {
|
||||||
// console.log(data);
|
// console.log(data);
|
||||||
sock.send(JSON.stringify({'data': data}));
|
sock.send(JSON.stringify({'data': data}));
|
||||||
});
|
});
|
||||||
|
|
||||||
sock.onopen = function() {
|
sock.onopen = function () {
|
||||||
term.open(terminal);
|
term.open(terminal);
|
||||||
toggle_fullscreen(term);
|
toggle_fullscreen(term);
|
||||||
update_font_family(term);
|
update_font_family(term);
|
||||||
|
@ -535,20 +517,21 @@ jQuery(function($){
|
||||||
title_element.text = url_opts_data.title || default_title;
|
title_element.text = url_opts_data.title || default_title;
|
||||||
if (url_opts_data.command) {
|
if (url_opts_data.command) {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
sock.send(JSON.stringify({'data': url_opts_data.command+'\r'}));
|
sock.send(JSON.stringify({'data': url_opts_data.command + '\r'}));
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
sock.onmessage = function(msg) {
|
sock.onmessage = function (msg) {
|
||||||
read_file_as_text(msg.data, term_write, decoder);
|
read_file_as_text(msg.data, term_write, decoder);
|
||||||
};
|
};
|
||||||
|
|
||||||
sock.onerror = function(e) {
|
sock.onerror = function (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
window.parent.postMessage({event: 'disconnected'}, '*')
|
||||||
};
|
};
|
||||||
|
|
||||||
sock.onclose = function(e) {
|
sock.onclose = function (e) {
|
||||||
term.dispose();
|
term.dispose();
|
||||||
term = undefined;
|
term = undefined;
|
||||||
sock = undefined;
|
sock = undefined;
|
||||||
|
@ -557,9 +540,10 @@ jQuery(function($){
|
||||||
state = DISCONNECTED;
|
state = DISCONNECTED;
|
||||||
default_title = 'WebSSH';
|
default_title = 'WebSSH';
|
||||||
title_element.text = default_title;
|
title_element.text = default_title;
|
||||||
|
window.parent.postMessage({event: 'disconnected'}, '*')
|
||||||
};
|
};
|
||||||
|
|
||||||
$(window).resize(function(){
|
$(window).resize(function () {
|
||||||
if (term) {
|
if (term) {
|
||||||
resize_terminal(term);
|
resize_terminal(term);
|
||||||
}
|
}
|
||||||
|
@ -570,11 +554,11 @@ jQuery(function($){
|
||||||
function wrap_object(opts) {
|
function wrap_object(opts) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
|
|
||||||
obj.get = function(attr) {
|
obj.get = function (attr) {
|
||||||
return opts[attr] || '';
|
return opts[attr] || '';
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.set = function(attr, val) {
|
obj.set = function (attr, val) {
|
||||||
opts[attr] = val;
|
opts[attr] = val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -599,16 +583,10 @@ jQuery(function($){
|
||||||
function validate_form_data(data) {
|
function validate_form_data(data) {
|
||||||
clean_data(data);
|
clean_data(data);
|
||||||
|
|
||||||
var hostname = data.get('hostname'),
|
var hostname = data.get('hostname'), port = data.get('port'), username = data.get('username'),
|
||||||
port = data.get('port'),
|
pk = data.get('privatekey'), result = {
|
||||||
username = data.get('username'),
|
valid: false, data: data, title: ''
|
||||||
pk = data.get('privatekey'),
|
}, errors = [], size;
|
||||||
result = {
|
|
||||||
valid: false,
|
|
||||||
data: data,
|
|
||||||
title: ''
|
|
||||||
},
|
|
||||||
errors = [], size;
|
|
||||||
|
|
||||||
if (!hostname) {
|
if (!hostname) {
|
||||||
errors.push('Value of hostname is required.');
|
errors.push('Value of hostname is required.');
|
||||||
|
@ -670,10 +648,8 @@ jQuery(function($){
|
||||||
|
|
||||||
function connect_without_options() {
|
function connect_without_options() {
|
||||||
// use data from the form
|
// use data from the form
|
||||||
var form = document.querySelector(form_id),
|
var form = document.querySelector(form_id), inputs = form.querySelectorAll('input[type="file"]'),
|
||||||
inputs = form.querySelectorAll('input[type="file"]'),
|
url = form.action, data, pk;
|
||||||
url = form.action,
|
|
||||||
data, pk;
|
|
||||||
|
|
||||||
disable_file_inputs(inputs);
|
disable_file_inputs(inputs);
|
||||||
data = new FormData(form);
|
data = new FormData(form);
|
||||||
|
@ -698,11 +674,12 @@ jQuery(function($){
|
||||||
var result = validate_form_data(data);
|
var result = validate_form_data(data);
|
||||||
if (!result.valid) {
|
if (!result.valid) {
|
||||||
log_status(result.errors.join('\n'));
|
log_status(result.errors.join('\n'));
|
||||||
|
window.parent.postMessage({event: 'connected'}, '*')
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pk && pk.size && !debug) {
|
if (pk && pk.size && !debug) {
|
||||||
read_file_as_text(pk, function(text) {
|
read_file_as_text(pk, function (text) {
|
||||||
if (text === undefined) {
|
if (text === undefined) {
|
||||||
log_status('Invalid private key: ' + pk.name);
|
log_status('Invalid private key: ' + pk.name);
|
||||||
} else {
|
} else {
|
||||||
|
@ -719,13 +696,13 @@ jQuery(function($){
|
||||||
|
|
||||||
function connect_with_options(data) {
|
function connect_with_options(data) {
|
||||||
// use data from the arguments
|
// use data from the arguments
|
||||||
var form = document.querySelector(form_id),
|
var form = document.querySelector(form_id), url = data.url || form.action,
|
||||||
url = data.url || form.action,
|
|
||||||
_xsrf = form.querySelector('input[name="_xsrf"]');
|
_xsrf = form.querySelector('input[name="_xsrf"]');
|
||||||
|
|
||||||
var result = validate_form_data(wrap_object(data));
|
var result = validate_form_data(wrap_object(data));
|
||||||
if (!result.valid) {
|
if (!result.valid) {
|
||||||
log_status(result.errors.join('\n'));
|
log_status(result.errors.join('\n'));
|
||||||
|
window.parent.postMessage({event: 'connected'}, '*')
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,20 +716,19 @@ jQuery(function($){
|
||||||
button.prop('disabled', true);
|
button.prop('disabled', true);
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: url,
|
url: url, type: 'post', data: data, complete: ajax_complete_callback,
|
||||||
type: 'post',
|
}).then(() => {
|
||||||
data: data,
|
window.parent.postMessage({event: 'connected'}, '*')
|
||||||
complete: ajax_complete_callback
|
}).catch(() => {
|
||||||
});
|
window.parent.postMessage({event: 'connected'}, '*')
|
||||||
|
})
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function connect(hostname, port, username, password, privatekey, passphrase, totp) {
|
function connect(hostname, port, username, password, privatekey, passphrase, totp, proxyType, proxyIp, proxyPort, proxyRdns = true, proxyUser, proxyPass) {
|
||||||
// for console use
|
|
||||||
var result, opts;
|
var result, opts;
|
||||||
|
|
||||||
if (state !== DISCONNECTED) {
|
if (state !== DISCONNECTED) {
|
||||||
console.log(messages[state]);
|
console.log(messages[state]);
|
||||||
return;
|
return;
|
||||||
|
@ -769,7 +745,13 @@ jQuery(function($){
|
||||||
password: password,
|
password: password,
|
||||||
privatekey: privatekey,
|
privatekey: privatekey,
|
||||||
passphrase: passphrase,
|
passphrase: passphrase,
|
||||||
totp: totp
|
totp: totp,
|
||||||
|
proxyType: proxyType,
|
||||||
|
proxyIp: proxyIp,
|
||||||
|
proxyPort: proxyPort,
|
||||||
|
proxyRdns: proxyRdns,
|
||||||
|
proxyUser: proxyUser,
|
||||||
|
proxyPass: proxyPass
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
opts = hostname;
|
opts = hostname;
|
||||||
|
@ -786,21 +768,29 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
store_items(fields, result.data);
|
store_items(fields, result.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onmessage = function (event) {
|
||||||
|
//如果是command则执行
|
||||||
|
if (event.data.command) {
|
||||||
|
console.log('command', event.data.command);
|
||||||
|
window.sock.send(JSON.stringify({'data': event.data.command + '\r'}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wssh.connect = connect;
|
wssh.connect = connect;
|
||||||
|
|
||||||
$(form_id).submit(function(event){
|
$(form_id).submit(function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
connect();
|
connect();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function cross_origin_connect(event)
|
function cross_origin_connect(event) {
|
||||||
{
|
|
||||||
console.log(event.origin);
|
console.log(event.origin);
|
||||||
var prop = 'connect',
|
var prop = 'connect', args;
|
||||||
args;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
args = JSON.parse(event.data);
|
args = JSON.parse(event.data);
|
||||||
|
@ -823,23 +813,23 @@ jQuery(function($){
|
||||||
window.addEventListener('message', cross_origin_connect, false);
|
window.addEventListener('message', cross_origin_connect, false);
|
||||||
|
|
||||||
if (document.fonts) {
|
if (document.fonts) {
|
||||||
document.fonts.ready.then(
|
document.fonts.ready.then(function () {
|
||||||
function () {
|
|
||||||
if (custom_font_is_loaded() === false) {
|
if (custom_font_is_loaded() === false) {
|
||||||
document.body.style.fontFamily = custom_font.family;
|
document.body.style.fontFamily = custom_font.family;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener("dragenter", (e) => {
|
||||||
|
console.log("dragenter事件触发");
|
||||||
|
e.target.style.backgroundColor = "green"
|
||||||
|
console.log("颜色改变");
|
||||||
|
})
|
||||||
|
|
||||||
parse_url_data(
|
|
||||||
decode_uri_component(window.location.search.substring(1)) + '&' + decode_uri_component(window.location.hash.substring(1)),
|
|
||||||
form_keys, opts_keys, url_form_data, url_opts_data
|
|
||||||
);
|
|
||||||
// console.log(url_form_data);
|
|
||||||
// console.log(url_opts_data);
|
|
||||||
|
|
||||||
|
parse_url_data(decode_uri_component(window.location.search.substring(1)) + '&' + decode_uri_component(window.location.hash.substring(1)), form_keys, opts_keys, url_form_data, url_opts_data);
|
||||||
|
console.log(url_form_data);
|
||||||
|
console.log("url_opts_data:", url_opts_data);
|
||||||
if (url_opts_data.term) {
|
if (url_opts_data.term) {
|
||||||
term_type.val(url_opts_data.term);
|
term_type.val(url_opts_data.term);
|
||||||
}
|
}
|
||||||
|
@ -850,6 +840,7 @@ jQuery(function($){
|
||||||
if (get_object_length(url_form_data)) {
|
if (get_object_length(url_form_data)) {
|
||||||
waiter.show();
|
waiter.show();
|
||||||
connect(url_form_data);
|
connect(url_form_data);
|
||||||
|
console.log('Connecting ...', url_form_data)
|
||||||
} else {
|
} else {
|
||||||
restore_items(fields);
|
restore_items(fields);
|
||||||
form_container.show();
|
form_container.show();
|
||||||
|
|
Loading…
Reference in New Issue