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 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:
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue