Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions microservices/admin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
env.yaml
sessions
183 changes: 183 additions & 0 deletions microservices/admin/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
const express = require("express");
const passport = require("passport");
const session = require("express-session");
const SessionFileStore = require("session-file-store")(session);
const GitHubStrategy = require("passport-github2");
const compression = require("compression");
const ejs = require("ejs");
const config = require("./config.js")();

const app = express();

// --- View Engine Setup ---
app.set("views", "./views");
app.set("view engine", "ejs");

// --- Webserver Setup ---
app.use("/", express.static("./static"));
app.set("trust proxy", true);

// --- Authentication Setup ---
app.use(
session({
secret: config.SESSION_SECRET,
resave: false,
saveUninitialized: false,
store: new SessionFileStore({
path: "./sessions",
ttl: 3600
}),
}),
);

app.use(passport.authenticate("session"));

passport.serializeUser((user, cb) => {
process.nextTick(() => {
cb(null, user);
// This will allow the user object being passed to be available via
// req.session.passport.user
});
});

passport.deserializeUser((user, cb) => {
process.nextTick(() => {
return cb(null, user);
});
});

passport.use(
"github",
new GitHubStrategy({
clientID: config.GITHUB_CLIENT_ID,
clientSecret: config.GITHUB_CLIENT_SECRET,
callbackURL: "http://127.0.0.1:8080/auth/github/callback"
},
(accessToken, refreshToken, profile, done) => {
if (config.ALLOWED_NODE_IDS.includes(profile.nodeId)) {
const usrObj = {
id: profile.id,
nodeId: profile.nodeId,
displayName: profile.displayName,
username: profile.username,
avatar: profile.photos[0].value
};

return done(null, usrObj);

} else {
console.error(`${profile.nodeId}:${profile.username} attempted to authenticate!`);
return done(
`Unallowed user attempted to authenticate: '${profile.username}'!`,
null
);
}
})
);

// --- Compression Setup ---
app.use(compression());

// --- Authentication Routes ---

app.get("/auth/github",
passport.authenticate("github", { scope: [ "user:email" ] })
);

app.get(
"/auth/github/callback",
passport.authenticate("github", {
failureRedirect: "/login"
}),
(req, res) => {
// successful authentication, redirect home
res.redirect("/");
}
);

// --- Regular Routes ---

const authMiddleware = (req, res, next) => {
if (config.ALLOWED_NODE_IDS.includes(req.user?.nodeId)) {
// the user is successfully signed in, and still allowed to view this content
console.log(`Authenticated '${req.user.username}' to '${req.url}'`);
next();
} else {
// the user is NOT successfully logged in
res.redirect("/login");
}
};

app.get("/", authMiddleware, async (req, res) => {

const template = await ejs.renderFile(
"./views/home.ejs",
{
page: {
name: "Pulsar Admin Dashboard",
description: "The dashboard to help manage Pulsar's cloud resources."
},
user: req.user
}
);

res.set("Content-Type", "text/html");
res.status(200).send(template);
return;
});

app.get("/login", async (req, res) => {

const template = await ejs.renderFile(
"./views/login.ejs",
{
page: {
name: "Pulsar Admin Dashboard",
description: "The dashboard to help manage Pulsar's cloud resources."
}
}
);

res.set("Content-Type", "text/html");
res.status(200).send(template);
});

app.use(async (err, req, res, next) => {
// Having this as the last positional route, ensures it will handle all other
// unknown routes. Can either be not found or an error from another endpoint
if (err) {
console.error(err);
console.error(`An error was encountered handling the request: ${err.toString()}`);

const template = await ejs.renderFile(
"./views/error.ejs",
{
page: {
name: "Error"
},
content: err
}
);

res.set("Content-Type", "text/html");
res.status(500).send(template);
return;
} else {
// return not found page
const template = await ejs.renderFile(
"./views/not_found.ejs",
{
page: {
name: "Not Found"
},
path: req.path
}
);

res.set("Content-Type", "text/html");
res.status(404).send(template);
return;
}
});

module.exports = app;
37 changes: 37 additions & 0 deletions microservices/admin/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const fs = require("fs");
const yaml = require("js-yaml");

module.exports =
function getConfig() {
try {
let data = null;

try {
let fileContent = fs.readFileSync("./env.yaml", "utf8");
data = yaml.load(fileContent);
} catch(err) {
if (process.env.PULSAR_STATUS !== "dev") {
console.error(`Failed to load env.yaml in non-dev env! ${err}`);
process.exit(1);
} else {
data = {};
}
}

const findValue = (key, def) => {
return process.env[key] ?? data[key] ?? def;
};

return {
PORT: findValue("PORT", 8080),
GITHUB_CLIENT_ID: findValue("GITHUB_CLIENT_ID"),
GITHUB_CLIENT_SECRET: findValue("GITHUB_CLIENT_SECRET"),
SESSION_SECRET: findValue("SESSION_SECRET"),
ALLOWED_NODE_IDS: findValue("ALLOWED_NODE_IDS")
};

} catch(err) {
console.error(err);
process.exit(1);
}
}
7 changes: 7 additions & 0 deletions microservices/admin/env.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
PORT: 8080
GITHUB_CLIENT_ID: ""
GITHUB_CLIENT_SECRET: ""
SESSION_SECRET: "test"
ALLOWED_NODE_IDS:
- "node_id_1"
- "node_id_2"
12 changes: 12 additions & 0 deletions microservices/admin/oauth_app_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## There is no actual config available for this data
## But in the spirit of full documentation this will be added in a made up format.

client_id: ""
application_logo:
file: pulsar_discord.png
background_color: "#fff"
application_name: "Pulsar Admin Dashboard"
homepage_url: "https://pulsar-edit.dev"
application_description: "Admin Dashboard for Pulsar; Authorized users only."
callback_url: "https://admin.pulsar-edit.dev/auth/github/callback"
enable_device_flow: false
Loading