Compare commits
5 Commits
9fc6950664
...
b50f603ee2
Author | SHA1 | Date | |
---|---|---|---|
b50f603ee2 | |||
f4a04bc67b | |||
a7dac9f5f7 | |||
ede532df4c | |||
b5820dafde |
@ -1,6 +1,7 @@
|
||||
# Navy's webserver framework
|
||||
A template repository for creating Node.js based webservers with sharding.
|
||||
Main repository: https://git.corgi.wtf/Navy.gif/webserver-framework
|
||||
Frontend: https://git.corgi.wtf/Navy.gif/webserver-framework-frontend
|
||||
|
||||
## Technologies
|
||||
- Argon2
|
||||
@ -21,6 +22,12 @@ Fetching the upstream changes
|
||||
- Merge changes to the current branch `git merge upstream/master`.
|
||||
(Use `git remote -v` to list remotes)
|
||||
|
||||
**OAuth callbacks**
|
||||
By default any OAuth callbacks are expected at `/api/login/<methodname>`, where methodname is the name of the OAuth strategy. E.g. by default this framework has a discord strategy defined in Server.addAuthStrategies which expects a callback to `/api/login/discord`.
|
||||
|
||||
**Endpoints**
|
||||
Any all endpoints should go in the `/endpoints` directory and are expected to inherit from the Endpoint superclass.
|
||||
|
||||
## Main components
|
||||
**Controller:** `/src/controller/Controller.js`
|
||||
Master process, orchestrates the whole program. Takes care of starting up the shards and communication with them.
|
||||
|
@ -11,6 +11,7 @@ MONGO_PORT=27017
|
||||
MONGO_USER=
|
||||
MONGO_PASS=
|
||||
MONGO_DB=framework-proto
|
||||
MONGO_AUTH_DB=auth
|
||||
|
||||
# Encryption secret
|
||||
CRYPTO_SECRET=verySecretSecret
|
||||
|
@ -34,7 +34,7 @@ class Server extends EventEmitter {
|
||||
|
||||
const { MARIA_HOST, MARIA_USER, MARIA_PORT, MARIA_PASS, MARIA_DB,
|
||||
MONGO_HOST, MONGO_USER, MONGO_PORT, MONGO_PASS, MONGO_DB,
|
||||
NODE_ENV, SECRET, CRYPTO_SECRET, CRYPTO_SALT } = process.env;
|
||||
NODE_ENV, SECRET, CRYPTO_SECRET, CRYPTO_SALT, MONGO_AUTH_DB } = process.env;
|
||||
const { http: httpOpts, databases, validUserTypes } = options;
|
||||
|
||||
// This key never leaves memory and is exclusively used on the server, the salt can stay static
|
||||
@ -66,7 +66,7 @@ class Server extends EventEmitter {
|
||||
// Mariadb isn't strictly necessary here for anything, it's just here pre-emptively
|
||||
this.mariadb = new MariaDB(this, { options: databases.mariadb, MARIA_HOST, MARIA_USER, MARIA_PORT, MARIA_PASS, MARIA_DB });
|
||||
// Mongo is used for session and user storage
|
||||
this.mongodb = new MongoDB(this, { options: databases.mongodb, MONGO_HOST, MONGO_USER, MONGO_PORT, MONGO_PASS, MONGO_DB });
|
||||
this.mongodb = new MongoDB(this, { options: databases.mongodb, MONGO_HOST, MONGO_USER, MONGO_PORT, MONGO_PASS, MONGO_DB, MONGO_AUTH_DB });
|
||||
this.userDatabase = new UserDatabase(this, this.mongodb, { validUserTypes });
|
||||
// Alias
|
||||
this.users = this.userDatabase;
|
||||
@ -102,9 +102,6 @@ class Server extends EventEmitter {
|
||||
},
|
||||
crossOriginResourcePolicy: {
|
||||
policy: 'cross-origin'
|
||||
},
|
||||
crossOriginEmbedderPolicy: {
|
||||
policy: 'require-corp'
|
||||
}
|
||||
}));
|
||||
this.app.use(express.json({ limit: '10mb' }));
|
||||
|
@ -156,7 +156,7 @@ class UserDatabase extends AbstractUserDatabase {
|
||||
}
|
||||
|
||||
this.logger.info(`Creating new user from Discord profile: ${profile.username} (${profile.id})`);
|
||||
user = this._createUser({ type: 'user', name: profile.username });
|
||||
user = this._createUser({ type: 'user', username: profile.username });
|
||||
user.addExternalProfile('discord', profile);
|
||||
await user.save();
|
||||
this.cache.set(user.id, user);
|
||||
|
27
src/server/endpoints/api/Api404.js
Normal file
27
src/server/endpoints/api/Api404.js
Normal file
@ -0,0 +1,27 @@
|
||||
const { ApiEndpoint } = require("../../interfaces");
|
||||
|
||||
// Just so requests to /api/.. don't get sent the index.html file on invalid path
|
||||
// Could've also just defined this quick and dirty in the Server class,
|
||||
// but I feel this is better for readability
|
||||
class Api404 extends ApiEndpoint {
|
||||
|
||||
constructor (server) {
|
||||
|
||||
super(server, {
|
||||
name: 'api404',
|
||||
path: '/*'
|
||||
});
|
||||
|
||||
this.methods = [
|
||||
[ 'get', this.get.bind(this) ]
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
async get (req, res) {
|
||||
res.status(404).end();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Api404;
|
@ -18,7 +18,7 @@ class LogoutEndpoint extends ApiEndpoint {
|
||||
logout (req, res) {
|
||||
|
||||
req.session.destroy();
|
||||
res.clearCookie(this.server.authenticator.cookieName);
|
||||
res.clearCookie(this.server.auth.cookieName);
|
||||
res.end();
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class UsersEndpoint extends ApiEndpoint {
|
||||
const { amount, page } = query;
|
||||
if (!page) return res.status(400).send('Missing page number');
|
||||
const users = await this.server.users.fetchUsers(page, amount);
|
||||
res.json(users.map(user => user.json));
|
||||
res.json(users.map(user => user.safeJson));
|
||||
}
|
||||
|
||||
async user (req, res) {
|
||||
@ -30,7 +30,7 @@ class UsersEndpoint extends ApiEndpoint {
|
||||
const { userid } = params;
|
||||
const user = await this.server.users.fetchUser(userid);
|
||||
if (!user) return res.status(404).end();
|
||||
res.json(user);
|
||||
res.json(user.safeJson);
|
||||
}
|
||||
|
||||
async userApplications (req, res) {
|
||||
@ -39,7 +39,7 @@ class UsersEndpoint extends ApiEndpoint {
|
||||
const user = await this.server.users.fetchUser(userid);
|
||||
if (!user) return res.status(404).send('Could not find the user');
|
||||
const applications = await user.fetchApplications();
|
||||
res.json(Object.values(applications).map(app => app.json));
|
||||
res.json(Object.values(applications).map(app => app.safeJson));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,9 @@ const { ObjectId } = require('mongodb');
|
||||
const { Util } = require('../../util');
|
||||
const UserApplicataion = require('./UserApplication');
|
||||
|
||||
// Fields omitted in safeJson
|
||||
const ProtectedFields = [ '_id', '_otpSecret', '_passwordHash' ];
|
||||
|
||||
class User {
|
||||
|
||||
static defaultPermissions = {
|
||||
@ -29,6 +32,7 @@ class User {
|
||||
this._db = db;
|
||||
|
||||
this.temporary = data.temporary || false;
|
||||
this.disabled = data.disabled || false;
|
||||
|
||||
this._id = data._id || null;
|
||||
if (this.temporary) this._tempId = `temp-${Date.now()}`;
|
||||
@ -69,6 +73,7 @@ class User {
|
||||
this._2fa = data.twoFactor || false;
|
||||
|
||||
this.cachedTimestamp = Date.now();
|
||||
this.createdTimestamp = data.createdTimestamp || Date.now();
|
||||
|
||||
}
|
||||
|
||||
@ -171,21 +176,21 @@ class User {
|
||||
otpSecret: this._otpSecret,
|
||||
twoFactor: this._2fa,
|
||||
applications: this._applications,
|
||||
createdTimestamp: this.createdTimestamp,
|
||||
disabled: this.disabled,
|
||||
};
|
||||
}
|
||||
|
||||
get safeJson () {
|
||||
const { json } = this;
|
||||
for (const key of ProtectedFields) delete json[key];
|
||||
|
||||
return {
|
||||
...json,
|
||||
id: this.id,
|
||||
username: this.username,
|
||||
displayName: this.displayName,
|
||||
type: this.type,
|
||||
permissions: this.permissions,
|
||||
externalProfiles: Object.values(this.externalProfiles).map(prof => {
|
||||
return { id: prof.id, provider: prof.provider, username: prof.username };
|
||||
}),
|
||||
twoFactor: this._2fa,
|
||||
applications: this._applications,
|
||||
};
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user