add proxy

pull/364/head
hongjunlong 2023-10-06 12:34:01 +08:00
parent 1cf19c7186
commit b60acbaf00
11 changed files with 982 additions and 808 deletions

4
.idea/misc.xml Normal file
View File

@ -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>

8
.idea/modules.xml Normal file
View File

@ -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>

View File

@ -0,0 +1,3 @@
9
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d

View File

@ -0,0 +1,3 @@
9
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

14
.idea/webssh.iml Normal file
View File

@ -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>

113
.idea/workspace.xml Normal file
View File

@ -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">{
&quot;associatedIndex&quot;: 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>

View File

@ -6,6 +6,7 @@ import struct
import traceback
import weakref
import paramiko
import socks
import tornado.web
from concurrent.futures import ThreadPoolExecutor
@ -29,7 +30,6 @@ try:
except ImportError:
from urlparse import urlparse
DEFAULT_PORT = 22
swallow_http_errors = True
@ -101,7 +101,6 @@ class SSHClient(paramiko.SSHClient):
class PrivateKey(object):
max_length = 16384 # rough number
tag_to_name = {
@ -143,7 +142,7 @@ class PrivateKey(object):
logging.debug('Reset offset to {}.'.format(offset))
logging.debug('Try parsing it as {} type key'.format(name))
pkeycls = getattr(paramiko, name+'Key')
pkeycls = getattr(paramiko, name + 'Key')
pkey = None
try:
@ -184,7 +183,6 @@ class PrivateKey(object):
class MixinHandler(object):
custom_headers = {
'Server': 'TornadoServer'
}
@ -313,8 +311,7 @@ class NotFoundHandler(MixinHandler, tornado.web.ErrorHandler):
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):
super(IndexHandler, self).initialize(loop)
@ -396,6 +393,19 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
passphrase = self.get_argument('passphrase', 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):
self.lookup_hostname(hostname, port)
@ -405,7 +415,8 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
pkey = None
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)
return args
@ -446,13 +457,33 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
logging.warning('Could not detect the default encoding.')
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):
ssh = self.ssh_client
dst_addr = args[:2]
logging.info(args)
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:
ssh.connect(*args, timeout=options.timeout)
ssh.connect(*args[:5], timeout=options.timeout, sock=sock)
except socket.error:
raise ValueError('Unable to connect to {}:{}'.format(*dst_addr))
except paramiko.BadAuthenticationType:
@ -503,6 +534,7 @@ class IndexHandler(MixinHandler, tornado.web.RequestHandler):
self.check_origin()
logging.info('Connected from {}'.format(self.get_args()))
try:
args = self.get_args()
except InvalidValueError as exc:

View File

@ -4,16 +4,14 @@ var jQuery;
var wssh = {};
(function() {
(function () {
// For FormData without getter and setter
var proto = FormData.prototype,
data = {};
var proto = FormData.prototype, data = {};
if (!proto.get) {
proto.get = function (name) {
if (data[name] === undefined) {
var input = document.querySelector('input[name="' + name + '"]'),
value;
var input = document.querySelector('input[name="' + name + '"]'), value;
if (input) {
if (input.type === 'file') {
value = input.files[0];
@ -35,32 +33,17 @@ var wssh = {};
}());
jQuery(function($){
var status = $('#status'),
button = $('.btn-primary'),
form_container = $('.form-container'),
waiter = $('#waiter'),
term_type = $('#term'),
style = {},
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,
jQuery(function ($) {
var status = $('#status'), button = $('.btn-primary'), form_container = $('.form-container'), waiter = $('#waiter'),
term_type = $('#term'), style = {}, 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'],
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'],
url_form_data = {},
url_opts_data = {},
validated_form_data,
event_origin,
url_form_data = {}, 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*$)/;
@ -70,7 +53,7 @@ jQuery(function($){
for (i = 0; i < names.length; i++) {
name = names[i];
value = data.get(name);
if (value){
if (value) {
window.localStorage.setItem(name, value);
}
}
@ -80,23 +63,22 @@ jQuery(function($){
function restore_items(names) {
var i, name, value;
for (i=0; i < names.length; i++) {
for (i = 0; i < names.length; i++) {
name = names[i];
value = window.localStorage.getItem(name);
if (value) {
$('#'+name).val(value);
$('#' + name).val(value);
}
}
}
function populate_form(data) {
var names = form_keys.concat(['passphrase']),
i, name;
var names = form_keys.concat(['passphrase']), i, name;
for (i=0; i < names.length; i++) {
for (i = 0; i < names.length; 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) {
try {
return decodeURIComponent(uri);
} catch(e) {
} catch (e) {
console.error(e);
}
return '';
@ -127,8 +109,7 @@ jQuery(function($){
function parse_url_data(string, form_keys, opts_keys, form_map, opts_map) {
var i, pair, key, val,
arr = string.split('&');
var i, pair, key, val, arr = string.split('&');
for (i = 0; i < arr.length; i++) {
pair = arr[i].split('=');
@ -137,7 +118,8 @@ jQuery(function($){
if (form_keys.indexOf(key) >= 0) {
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;
}
}
@ -261,7 +243,7 @@ jQuery(function($){
decoder = new window.TextDecoder('utf-8', {'fatal': true});
}
reader.onload = function() {
reader.onload = function () {
var text;
try {
text = decoder.decode(reader.result);
@ -289,7 +271,7 @@ jQuery(function($){
encoding = 'utf-8';
}
reader.onload = function() {
reader.onload = function () {
if (callback) {
callback(reader.result);
}
@ -359,13 +341,10 @@ jQuery(function($){
}
var ws_url = window.location.href.split(/\?|#/, 1)[0].replace('http', 'ws'),
join = (ws_url[ws_url.length-1] === '/' ? '' : '/'),
url = ws_url + join + 'ws?id=' + msg.id,
sock = new window.WebSocket(url),
encoding = 'utf-8',
join = (ws_url[ws_url.length - 1] === '/' ? '' : '/'), url = ws_url + join + 'ws?id=' + msg.id,
sock = new window.WebSocket(url), encoding = 'utf-8',
decoder = window.TextDecoder ? new window.TextDecoder(encoding) : encoding,
terminal = document.getElementById('terminal'),
termOptions = {
terminal = document.getElementById('terminal'), termOptions = {
cursorBlink: true,
theme: {
background: url_opts_data.bgcolor || 'black',
@ -374,6 +353,8 @@ jQuery(function($){
}
};
window.sock = sock;
if (url_opts_data.fontsize) {
var fontsize = window.parseInt(url_opts_data.fontsize);
if (fontsize && fontsize > 0) {
@ -397,6 +378,7 @@ jQuery(function($){
function term_write(text) {
if (term) {
term.write(text);
window.parent.postMessage({event: 'command', data: text}, '*')
if (!term.resized) {
resize_terminal(term);
term.resized = true;
@ -438,13 +420,13 @@ jQuery(function($){
}
wssh.geometry = function() {
wssh.geometry = function () {
// for console use
var geometry = current_geometry(term);
console.log('Current window geometry: ' + JSON.stringify(geometry));
};
wssh.send = function(data) {
wssh.send = function (data) {
// for console use
if (!sock) {
console.log('Websocket was already closed');
@ -465,7 +447,7 @@ jQuery(function($){
}
};
wssh.reset_encoding = function() {
wssh.reset_encoding = function () {
// for console use
if (encoding === 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
if (term === undefined) {
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);
};
wssh.set_fontcolor = function(color) {
wssh.set_fontcolor = function (color) {
set_font_color(term, color);
};
wssh.custom_font = function() {
wssh.custom_font = function () {
update_font_family(term);
};
wssh.default_font = function() {
wssh.default_font = function () {
reset_font_family(term);
};
term.on_resize = function(cols, rows) {
term.on_resize = function (cols, rows) {
if (cols !== this.cols || rows !== this.rows) {
console.log('Resizing terminal to geometry: ' + format_geometry(cols, rows));
this.resize(cols, rows);
@ -521,12 +503,12 @@ jQuery(function($){
}
};
term.onData(function(data) {
term.onData(function (data) {
// console.log(data);
sock.send(JSON.stringify({'data': data}));
});
sock.onopen = function() {
sock.onopen = function () {
term.open(terminal);
toggle_fullscreen(term);
update_font_family(term);
@ -535,20 +517,21 @@ jQuery(function($){
title_element.text = url_opts_data.title || default_title;
if (url_opts_data.command) {
setTimeout(function () {
sock.send(JSON.stringify({'data': url_opts_data.command+'\r'}));
sock.send(JSON.stringify({'data': url_opts_data.command + '\r'}));
}, 500);
}
};
sock.onmessage = function(msg) {
sock.onmessage = function (msg) {
read_file_as_text(msg.data, term_write, decoder);
};
sock.onerror = function(e) {
sock.onerror = function (e) {
console.error(e);
window.parent.postMessage({event: 'disconnected'}, '*')
};
sock.onclose = function(e) {
sock.onclose = function (e) {
term.dispose();
term = undefined;
sock = undefined;
@ -557,9 +540,10 @@ jQuery(function($){
state = DISCONNECTED;
default_title = 'WebSSH';
title_element.text = default_title;
window.parent.postMessage({event: 'disconnected'}, '*')
};
$(window).resize(function(){
$(window).resize(function () {
if (term) {
resize_terminal(term);
}
@ -570,11 +554,11 @@ jQuery(function($){
function wrap_object(opts) {
var obj = {};
obj.get = function(attr) {
obj.get = function (attr) {
return opts[attr] || '';
};
obj.set = function(attr, val) {
obj.set = function (attr, val) {
opts[attr] = val;
};
@ -599,16 +583,10 @@ jQuery(function($){
function validate_form_data(data) {
clean_data(data);
var hostname = data.get('hostname'),
port = data.get('port'),
username = data.get('username'),
pk = data.get('privatekey'),
result = {
valid: false,
data: data,
title: ''
},
errors = [], size;
var hostname = data.get('hostname'), port = data.get('port'), username = data.get('username'),
pk = data.get('privatekey'), result = {
valid: false, data: data, title: ''
}, errors = [], size;
if (!hostname) {
errors.push('Value of hostname is required.');
@ -670,10 +648,8 @@ jQuery(function($){
function connect_without_options() {
// use data from the form
var form = document.querySelector(form_id),
inputs = form.querySelectorAll('input[type="file"]'),
url = form.action,
data, pk;
var form = document.querySelector(form_id), inputs = form.querySelectorAll('input[type="file"]'),
url = form.action, data, pk;
disable_file_inputs(inputs);
data = new FormData(form);
@ -698,11 +674,12 @@ jQuery(function($){
var result = validate_form_data(data);
if (!result.valid) {
log_status(result.errors.join('\n'));
window.parent.postMessage({event: 'connected'}, '*')
return;
}
if (pk && pk.size && !debug) {
read_file_as_text(pk, function(text) {
read_file_as_text(pk, function (text) {
if (text === undefined) {
log_status('Invalid private key: ' + pk.name);
} else {
@ -719,13 +696,13 @@ jQuery(function($){
function connect_with_options(data) {
// use data from the arguments
var form = document.querySelector(form_id),
url = data.url || form.action,
var form = document.querySelector(form_id), url = data.url || form.action,
_xsrf = form.querySelector('input[name="_xsrf"]');
var result = validate_form_data(wrap_object(data));
if (!result.valid) {
log_status(result.errors.join('\n'));
window.parent.postMessage({event: 'connected'}, '*')
return;
}
@ -739,20 +716,19 @@ jQuery(function($){
button.prop('disabled', true);
$.ajax({
url: url,
type: 'post',
data: data,
complete: ajax_complete_callback
});
url: url, type: 'post', data: data, complete: ajax_complete_callback,
}).then(() => {
window.parent.postMessage({event: 'connected'}, '*')
}).catch(() => {
window.parent.postMessage({event: 'connected'}, '*')
})
return result;
}
function connect(hostname, port, username, password, privatekey, passphrase, totp) {
// for console use
function connect(hostname, port, username, password, privatekey, passphrase, totp, proxyType, proxyIp, proxyPort, proxyRdns = true, proxyUser, proxyPass) {
var result, opts;
if (state !== DISCONNECTED) {
console.log(messages[state]);
return;
@ -769,7 +745,13 @@ jQuery(function($){
password: password,
privatekey: privatekey,
passphrase: passphrase,
totp: totp
totp: totp,
proxyType: proxyType,
proxyIp: proxyIp,
proxyPort: proxyPort,
proxyRdns: proxyRdns,
proxyUser: proxyUser,
proxyPass: proxyPass
};
} else {
opts = hostname;
@ -786,21 +768,29 @@ jQuery(function($){
}
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;
$(form_id).submit(function(event){
$(form_id).submit(function (event) {
event.preventDefault();
connect();
});
function cross_origin_connect(event)
{
function cross_origin_connect(event) {
console.log(event.origin);
var prop = 'connect',
args;
var prop = 'connect', args;
try {
args = JSON.parse(event.data);
@ -823,23 +813,23 @@ jQuery(function($){
window.addEventListener('message', cross_origin_connect, false);
if (document.fonts) {
document.fonts.ready.then(
function () {
document.fonts.ready.then(function () {
if (custom_font_is_loaded() === false) {
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) {
term_type.val(url_opts_data.term);
}
@ -850,6 +840,7 @@ jQuery(function($){
if (get_object_length(url_form_data)) {
waiter.show();
connect(url_form_data);
console.log('Connecting ...', url_form_data)
} else {
restore_items(fields);
form_container.show();