nach AI vibe coding
This commit is contained in:
53
auth/auth.js
53
auth/auth.js
@@ -1,42 +1,43 @@
|
||||
const express = require("express");
|
||||
const cookieParser = require("cookie-parser");
|
||||
import express from "express";
|
||||
import cookieParser from "cookie-parser";
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use(cookieParser());
|
||||
|
||||
const PORT = 3000;
|
||||
const USERS = { "admin":"test123" }; // mocked
|
||||
|
||||
// Test-User
|
||||
const USER = {
|
||||
username: "admin",
|
||||
password: "test123"
|
||||
};
|
||||
app.post("/api/login", (req,res)=>{
|
||||
const { user, pass } = req.body;
|
||||
|
||||
// Login
|
||||
app.post("/api/login", (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (username === USER.username && password === USER.password) {
|
||||
res.cookie("session", "valid", {
|
||||
console.log(`Auth-Service login attempt for ${user}`);
|
||||
if(USERS[user] && USERS[user] === pass){
|
||||
// Set Session Cookie
|
||||
res.cookie("SESSIONID", "dummy-session-"+user, {
|
||||
httpOnly: true,
|
||||
sameSite: "Lax",
|
||||
secure: false, // in production: set to true when serving over HTTPS
|
||||
// domain: ".server.schooltech.ch", // removed for local dev; set in production
|
||||
sameSite: "Lax", // local dev; use "None" + secure:true for iframe production
|
||||
path: "/"
|
||||
});
|
||||
return res.json({ success: true });
|
||||
res.status(200).send({ ok:true });
|
||||
} else {
|
||||
res.status(401).send({ ok:false });
|
||||
}
|
||||
|
||||
res.status(401).json({ success: false });
|
||||
});
|
||||
|
||||
// Auth-Check für späteres Nginx auth_request
|
||||
app.get("/internal/auth", (req, res) => {
|
||||
if (req.cookies.session === "valid") {
|
||||
return res.sendStatus(200);
|
||||
}
|
||||
res.sendStatus(401);
|
||||
// Event logging endpoint for frontend button presses
|
||||
app.post('/api/event', (req,res)=>{
|
||||
const svc = req.body.service || req.body.action || 'unknown';
|
||||
const user = req.cookies.SESSIONID || 'anonymous';
|
||||
console.log(`Event: user=${user} service=${svc} payload=${JSON.stringify(req.body)}`);
|
||||
res.status(200).send({ ok:true });
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Auth service listening on ${PORT}`);
|
||||
// Optional für Nginx auth_request
|
||||
app.get("/internal/auth", (req,res)=>{
|
||||
if(req.cookies.SESSIONID) return res.sendStatus(200);
|
||||
return res.sendStatus(401);
|
||||
});
|
||||
|
||||
app.listen(3000, ()=>console.log("Auth-Service läuft auf 3000"));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "appserver-auth",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"main": "auth.js",
|
||||
"dependencies": {
|
||||
"express": "^4.19.2",
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
services:
|
||||
|
||||
|
||||
AppServerPortalUI:
|
||||
image: nginx:alpine
|
||||
container_name: appServer_PortalUI
|
||||
volumes:
|
||||
- /home/chk/Documents/AppServerPortalUI/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- /home/chk/Documents/AppServerPortalUI/public:/usr/share/nginx/html:ro
|
||||
ports:
|
||||
- "5080:80"
|
||||
networks:
|
||||
- default
|
||||
restart: unless-stopped
|
||||
command: ["nginx", "-g", "daemon off;"]
|
||||
|
||||
AppServerAuth:
|
||||
image: node:18
|
||||
container_name: appServer_Auth
|
||||
volumes:
|
||||
- /home/chk/Documents/AppServerPortalUI/auth:/usr/src/app
|
||||
working_dir: /usr/src/app
|
||||
command: sh -c "npm install && node auth.js"
|
||||
ports:
|
||||
- "10300:3000" # optional, für Tests
|
||||
networks:
|
||||
- default
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
default:
|
||||
|
||||
85
nginx.conf
85
nginx.conf
@@ -1,11 +1,92 @@
|
||||
error_log /var/log/nginx/error.log info;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri /index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# API calls to Auth service inside Docker network
|
||||
location /api/ {
|
||||
proxy_pass http://appserverauth:3000/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name abc.server.schooltech.ch;
|
||||
|
||||
auth_request /nginxauth;
|
||||
|
||||
location / {
|
||||
proxy_pass https://thinkcentre.local:10010/;
|
||||
|
||||
# WebSocket and HTTPS upstream settings
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_name abc.server.schooltech.ch;
|
||||
proxy_ssl_verify off;
|
||||
|
||||
proxy_set_header Host abc.server.schooltech.ch;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Origin $http_origin;
|
||||
|
||||
# iFrame erlauben
|
||||
proxy_hide_header X-Frame-Options;
|
||||
add_header X-Frame-Options "ALLOWALL";
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
add_header Content-Security-Policy "frame-ancestors *";
|
||||
}
|
||||
|
||||
location = /nginxauth {
|
||||
internal;
|
||||
proxy_pass http://appserverauth:3000/internal/auth;
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name xyz.server.schooltech.ch;
|
||||
|
||||
auth_request /nginxauth;
|
||||
|
||||
location / {
|
||||
proxy_pass http://thinkcentre.local:8080/;
|
||||
|
||||
# WebSocket support
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
proxy_set_header Host xyz.server.schooltech.ch;
|
||||
proxy_set_header Origin $http_origin;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# iFrame erlauben
|
||||
proxy_hide_header X-Frame-Options;
|
||||
add_header X-Frame-Options "ALLOWALL";
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
add_header Content-Security-Policy "frame-ancestors *";
|
||||
}
|
||||
|
||||
location = /nginxauth {
|
||||
internal;
|
||||
proxy_pass http://appserverauth:3000/internal/auth;
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
}
|
||||
}
|
||||
101
public/app.js
101
public/app.js
@@ -1,35 +1,84 @@
|
||||
// ==== app.js ====
|
||||
|
||||
// Service-Liste
|
||||
const services = [
|
||||
{
|
||||
id: "abc",
|
||||
name: "Control GamePad",
|
||||
url: "https://thinkcentre.local:10010/"
|
||||
},
|
||||
{
|
||||
id: "xyz",
|
||||
name: "Guacamole",
|
||||
url: "http://thinkcentre.local:8080/"
|
||||
}
|
||||
{ id: "abc", name: "Control GamePad", url: "https://abc.server.schooltech.ch" },
|
||||
{ id: "xyz", name: "Guacamole", url: "https://xyz.server.schooltech.ch" }
|
||||
];
|
||||
|
||||
// DOM-Elemente
|
||||
const iframe = document.getElementById("service-frame");
|
||||
const loginModal = document.getElementById("login-modal");
|
||||
const loginBtn = document.getElementById("login-btn");
|
||||
const loginSubmit = document.getElementById("login-submit");
|
||||
const loginMsg = document.getElementById("login-msg");
|
||||
const nav = document.getElementById("services");
|
||||
const grid = document.getElementById("service-grid");
|
||||
|
||||
services.forEach(svc => {
|
||||
// Header Button
|
||||
let loggedIn = false;
|
||||
|
||||
// === Login Modal anzeigen ===
|
||||
loginBtn.onclick = () => {
|
||||
loginModal.style.display = "block";
|
||||
};
|
||||
|
||||
// === Login Submit ===
|
||||
loginSubmit.onclick = async () => {
|
||||
const user = document.getElementById("username").value;
|
||||
const pass = document.getElementById("password").value;
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/login", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ user, pass })
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
loggedIn = true;
|
||||
loginModal.style.display = "none";
|
||||
loginMsg.textContent = "";
|
||||
setupServiceButtons();
|
||||
} else {
|
||||
loginMsg.textContent = "Login fehlgeschlagen";
|
||||
}
|
||||
} catch (e) {
|
||||
loginMsg.textContent = "Fehler: " + e.message;
|
||||
}
|
||||
};
|
||||
|
||||
// === Service Buttons dynamisch erstellen ===
|
||||
function setupServiceButtons() {
|
||||
nav.innerHTML = ""; // clear
|
||||
services.forEach(svc => {
|
||||
const btn = document.createElement("button");
|
||||
btn.textContent = svc.name;
|
||||
btn.onclick = () => go(svc);
|
||||
btn.onclick = async () => {
|
||||
console.log('Button clicked, opening', svc.id);
|
||||
try{
|
||||
await fetch('/api/event', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ event: 'open', service: svc.id, url: svc.url })
|
||||
});
|
||||
}catch(e){ console.error('Event log failed', e); }
|
||||
openService(svc);
|
||||
};
|
||||
nav.appendChild(btn);
|
||||
|
||||
// Card
|
||||
const card = document.createElement("div");
|
||||
card.className = "service-card";
|
||||
card.textContent = svc.name;
|
||||
card.onclick = () => go(svc);
|
||||
grid.appendChild(card);
|
||||
});
|
||||
|
||||
function go(service) {
|
||||
localStorage.setItem("lastService", service.id);
|
||||
window.location.href = service.url;
|
||||
});
|
||||
}
|
||||
|
||||
// === Service in iFrame öffnen ===
|
||||
function openService(svc) {
|
||||
iframe.src = svc.url;
|
||||
iframe.style.display = "block";
|
||||
window.scrollTo(0,0);
|
||||
}
|
||||
|
||||
// Optional: Logout-Funktion
|
||||
function logout() {
|
||||
loggedIn = false;
|
||||
iframe.src = "";
|
||||
iframe.style.display = "none";
|
||||
nav.innerHTML = "";
|
||||
loginModal.style.display = "block";
|
||||
}
|
||||
|
||||
@@ -9,19 +9,28 @@
|
||||
|
||||
<header id="header">
|
||||
<div class="logo">schooltech</div>
|
||||
<nav id="services">
|
||||
<!-- dynamisch -->
|
||||
</nav>
|
||||
<div class="user">User</div>
|
||||
<nav id="services"></nav>
|
||||
<div class="user">
|
||||
<button id="login-btn">Login</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<h1>Willkommen</h1>
|
||||
<p>Bitte wählen Sie einen Service.</p>
|
||||
<h1>Willkommen im Service Portal</h1>
|
||||
|
||||
<div id="service-grid"></div>
|
||||
<!-- iFrame für Services -->
|
||||
<iframe id="service-frame" style="width:100%;height:80vh;display:none;"></iframe>
|
||||
|
||||
<!-- Login Modal -->
|
||||
<div id="login-modal" style="display:none;">
|
||||
<label>User: <input type="text" id="username"/></label>
|
||||
<label>Pass: <input type="password" id="password"/></label>
|
||||
<button id="login-submit">Login</button>
|
||||
<div id="login-msg"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user