如果部署在 Python Anywhere 上,我如何确保此 Python Flask 应用程序能够正常运行?

问题描述 投票:0回答:0

概述:我正在尝试开发一个基于 Web 的 SSL 扫描器,作为后端,我正在使用子进程模块通过 python 代码在 ubuntu 发行版中执行 testssl.sh 脚本。

当前状态:我开发了一个前端,它有一个按钮和一个输入字段,用户应该在其中输入主机名/IP 地址,然后为了执行扫描,用户必须单击“开始扫描”按钮,这将允许 Python FLask 应用程序从表单中删除主机名,然后执行扫描,同时扫描正在运行,网页应该显示消息“扫描 hotsname 的服务器配置”,然后显示相应的消息扫描完成后,在网页上提供报告的下载链接。

我已经在 Python Anywhere 上部署了 Python Flask 应用程序,在浏览网站时,HTML 网页按预期显示,但问题是在本地主机中,当我单击网页上的“开始扫描”按钮时,它显示消息“扫描 hotsname 的服务器配置”,扫描实际运行并在大约 7 到 10 分钟内生成报告(取决于正在测试的已部署服务器配置的复杂性)。

问题:关于 flask 应用程序,当我从 Pythonanywhere 浏览网站时,单击开始扫描按钮后,它显示消息 “主机名扫描完成:{hostname}。5 秒内刷新。” 就在几秒钟。但这在本地主机上运行成功。

我附上了 Python Flask 代码和 HTML 代码供您参考,如果有人能指导我如何解决这个问题,我将非常感激?

HTML代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
  <title>SSL Scanner</title>
  <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
  <link rel="shortcut icon" type="image/x-icon" href="{{ url_for('static', filename='images/icons.ico') }}" />
</head>

<body>
  <div id="header">
    <div id="logo">
      <img src="{{ url_for('static', filename='images/image.jpeg') }}" width="150" height="50" alt="Logo"
        title="Scanner Logo" />
    </div>
    <div>
      <a href="" id="documentation">Documentation</a>
      <a href="mailto:[email protected]" id="contactUs">Contact Us</a>
    </div>
  </div>

  <div id="submitBox">
    <form method="POST" action="/scan" style="color: rgb(255, 119, 1)">
      <label for="hostname"><b>Hostname</b></label>
      <input type="text" name="hostname" id="hostname" required />
      <button id="submit-btn" type="submit" style="
            color: rgb(227, 216, 203);
            font-weight: bold;
            background-color: rgb(255, 119, 1);
            border-radius: 5px;
            padding: 8px 12px;
            border: none;
            cursor: pointer;
          ">
        Begin Scan
      </button>
      <label style="margin-left: 5px">Do not refresh or go back during an ongoing scan.</label>
    </form>
  </div>

  <div id="loading" style="
        display: none;
        padding: 30px;
        text-align: center;
        color: rgb(255, 119, 1);
      ">
    Scanning the server configuration of <span id="hostname-text"></span>...
  </div>
  <div id="return_output" style="padding: 10px; text-align: center; color: rgb(255, 119, 1)">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
      $("form").submit(function (event) {
        event.preventDefault();
        var hostname = $("#hostname").val();
        $("#hostname-text").text(hostname);
        $("#submit-btn").attr("disabled", true);
        $("#loading").show();
        $("#return_output").empty(); // Remove previous output message and download link when a hostname is submitted
        $.ajax({
          type: "POST",
          url: "/scan",
          data: $("form").serialize(),
          success: function (response) {
            // Display the output message
            $("#return_output").text(response.return_output);
            // Check if download link is available in response
            if (response.download_link) {
              // Create a download link element
              var downloadLink = $("<a>")
                .attr("href", response.download_link)
                .attr("download", "report.html")
                .text("   Download Scan Report");
              // Append download link element to the return_output div
              $("#return_output").append(downloadLink);
            }
            // Refreshes the webpage after 5 seconds to populate the table row and allows the user to see the output message alongwith download link in the meantime
            setTimeout(function () {
              location.reload();
            }, 5000);
          },
          error: function (error) {
            console.log(error);
          },
          complete: function () {
            $("#submit-btn").attr("disabled", false);
            $("#loading").hide();
          },
        });
      });
    </script>
  </div>
  <div id="last15scans" style="padding: 10px">
    <h4>Previously Generated Reports</h4>
    <table style="border: 2px solid rgb(255, 119, 1); border-collapse: collapse">
      <thead>
        <tr>
          <th>Hostname</th>
          <th>Date and Time</th>
          <th>Download Link</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
  </div>
  <script>
    $(document).ready(function () {
      // Retrieve last 15 scans data from Flask API and populate the table
      $.ajax({
        type: "GET",
        url: "/last15scans",
        success: function (data) {
          $.each(data, function (i, item) {
            var tr = $("<tr>");
            tr.append($("<td>").text(item.hostname));
            tr.append($("<td>").text(item.date_time));
            var downloadLink = $("<a>")
              .attr("href", item.download_link)
              .attr("download", "report.html")
              .text("Download");
            tr.append($("<td>").append(downloadLink));
            $("tbody", "#last15scans").append(tr);
          });
        },
        error: function (error) {
          console.log(error);
        },
      });
    });
  </script>
  <footer>
    <p>&copy; 2023 <b>PB Inc.</b></p>
  </footer>
</body>

</html>

改良烧瓶应用

from flask import Flask, render_template, request, jsonify, url_for, send_file
import os
import datetime
import subprocess

app = Flask(__name__)  # app: Test SSL Interface

dateandtime = datetime.datetime.now().strftime("%H%M")


@app.route("/")
def index():
    return render_template("Internal_Scanner.html")


@app.route("/scan", methods=["POST"])
def scan():
    # Get the hostname from the form data
    hostname = request.form["hostname"]

    if len(hostname) > 50:
        return jsonify({"return_output": "The hostname is too long."})
    elif hostname.find(" ") != -1:
        return jsonify(
            {
                "return_output": "The entered hostname is not valid as it has a whitespace."
            }
        )
    else:
        if hostname.find(":") == -1:
            htmlfilename = f"{hostname}_{dateandtime}.html"
        else:
            htmlfilename = f"{(hostname.split(':'))[0]}_{dateandtime}.html"

        # Call the backend code to scan the given hostname
        testssl_script_path = r"/mnt/c/inetpub/wwwroot/sslsc/testssl.sh-3.1dev"
        
        command = f'''bash --login -c "cd \\"{testssl_script_path}\\" && ./testssl.sh --htmlfile ../reports/scans/{htmlfilename} -p -s -f -P -S -h -H -I -T -BB -R -C -B -O -W -F -D -4 --openssl-timeout 5 {hostname}"'''
        # Execute the command
        subprocess.call(command, shell=True)

        return_output = (
            f"Scan completed for hostname: {hostname}. Refreshing in 5 seconds."
        )
        download_link = f"/api/download/{htmlfilename}"
        return jsonify({"return_output": return_output, "download_link": download_link})


@app.route("/api/download/<string:filename>", methods=["GET"])
def download_report(filename):
    # Serve the file from the reports directory
    # r"C:\WSL\reports\scans"
    file_path = os.path.join(r"C:\inetpub\wwwroot\sslsc\reports\scans", filename)
    if os.path.isfile(file_path):
        return send_file(file_path, as_attachment=True)
    else:
        return jsonify({"error": "File not found"})


if __name__ == "__main__":
    app.run()

烧瓶应用

from flask import Flask, render_template, request, jsonify, url_for, send_file
import os
import datetime
import subprocess

app = Flask(__name__)  # app: Test SSL Interface

dateandtime = datetime.datetime.now().strftime("%H%M")

@app.route("/")
def index():
    return render_template("Internal_Scanner.html")


@app.route("/scan", methods=["POST"])
def scan():
    # Get the hostname from the form data
    hostname = request.form["hostname"]

    if len(hostname) > 50:
        return jsonify({"return_output": "The hostname is too long."})
    elif hostname.find(" ") != -1:
        return jsonify(
            {
                "return_output": "The entered hostname is not valid as it has a whitespace."
            }
        )
    else:
        if hostname.find(":") == -1:
            htmlfilename = f"{hostname}_{dateandtime}.html"
        else:
            htmlfilename = f"{(hostname.split(':'))[0]}_{dateandtime}.html"

        # Call the backend code to scan the given hostname
        # Opens the actual path to the ubuntu.exe file and executes the ubuntu.exe file
        process = subprocess.Popen(
            [r"C:\inetpub\wwwroot\Ubuntu\Ubuntu_2004.2021.825.0_x64\ubuntu.exe"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
        )
        # Change the directory where the testssl.sh script is stored
        process.stdin.write(b"cd /mnt/c/inetpub/wwwroot/sslsc/testssl.sh-3.1dev\n")
        process.stdin.flush()

        # Execute the testssl.sh script with the URL and redirect the output to a folder
        if hostname.find(":") == -1:
            htmlfilename = f"{hostname}_{dateandtime}.html"
            jsonfilename = f"{hostname}_{dateandtime}.json"
        else:
            htmlfilename = f"{(hostname.split(':'))[0]}_{dateandtime}.html"
            jsonfilename = f"{(hostname.split(':'))[0]}_{dateandtime}.json"

        command = f"./testssl.sh --htmlfile ../reports/scans/{htmlfilename} --jsonfile ../reports/jsons/{jsonfilename} -p -s -f -P -S -h -H -I -T -BB -R -C -B -O -W -F -D -4 --openssl-timeout 5 {hostname}\n"
        process.stdin.write(command.encode())
        process.stdin.flush()
        process.communicate()
        return_output = f"Scan completed for hostname: {hostname}. Refreshing in 5 seconds."
        download_link = f"/api/download/{htmlfilename}"
        return jsonify({"return_output": return_output, "download_link": download_link})


@app.route("/api/download/<string:filename>", methods=["GET"])
def download_report(filename):
    # Serve the file from the reports directory
    # r"C:\WSL\reports\scans"
    file_path = os.path.join(r"C:\inetpub\wwwroot\sslsc\reports\scans", filename)
    if os.path.isfile(file_path):
        return send_file(file_path, as_attachment=True)
    else:
        return jsonify({"error": "File not found"})

if __name__ == "__main__":
    app.run()

早些时候我将它部署在 IIS 10 上,我也遇到了同样的问题。有什么方法可以通过这种方式实现目标吗?

python flask subprocess pythonanywhere testssl.sh
© www.soinside.com 2019 - 2024. All rights reserved.