Skip to content

Commit

Permalink
add basic login system with express and mustache
Browse files Browse the repository at this point in the history
  • Loading branch information
FarzadHayat committed Jan 2, 2025
1 parent 335cfc9 commit 3b21cd1
Show file tree
Hide file tree
Showing 9 changed files with 545 additions and 66 deletions.
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
UPLOADCARE_SECRET_KEY=<your-secret-key>
TINYMCE_API_KEY=your-api-key
UPLOADCARE_PUBLIC_KEY=your-public-key
UPLOADCARE_SECRET_KEY=your-secret-key
SESSION_SECRET=your-session-secret
42 changes: 42 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: "CodeQL"

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
## Add schedule if needed
# schedule:
# - cron: "* * * * 0"

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: [javascript]

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-and-quality

- name: Autobuild
uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{ matrix.language }}"
27 changes: 27 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import "dotenv/config";

// Replace this with your TinyMCE API key from https://www.tiny.cloud/my-account/integrate/
const apiKey = process.env.TINYMCE_API_KEY;

// Replace this with your Uploadcare PUBLIC key from https://app.uploadcare.com/
const uploadcarePublicKey = process.env.UPLOADCARE_PUBLIC_KEY;

// Replace this with your Uploadcare SECRET key from https://app.uploadcare.com/
const uploadcareSecretKey = process.env.UPLOADCARE_SECRET_KEY;

// Replace this with your session secret (not necessary for testing purposes)
const sessionSecret = process.env.SESSION_SECRET;

// This is the fake database that the login authenticates against
const users = [
{ username: "johndoe", password: "password", fullname: "John Doe" },
{ username: "janedoe", password: "password", fullname: "Jane Doe" },
];

export default {
apiKey,
uploadcarePublicKey,
uploadcareSecretKey,
sessionSecret,
users,
};
44 changes: 0 additions & 44 deletions index.html

This file was deleted.

122 changes: 104 additions & 18 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,111 @@
import express from "express";
import cors from "cors";
import path from "path";
import "dotenv/config";
import mustacheExpress from "mustache-express";
import portfinder from "portfinder";
import session from "express-session";
import config from "./config.js";
import { generateSecureSignature } from "@uploadcare/signed-uploads";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const setupExpress = (port) => {
const app = express();

app.engine("mustache", mustacheExpress());
app.set("view engine", "mustache");
app.set("views", `${__dirname}/views`);

app.set("trust proxy", 1);
app.use(
session({
secret: config.sessionSecret,
resave: false,
saveUninitialized: true,
cookie: { secure: false },
})
);

app.use(express.static("public"));
app.use(express.urlencoded({ extended: false }));

setupRoutes(app);

app.listen(port, () =>
console.log(
`Image Optimizer Signed Uploads starter project is now available at: http://localhost:${port}/`
)
);
};

const setupRoutes = (app) => {
app.get("/", (req, res) => {
res.render("index");
});

app.get("/editor", (req, res) => {
if (req.session.user) {
res.render("editor", {
apiKey: config.apiKey,
uploadcarePublicKey: config.uploadcarePublicKey,
fullname: req.session.user.fullname,
});
} else {
res.redirect("/");
}
});

const app = express();
app.use(cors());
app.get("/logout", (req, res) => {
req.session.destroy();
res.redirect("/");
});

app.get("/", (_req, res) => {
res.sendFile(path.resolve() + "/index.html");
});
app.post("/", (req, res) => {
const user = config.users.find(
({ username, password }) =>
username === req.body.username && password === req.body.password
);
if (user) {
req.session.user = user;
res.redirect("/editor");
} else {
res.render("index", { error: "Incorrect username or password." });
}
});

app.get("/signature", (req, res) => {
const secretKey = process.env.UPLOADCARE_SECRET_KEY;
const { secureSignature: signature, secureExpire: expire } =
generateSecureSignature(secretKey, {
expire: Date.now() + 60 * 30 * 1000,
});
res.json({ signature, expire });
});
app.post("/signature", (req, res) => {
const user = req.session.user;
if (user) {
try {
const { secureSignature: signature, secureExpire: expire } =
generateSecureSignature(config.uploadcareSecretKey, {
expire: Date.now() + 60 * 30 * 1000, // 30 minutes expiration
});
res.json({ signature, expire });
} catch (e) {
res.status(500).send("Failed to generate signature.");
console.error(e.message);
}
} else {
res.status(401).send(
"Could not produce a signature since the user is not logged in."
);
}
});
};

app.listen(3000, () =>
console.log("Server is running on http://localhost:3000")
portfinder.getPort(
{
port: 3000,
stopPort: 4000,
},
(err, port) => {
if (err) {
console.error("Error:", err.message);
process.exit(-1);
} else {
setupExpress(port);
}
}
);
Loading

0 comments on commit 3b21cd1

Please sign in to comment.