Merge pull request #177 from abneeeees/improvement/header-and-footer
feat(header and footer): Enhance header and footer
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
WEB_APP_PORT=5000
|
WEB_APP_PORT=5000
|
||||||
|
|
||||||
# Application configuration
|
# Application configuration
|
||||||
|
PROJECT_VERSION=3.1.2
|
||||||
MAX_CONTENT_LENGTH=3145728
|
MAX_CONTENT_LENGTH=3145728
|
||||||
MAX_PENDING_TIME=600
|
MAX_PENDING_TIME=600
|
||||||
MAX_STORE_TIME=259200
|
MAX_STORE_TIME=259200
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ Thanks to contributors:
|
|||||||
- [Zeecka](https://www.zeecka.fr/) - **(author)**
|
- [Zeecka](https://www.zeecka.fr/) - **(author)**
|
||||||
- [aradhyacp](https://github.com/aradhyacp)
|
- [aradhyacp](https://github.com/aradhyacp)
|
||||||
- [Philip Zimmermann](https://github.com/Philip-Zimmermann)
|
- [Philip Zimmermann](https://github.com/Philip-Zimmermann)
|
||||||
|
- [abneeeees](https://github.com/abneeeees)
|
||||||
|
|
||||||
Thanks to the open-source community:
|
Thanks to the open-source community:
|
||||||
[binwalk](https://github.com/ReFirmLabs/binwalk), [exiftool](https://exiftool.org/), [GraphicsMagick identify](http://www.graphicsmagick.org/identify.html), [foremost](https://foremost.sourceforge.net/), [openstego](https://www.openstego.com/), [outguess](https://www.rbcafe.com/software/outguess/), [pngcheck](https://www.libpng.org/pub/png/apps/pngcheck.html), [steghide](https://steghide.sourceforge.net/), [strings](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/strings.html), [zsteg](https://github.com/zed-0xff/zsteg), ...
|
[binwalk](https://github.com/ReFirmLabs/binwalk), [exiftool](https://exiftool.org/), [GraphicsMagick identify](http://www.graphicsmagick.org/identify.html), [foremost](https://foremost.sourceforge.net/), [openstego](https://www.openstego.com/), [outguess](https://www.rbcafe.com/software/outguess/), [pngcheck](https://www.libpng.org/pub/png/apps/pngcheck.html), [steghide](https://steghide.sourceforge.net/), [strings](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/strings.html), [zsteg](https://github.com/zed-0xff/zsteg), ...
|
||||||
|
|||||||
@@ -36,11 +36,17 @@ def create_app() -> Flask:
|
|||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.json.sort_keys = False # type: ignore
|
app.json.sort_keys = False # type: ignore
|
||||||
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI")
|
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DB_URI")
|
||||||
|
app.config["PROJECT_VERSION"] = os.getenv("PROJECT_VERSION")
|
||||||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
||||||
app.config["MAX_CONTENT_LENGTH"] = int(os.environ.get("MAX_CONTENT_LENGTH", 1024 * 1024))
|
app.config["MAX_CONTENT_LENGTH"] = int(os.environ.get("MAX_CONTENT_LENGTH", 1024 * 1024))
|
||||||
app.config["REDIS_QUEUE"] = Queue(connection=Redis(host="redis", port=6379))
|
app.config["REDIS_QUEUE"] = Queue(connection=Redis(host="redis", port=6379))
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_datetime() -> dict[str, Any]:
|
||||||
|
"""Inject datetime into all templates."""
|
||||||
|
return {"datetime": datetime}
|
||||||
|
|
||||||
@app.errorhandler(413)
|
@app.errorhandler(413)
|
||||||
def too_large(_: Any) -> tuple[Response, int]:
|
def too_large(_: Any) -> tuple[Response, int]:
|
||||||
"""Error Handler for Max File Size."""
|
"""Error Handler for Max File Size."""
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -105,11 +105,12 @@ document.addEventListener('click', function (event) {
|
|||||||
// Check if the clicked element is a copy icon
|
// Check if the clicked element is a copy icon
|
||||||
if (event.target.classList.contains('copy-icon')) {
|
if (event.target.classList.contains('copy-icon')) {
|
||||||
const icon = event.target;
|
const icon = event.target;
|
||||||
const textarea = icon.closest('.textarea-container').querySelector('textarea');
|
const codeContainer = icon.closest('.code-container');
|
||||||
|
const codeBlock = codeContainer ? codeContainer.querySelector('code') : null;
|
||||||
|
|
||||||
if (textarea) {
|
if (codeBlock) {
|
||||||
textarea.select();
|
const textToCopy = codeBlock.textContent;
|
||||||
navigator.clipboard.writeText(textarea.value).then(() => {
|
navigator.clipboard.writeText(textToCopy).then(() => {
|
||||||
icon.classList.remove('fa-copy');
|
icon.classList.remove('fa-copy');
|
||||||
icon.classList.add('fa-check');
|
icon.classList.add('fa-check');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -487,16 +488,13 @@ function parseResult(result) {
|
|||||||
analyzer.innerHTML += `<div class="alert alert-success" role="alert">${output}</div>`;
|
analyzer.innerHTML += `<div class="alert alert-success" role="alert">${output}</div>`;
|
||||||
} else if (Array.isArray(result[tool]["output"])) {
|
} else if (Array.isArray(result[tool]["output"])) {
|
||||||
if (result[tool]["output"].length > 0) {
|
if (result[tool]["output"].length > 0) {
|
||||||
var texarea_content = `<div class="textarea-container">`;
|
var code_content = `<div class="code-container position-relative mb-2">`;
|
||||||
texarea_content += `<textarea class="form-control w-100 mb-2" rows="8" readonly>`;
|
code_content += `<pre class="mb-0"><code>`;
|
||||||
for (const line of result[tool]["output"]) {
|
code_content += result[tool]["output"].map(line => escapeHtml(line)).join('\n').trim();
|
||||||
texarea_content += escapeHtml(`${line}\n`);
|
code_content += `</code></pre>`;
|
||||||
}
|
code_content += `<i class="fas fa-copy copy-icon"></i>`;
|
||||||
texarea_content = texarea_content.trim();
|
code_content += `</div>`;
|
||||||
texarea_content += `</textarea>`;
|
analyzer.innerHTML += code_content;
|
||||||
texarea_content += `<i class="fas fa-copy copy-icon"></i>`;
|
|
||||||
texarea_content += `</div>`;
|
|
||||||
analyzer.innerHTML += texarea_content;
|
|
||||||
}
|
}
|
||||||
} else if (typeof result[tool]["output"] === "object") {
|
} else if (typeof result[tool]["output"] === "object") {
|
||||||
var table_content = `<div class="table-container">`;
|
var table_content = `<div class="table-container">`;
|
||||||
@@ -739,3 +737,4 @@ if (browseBtn) {
|
|||||||
xhr.send(formData);
|
xhr.send(formData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,30 +2,48 @@
|
|||||||
<html lang="en" data-bs-theme="dark">
|
<html lang="en" data-bs-theme="dark">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||||
<title>Aperi'Solve</title>
|
<meta name="description" content="Aperi'Solve - Online steganography analysis platform for images">
|
||||||
<link rel="icon" type="image/svg+xml" href="/static/img/logo.svg" />
|
<title>Aperi'Solve - Steganography Analysis</title>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Code&display=swap" rel="stylesheet" />
|
<link rel="icon" type="image/svg+xml" href="/static/img/logo.svg">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://cdnjs.cloudflare.com">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&display=swap" rel="stylesheet">
|
||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css" rel="stylesheet">
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css" rel="stylesheet">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" />
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="/static/css/aperisolve.css" rel="stylesheet" />
|
<link href="/static/css/aperisolve.css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="text-light">
|
<body class="d-flex flex-column min-vh-100 text-light">
|
||||||
<div id="three-bg"></div>
|
<div id="three-bg"></div>
|
||||||
|
|
||||||
|
<!-- Main content area -->
|
||||||
|
<main class="flex-grow-1">
|
||||||
<div class="container mt-5">
|
<div class="container mt-5">
|
||||||
<a class="title_link" href="/">
|
<header class="site-header mb-4">
|
||||||
<h1 class="mb-4"><img id="water-logo" src="/static/img/logo.svg" /> Aperi'Solve</h1>
|
<a class="title-link d-inline-flex align-items-center text-decoration-none" href="/" aria-label="Aperi'Solve Home">
|
||||||
|
<img src="/static/img/logo.svg" alt="Aperi'Solve logo" class="logo-img me-3" width="80" height="80">
|
||||||
|
<div class="d-flex flex-column">
|
||||||
|
<span class="title-text">Aperi'Solve</span>
|
||||||
|
<span class="title-version">v.{{ config["PROJECT_VERSION"] }}</span>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
</header>
|
||||||
{% block body_content %} {% endblock %}
|
{% block body_content %} {% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
{% include "footer.html" %}
|
||||||
|
|
||||||
<!-- Modal Structure -->
|
<!-- Modal Structure -->
|
||||||
<div id="image-modal-container">
|
<div id="image-modal-container">
|
||||||
<img id="modal-image" src="" />
|
<img id="modal-image" src="" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
<script src="/static/js/aperisolve.js"></script>
|
<script src="/static/js/aperisolve.js"></script>
|
||||||
<!-- Background -->
|
|
||||||
<script type="importmap">
|
<script type="importmap">
|
||||||
{
|
{
|
||||||
"imports": {
|
"imports": {
|
||||||
@@ -36,7 +54,6 @@
|
|||||||
</script>
|
</script>
|
||||||
<script type="module" src="/static/js/background.js"></script>
|
<script type="module" src="/static/js/background.js"></script>
|
||||||
{% block footer_content %} {% endblock %}
|
{% block footer_content %} {% endblock %}
|
||||||
{% include "footer.html" %}
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% block body_content %}
|
{% block body_content %}
|
||||||
<div id="httperror">
|
<section id="httperror" class="text-center py-5">
|
||||||
<h1>{{ statuscode }}</h1>
|
<h1 class="display-1 mb-4">{{ statuscode }}</h1>
|
||||||
<br>
|
<h2 class="h3 text-light-emphasis">{{ message }}</h2>
|
||||||
<h2>{{ message }}</h2>
|
</section>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,23 +1,26 @@
|
|||||||
<footer class="d-flex justify-content-center gap-4 my-4">
|
<footer class="mt-auto py-3 px-3">
|
||||||
<div>
|
<div class="container-fluid">
|
||||||
<a href="https://buymeacoffee.com/aperisolve" title="Coffee" class="text-light text-decoration-none">
|
<div class="d-flex justify-content-between align-items-center flex-wrap gap-3">
|
||||||
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" id="coffee" />
|
<!-- Copyright -->
|
||||||
|
<div class="footer-text">
|
||||||
|
Aperi'Solve (v.{{ config["PROJECT_VERSION"] }}) © {{ datetime.today().year }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Links -->
|
||||||
|
<div class="d-flex align-items-center gap-3 flex-wrap">
|
||||||
|
<a href="https://buymeacoffee.com/aperisolve" title="Buy Me A Coffee" class="footer-link">
|
||||||
|
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" class="footer-icon-img" />
|
||||||
|
</a>
|
||||||
|
<a href="/faq" title="FAQ" class="footer-link">
|
||||||
|
<i class="fa-regular fa-circle-question fa-lg"></i>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Zeecka/AperiSolve" target="_blank" rel="noopener" title="GitHub" class="footer-link">
|
||||||
|
<i class="fa-brands fa-github fa-lg"></i>
|
||||||
|
</a>
|
||||||
|
<a href="https://x.com/Zeecka_" target="_blank" rel="noopener" title="Twitter" class="footer-link">
|
||||||
|
<i class="fa-brands fa-x-twitter fa-lg"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<a href="/faq" title="FAQ" class="text-light text-decoration-none">
|
|
||||||
<i class="fa-regular fa-circle-question"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<a href="https://github.com/Zeecka/AperiSolve" target="_blank" title="GitHub"
|
|
||||||
class="text-light text-decoration-none">
|
|
||||||
<i class="fa-brands fa-github"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a href="https://x.com/Zeecka_" target="_blank" title="Twitter" class="text-light text-decoration-none">
|
|
||||||
<i class="fa-brands fa-x-twitter"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -1,39 +1,59 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% block body_content %}
|
{% block body_content %}
|
||||||
<form id="upload-form" class="card p-4" method="POST" enctype="multipart/form-data">
|
<form id="upload-form" class="card p-4 mb-4" method="POST" enctype="multipart/form-data">
|
||||||
|
<!-- Description Section -->
|
||||||
|
<section class="mb-4">
|
||||||
|
<h2 class="h4 mb-3">What is this?</h2>
|
||||||
|
<p class="text-light-emphasis mb-0">
|
||||||
|
Aperi'Solve is an online platform which performs layer analysis on images.
|
||||||
|
The platform also uses zsteg, steghide, outguess, exiftool, binwalk, foremost and strings
|
||||||
|
for deeper steganography analysis. Supports: PNG, JPG, GIF, BMP, JPEG, JFIF, JPE, TIFF...
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Drop Zone -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div>
|
<label for="image" class="form-label visually-hidden">Image file</label>
|
||||||
<h2>What is this ?</h2>
|
<div id="drop-zone" class="drop-zone border border-2 border-dashed rounded-3 p-4 text-center">
|
||||||
<p>Aperi'Solve is an online platform which performs layer analysis on image. The platform also uses zsteg,
|
<p id="drag-msg" class="mb-3">📂 Drag and drop an image here or click to select</p>
|
||||||
steghide, outguess, exiftool, binwalk, foremost and strings for deeper steganography analysis. The platform
|
<input type="file" id="image" name="image" accept="image/*" class="visually-hidden" required>
|
||||||
supports the following images format: .png, .jpg, .gif, .bmp, .jpeg, .jfif, .jpe, .tiff...</p>
|
<button type="button" class="btn btn-secondary" id="browse-btn" aria-label="Choose image file">
|
||||||
</div>
|
<i class="fa fa-folder-open me-2"></i>Choose an image
|
||||||
<div id="drop-zone" class="border border-secondary rounded p-4 text-center mb-3">
|
|
||||||
<p id="drag-msg">📂 Drag and drop an image here or click to select</p>
|
|
||||||
<input type="file" id="image" name="image" accept="image/*" hidden required />
|
|
||||||
<button type="button" class="btn btn-secondary mt-2" id="browse-btn">
|
|
||||||
Choose an image
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Password Field -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="password" class="form-label">Password (optional)</label>
|
<label for="password" class="form-label">Password <small class="text-muted">(optional)</small></label>
|
||||||
<input class="form-control" type="text" name="password" id="password" />
|
<input class="form-control" type="text" name="password" id="password" placeholder="Enter password if required">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-check mb-3">
|
|
||||||
<input class="form-check-input" type="checkbox" id="deep" />
|
<!-- Deep Analysis Toggle -->
|
||||||
<label class="form-check-label" for="deep">Deep analysis</label>
|
<div class="form-check form-switch mb-4">
|
||||||
|
<input class="form-check-input" type="checkbox" role="switch" id="deep">
|
||||||
|
<label class="form-check-label" for="deep">
|
||||||
|
Deep analysis <small class="text-muted">(slower, more thorough)</small>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
|
||||||
<div class="progress mt-3 d-none" id="progress-container">
|
<!-- Submit Button -->
|
||||||
<div class="progress-bar" id="progress-bar" role="progress-bar" style="width: 0%">
|
<button type="submit" class="btn btn-primary btn-lg w-100">
|
||||||
|
<i class="fa fa-upload me-2"></i>Analyze Image
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Progress Bar -->
|
||||||
|
<div class="progress mt-3 d-none" id="progress-container" role="progressbar" aria-label="Upload progress">
|
||||||
|
<div class="progress-bar progress-bar-striped progress-bar-animated" id="progress-bar" style="width: 0%">
|
||||||
0%
|
0%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div id="result" class="mt-5">
|
|
||||||
<div id="result-infos" class="mb-3"></div>
|
<!-- Results Section -->
|
||||||
<div id="result-analyzers" class="mb-3"></div>
|
<section id="result" class="results-section pb-4">
|
||||||
<div id="result-removal" class="mb-3"></div>
|
<div id="result-infos" class="mb-4"></div>
|
||||||
</div>
|
<div id="result-analyzers" class="mb-4"></div>
|
||||||
|
<div id="result-removal" class="mb-4"></div>
|
||||||
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% block body_content %}
|
{% block body_content %}
|
||||||
<div id="result" class="mt-5">
|
<section id="result" class="results-section">
|
||||||
<div id="result-infos" class="mb-3"></div>
|
<div id="result-infos" class="mb-4"></div>
|
||||||
<div id="result-analyzers" class="mb-3"></div>
|
<div id="result-analyzers" class="mb-4"></div>
|
||||||
<div id="result-removal" class="mb-3"></div>
|
<div id="result-removal" class="mb-4"></div>
|
||||||
</div>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block footer_content %}
|
{% block footer_content %}
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% block body_content %}
|
{% block body_content %}
|
||||||
<div id="result" class="mt-5">
|
<section id="result" class="results-section">
|
||||||
{% for img in images %}<!--
|
<h2 class="h3 mb-4">Browse Submissions</h2>
|
||||||
--><div class="browse-images">
|
<div class="row g-3">
|
||||||
<a href="{{ img.link }}" target="_blank"><img src="{{ img.file }}"/></a>
|
{% for img in images %}
|
||||||
</div><!--
|
<div class="col-6 col-md-4 col-lg-3">
|
||||||
-->{% endfor %}
|
<a href="{{ img.link }}" target="_blank" class="d-block browse-image-link">
|
||||||
|
<img src="{{ img.file }}" alt="Submission thumbnail" class="img-fluid rounded" loading="lazy">
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user