Skip to content

Commit

Permalink
some minor improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
lmarschall committed Sep 3, 2024
1 parent 149ed9b commit 6a5361d
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 58 deletions.
4 changes: 2 additions & 2 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# build stage
FROM node:20.10 AS build
FROM node:20 AS build

# make the 'build' folder the current working directory
WORKDIR /usr/src/build
Expand All @@ -21,7 +21,7 @@ RUN npm run build


# run stage
FROM node:20.10
FROM node:20-bullseye-slim AS run

# set environment variables
ENV NODE_ENV production
Expand Down
15 changes: 10 additions & 5 deletions backend/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@
curl -o .env.template https://raw.githubusercontent.com/lmarschall/wembat/main/backend/.env.template
curl -o docker-compose.yml https://raw.githubusercontent.com/lmarschall/wembat/main/backend/docker-compose.yml

# Define the template file and output file
# create keys for api server
mkdir ./keys
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -out ./keys/privateKey.pem -outform PEM
openssl ec -in ./keys/privateKey.pem -pubout -out ./keys/publicKey.pem

# define the template file and output file
TEMPLATE_FILE=".env.template"
OUTPUT_FILE=".env"

# generate random password
postgresPassword=$(openssl rand -base64 12)

# Define the placeholders and their corresponding values
# define the placeholders and their corresponding values
PLACEHOLDERS=(
"PLACEHOLDER_DATABASE_POSTGRES_USER"
"PLACEHOLDER_DATABASE_POSTGRES_PASSWORD"
Expand All @@ -33,16 +38,16 @@ VALUES=(
"postgres://postgresUser:postgres@postgres:5432/postgresDatabase?connect_timeout=300"
)

# Check if template file exists
# check if template file exists
if [ ! -f "$TEMPLATE_FILE" ]; then
echo "Template file $TEMPLATE_FILE does not exist."
exit 1
fi

# Create a copy of the template to the output file
# create a copy of the template to the output file
cp "$TEMPLATE_FILE" "$OUTPUT_FILE"

# Loop through placeholders and replace them with values in the output file
# loop through placeholders and replace them with values in the output file
for i in "${!PLACEHOLDERS[@]}"; do
sed -i "s/${PLACEHOLDERS[$i]}/${VALUES[$i]}/g" "$OUTPUT_FILE"
done
Expand Down
1 change: 1 addition & 0 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "debian-openssl-1.1.x"]
}

datasource db {
Expand Down
33 changes: 33 additions & 0 deletions backend/src/admin/functions/applicationCreate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Application, PrismaClient } from "@prisma/client";
import { Request, Response } from "express";

const prisma = new PrismaClient();

type ApplicationInfo = {
appDomain: string;
};

export async function applicationCreate(req: Request, res: Response) {
try {

if (!req.body.applicationInfo) throw Error("Application Info not present");
const { appDomain } = req.body.userInfo as ApplicationInfo;

const app = await prisma.application
.create({
data: {
domain: appDomain,
}
})
.catch((err) => {
console.log(err);
throw Error("Error while creating new application");
}) as Application;

res.json(app);

} catch (err) {
console.error(err);
res.status(500).send("Internal Server Error");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Request, Response } from "express";

const prisma = new PrismaClient();

export async function listApplications(req: Request, res: Response) {
export async function applicationList(req: Request, res: Response) {
try {

// const appUId = res.locals.payload.appUId;
Expand Down
31 changes: 31 additions & 0 deletions backend/src/admin/functions/applicationToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { PrismaClient } from "@prisma/client";
import { Request, Response } from "express";
import { createApplicationJWT } from "../../crypto";

const prisma = new PrismaClient();

interface ApplicationInfo {
appUId: string;
}

export async function applicationToken(req: Request, res: Response) {
try {

// const appUId = res.locals.payload.appUId;
if (!req.body.applicationInfo) throw Error("Application Info not present");
const { appUId } = req.body.userInfo as ApplicationInfo;
const app = await prisma.application.findUnique({
where: {
uid: appUId
}
});

const token = await createApplicationJWT(app);

res.json(token);

} catch (err) {
console.error(err);
res.status(500).send("Internal Server Error");
}
}
23 changes: 18 additions & 5 deletions backend/src/admin/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import { Router } from "express";
import { listApplications } from "./functions/listApplications";
import { applicationList } from "./functions/applicationList";
import { applicationCreate } from "./functions/applicationCreate";
import { applicationToken } from "./functions/applicationToken";
import { validateJWTToken } from "../validate";

export const adminRoutes = Router();

// const validateJWTToken = [validateWebAuthnToken];

adminRoutes.get(
"/application/list",
// validateJWTToken,
async (req, res) => listApplications(req, res)
validateJWTToken,
async (req, res) => applicationList(req, res)
);

adminRoutes.post(
"/application/token",
validateJWTToken,
async (req, res) => applicationToken(req, res)
);

adminRoutes.post(
"/application/create",
validateJWTToken,
async (req, res) => applicationCreate(req, res)
);
Original file line number Diff line number Diff line change
@@ -1,47 +1,6 @@
import { Request, Response } from "express";
import { checkForWebAuthnToken } from "../redis";
import { decodeProtectedHeader, importJWK, jwtVerify } from "jose";

export async function validateWebAuthnToken(
req: Request,
res: Response,
next: any
) {
console.log("validate webauthn token");

try {
if (req.headers.authorization == null) return res.status(401).send();

const authorization = req.headers.authorization.split(" ");

if (authorization[0] !== "Bearer") return res.status(401).send();

const jwt = authorization[1];
// check if jwt token was issued by us
if ((await checkForWebAuthnToken(jwt)) === false)
return res.status(401).send();

// extract public key from jwk parameters
const header = decodeProtectedHeader(jwt);
const algorithm = header.alg;
const spki = header.jwk;

if (algorithm !== "ES256" || spki == undefined)
return res.status(401).send();

const importedKey = await importJWK(spki, algorithm);
const { payload, protectedHeader } = await jwtVerify(jwt, importedKey, {
issuer: "http://localhost:8080",
algorithms: ["ES256"],
});
res.locals.payload = payload;
return next();
} catch (error) {
console.log(error);
return res.status(401).send();
}
}

export async function validateApplicationToken(
req: Request,
res: Response,
Expand Down
43 changes: 43 additions & 0 deletions backend/src/validate/functions/validateWebAuthn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Request, Response } from "express";
import { checkForWebAuthnToken } from "../../redis";
import { decodeProtectedHeader, importJWK, jwtVerify } from "jose";

export async function validateWebAuthnToken(
req: Request,
res: Response,
next: any
) {
console.log("validate webauthn token");

try {
if (req.headers.authorization == null) return res.status(401).send();

const authorization = req.headers.authorization.split(" ");

if (authorization[0] !== "Bearer") return res.status(401).send();

const jwt = authorization[1];
// check if jwt token was issued by us
if ((await checkForWebAuthnToken(jwt)) === false)
return res.status(401).send();

// extract public key from jwk parameters
const header = decodeProtectedHeader(jwt);
const algorithm = header.alg;
const spki = header.jwk;

if (algorithm !== "ES256" || spki == undefined)
return res.status(401).send();

const importedKey = await importJWK(spki, algorithm);
const { payload, protectedHeader } = await jwtVerify(jwt, importedKey, {
issuer: "http://localhost:8080",
algorithms: ["ES256"],
});
res.locals.payload = payload;
return next();
} catch (error) {
console.log(error);
return res.status(401).send();
}
}
5 changes: 5 additions & 0 deletions backend/src/validate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { validateWebAuthnToken } from "./functions/validateWebAuthn";
import { validateApplicationToken } from "./functions/validateApplication";

export const validateAppToken = [validateApplicationToken];
export const validateJWTToken = [validateWebAuthnToken];
5 changes: 1 addition & 4 deletions backend/src/webauthn/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@ import { login } from "./functions/login";
import { updateCredentials } from "./functions/updateCredentials";
import { requestOnboard } from "./functions/requestOnboard";
import { onboard } from "./functions/onboard";
import { validateApplicationToken, validateWebAuthnToken } from "./validate";
import { validateAppToken, validateJWTToken } from "../validate";

export const webauthnRoutes = Router();

const validateAppToken = [validateApplicationToken];
const validateJWTToken = [validateWebAuthnToken];

webauthnRoutes.post(
"/request-register",
validateAppToken,
Expand Down

0 comments on commit 6a5361d

Please sign in to comment.