moved majority of html into dedicated files and created a loader for the templates to separate code from html
This commit is contained in:
15
src/templates/__init__.py
Normal file
15
src/templates/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Templates package for the deception server.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .template_loader import load_template, clear_cache, TemplateNotFoundError
|
||||||
|
from . import html_templates
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'load_template',
|
||||||
|
'clear_cache',
|
||||||
|
'TemplateNotFoundError',
|
||||||
|
'html_templates',
|
||||||
|
]
|
||||||
20
src/templates/html/directory_listing.html
Normal file
20
src/templates/html/directory_listing.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><title>Index of {path}</title>
|
||||||
|
<style>
|
||||||
|
body {{ font-family: monospace; background: #fff; padding: 20px; }}
|
||||||
|
h1 {{ border-bottom: 1px solid #ccc; padding-bottom: 10px; }}
|
||||||
|
table {{ width: 100%; border-collapse: collapse; }}
|
||||||
|
th {{ text-align: left; padding: 10px; background: #f0f0f0; }}
|
||||||
|
td {{ padding: 8px; border-bottom: 1px solid #eee; }}
|
||||||
|
a {{ color: #0066cc; text-decoration: none; }}
|
||||||
|
a:hover {{ text-decoration: underline; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Index of {path}</h1>
|
||||||
|
<table>
|
||||||
|
<tr><th>Name</th><th>Last Modified</th><th>Size</th></tr>
|
||||||
|
<tr><td><a href="../">Parent Directory</a></td><td>-</td><td>-</td></tr>
|
||||||
|
{rows}
|
||||||
|
</table></body></html>
|
||||||
1
src/templates/html/directory_row.html
Normal file
1
src/templates/html/directory_row.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<tr><td><a href="{href}">{name}</a></td><td>{date}</td><td>{size}</td></tr>
|
||||||
29
src/templates/html/login_error.html
Normal file
29
src/templates/html/login_error.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Login Failed</title>
|
||||||
|
<style>
|
||||||
|
body {{ font-family: Arial, sans-serif; background: #f0f0f0; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }}
|
||||||
|
.login-box {{ background: white; padding: 40px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); width: 300px; }}
|
||||||
|
h2 {{ margin-top: 0; color: #333; }}
|
||||||
|
.error {{ color: #d63301; background: #ffebe8; border: 1px solid #d63301; padding: 12px; margin-bottom: 20px; border-radius: 4px; }}
|
||||||
|
input {{ width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; }}
|
||||||
|
button {{ width: 100%; padding: 10px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }}
|
||||||
|
button:hover {{ background: #0056b3; }}
|
||||||
|
a {{ color: #007bff; font-size: 14px; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="login-box">
|
||||||
|
<h2>Admin Login</h2>
|
||||||
|
<div class="error"><strong>ERROR:</strong> Invalid username or password.</div>
|
||||||
|
<form action="/admin/login" method="post">
|
||||||
|
<input type="text" name="username" placeholder="Username" required>
|
||||||
|
<input type="password" name="password" placeholder="Password" required>
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
<p style="margin-top: 20px; text-align: center;"><a href="/forgot-password">Forgot your password?</a></p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
25
src/templates/html/login_form.html
Normal file
25
src/templates/html/login_form.html
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Admin Login</title>
|
||||||
|
<style>
|
||||||
|
body {{ font-family: Arial, sans-serif; background: #f0f0f0; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }}
|
||||||
|
.login-box {{ background: white; padding: 40px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); width: 300px; }}
|
||||||
|
h2 {{ margin-top: 0; color: #333; }}
|
||||||
|
input {{ width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; }}
|
||||||
|
button {{ width: 100%; padding: 10px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }}
|
||||||
|
button:hover {{ background: #0056b3; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="login-box">
|
||||||
|
<h2>Admin Login</h2>
|
||||||
|
<form action="/admin/login" method="post">
|
||||||
|
<input type="text" name="username" placeholder="Username" required>
|
||||||
|
<input type="password" name="password" placeholder="Password" required>
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
24
src/templates/html/phpmyadmin.html
Normal file
24
src/templates/html/phpmyadmin.html
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>phpMyAdmin</title>
|
||||||
|
<style>
|
||||||
|
body {{ font-family: 'Segoe UI', Tahoma, sans-serif; margin: 0; background: #f0f0f0; }}
|
||||||
|
.header {{ background: #2979ff; color: white; padding: 10px 20px; }}
|
||||||
|
.login {{ background: white; width: 400px; margin: 100px auto; padding: 30px; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
|
||||||
|
input {{ width: 100%; padding: 8px; margin: 8px 0; border: 1px solid #ddd; }}
|
||||||
|
button {{ padding: 10px 20px; background: #2979ff; color: white; border: none; cursor: pointer; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header"><h1>phpMyAdmin</h1></div>
|
||||||
|
<div class="login">
|
||||||
|
<h2>MySQL Server Login</h2>
|
||||||
|
<form action="/phpMyAdmin/index.php" method="post">
|
||||||
|
<input type="text" name="pma_username" placeholder="Username">
|
||||||
|
<input type="password" name="pma_password" placeholder="Password">
|
||||||
|
<button type="submit">Go</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
19
src/templates/html/robots.txt
Normal file
19
src/templates/html/robots.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /admin/
|
||||||
|
Disallow: /api/
|
||||||
|
Disallow: /backup/
|
||||||
|
Disallow: /config/
|
||||||
|
Disallow: /database/
|
||||||
|
Disallow: /private/
|
||||||
|
Disallow: /uploads/
|
||||||
|
Disallow: /wp-admin/
|
||||||
|
Disallow: /phpMyAdmin/
|
||||||
|
Disallow: /admin/login.php
|
||||||
|
Disallow: /api/v1/users
|
||||||
|
Disallow: /api/v2/secrets
|
||||||
|
Disallow: /.env
|
||||||
|
Disallow: /credentials.txt
|
||||||
|
Disallow: /passwords.txt
|
||||||
|
Disallow: /.git/
|
||||||
|
Disallow: /backup.sql
|
||||||
|
Disallow: /db_backup.sql
|
||||||
73
src/templates/html/wordpress.html
Normal file
73
src/templates/html/wordpress.html
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>My Blog – Just another WordPress site</title>
|
||||||
|
<link rel='dns-prefetch' href='//s.w.org' />
|
||||||
|
<link rel='stylesheet' id='wp-block-library-css' href='/wp-includes/css/dist/block-library/style.min.css' type='text/css' media='all' />
|
||||||
|
<link rel='stylesheet' id='twentytwentythree-style-css' href='/wp-content/themes/twentytwentythree/style.css' type='text/css' media='all' />
|
||||||
|
<link rel='https://api.w.org/' href='/wp-json/' />
|
||||||
|
<meta name="generator" content="WordPress 6.4.2" />
|
||||||
|
<style>
|
||||||
|
body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; margin: 0; padding: 0; background: #fff; }}
|
||||||
|
.site-header {{ background: #23282d; color: white; padding: 20px; border-bottom: 4px solid #0073aa; }}
|
||||||
|
.site-header h1 {{ margin: 0; font-size: 28px; }}
|
||||||
|
.site-header p {{ margin: 5px 0 0; color: #d0d0d0; }}
|
||||||
|
.site-content {{ max-width: 1200px; margin: 40px auto; padding: 0 20px; }}
|
||||||
|
.entry {{ background: #fff; margin-bottom: 40px; padding: 30px; border: 1px solid #ddd; border-radius: 4px; }}
|
||||||
|
.entry-title {{ font-size: 32px; margin-top: 0; color: #23282d; }}
|
||||||
|
.entry-meta {{ color: #666; font-size: 14px; margin-bottom: 20px; }}
|
||||||
|
.entry-content {{ line-height: 1.8; color: #444; }}
|
||||||
|
.site-footer {{ background: #f7f7f7; padding: 20px; text-align: center; color: #666; border-top: 1px solid #ddd; margin-top: 60px; }}
|
||||||
|
a {{ color: #0073aa; text-decoration: none; }}
|
||||||
|
a:hover {{ text-decoration: underline; }}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="home blog wp-embed-responsive">
|
||||||
|
<div id="page" class="site">
|
||||||
|
<header id="masthead" class="site-header">
|
||||||
|
<div class="site-branding">
|
||||||
|
<h1 class="site-title">My Blog</h1>
|
||||||
|
<p class="site-description">Just another WordPress site</p>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div id="content" class="site-content">
|
||||||
|
<article id="post-1" class="entry">
|
||||||
|
<header class="entry-header">
|
||||||
|
<h2 class="entry-title">Hello world!</h2>
|
||||||
|
<div class="entry-meta">
|
||||||
|
<span class="posted-on">Posted on <time datetime="2024-12-01">December 1, 2024</time></span>
|
||||||
|
<span class="byline"> by <span class="author">admin</span></span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="entry-content">
|
||||||
|
<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article id="post-2" class="entry">
|
||||||
|
<header class="entry-header">
|
||||||
|
<h2 class="entry-title">About This Site</h2>
|
||||||
|
<div class="entry-meta">
|
||||||
|
<span class="posted-on">Posted on <time datetime="2024-11-28">November 28, 2024</time></span>
|
||||||
|
<span class="byline"> by <span class="author">admin</span></span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="entry-content">
|
||||||
|
<p>This is a sample page. You can use it to write about your site, yourself, or anything else you'd like.</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer id="colophon" class="site-footer">
|
||||||
|
<div class="site-info">
|
||||||
|
Proudly powered by <a href="https://wordpress.org/">WordPress</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
<script type='text/javascript' src='/wp-includes/js/wp-embed.min.js'></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -2,228 +2,46 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
HTML templates for the deception server.
|
HTML templates for the deception server.
|
||||||
Edit these templates to customize the appearance of fake pages.
|
Templates are loaded from the html/ subdirectory.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from .template_loader import load_template
|
||||||
|
|
||||||
|
|
||||||
def login_form() -> str:
|
def login_form() -> str:
|
||||||
"""Generate fake login page"""
|
"""Generate fake login page"""
|
||||||
return """<!DOCTYPE html>
|
return load_template("login_form")
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Admin Login</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; background: #f0f0f0; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
|
|
||||||
.login-box { background: white; padding: 40px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); width: 300px; }
|
|
||||||
h2 { margin-top: 0; color: #333; }
|
|
||||||
input { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; }
|
|
||||||
button { width: 100%; padding: 10px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
|
||||||
button:hover { background: #0056b3; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="login-box">
|
|
||||||
<h2>Admin Login</h2>
|
|
||||||
<form action="/admin/login" method="post">
|
|
||||||
<input type="text" name="username" placeholder="Username" required>
|
|
||||||
<input type="password" name="password" placeholder="Password" required>
|
|
||||||
<button type="submit">Login</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>"""
|
|
||||||
|
|
||||||
|
|
||||||
def login_error() -> str:
|
def login_error() -> str:
|
||||||
"""Generate fake login error page"""
|
"""Generate fake login error page"""
|
||||||
return """<!DOCTYPE html>
|
return load_template("login_error")
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Login Failed</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; background: #f0f0f0; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
|
|
||||||
.login-box { background: white; padding: 40px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); width: 300px; }
|
|
||||||
h2 { margin-top: 0; color: #333; }
|
|
||||||
.error { color: #d63301; background: #ffebe8; border: 1px solid #d63301; padding: 12px; margin-bottom: 20px; border-radius: 4px; }
|
|
||||||
input { width: 100%; padding: 10px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; }
|
|
||||||
button { width: 100%; padding: 10px; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
|
|
||||||
button:hover { background: #0056b3; }
|
|
||||||
a { color: #007bff; font-size: 14px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="login-box">
|
|
||||||
<h2>Admin Login</h2>
|
|
||||||
<div class="error"><strong>ERROR:</strong> Invalid username or password.</div>
|
|
||||||
<form action="/admin/login" method="post">
|
|
||||||
<input type="text" name="username" placeholder="Username" required>
|
|
||||||
<input type="password" name="password" placeholder="Password" required>
|
|
||||||
<button type="submit">Login</button>
|
|
||||||
</form>
|
|
||||||
<p style="margin-top: 20px; text-align: center;"><a href="/forgot-password">Forgot your password?</a></p>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>"""
|
|
||||||
|
|
||||||
|
|
||||||
def wordpress() -> str:
|
def wordpress() -> str:
|
||||||
"""Generate fake WordPress page"""
|
"""Generate fake WordPress page"""
|
||||||
return """<!DOCTYPE html>
|
return load_template("wordpress")
|
||||||
<html lang="en-US">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>My Blog – Just another WordPress site</title>
|
|
||||||
<link rel='dns-prefetch' href='//s.w.org' />
|
|
||||||
<link rel='stylesheet' id='wp-block-library-css' href='/wp-includes/css/dist/block-library/style.min.css' type='text/css' media='all' />
|
|
||||||
<link rel='stylesheet' id='twentytwentythree-style-css' href='/wp-content/themes/twentytwentythree/style.css' type='text/css' media='all' />
|
|
||||||
<link rel='https://api.w.org/' href='/wp-json/' />
|
|
||||||
<meta name="generator" content="WordPress 6.4.2" />
|
|
||||||
<style>
|
|
||||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; margin: 0; padding: 0; background: #fff; }
|
|
||||||
.site-header { background: #23282d; color: white; padding: 20px; border-bottom: 4px solid #0073aa; }
|
|
||||||
.site-header h1 { margin: 0; font-size: 28px; }
|
|
||||||
.site-header p { margin: 5px 0 0; color: #d0d0d0; }
|
|
||||||
.site-content { max-width: 1200px; margin: 40px auto; padding: 0 20px; }
|
|
||||||
.entry { background: #fff; margin-bottom: 40px; padding: 30px; border: 1px solid #ddd; border-radius: 4px; }
|
|
||||||
.entry-title { font-size: 32px; margin-top: 0; color: #23282d; }
|
|
||||||
.entry-meta { color: #666; font-size: 14px; margin-bottom: 20px; }
|
|
||||||
.entry-content { line-height: 1.8; color: #444; }
|
|
||||||
.site-footer { background: #f7f7f7; padding: 20px; text-align: center; color: #666; border-top: 1px solid #ddd; margin-top: 60px; }
|
|
||||||
a { color: #0073aa; text-decoration: none; }
|
|
||||||
a:hover { text-decoration: underline; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body class="home blog wp-embed-responsive">
|
|
||||||
<div id="page" class="site">
|
|
||||||
<header id="masthead" class="site-header">
|
|
||||||
<div class="site-branding">
|
|
||||||
<h1 class="site-title">My Blog</h1>
|
|
||||||
<p class="site-description">Just another WordPress site</p>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div id="content" class="site-content">
|
|
||||||
<article id="post-1" class="entry">
|
|
||||||
<header class="entry-header">
|
|
||||||
<h2 class="entry-title">Hello world!</h2>
|
|
||||||
<div class="entry-meta">
|
|
||||||
<span class="posted-on">Posted on <time datetime="2024-12-01">December 1, 2024</time></span>
|
|
||||||
<span class="byline"> by <span class="author">admin</span></span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="entry-content">
|
|
||||||
<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>
|
|
||||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article id="post-2" class="entry">
|
|
||||||
<header class="entry-header">
|
|
||||||
<h2 class="entry-title">About This Site</h2>
|
|
||||||
<div class="entry-meta">
|
|
||||||
<span class="posted-on">Posted on <time datetime="2024-11-28">November 28, 2024</time></span>
|
|
||||||
<span class="byline"> by <span class="author">admin</span></span>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<div class="entry-content">
|
|
||||||
<p>This is a sample page. You can use it to write about your site, yourself, or anything else you'd like.</p>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer id="colophon" class="site-footer">
|
|
||||||
<div class="site-info">
|
|
||||||
Proudly powered by <a href="https://wordpress.org/">WordPress</a>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
<script type='text/javascript' src='/wp-includes/js/wp-embed.min.js'></script>
|
|
||||||
</body>
|
|
||||||
</html>"""
|
|
||||||
|
|
||||||
|
|
||||||
def phpmyadmin() -> str:
|
def phpmyadmin() -> str:
|
||||||
"""Generate fake phpMyAdmin page"""
|
"""Generate fake phpMyAdmin page"""
|
||||||
return """<!DOCTYPE html>
|
return load_template("phpmyadmin")
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>phpMyAdmin</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: 'Segoe UI', Tahoma, sans-serif; margin: 0; background: #f0f0f0; }
|
|
||||||
.header { background: #2979ff; color: white; padding: 10px 20px; }
|
|
||||||
.login { background: white; width: 400px; margin: 100px auto; padding: 30px; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
||||||
input { width: 100%; padding: 8px; margin: 8px 0; border: 1px solid #ddd; }
|
|
||||||
button { padding: 10px 20px; background: #2979ff; color: white; border: none; cursor: pointer; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="header"><h1>phpMyAdmin</h1></div>
|
|
||||||
<div class="login">
|
|
||||||
<h2>MySQL Server Login</h2>
|
|
||||||
<form action="/phpMyAdmin/index.php" method="post">
|
|
||||||
<input type="text" name="pma_username" placeholder="Username">
|
|
||||||
<input type="password" name="pma_password" placeholder="Password">
|
|
||||||
<button type="submit">Go</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>"""
|
|
||||||
|
|
||||||
|
|
||||||
def robots_txt() -> str:
|
def robots_txt() -> str:
|
||||||
"""Generate juicy robots.txt"""
|
"""Generate juicy robots.txt"""
|
||||||
return """User-agent: *
|
return load_template("robots.txt")
|
||||||
Disallow: /admin/
|
|
||||||
Disallow: /api/
|
|
||||||
Disallow: /backup/
|
|
||||||
Disallow: /config/
|
|
||||||
Disallow: /database/
|
|
||||||
Disallow: /private/
|
|
||||||
Disallow: /uploads/
|
|
||||||
Disallow: /wp-admin/
|
|
||||||
Disallow: /phpMyAdmin/
|
|
||||||
Disallow: /admin/login.php
|
|
||||||
Disallow: /api/v1/users
|
|
||||||
Disallow: /api/v2/secrets
|
|
||||||
Disallow: /.env
|
|
||||||
Disallow: /credentials.txt
|
|
||||||
Disallow: /passwords.txt
|
|
||||||
Disallow: /.git/
|
|
||||||
Disallow: /backup.sql
|
|
||||||
Disallow: /db_backup.sql
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
def directory_listing(path: str, dirs: list, files: list) -> str:
|
def directory_listing(path: str, dirs: list, files: list) -> str:
|
||||||
"""Generate fake directory listing"""
|
"""Generate fake directory listing"""
|
||||||
html = f"""<!DOCTYPE html>
|
row_template = load_template("directory_row")
|
||||||
<html>
|
|
||||||
<head><title>Index of {path}</title>
|
|
||||||
<style>
|
|
||||||
body {{ font-family: monospace; background: #fff; padding: 20px; }}
|
|
||||||
h1 {{ border-bottom: 1px solid #ccc; padding-bottom: 10px; }}
|
|
||||||
table {{ width: 100%; border-collapse: collapse; }}
|
|
||||||
th {{ text-align: left; padding: 10px; background: #f0f0f0; }}
|
|
||||||
td {{ padding: 8px; border-bottom: 1px solid #eee; }}
|
|
||||||
a {{ color: #0066cc; text-decoration: none; }}
|
|
||||||
a:hover {{ text-decoration: underline; }}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Index of {path}</h1>
|
|
||||||
<table>
|
|
||||||
<tr><th>Name</th><th>Last Modified</th><th>Size</th></tr>
|
|
||||||
<tr><td><a href="../">Parent Directory</a></td><td>-</td><td>-</td></tr>
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
rows = ""
|
||||||
for d in dirs:
|
for d in dirs:
|
||||||
html += f'<tr><td><a href="{d}">{d}</a></td><td>2024-12-01 10:30</td><td>-</td></tr>\n'
|
rows += row_template.format(href=d, name=d, date="2024-12-01 10:30", size="-")
|
||||||
|
|
||||||
for f, size in files:
|
for f, size in files:
|
||||||
html += f'<tr><td><a href="{f}">{f}</a></td><td>2024-12-01 14:22</td><td>{size}</td></tr>\n'
|
rows += row_template.format(href=f, name=f, date="2024-12-01 14:22", size=size)
|
||||||
|
|
||||||
html += '</table></body></html>'
|
return load_template("directory_listing", path=path, rows=rows)
|
||||||
return html
|
|
||||||
|
|||||||
67
src/templates/template_loader.py
Normal file
67
src/templates/template_loader.py
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
Template loader for HTML templates.
|
||||||
|
Loads templates from the html/ subdirectory and supports string formatting for dynamic content.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateNotFoundError(Exception):
|
||||||
|
"""Raised when a template file cannot be found."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Module-level cache for loaded templates
|
||||||
|
_template_cache: Dict[str, str] = {}
|
||||||
|
|
||||||
|
# Base directory for template files
|
||||||
|
_TEMPLATE_DIR = Path(__file__).parent / "html"
|
||||||
|
|
||||||
|
|
||||||
|
def load_template(name: str, **kwargs) -> str:
|
||||||
|
"""
|
||||||
|
Load a template by name and optionally substitute placeholders.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Template name (without extension for HTML, with extension for others like .txt)
|
||||||
|
**kwargs: Key-value pairs for placeholder substitution using str.format()
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Rendered template string
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
TemplateNotFoundError: If template file doesn't exist
|
||||||
|
|
||||||
|
Example:
|
||||||
|
>>> load_template("login_form") # Loads html/login_form.html
|
||||||
|
>>> load_template("robots.txt") # Loads html/robots.txt
|
||||||
|
>>> load_template("directory_listing", path="/var/www", rows="<tr>...</tr>")
|
||||||
|
"""
|
||||||
|
# Check cache first
|
||||||
|
if name not in _template_cache:
|
||||||
|
# Determine file path based on whether name has an extension
|
||||||
|
if '.' in name:
|
||||||
|
file_path = _TEMPLATE_DIR / name
|
||||||
|
else:
|
||||||
|
file_path = _TEMPLATE_DIR / f"{name}.html"
|
||||||
|
|
||||||
|
if not file_path.exists():
|
||||||
|
raise TemplateNotFoundError(f"Template '{name}' not found at {file_path}")
|
||||||
|
|
||||||
|
_template_cache[name] = file_path.read_text(encoding='utf-8')
|
||||||
|
|
||||||
|
template = _template_cache[name]
|
||||||
|
|
||||||
|
# Apply substitutions if kwargs provided
|
||||||
|
if kwargs:
|
||||||
|
template = template.format(**kwargs)
|
||||||
|
|
||||||
|
return template
|
||||||
|
|
||||||
|
|
||||||
|
def clear_cache() -> None:
|
||||||
|
"""Clear the template cache. Useful for testing or development."""
|
||||||
|
_template_cache.clear()
|
||||||
Reference in New Issue
Block a user