xterm.js 組件實現WebSSH功能

本次實驗將使用Django 3.0 配合 dwebsocket websocket組件,實現一個網頁版的SSH命令行工具,其支持 vim , 支持 ping等交互命令,惟一的一個小缺點是略卡,不知道是我電腦問題仍是這個socket框架不穩定呢,若是作項目建議不要手擼代碼,其實已經有很是好的解決方案了 https://github.com/huashengdun/websshjavascript

基本用法css

<html>
<head>
  <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
  <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
</head>
<body>
  <div id="terminal"></div>
  <script type="text/javascript">
      var window_width = $(window).width();
      var window_height = $(window).height();
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:true,
                cursorBlink:true
            }
    );
    term.open(document.getElementById('terminal'));
    term.write('Hello lyshark \x1B[1;3;31mxterm.js\x1B[0m $ ')
  </script>
</body>
</html>

命令執行html

<html>
<head>
  <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
  <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
</head>
<body>
<input type="button" value="執行命令" onclick="show()">
  <div id="terminal"></div>
  <script type="text/javascript">
      var window_width = $(window).width();
      var window_height = $(window).height();
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:false,
                cursorBlink:false
            }
    );
    term.open(document.getElementById('terminal'));
      function show(){
          $.ajax({
              url:"/term/",
              type:"POST",
              contentType:"application/json;",
              data: "ok",
              success:function (res) {
                  var data = JSON.parse(res);
                  console.log(data["cmd"]);
                  term.writeln(data["cmd"]);
              }
          });
      }
  </script>
</body>
</html>
from django.shortcuts import render,HttpResponse
import subprocess,json

def term(request):
    if request.method == "POST":
        data = request.body.decode("utf-8")
        if data == "ok":
            proc = subprocess.Popen("ipconfig",stdout=subprocess.PIPE,shell=True)
            cc = str(proc.stdout.readlines())
            return HttpResponse(json.dumps({"cmd":cc}))
    return render(request, "index.html")

光標問題已經解決了,找了好久的,操蛋啊。java

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
  <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
</head>
<body>
<input type="button" value="執行命令" onclick="show()">
  <div id="terminal"></div>
  <script type="text/javascript">
      var window_width = $(window).width();
      var window_height = $(window).height();
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:false,
                convertEol: true,
                cursorBlink:false,
                rendererType: "canvas",
                theme:{
                    foreground: 'yellow',
                    background: 'rgba(6,1,1,0.55)',
                }
            }
    );
    term.open(document.getElementById('terminal'));
      function show(){
          $.ajax({
              url:"/term/",
              type:"POST",
              contentType:"application/json;",
              data: "ok",
              success:function (res) {
                      term.writeln(res);
              }
          });
      }
  </script>
</body>
</html>
from django.shortcuts import render,HttpResponse
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def ssh_cmd(user,passwd,port,cmd):
    ssh.connect("192.168.1.20",port=port,username=user,password=passwd)
    cmd=cmd
    stdin, stdout, stderr = ssh.exec_command(cmd)
    result = stdout.read()
    if not result:
        result=stderr.read()
    ssh.close()
    return result.decode()

def term(request):
    if request.method == "POST":
        data = request.body.decode("utf-8")
        if data == "ok":
            a = ssh_cmd("root","123","22","ifconfig")
            return HttpResponse(a)
    return render(request, "index.html")

來咱們繼續,加上邊框,進行定製。jquery

{% extends "admin/base_site.html" %}
{% load i18n static %}

{% block content %}
    <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
    <link rel="stylesheet" href="https://www.blib.cn/cdn/bootstrap3.css" />
    <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>

    <div class="panel panel-primary">
        <div class="panel-heading">
            <h3 class="panel-title">批量命令執行CMD工具</h3>
        </div>
        <div class="panel-body">
              <div id="terminal"></div>
        </div>
        <div class="panel-footer">
            <input type="button" value="執行命令" onclick="show()">
        </div>
    </div>

    <script type="text/javascript">
      var window_width = $(window).width()-200;
      var window_height = $(window).height()-200;
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:false,
                convertEol: true,
                cursorBlink:false,
                rendererType: "canvas",
            }
    );
    term.open(document.getElementById('terminal'));
      function show(){
          $.ajax({
              url:"/term/",
              type:"POST",
              contentType:"application/json;",
              data: "ok",
              success:function (res) {
                  //term.clear();
                  term.writeln(res);
              }
          });
      }
    </script>
{% endblock %}
from django.shortcuts import render,HttpResponse
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def ssh_shell(address,username,password,port,command):
    ssh.connect(address,port=port,username=username,password=password)
    stdin, stdout, stderr = ssh.exec_command(command)
    result = stdout.read()
    if not result:
        result=stderr.read()
    ssh.close()
    return result.decode()


def term(request):
    if request.method == "POST":
        data = request.body.decode("utf-8")
        if data == "ok":
            a = ssh_shell("192.168.1.20","root","123","22","yum")
            print(a)
            return HttpResponse(a)
    return render(request, "index.html")

繼續改造啊,先玩着,後期上websocket.git

views.py
from django.shortcuts import render,HttpResponse
import paramiko,json,time

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def ssh_shell(address,username,password,port,command):
    try:
        ssh.connect(address,port=port,username=username,password=password)
        stdin, stdout, stderr = ssh.exec_command(command)
        result = stdout.read()
        if not result:
            result=stderr.read()
        ssh.close()
        return result.decode()
    except Exception:
        ssh.close()
def term(request):
    if request.method == "POST":
        data = request.body.decode("utf-8")
        json_data = json.loads(data)
        address = json_data.get("address")
        command = json_data.get("command")
        if len(address) >=2 and len(command) >=2:
            ret = ssh_shell(address,"root","123","22",command)
            if ret !=None:
                times = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                times = "---> \x1B[1;3;32m 執行時間: [ {} ] \x1B[0m".format(times)
                address = "\x1B[1;3;33m 主機地址: [ {} ] \x1B[0m".format(address)
                command = "\x1B[1;3;35m 執行命令: [ {} ] \x1B[0m".format(command)
                retn = times + address + command + "\x1B[1;3;25m 回執: [ok] \x1B[0m"
                return HttpResponse(retn)
            else:
                times = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                times = "---> \x1B[1;3;32m 執行時間: [ {} ] \x1B[0m".format(times)
                address = "\x1B[1;3;33m 主機地址: [ {} ] \x1B[0m".format(address)
                command = "\x1B[1;3;35m 執行命令: [ {} ] \x1B[0m".format(command)
                retn = times + address + command + "\x1B[1;3;20m 回執: [Error] \x1B[0m"
                return HttpResponse(retn)
        else:
            return HttpResponse("主機地址或命令行不能爲空...")
    return render(request, "index.html")
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% block content %}
    <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
    <link rel="stylesheet" href="https://www.blib.cn/cdn/bootstrap3.css" />
    <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>

    <div class="panel panel-primary">
        <div class="panel-heading">
            <h3 class="panel-title">批量命令執行CMD工具</h3>
        </div>
        <div class="panel-body">
              <div id="terminal"></div>
        </div>
        <div class="panel-footer">
            <input type="text" id="address" placeholder="主機範圍" style="width:200px;height:40px"/>
            <input type="text" id="command" placeholder="執行命令" style="width:400px;height:40px"/>
            <input type="button" value="執行命令" onclick="show()">
        </div>
    </div>
    <script type="text/javascript">
      var window_width = $(window).width()-200;
      var window_height = $(window).height()-300;
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:false,
                convertEol: true,
                cursorBlink:true,
                cursorStyle:null,
                rendererType: "canvas",
            }
    );
    term.open(document.getElementById('terminal'));
      function show(){
          var address = $("#address").val();
          var command = $("#command").val();
          console.log(command);
          $.ajax({
              url:"/term/",
              type:"POST",
              contentType:"application/json;",
              data: JSON.stringify({"address":address,"command":command}),
              success:function (res) {
                  term.writeln(res);
              }
          });
      }
    </script>
{% endblock %}
from MyWeb import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('term/',views.term)
]

Dwebsocket

網上找到一個老版本的,改造了一下 能夠支持 django 3.0 。github

index.htmlweb

<html>
<head>
    <title>django-websocket</title>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
    <script type="text/javascript">
        $(function () {
            $('#connect_websocket').click(function () {
                if(window.s){
                    // 若是已經鏈接了,就關閉,從新鏈接
                    window.s.close()
                }
                var s = new WebSocket("ws://" + window.location.host + "/echo/");
                s.onopen = function () {
                    console.log('WebSocket open');
                };
                s.onmessage = function (e) {
                    console.log('message: ' + e.data);
                };
                s.onclose = function (e) {
                    console.log('WebSocket close');
                };
                // 把s掛到全局
                window.s = s;
            });

            $('#send_message').click(function () {
                if(!window.s){
                    alert("Please connect server.");
                }else{
                    window.s.send($('#message').val());
                }
            });

            $('#close_websocket').click(function () {
                if(window.s){
                    window.s.close();

                }
            });

        });
    </script>
</head>

<body>
<input type="text" id="message" value="Hello, World!" />
<button type="button" id="connect_websocket">Connect websocket</button>
<button type="button" id="send_message">Send message</button>
<button type="button" id="close_websocket">Close websocket</button>
<h1>Received Messages</h1>
<div id="messagecontainer"></div>
</body>
</html>

views.pyajax

from django.shortcuts import render,HttpResponse
from dwebsocket.decorators import accept_websocket,require_websocket

def index(request):
    return render(request,"index.html")

@accept_websocket
def echo(request):
    if not request.is_websocket():#判斷是否是websocket鏈接
        try:#若是是普通的http方法
            message = request.GET['message']
            return HttpResponse(message)
        except:
            return render(request,'index.html')
    else:
        for message in request.websocket:
            request.websocket.send(message)#發送消息到客戶端
from MyWeb import views

urlpatterns = [
    path('', views.index),
    path('echo/', views.echo),
]

頁面加載後自動鏈接shell

<html>
<head>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
    <script type="text/javascript">
        $(function () {
            if(window.s){
                window.s.close()
            }else{
                var s = new WebSocket("ws://" + window.location.host + "/echo/");
            }
            s.onmessage = function (e) {
                console.log('message: ' + e.data);
            };
            // 把s掛到全局
            window.s = s;

            $('#send_message').click(function () {
                    window.s.send("hello lyshark");
            });
        });
    </script>
</head>
<body>
<button type="button" id="send_message">Send message</button>
</body>
</html>

<html>
<head>
    <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
    <link rel="stylesheet" href="https://www.blib.cn/cdn/bootstrap3.css" />
    <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
    <div id="terminal"></div>
    <script>
      var window_width = $(window).width();
      var window_height = $(window).height();
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:false,
                convertEol: true,
                cursorBlink:false,
                cursorStyle:null,
                rendererType: "canvas",
            }
    );
    </script>
    <script type="text/javascript">
       $(function () {
           var sock = new WebSocket("ws://" + window.location.host + "/echo/");
           // 打開 websocket 打開 web 終端
            sock.addEventListener("open",function () {
                term.open(document.getElementById('terminal'));
                term.writeln("socket init ok...");
            });
            // 讀取服務器發來的數據
            sock.addEventListener("message",function (recv) {
                term.write(recv.data);
            });

            var message = {"status":null,"data":null};
            term.on("data",function(data){
                message['status'] = 0;
                message['data'] = data;
                var send_data = JSON.stringify(message);
                window.sock.send(send_data);
                console.log(send_data);
                
            });
            window.sock = sock;
        });
</script>
</head>
<body>
<button type="button" id="send_message">Send message</button>
</body>
</html>
from django.shortcuts import render,HttpResponse
from dwebsocket.decorators import accept_websocket
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def ssh_cmd(user,passwd,port,cmd):
    ssh.connect("192.168.1.20",port=port,username=user,password=passwd)
    cmd=cmd
    stdin, stdout, stderr = ssh.exec_command(cmd)
    result = stdout.read()
    if not result:
        result=stderr.read()
    ssh.close()
    return result.decode()


def index(request):
    return render(request,"index.html")

@accept_websocket
def echo(request):
    if not request.is_websocket():#判斷是否是websocket鏈接
        try:
            message = request.GET['message']
            a = ssh_cmd("root","123","22","ls -lh")
            print(a)
            return HttpResponse(a)
        except:
            return render(request,'index.html')
    else:
        for message in request.websocket:
            request.websocket.send(message)#發送消息到客戶端

繼續嘗試,ssh隧道怎末開?

<html>
<head>
    <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
    <link rel="stylesheet" href="https://www.blib.cn/cdn/bootstrap3.css" />
    <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
    <div id="terminal"></div>
    <script>
      var window_width = $(window).width();
      var window_height = $(window).height();
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:false,
                convertEol: true,
                cursorBlink:false,
                cursorStyle:null,
                rendererType: "canvas",
            }
    );
    </script>
    <script type="text/javascript">
       $(function () {
           var sock = new WebSocket("ws://" + window.location.host + "/echo/");
           // 打開 websocket 打開 web 終端
            sock.addEventListener("open",function () {
                term.open(document.getElementById('terminal'));
                term.writeln("socket init ok...");
            });
            // 讀取服務器發來的數據
            sock.addEventListener("message",function (recv) {
                term.write(recv.data);
            });

            var message ="";
            term.on("data",function(data){
                console.log(message);
                if(data == "\r")
                {
                    term.writeln(message);
                    window.sock.send(message);
                    message = "";

                }else
                {
                    message = message +data;
                    term.write(data);
                }
            });
            window.sock = sock;
        });
</script>
</head>
</html>
from django.shortcuts import render,HttpResponse
from dwebsocket.decorators import accept_websocket
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def ssh_cmd():
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect("192.168.1.20", username="root", password="123")
    ssh_session = client.get_transport().open_session()
    return ssh_session

@accept_websocket
def echo(request):
    sessions = ssh_cmd()
    if not request.is_websocket():
        return render(request,'index.html')
    else:
        for message in request.websocket:
            sessions.exec_command(message)
            ret = sessions.recv(2048)
            request.websocket.send(ret)

簡單的隧道。

import paramiko

tran = paramiko.Transport(('192.168.1.20', 22,))
tran.start_client()
tran.auth_password('root', '123')
chan = tran.open_session()
chan.get_pty()
chan.invoke_shell()

while True:
    a = chan.recv(1024)
    print(a)
    chan.send('ls -lh\r')
<html>
<head>
    <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
    <link rel="stylesheet" href="https://www.blib.cn/cdn/bootstrap3.css" />
    <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
    <div id="terminal"></div>
    <script>
      var window_width = $(window).width();
      var window_height = $(window).height();
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:false,
                convertEol: true,
                cursorBlink:false,
                cursorStyle:null,
                rendererType: "canvas",
            }
    );
    </script>
    <script type="text/javascript">
       $(function () {
           var sock = new WebSocket("ws://" + window.location.host + "/echo/");
           // 打開 websocket 打開 web 終端
            sock.addEventListener("open",function () {
                term.open(document.getElementById('terminal'));
                term.writeln("socket init ok...");
            });
            // 讀取服務器發來的數據
            sock.addEventListener("message",function (recv) {
                term.write(recv.data);
            });

            term.on("data",function(data){
                    term.write(data);
                    window.sock.send(data);
            });
            window.sock = sock;
        });
</script>
</head>
</html>
from django.shortcuts import render,HttpResponse
from dwebsocket.decorators import accept_websocket
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def ssh_cmd():
    tran = paramiko.Transport(('192.168.1.20', 22,))
    tran.start_client()
    tran.auth_password('root', '123')
    chan = tran.open_session()
    chan.get_pty()
    chan.invoke_shell()
    return chan

@accept_websocket
def echo(request):
    sessions = ssh_cmd()
    if not request.is_websocket():
        return render(request,'index.html')
    else:
        for message in request.websocket:
            while True:
                ret = sessions.recv(2048)
                request.websocket.send(ret)

完成了 webssh 代碼還不太穩定,完善後放出來。

代碼,其實比想象中的簡單得多,我嘗試了好久。

<html>
<head>
    <link rel="stylesheet" href="https://www.blib.cn/cdn/xterm.css" />
    <link rel="stylesheet" href="https://www.blib.cn/cdn/bootstrap3.css" />
    <script src="https://www.blib.cn/cdn/xterm.js"></script>
    <script src="https://www.blib.cn/cdn/jquery.js"></script>
    <div id="terminal"></div>
    <script>
      var window_width = $(window).width();
      var window_height = $(window).height();
      var term = new Terminal(
            {
                cols: Math.floor(window_width/9),
                rows: Math.floor(window_height/20),
                useStyle:false,
                convertEol: true,
                cursorBlink:true,
                cursorStyle:null,
            });
        console.log("高度" + window_height + "寬度" + window_width);
        var sock = new WebSocket("ws://" + window.location.host + "/echo/");
        sock.addEventListener("open",function () {
            term.open(document.getElementById('terminal'));
        });
        sock.addEventListener("message",function (recv) {
            term.write(recv.data);
        });
        term.on("data",function(data){
            sock.send(data);
        });
        window.sock = sock;
</script>
</head>
</html>
from django.shortcuts import render,HttpResponse
from dwebsocket.decorators import accept_websocket
import paramiko

def ssh_cmd():
    tran = paramiko.Transport(('192.168.1.20', 22,))
    tran.start_client()
    tran.auth_password('root', '123')
    chan = tran.open_session()
    chan.get_pty(height=492,width=1312)
    chan.invoke_shell()
    return chan
sessions = ssh_cmd()

@accept_websocket
def echo(request):
    if not request.is_websocket():
        return render(request,'index.html')
    else:
        try:
            for message in request.websocket:
                ret = sessions.recv(10240)
                request.websocket.send(ret)
                sessions.send(message)
        except Exception:
            print("error")

最後加一個在線編輯器代碼。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="https://www.blib.cn/cdn/codemirror/codemirror.css"/>
    <script src="https://www.blib.cn/cdn/codemirror/codemirror.js"></script>
</head>
<body>
<textarea class="form-control" id="code" name="code"></textarea>
    <script type="text/javascript" charset="utf-8">
        var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
            mode: "groovy",       // 設置高亮類型
            theme: "neat",        // 設置主題
            lineNumbers: true,	  // 顯示行號
            foldGutter: true,
            gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
    });
        editor.setSize('500px', '400px');    // 設置框架大小
        editor.setValue("hello lyshark");    // 給代碼框賦值
        editor.getValue();                   // 獲取代碼框的值
    </script>
</body>
</html>
相關文章
相關標籤/搜索