This commit is contained in:
Patryk Koreń
2026-07-02 23:55:40 +02:00
parent 04e34d15b5
commit e7ec832f5b
53 changed files with 9985 additions and 17 deletions

73
back/src/ldap/auth.ts Normal file
View File

@@ -0,0 +1,73 @@
// src/ldap/auth.ts
import ldap from "ldapjs";
import { createClient, BASE_DN, BIND_DN, BIND_PASSWORD } from "./client";
export interface AuthResult {
dn: string;
username: string;
}
function bindClient(client: ldap.Client, dn: string, password: string) {
return new Promise<void>((resolve, reject) => {
client.bind(dn, password, (err) => {
if (err) reject(err);
else resolve();
});
});
}
function searchUserDN(
client: ldap.Client,
username: string
): Promise<string | null> {
return new Promise((resolve, reject) => {
const filter = `(uid=${username})` as const
const opts = {
filter,
scope: "sub" as const,
};
client.search(`ou=people,${BASE_DN}`, opts, (err, res) => {
if (err) return reject(err);
let userDN: string | null = null;
res.on("searchEntry", (entry) => {
userDN = entry.objectName?.toString() ?? null;
});
res.on("error", reject);
res.on("end", () => resolve(userDN));
});
});
}
export async function authenticate(
username: string,
password: string
): Promise<AuthResult> {
const client = createClient();
try {
// 1. bind service account
await bindClient(client, BIND_DN, BIND_PASSWORD);
// 2. find user DN
const userDN = await searchUserDN(client, username);
if (!userDN) {
throw new Error("User not found");
}
// 3. re-bind as user (password check)
await bindClient(client, userDN, password);
return {
dn: userDN,
username,
};
} finally {
client.unbind();
}
}

15
back/src/ldap/client.ts Normal file
View File

@@ -0,0 +1,15 @@
// src/ldap/client.ts
import ldap from "ldapjs";
export const LDAP_URL = process.env.LDAP_URL!;
export const BASE_DN = process.env.LDAP_BASE_DN!;
export const BIND_DN = process.env.LDAP_BIND_DN!;
export const BIND_PASSWORD = process.env.LDAP_BIND_PASSWORD!;
export function createClient() {
return ldap.createClient({
url: LDAP_URL,
timeout: 5000,
reconnect: true,
});
}

View File

@@ -0,0 +1,22 @@
import jwt from "jsonwebtoken";
import type { Request, Response, NextFunction } from "express";
export function authMiddleware(req: Request, res: Response, next: NextFunction) {
const header = req.headers.authorization;
const error = "You must be logged in to access this page"
if (!header) {
return res.status(401).json({ error });
}
const token = header.split(" ")[1]; // "Bearer TOKEN"
try {
if (!token) throw new Error("No Bearer Token")
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
(req as any).user = decoded;
next();
} catch (err) {
return res.status(401).json({ error });
}
}

36
back/src/routes/auth.ts Normal file
View File

@@ -0,0 +1,36 @@
// src/routes/auth.ts
import { Router } from "express";
import jwt from "jsonwebtoken";
import { authenticate } from "../ldap/auth";
const router = Router();
router.post("/login", async (req, res) => {
const { username, password } = req.body;
try {
const user = await authenticate(username, password);
const token = jwt.sign(
{
sub: user.dn,
username: user.username,
},
process.env.JWT_SECRET!,
{ expiresIn: "1h" }
);
res.json({
token,
user,
});
} catch (err: any) {
console.error(err)
res.status(401).json({
error: "Invalid credentials",
details: err.message,
});
}
});
export default router;

View File

@@ -0,0 +1,12 @@
// src/routes/auth.ts
import { Router } from "express";
const router = Router();
router.get("/video", async (req, res) => {
res.json({
tajne: "XD"
});
})
export default router;

32
back/src/server.ts Normal file
View File

@@ -0,0 +1,32 @@
// src/server.ts
import express from "express";
import dotenv from "dotenv";
import authRoutes from "./routes/auth";
import protectedRoutes from "./routes/protected";
import cors from "cors";
import { authMiddleware } from "./middleware/auth";
dotenv.config();
const app = express();
app.use(cors({
origin: "http://localhost:5173",
methods: ["GET", "POST"],
credentials: true
}));
app.use(express.json());
app.use("/auth", authRoutes);
app.use("/protected", authMiddleware, protectedRoutes);
app.get("/health", (_, res) => {
res.json({ status: "ok" });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});