This commit is contained in:
2025-12-01 16:25:44 +01:00
parent 8485bd7c8d
commit 78a6ee63c7
10 changed files with 199 additions and 153 deletions

Binary file not shown.

View File

@@ -1,9 +1,11 @@
from fastapi import FastAPI, APIRouter, Request from fastapi import FastAPI, APIRouter, Request
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from security import security_router from security import security_router
import uvicorn import uvicorn
app = FastAPI() app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
app.include_router(security_router) app.include_router(security_router)
templates = Jinja2Templates(directory="templates") templates = Jinja2Templates(directory="templates")
@@ -11,11 +13,20 @@ templates = Jinja2Templates(directory="templates")
@app.get("/") @app.get("/")
async def read_root(request: Request): async def read_root(request: Request):
data = "hi" routes = []
for route in request.app.routes:
if route.name in ["openapi", "swagger_ui_html", "swagger_ui_redirect", "redoc_html", "static", "read_root"]:
continue
routes.append({
"path": getattr(route, "path", "N/A"),
"name": getattr(route, "name", "N/A"),
"methods": list(route.methods) if hasattr(route, "methods") else []
})
return templates.TemplateResponse( return templates.TemplateResponse(
request=request, request=request,
name="index.html", name="index.html",
contents={"data": data} context={"routes": routes}
) )
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -6,12 +6,7 @@ templates = Jinja2Templates(directory="templates")
@security_router.get("/browser") @security_router.get("/browser")
async def security_check_list(request: Request): async def browser_local_cryptography_strength(request: Request):
return templates.TemplateResponse( return templates.TemplateResponse(
request=request, name="browser_random_number.html", contents={"rand": "rand"} request=request, name="browser_random_number.html", contents={"rand": "rand"}
) )
@security_router.get("/browser")
async def security_check_browser():
return {"message": "checking browser security"}

BIN
app/static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

@@ -1,45 +1,54 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://cdn.jsdelivr.net/npm/flowbite@2.5.2/dist/flowbite.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/flowbite@2.5.2/dist/flowbite.min.js"></script>
<script src="https://webgl2fundamentals.org/webgl/resources/webgl-utils.js"></script>
<title>{% block title %}My FastAPI App{% endblock %}</title>
{% block css %}
{% endblock %}
</head>
<body>
<nav class="bg-white border-gray-200 dark:bg-gray-900"> <head>
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4"> <meta charset="UTF-8">
<a href="https://security.ekstrah.com/" class="flex items-center space-x-3 rtl:space-x-reverse"> <link href="https://cdn.jsdelivr.net/npm/flowbite@2.5.2/dist/flowbite.min.css" rel="stylesheet" />
<img src="https://pics.ekstrah.com/0p36up.png" class="h-8" alt="Flowbite Logo" /> <script src="https://cdn.jsdelivr.net/npm/flowbite@2.5.2/dist/flowbite.min.js"></script>
</a> <script src="https://webgl2fundamentals.org/webgl/resources/webgl-utils.js"></script>
<button data-collapse-toggle="navbar-default" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" aria-controls="navbar-default" aria-expanded="false"> <title>{% block title %}My FastAPI App{% endblock %}</title>
{% block css %}
{% endblock %}
</head>
<body>
<nav class="bg-white border-gray-200 dark:bg-gray-900">
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
<a href="https://security.ekstrah.com/" class="flex items-center space-x-3 rtl:space-x-reverse">
<img src="{{ url_for('static', path='logo.png') }}" class="h-24" alt="Flowbite Logo" />
</a>
<button data-collapse-toggle="navbar-default" type="button"
class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
aria-controls="navbar-default" aria-expanded="false">
<span class="sr-only">Open main menu</span> <span class="sr-only">Open main menu</span>
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14"> <svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M1 1h15M1 7h15M1 13h15" />
</svg> </svg>
</button> </button>
<div class="hidden w-full md:block md:w-auto" id="navbar-default"> <div class="hidden w-full md:block md:w-auto" id="navbar-default">
<ul class="font-medium flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700"> <ul
<li> class="font-medium flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
<a href="#" class="block py-2 px-3 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0 dark:text-white md:dark:text-blue-500" aria-current="page">Home</a> <li>
</li> <a href="#"
</ul> class="block py-2 px-3 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0 dark:text-white md:dark:text-blue-500"
aria-current="page">Home</a>
</li>
</ul>
</div>
</div> </div>
</div> </nav>
</nav>
{% block content %} {% block content %}
{% endblock %} {% endblock %}
{% block js %} {% block js %}
{% endblock %} {% endblock %}
<footer class="flex justify-center mt-8"> <footer class="flex justify-center mt-8">
<p>&copy; 2024 EKSTRAH Security Application</p> <p>&copy; 2025 EKSTRAH Security Application</p>
</footer> </footer>
</body> </body>
</html>
</html>

View File

@@ -4,20 +4,22 @@
{% block content %} {% block content %}
<div class="max-w-scree grid grid-cols-1 items-center divide-y"> <div class="max-w-scree grid grid-cols-1 items-center divide-y">
<div class="flex justify-center pt-6"> <div class="flex flex-col justify-center pt-6 text-center">
<p class="text-2xl" id="browser-name">Detected Browser: Something</p> <p class="text-2xl" id="browser-name">Detected Browser: Something</p>
<p class="mt-2 text-gray-600 dark:text-gray-400">This visualization demonstrates the strength and uniformity of your
browser's random number generator.</p>
</div> </div>
<div class="flex justify-center pt-6"> <div class="flex justify-center pt-6">
<canvas id="randNumCanvas" width="1000" height="1000"></canvas> <canvas id="randNumCanvas" width="1000" height="1000"></canvas>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block js %} {% block js %}
<script> <script>
"use strict"; "use strict";
var vertexShaderSource = `#version 300 es var vertexShaderSource = `#version 300 es
// an attribute is an input (in) to a vertex shader. // an attribute is an input (in) to a vertex shader.
// It will receive data from a buffer // It will receive data from a buffer
@@ -42,7 +44,7 @@ void main() {
} }
`; `;
var fragmentShaderSource = `#version 300 es var fragmentShaderSource = `#version 300 es
precision highp float; precision highp float;
@@ -56,143 +58,143 @@ void main() {
} }
`; `;
function main() { function main() {
// Get A WebGL context // Get A WebGL context
var canvas = document.querySelector("#randNumCanvas"); var canvas = document.querySelector("#randNumCanvas");
var gl = canvas.getContext("webgl2"); var gl = canvas.getContext("webgl2");
if (!gl) { if (!gl) {
return; return;
} }
// Use our boilerplate utils to compile the shaders and link into a program // Use our boilerplate utils to compile the shaders and link into a program
var program = webglUtils.createProgramFromSources(gl, var program = webglUtils.createProgramFromSources(gl,
[vertexShaderSource, fragmentShaderSource]); [vertexShaderSource, fragmentShaderSource]);
// look up where the vertex data needs to go. // look up where the vertex data needs to go.
var positionAttributeLocation = gl.getAttribLocation(program, "a_position"); var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
// look up uniform locations // look up uniform locations
var resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution"); var resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution");
var colorLocation = gl.getUniformLocation(program, "u_color"); var colorLocation = gl.getUniformLocation(program, "u_color");
// Create a buffer // Create a buffer
var positionBuffer = gl.createBuffer(); var positionBuffer = gl.createBuffer();
// Create a vertex array object (attribute state) // Create a vertex array object (attribute state)
var vao = gl.createVertexArray(); var vao = gl.createVertexArray();
// and make it the one we're currently working with // and make it the one we're currently working with
gl.bindVertexArray(vao); gl.bindVertexArray(vao);
// Turn on the attribute // Turn on the attribute
gl.enableVertexAttribArray(positionAttributeLocation); gl.enableVertexAttribArray(positionAttributeLocation);
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER) // Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 2 components per iteration var size = 2; // 2 components per iteration
var type = gl.FLOAT; // the data is 32bit floats var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer( gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset); positionAttributeLocation, size, type, normalize, stride, offset);
webglUtils.resizeCanvasToDisplaySize(gl.canvas); webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// Tell WebGL how to convert from clip space to pixels // Tell WebGL how to convert from clip space to pixels
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas // Clear the canvas
gl.clearColor(0, 0, 0, 0); gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Tell it to use our program (pair of shaders) // Tell it to use our program (pair of shaders)
gl.useProgram(program); gl.useProgram(program);
// Bind the attribute/buffer set we want. // Bind the attribute/buffer set we want.
gl.bindVertexArray(vao); gl.bindVertexArray(vao);
// Pass in the canvas resolution so we can convert from // Pass in the canvas resolution so we can convert from
// pixels to clipspace in the shader // pixels to clipspace in the shader
gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height); gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
//const array = new Uint16Array(30_000); //const array = new Uint16Array(30_000);
//const randNum = self.crypto.getRandomValues(array); //const randNum = self.crypto.getRandomValues(array);
// draw 50 random rectangles in random colors // draw 50 random rectangles in random colors
var primitiveType = gl.TRIANGLES; var primitiveType = gl.TRIANGLES;
var offset = 0; var offset = 0;
var count = 6; var count = 6;
var counter = 0; var counter = 0;
var array2D = []; var array2D = [];
var y_cnt = 0; var y_cnt = 0;
var x_cnt = 0; var x_cnt = 0;
for (var size = 0; size < 1000; ++size) { for (var size = 0; size < 1000; ++size) {
array2D[size] = self.crypto.getRandomValues(new Uint16Array(1000)); array2D[size] = self.crypto.getRandomValues(new Uint16Array(1000));
} }
for (var y = 0; y < 2000; y = y + 2) { for (var y = 0; y < 2000; y = y + 2) {
for (var x = 0; x < 2000; x = x + 2) { for (var x = 0; x < 2000; x = x + 2) {
setRectangle(gl, x, y, 2, 2); setRectangle(gl, x, y, 2, 2);
gl.uniform4f(colorLocation, 0.0, 0.0, 0.0, normalizeUint16(array2D[y/2][x/2])); gl.uniform4f(colorLocation, 0.0, 0.0, 0.0, normalizeUint16(array2D[y / 2][x / 2]));
gl.drawArrays(primitiveType, offset, count); gl.drawArrays(primitiveType, offset, count);
counter++; counter++;
}
} }
} }
}
// Returns a random integer from 0 to range - 1. // Returns a random integer from 0 to range - 1.
function randomInt(range) { function randomInt(range) {
return Math.floor(Math.random() * range); return Math.floor(Math.random() * range);
} }
function normalizeUint16(val) { function normalizeUint16(val) {
return val/65535; return val / 65535;
}
// Fill the buffer with the values that define a rectangle. }
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2,
]), gl.STATIC_DRAW);
}
main(); // Fill the buffer with the values that define a rectangle.
function setRectangle(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2,
]), gl.STATIC_DRAW);
}
main();
</script> </script>
<script> <script>
// Function to detect the browser name // Function to detect the browser name
function detectBrowser() { function detectBrowser() {
var userAgent = navigator.userAgent; var userAgent = navigator.userAgent;
if (userAgent.indexOf("Edg") > -1) { if (userAgent.indexOf("Edg") > -1) {
return "Microsoft Edge"; return "Microsoft Edge";
} else if (userAgent.indexOf("Chrome") > -1) { } else if (userAgent.indexOf("Chrome") > -1) {
return "Chrome"; return "Chrome";
} else if (userAgent.indexOf("Firefox") > -1) { } else if (userAgent.indexOf("Firefox") > -1) {
return "Firefox"; return "Firefox";
} else if (userAgent.indexOf("Safari") > -1) { } else if (userAgent.indexOf("Safari") > -1) {
return "Safari"; return "Safari";
} else if (userAgent.indexOf("Opera") > -1) { } else if (userAgent.indexOf("Opera") > -1) {
return "Opera"; return "Opera";
} else if (userAgent.indexOf("Trident") > -1 || userAgent.indexOf("MSIE") > -1) { } else if (userAgent.indexOf("Trident") > -1 || userAgent.indexOf("MSIE") > -1) {
return "Internet Explorer"; return "Internet Explorer";
} }
return "Unknown"; return "Unknown";
} }
// Get the browser name and display it // Get the browser name and display it
var browserName = detectBrowser(); var browserName = detectBrowser();
document.getElementById("browser-name").innerText = "Detected Browser: " + browserName; document.getElementById("browser-name").innerText = "Detected Browser: " + browserName;
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -3,12 +3,38 @@
{% block title %}Home Page{% endblock %} {% block title %}Home Page{% endblock %}
{% block content %} {% block content %}
<div class="container"> <div class="container mx-auto px-4 py-8">
<h1>Hello World</h1> <h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-6">Available Endpoints</h1>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{% for route in routes %}
<div
class="bg-white dark:bg-gray-800 rounded-lg shadow-md hover:shadow-lg transition-shadow duration-300 overflow-hidden border border-gray-200 dark:border-gray-700">
<div class="p-6">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-2">{{ route.name }}</h2>
<div class="mb-4">
<span
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300">
{{ route.methods | join(', ') }}
</span>
</div>
<div class="flex items-center justify-between">
<code
class="text-sm text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">{{ route.path }}</code>
{% if 'GET' in route.methods %}
<a href="{{ route.path }}"
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">
Visit
</a>
{% endif %}
</div>
</div>
</div>
{% endfor %}
</div>
</div> </div>
{% endblock %} {% endblock %}
{% block css %} {% block css %}
{{ super() }} {{ super() }}
{% endblock %} {% endblock %}

View File

@@ -4,4 +4,7 @@ services:
user: 1000:1000 # should be owner of volumes user: 1000:1000 # should be owner of volumes
ports: ports:
- 35050:35050 - 35050:35050
volumes:
- ./app:/code/app
command: fastapi dev main.py --host 0.0.0.0 --port 35050
restart: unless-stopped restart: unless-stopped