فهرست منبع

Merge branch 'release/1.0.0'

tianyunperfect 5 سال پیش
والد
کامیت
3be7ad4881
100فایلهای تغییر یافته به همراه270 افزوده شده و 6 حذف شده
  1. 19 6
      app.py
  2. 29 0
      execUtil.py
  3. 2 0
      requirements.txt
  4. 1 0
      static/axios.min.js
  5. 1 0
      static/css/layui.css
  6. 1 0
      static/css/layui.mobile.css
  7. 2 0
      static/css/modules/code.css
  8. 1 0
      static/css/modules/laydate/default/laydate.css
  9. BIN
      static/css/modules/layer/default/icon-ext.png
  10. BIN
      static/css/modules/layer/default/icon.png
  11. 1 0
      static/css/modules/layer/default/layer.css
  12. BIN
      static/css/modules/layer/default/loading-0.gif
  13. BIN
      static/css/modules/layer/default/loading-1.gif
  14. BIN
      static/css/modules/layer/default/loading-2.gif
  15. BIN
      static/font/iconfont.eot
  16. 25 0
      static/font/iconfont.svg
  17. BIN
      static/font/iconfont.ttf
  18. BIN
      static/font/iconfont.woff
  19. BIN
      static/font/iconfont.woff2
  20. BIN
      static/images/face/0.gif
  21. BIN
      static/images/face/1.gif
  22. BIN
      static/images/face/10.gif
  23. BIN
      static/images/face/11.gif
  24. BIN
      static/images/face/12.gif
  25. BIN
      static/images/face/13.gif
  26. BIN
      static/images/face/14.gif
  27. BIN
      static/images/face/15.gif
  28. BIN
      static/images/face/16.gif
  29. BIN
      static/images/face/17.gif
  30. BIN
      static/images/face/18.gif
  31. BIN
      static/images/face/19.gif
  32. BIN
      static/images/face/2.gif
  33. BIN
      static/images/face/20.gif
  34. BIN
      static/images/face/21.gif
  35. BIN
      static/images/face/22.gif
  36. BIN
      static/images/face/23.gif
  37. BIN
      static/images/face/24.gif
  38. BIN
      static/images/face/25.gif
  39. BIN
      static/images/face/26.gif
  40. BIN
      static/images/face/27.gif
  41. BIN
      static/images/face/28.gif
  42. BIN
      static/images/face/29.gif
  43. BIN
      static/images/face/3.gif
  44. BIN
      static/images/face/30.gif
  45. BIN
      static/images/face/31.gif
  46. BIN
      static/images/face/32.gif
  47. BIN
      static/images/face/33.gif
  48. BIN
      static/images/face/34.gif
  49. BIN
      static/images/face/35.gif
  50. BIN
      static/images/face/36.gif
  51. BIN
      static/images/face/37.gif
  52. BIN
      static/images/face/38.gif
  53. BIN
      static/images/face/39.gif
  54. BIN
      static/images/face/4.gif
  55. BIN
      static/images/face/40.gif
  56. BIN
      static/images/face/41.gif
  57. BIN
      static/images/face/42.gif
  58. BIN
      static/images/face/43.gif
  59. BIN
      static/images/face/44.gif
  60. BIN
      static/images/face/45.gif
  61. BIN
      static/images/face/46.gif
  62. BIN
      static/images/face/47.gif
  63. BIN
      static/images/face/48.gif
  64. BIN
      static/images/face/49.gif
  65. BIN
      static/images/face/5.gif
  66. BIN
      static/images/face/50.gif
  67. BIN
      static/images/face/51.gif
  68. BIN
      static/images/face/52.gif
  69. BIN
      static/images/face/53.gif
  70. BIN
      static/images/face/54.gif
  71. BIN
      static/images/face/55.gif
  72. BIN
      static/images/face/56.gif
  73. BIN
      static/images/face/57.gif
  74. BIN
      static/images/face/58.gif
  75. BIN
      static/images/face/59.gif
  76. BIN
      static/images/face/6.gif
  77. BIN
      static/images/face/60.gif
  78. BIN
      static/images/face/61.gif
  79. BIN
      static/images/face/62.gif
  80. BIN
      static/images/face/63.gif
  81. BIN
      static/images/face/64.gif
  82. BIN
      static/images/face/65.gif
  83. BIN
      static/images/face/66.gif
  84. BIN
      static/images/face/67.gif
  85. BIN
      static/images/face/68.gif
  86. BIN
      static/images/face/69.gif
  87. BIN
      static/images/face/7.gif
  88. BIN
      static/images/face/70.gif
  89. BIN
      static/images/face/71.gif
  90. BIN
      static/images/face/8.gif
  91. BIN
      static/images/face/9.gif
  92. 178 0
      static/index.html
  93. 1 0
      static/lay/modules/carousel.js
  94. 2 0
      static/lay/modules/code.js
  95. 1 0
      static/lay/modules/colorpicker.js
  96. 1 0
      static/lay/modules/element.js
  97. 2 0
      static/lay/modules/flow.js
  98. 1 0
      static/lay/modules/form.js
  99. 1 0
      static/lay/modules/jquery.js
  100. 1 0
      static/lay/modules/laydate.js

+ 19 - 6
app.py

@@ -1,17 +1,30 @@
 from flask import Flask, redirect, request
+from execUtil import get_client, run_cmd
 
-# 设置static为url根目录
 app = Flask(__name__, static_url_path="")
-# 文件上传大小 3MB
-app.config['MAX_CONTENT_LENGTH'] = 3 * 1024 * 1024
 
 
-@app.route("/", methods=['post', 'get'])
+@app.route("/", methods=['get'])
 def hello():
     print(request.json)  # json参数
-    print(request.args)  # param参数
     return redirect("/index.html")
 
 
+@app.route("/exec", methods=['post'])
+def exe_str_cmd():
+    """执行cmd"""
+    try:
+        req_json = request.json
+        client = get_client(req_json)
+        # 转换执行字符串
+        exec_str = "&&".join(list(filter(lambda x: not str.startswith(x, "#"), req_json.get('exec_str').splitlines())))
+        result_str = run_cmd(client, exec_str)
+        client.close()
+        return result_str
+        # return "OK"
+    except Exception as e:
+        return str(e)
+
+
 if __name__ == '__main__':
-    app.run()
+    app.run(host='0.0.0.0', port=5000)

+ 29 - 0
execUtil.py

@@ -0,0 +1,29 @@
+import paramiko
+
+
+def run_cmd(ssh_client, cmd):
+    """
+    运行单条命令
+    :param ssh_client:
+    :param cmd:
+    :return:
+    """
+    # bash -l -c解释:-l(login)表示bash作为一个login shell;-c(command)表示执行后面字符串内的命令,这样执行的脚本,可以获取到/etc/profile里的全局变量,包括我们搜索命令的目录PATH
+    print("执行命令: " + cmd)
+    stdin, stdout, stderr = ssh_client.exec_command(cmd)
+    res, err = stdout.read(), stderr.read()
+    result = res if res else err
+    result = result.decode('utf-8')
+    print("运行结果: " + result)
+    return result
+
+
+def get_client(json):
+    """获取sshClient"""
+    ssh_client = paramiko.SSHClient()
+    ssh_client.load_system_host_keys()
+    ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+
+    ssh_client.connect(hostname=json.get('host'), port=int(json.get('port')), username=json.get('username'),
+                       password=json.get('password'), timeout=int(json.get('timeout')))
+    return ssh_client

+ 2 - 0
requirements.txt

@@ -1 +1,3 @@
 Flask==1.1.2
+
+paramiko~=2.7.1

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/axios.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/css/layui.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/css/layui.mobile.css


+ 2 - 0
static/css/modules/code.css

@@ -0,0 +1,2 @@
+/** layui-v2.5.4 MIT License By https://www.layui.com */
+ html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/css/modules/laydate/default/laydate.css


BIN
static/css/modules/layer/default/icon-ext.png


BIN
static/css/modules/layer/default/icon.png


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/css/modules/layer/default/layer.css


BIN
static/css/modules/layer/default/loading-0.gif


BIN
static/css/modules/layer/default/loading-1.gif


BIN
static/css/modules/layer/default/loading-2.gif


BIN
static/font/iconfont.eot


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 25 - 0
static/font/iconfont.svg


BIN
static/font/iconfont.ttf


BIN
static/font/iconfont.woff


BIN
static/font/iconfont.woff2


BIN
static/images/face/0.gif


BIN
static/images/face/1.gif


BIN
static/images/face/10.gif


BIN
static/images/face/11.gif


BIN
static/images/face/12.gif


BIN
static/images/face/13.gif


BIN
static/images/face/14.gif


BIN
static/images/face/15.gif


BIN
static/images/face/16.gif


BIN
static/images/face/17.gif


BIN
static/images/face/18.gif


BIN
static/images/face/19.gif


BIN
static/images/face/2.gif


BIN
static/images/face/20.gif


BIN
static/images/face/21.gif


BIN
static/images/face/22.gif


BIN
static/images/face/23.gif


BIN
static/images/face/24.gif


BIN
static/images/face/25.gif


BIN
static/images/face/26.gif


BIN
static/images/face/27.gif


BIN
static/images/face/28.gif


BIN
static/images/face/29.gif


BIN
static/images/face/3.gif


BIN
static/images/face/30.gif


BIN
static/images/face/31.gif


BIN
static/images/face/32.gif


BIN
static/images/face/33.gif


BIN
static/images/face/34.gif


BIN
static/images/face/35.gif


BIN
static/images/face/36.gif


BIN
static/images/face/37.gif


BIN
static/images/face/38.gif


BIN
static/images/face/39.gif


BIN
static/images/face/4.gif


BIN
static/images/face/40.gif


BIN
static/images/face/41.gif


BIN
static/images/face/42.gif


BIN
static/images/face/43.gif


BIN
static/images/face/44.gif


BIN
static/images/face/45.gif


BIN
static/images/face/46.gif


BIN
static/images/face/47.gif


BIN
static/images/face/48.gif


BIN
static/images/face/49.gif


BIN
static/images/face/5.gif


BIN
static/images/face/50.gif


BIN
static/images/face/51.gif


BIN
static/images/face/52.gif


BIN
static/images/face/53.gif


BIN
static/images/face/54.gif


BIN
static/images/face/55.gif


BIN
static/images/face/56.gif


BIN
static/images/face/57.gif


BIN
static/images/face/58.gif


BIN
static/images/face/59.gif


BIN
static/images/face/6.gif


BIN
static/images/face/60.gif


BIN
static/images/face/61.gif


BIN
static/images/face/62.gif


BIN
static/images/face/63.gif


BIN
static/images/face/64.gif


BIN
static/images/face/65.gif


BIN
static/images/face/66.gif


BIN
static/images/face/67.gif


BIN
static/images/face/68.gif


BIN
static/images/face/69.gif


BIN
static/images/face/7.gif


BIN
static/images/face/70.gif


BIN
static/images/face/71.gif


BIN
static/images/face/8.gif


BIN
static/images/face/9.gif


+ 178 - 0
static/index.html

@@ -0,0 +1,178 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>exe_cmd</title>
+    <meta name="renderer" content="webkit">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+    <link rel="stylesheet" href="css/layui.css">
+    <script src="layui.all.js"></script>
+    <script src="axios.min.js"></script>
+    <style>
+
+    </style>
+</head>
+<body>
+<div class="layui-tab">
+    <ul class="layui-tab-title">
+        <li class="layui-this">用户设置</li>
+        <li>命令执行</li>
+    </ul>
+    <div class="layui-tab-content">
+        <div class="layui-tab-item layui-show">
+            <form class="layui-form" action="">
+                <div class="layui-form-item">
+                    <label class="layui-form-label">IP</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="title" lay-verify="title" autocomplete="off" placeholder="IP"
+                               class="layui-input" id="host">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">端口</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="title" lay-verify="title" autocomplete="off" placeholder="端口"
+                               class="layui-input" id="port">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">用户名</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="title" lay-verify="title" autocomplete="off" placeholder="用户名"
+                               class="layui-input" id="username">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">密码</label>
+                    <div class="layui-input-block">
+                        <input type="password" name="title" lay-verify="title" autocomplete="off" class="layui-input"
+                               id="password">
+                    </div>
+                </div>
+                <div class="layui-form-item">
+                    <label class="layui-form-label">超时时间</label>
+                    <div class="layui-input-block">
+                        <input type="text" name="timeout" lay-verify="title" autocomplete="off" class="layui-input"
+                               id="timeout">
+                    </div>
+                </div>
+            </form>
+        </div>
+        <div class="layui-tab-item">
+            <div class="layui-tab-item layui-show">
+                <form class="layui-form" action="">
+
+                    <div class="layui-form-item layui-form-text">
+                        <label class="layui-form-label">命令</label>
+                        <div class="layui-input-block">
+                            <textarea placeholder="请输入内容" class="layui-textarea" autoHeight="true" id="exec_str"></textarea>
+                        </div>
+                    </div>
+
+                    <div class="layui-form-item">
+                        <div class="layui-input-block">
+                            <button type="button" class="layui-btn" lay-filter="demo1" id="exec">执行选中内容</button>
+                        </div>
+                    </div>
+                    <div class="layui-form-item layui-form-text">
+                        <label class="layui-form-label">返回结果</label>
+                        <div class="layui-input-block">
+                            <textarea disabled style="height:500px" class="layui-textarea" autoHeight="true" id="return_str"></textarea>
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    let form = layui.form
+    let layer = layui.layer;
+    let $ = layui.jquery;
+    layui.code();
+    let historyList = [];
+    $(function () {
+        let hostInfo = localStorage.getItem('hostInfo');
+        if (hostInfo) {
+            hostInfo = JSON.parse(hostInfo);
+            $("#host").val(hostInfo["host"]);
+            $("#port").val(hostInfo["port"]);
+            $("#username").val(hostInfo["username"]);
+            $("#password").val(hostInfo["password"]);
+            $("#timeout").val(hostInfo["timeout"]);
+            $("#exec_str").val(hostInfo["exec_str"]);
+        }
+    });
+
+    // 文本域自动扩充,参考:https://fly.layui.com/jie/64353/
+    $.fn.autoHeight = function () {
+        function autoHeight(elem) {
+            elem.style.height = 'auto';
+            elem.scrollTop = 0; //防抖动
+            elem.style.height = elem.scrollHeight + 'px';
+        }
+
+        this.each(function () {
+            autoHeight(this);
+            $(this).on('keyup', function () {
+                autoHeight(this);
+            });
+        });
+    };
+    $('textarea[autoHeight]').autoHeight();
+
+    function getSelectText() {
+        var txt = "";
+        if (document.selection) {
+            txt = document.selection.createRange().text;
+        } else {
+            txt = document.getSelection();
+            //txt = window.getSelection();
+        }
+        return $.trim(txt.toString());
+    }
+
+    $("#exec_str").on('change',function () {
+        let data = {
+            "host": $("#host").val(),
+            "port": $("#port").val(),
+            "username": $("#username").val(),
+            "password": $("#password").val(),
+            "timeout": $("#timeout").val(),
+            "exec_str": $("#exec_str").val(),
+        };
+        localStorage.setItem('hostInfo', JSON.stringify(data));
+    });
+
+    $("#exec").click(function () {
+        let selectText = getSelectText();
+        if (selectText.length <= 0) {
+            return;
+        }
+        let data = {
+            "host": $("#host").val(),
+            "port": $("#port").val(),
+            "username": $("#username").val(),
+            "password": $("#password").val(),
+            "timeout": $("#timeout").val(),
+            "exec_str": selectText,
+        };
+        $("#exec").addClass('layui-btn-disabled');
+        axios.post("/exec", data).then(function (res) {
+            data = res.data;
+
+            if (historyList.length >= 50) {
+                historyList.pop();
+            }
+            historyList.unshift(data);
+            $("#return_str").val(historyList.join('\n'));
+            $("#return_str").css('height','500px');
+            $("#exec").removeClass('layui-btn-disabled');
+        });
+
+    });
+
+</script>
+</body>
+</html>

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/lay/modules/carousel.js


+ 2 - 0
static/lay/modules/code.js

@@ -0,0 +1,2 @@
+/** layui-v2.5.4 MIT License By https://www.layui.com */
+ ;layui.define("jquery",function(e){"use strict";var a=layui.$,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#39;").replace(/"/g,"&quot;")),c.html('<ol class="layui-code-ol"><li>'+o.replace(/[\r\t\n]+/g,"</li><li>")+"</li></ol>"),c.find(">.layui-code-h3")[0]||c.prepend('<h3 class="layui-code-h3">'+(c.attr("lay-title")||e.title||"code")+(e.about?'<a href="'+l+'" target="_blank">layui.code</a>':"")+"</h3>");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss");

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/lay/modules/colorpicker.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/lay/modules/element.js


+ 2 - 0
static/lay/modules/flow.js

@@ -0,0 +1,2 @@
+/** layui-v2.5.4 MIT License By https://www.layui.com */
+ ;layui.define("jquery",function(e){"use strict";var l=layui.$,o=function(e){},t='<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon ">&#xe63e;</i>';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var f=l(e.elem);if(f[0]){var m=l(e.scrollElem||document),u=e.mb||50,s=!("isAuto"in e)||e.isAuto,v=e.end||"没有更多了",y=e.scrollElem&&e.scrollElem!==document,d="<cite>加载更多</cite>",h=l('<div class="layui-flow-more"><a href="javascript:;">'+d+"</a></div>");f.find(".layui-flow-more")[0]||f.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(v):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(m.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=y?e.height():l(window).height(),n=y?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=u&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var m=e.attr("lay-src");layui.img(m,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",m).removeAttr("lay-src"),l[0]&&f(l),i++})}},f=function(e,o){var f=a?(o||n).height():l(window).height(),m=n.scrollTop(),u=m+f;if(t.lazyimg.elem=l(r),e)c(e,f);else for(var s=0;s<t.lazyimg.elem.length;s++){var v=t.lazyimg.elem.eq(s),y=a?function(){return v.offset().top-n.offset().top+m}():v.offset().top;if(c(v,f),i=s,y>u)break}};if(f(),!o){var m;n.on("scroll",function(){var e=l(this);m&&clearTimeout(m),m=setTimeout(function(){f(null,e)},50)}),o=!0}return f},e("flow",new o)});

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/lay/modules/form.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/lay/modules/jquery.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 1 - 0
static/lay/modules/laydate.js


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است