#!/usr/bin/env python3
"""
Intentionally vulnerable login app for the "Analyzing Insecure Traffic
with Wireshark" lab in cloud_pt.

Serves a login form over plain HTTP (no TLS). Submitted credentials travel
as an unencrypted application/x-www-form-urlencoded POST body, so anyone
capturing traffic between the browser and this server (e.g. with
Wireshark) can read the username and password in the clear. That's the
entire point: replicate what http://testphp.vulnweb.com/login.php used to
demonstrate, now that it's gone.

Run it, then browse to the printed URL:

    python app.py

Demo credentials: username "test", password "test" (matches the original
lab's instructions and the self-check answers on the lab page).

Binds to 127.0.0.1 by default, so the traffic stays on your own machine.
Capture it in Wireshark on the loopback interface, not Wi-Fi/Ethernet.
Only use --host 0.0.0.0 on a network you have explicit permission to run
an insecure, unauthenticated login page on.

Intended to be run from a BTECH Lab Laptop, not a high school computer or
a BTECH PC. If you're running it from home instead, only do so if you
trust the copy of this file you downloaded.
"""

import argparse
import html
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs

DEMO_USERNAME = "test"
DEMO_PASSWORD = "test"

LOGIN_FORM = """<!doctype html>
<html>
<head><title>Insecure Login</title></head>
<body style="font-family: sans-serif; max-width: 420px; margin: 4rem auto;">
<h2>Employee Portal Login</h2>
<p style="color: #b3261e;">This page is served over plain HTTP. Nothing you type here is encrypted.</p>
<form method="post" action="/login.php">
  <p><label>Username<br><input type="text" name="username"></label></p>
  <p><label>Password<br><input type="password" name="password"></label></p>
  <p><button type="submit">Login</button></p>
</form>
<p><em>Demo credentials: test / test</em></p>
{message}
</body>
</html>"""


class InsecureLoginHandler(BaseHTTPRequestHandler):
    server_version = "InsecureLoginDemo/1.0"

    def _send_html(self, body):
        encoded = body.encode("utf-8")
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(encoded)))
        self.end_headers()
        self.wfile.write(encoded)

    def do_GET(self):
        if self.path in ("/", "/login.php"):
            self._send_html(LOGIN_FORM.format(message=""))
        else:
            self.send_error(404)

    def do_POST(self):
        if self.path != "/login.php":
            self.send_error(404)
            return

        length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(length).decode("utf-8", errors="replace")
        fields = parse_qs(body)
        username = html.escape(fields.get("username", [""])[0])
        password = html.escape(fields.get("password", [""])[0])

        if username == DEMO_USERNAME and password == DEMO_PASSWORD:
            message = f"<p style='color: #1a7f4a;'>Login successful. Welcome, {username}.</p>"
        else:
            message = f"<p style='color: #b3261e;'>Login failed for username \"{username}\".</p>"

        self._send_html(LOGIN_FORM.format(message=message))

    def log_message(self, fmt, *args):
        print(f"[{self.address_string()}] {fmt % args}")


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--host", default="127.0.0.1", help="bind address (default: 127.0.0.1)")
    parser.add_argument("--port", type=int, default=8080, help="bind port (default: 8080)")
    args = parser.parse_args()

    server = HTTPServer((args.host, args.port), InsecureLoginHandler)
    print(f"Insecure login demo running at http://{args.host}:{args.port}/login.php")
    print("This is plain HTTP with no encryption. That's intentional. Ctrl+C to stop.")
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        server.server_close()


if __name__ == "__main__":
    main()
