Compare commits
5 Commits
d3251eba11
...
893aed0945
Author | SHA1 | Date | |
---|---|---|---|
893aed0945 | |||
e2aa998723 | |||
f0320d1350 | |||
74ea4d73d6 | |||
1218512972 |
@ -48,11 +48,13 @@ class Server extends EventEmitter {
|
|||||||
this._proto = NODE_ENV === 'development' ? 'http' : 'https';
|
this._proto = NODE_ENV === 'development' ? 'http' : 'https';
|
||||||
|
|
||||||
if (!httpOpts?.port) return Util.fatal(new Error(`Missing http.port in server options`));
|
if (!httpOpts?.port) return Util.fatal(new Error(`Missing http.port in server options`));
|
||||||
|
// Port number is automatically incremented based on shard #
|
||||||
this.port = httpOpts.port + this._shardId;
|
this.port = httpOpts.port + this._shardId;
|
||||||
|
// Primarily used by the OAuth methods for the callback url
|
||||||
this.domain = NODE_ENV === 'development' ? `localhost:${this.port}` : options.domain;
|
this.domain = NODE_ENV === 'development' ? `localhost:${this.port}` : options.domain;
|
||||||
this.serveFiles = null;
|
this.serveFiles = null; // Holds a reference to the directory from which to serve content
|
||||||
this.registrationEnabled = options.registrationEnabled;
|
|
||||||
if (options.serveFiles) this.serveFiles = path.resolve(options.serveFiles);
|
if (options.serveFiles) this.serveFiles = path.resolve(options.serveFiles);
|
||||||
|
this.registrationEnabled = options.registrationEnabled;
|
||||||
|
|
||||||
this.server = null;
|
this.server = null;
|
||||||
this.app = express();
|
this.app = express();
|
||||||
@ -61,11 +63,14 @@ class Server extends EventEmitter {
|
|||||||
this.registry = new Registry(this, { path: path.join(__dirname, 'endpoints') });
|
this.registry = new Registry(this, { path: path.join(__dirname, 'endpoints') });
|
||||||
this.logger = new LoggerClient({ ...options.logger, name: this.constructor.name });
|
this.logger = new LoggerClient({ ...options.logger, name: this.constructor.name });
|
||||||
|
|
||||||
// Mariadb isn't strictly necessart here for anything, it's just here pre-emptively
|
// 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 });
|
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
|
// 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 });
|
||||||
this.userDatabase = new UserDatabase(this, this.mongodb, { validUserTypes });
|
this.userDatabase = new UserDatabase(this, this.mongodb, { validUserTypes });
|
||||||
|
// Alias
|
||||||
|
this.users = this.userDatabase;
|
||||||
|
|
||||||
// Authenticator takes care of sessions, logins and authorisations
|
// Authenticator takes care of sessions, logins and authorisations
|
||||||
this.authenticator = new Authenticator(this, this.userDatabase, {
|
this.authenticator = new Authenticator(this, this.userDatabase, {
|
||||||
mongo: this.mongodb,
|
mongo: this.mongodb,
|
||||||
@ -92,7 +97,7 @@ class Server extends EventEmitter {
|
|||||||
'style-src': [ "'self'", "'unsafe-inline'" ],
|
'style-src': [ "'self'", "'unsafe-inline'" ],
|
||||||
'img-src': [ "'self'", "https:" ],
|
'img-src': [ "'self'", "https:" ],
|
||||||
'media-src': [ "'self'" ],
|
'media-src': [ "'self'" ],
|
||||||
'frame-src': [ "youtube.com", "www.youtube.com" ]
|
'frame-src': [ "'self'" ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
crossOriginResourcePolicy: {
|
crossOriginResourcePolicy: {
|
||||||
|
@ -31,6 +31,21 @@ class UserDatabase extends AbstractUserDatabase {
|
|||||||
// this.userCollection = this.db.collection(this._userColllection);
|
// this.userCollection = this.db.collection(this._userColllection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchUsers (page, amount = 10, query = {}) {
|
||||||
|
if (!page) throw new Error('Missing page number');
|
||||||
|
const data = await this.db.find('users', query, { limit: amount, skip: (page - 1) * amount });
|
||||||
|
const users = [];
|
||||||
|
for (const user of data) {
|
||||||
|
let u = this.cache.get(user._id);
|
||||||
|
if (!u) {
|
||||||
|
u = this._createUser(user);
|
||||||
|
this.cache.set(u.id, u);
|
||||||
|
}
|
||||||
|
users.push(u);
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
async fetchUser (id, force = false) {
|
async fetchUser (id, force = false) {
|
||||||
|
|
||||||
if (!id) throw new Error('Missing token');
|
if (!id) throw new Error('Missing token');
|
||||||
|
@ -70,6 +70,7 @@ class MongoDB {
|
|||||||
*/
|
*/
|
||||||
async find (db, query, options) {
|
async find (db, query, options) {
|
||||||
|
|
||||||
|
if (typeof db !== 'string') throw new TypeError('Expecting collection name for the first argument');
|
||||||
this.logger.debug(`Incoming find query for ${db} with parameters ${inspect(query)}`);
|
this.logger.debug(`Incoming find query for ${db} with parameters ${inspect(query)}`);
|
||||||
|
|
||||||
const cursor = this.db.collection(db).find(query, options);
|
const cursor = this.db.collection(db).find(query, options);
|
||||||
@ -87,6 +88,7 @@ class MongoDB {
|
|||||||
*/
|
*/
|
||||||
async findOne (db, query, options = {}) {
|
async findOne (db, query, options = {}) {
|
||||||
|
|
||||||
|
if (typeof db !== 'string') throw new TypeError('Expecting collection name for the first argument');
|
||||||
this.logger.debug(`Incoming findOne query for ${db} with parameters ${inspect(query)}`);
|
this.logger.debug(`Incoming findOne query for ${db} with parameters ${inspect(query)}`);
|
||||||
const result = await this.db.collection(db).findOne(query, options);
|
const result = await this.db.collection(db).findOne(query, options);
|
||||||
return result;
|
return result;
|
||||||
@ -104,6 +106,7 @@ class MongoDB {
|
|||||||
*/
|
*/
|
||||||
async updateMany (db, filter, data, upsert = false) {
|
async updateMany (db, filter, data, upsert = false) {
|
||||||
|
|
||||||
|
if (typeof db !== 'string') throw new TypeError('Expecting collection name for the first argument');
|
||||||
this.logger.debug(`Incoming update query for '${db}' with parameters\n${inspect(filter)}\nand data\n${inspect(data)}`);
|
this.logger.debug(`Incoming update query for '${db}' with parameters\n${inspect(filter)}\nand data\n${inspect(data)}`);
|
||||||
if (!filter) throw new Error(`Cannot run update many without a filter, if you mean to update every single document, pass an empty object`);
|
if (!filter) throw new Error(`Cannot run update many without a filter, if you mean to update every single document, pass an empty object`);
|
||||||
const result = await this.db.collection(db).updateMany(filter, { $set: data }, { upsert });
|
const result = await this.db.collection(db).updateMany(filter, { $set: data }, { upsert });
|
||||||
@ -122,6 +125,7 @@ class MongoDB {
|
|||||||
*/
|
*/
|
||||||
async updateOne (db, filter, data, upsert = false) {
|
async updateOne (db, filter, data, upsert = false) {
|
||||||
|
|
||||||
|
if (typeof db !== 'string') throw new TypeError('Expecting collection name for the first argument');
|
||||||
this.logger.debug(`Incoming updateOne query for ${db} with parameters ${inspect(filter)}`);
|
this.logger.debug(`Incoming updateOne query for ${db} with parameters ${inspect(filter)}`);
|
||||||
const result = await this.db.collection(db).updateOne(filter, { $set: data }, { upsert });
|
const result = await this.db.collection(db).updateOne(filter, { $set: data }, { upsert });
|
||||||
return result;
|
return result;
|
||||||
@ -139,6 +143,7 @@ class MongoDB {
|
|||||||
*/
|
*/
|
||||||
async insertOne (db, data) {
|
async insertOne (db, data) {
|
||||||
|
|
||||||
|
if (typeof db !== 'string') throw new TypeError('Expecting collection name for the first argument');
|
||||||
this.logger.debug(`Incoming insertOne query for ${db} with parameters ${inspect(data)}`);
|
this.logger.debug(`Incoming insertOne query for ${db} with parameters ${inspect(data)}`);
|
||||||
const result = await this.db.collection(db).insertOne(data);
|
const result = await this.db.collection(db).insertOne(data);
|
||||||
return result;
|
return result;
|
||||||
@ -157,6 +162,7 @@ class MongoDB {
|
|||||||
*/
|
*/
|
||||||
async push (db, filter, data, upsert = false) {
|
async push (db, filter, data, upsert = false) {
|
||||||
|
|
||||||
|
if (typeof db !== 'string') throw new TypeError('Expecting collection name for the first argument');
|
||||||
this.logger.debug(`Incoming push query for ${db}, with upsert ${upsert} and with parameters ${inspect(filter)} and data ${inspect(data)}`);
|
this.logger.debug(`Incoming push query for ${db}, with upsert ${upsert} and with parameters ${inspect(filter)} and data ${inspect(data)}`);
|
||||||
const result = await this.db.collection(db).updateOne(filter, { $push: data }, { upsert });
|
const result = await this.db.collection(db).updateOne(filter, { $push: data }, { upsert });
|
||||||
return result;
|
return result;
|
||||||
@ -174,6 +180,7 @@ class MongoDB {
|
|||||||
*/
|
*/
|
||||||
random (db, filter = {}, amount = 1) {
|
random (db, filter = {}, amount = 1) {
|
||||||
|
|
||||||
|
if (typeof db !== 'string') throw new TypeError('Expecting collection name for the first argument');
|
||||||
this.logger.debug(`Incoming random query for ${db} with parameters ${inspect(filter)} and amount ${amount}`);
|
this.logger.debug(`Incoming random query for ${db} with parameters ${inspect(filter)} and amount ${amount}`);
|
||||||
if (amount > 100) amount = 100;
|
if (amount > 100) amount = 100;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ class LoginEndpoint extends ApiEndpoint {
|
|||||||
if (!user._otpSecret) return res.status(400).send('2FA not initialised');
|
if (!user._otpSecret) return res.status(400).send('2FA not initialised');
|
||||||
if (!user._2fa) return res.status(400).send('2FA not enabled');
|
if (!user._2fa) return res.status(400).send('2FA not enabled');
|
||||||
|
|
||||||
if (!authenticator.check(code, user._otpSecret)) return res.status(400).send('Wrong code');
|
if (!authenticator.check(code, user._otpSecret)) return res.status(401).send('Wrong code');
|
||||||
session.verified = true;
|
session.verified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
src/server/endpoints/api/Users.js
Normal file
25
src/server/endpoints/api/Users.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const { ApiEndpoint } = require("../../interfaces");
|
||||||
|
|
||||||
|
class UsersEndpoint extends ApiEndpoint {
|
||||||
|
|
||||||
|
constructor (server) {
|
||||||
|
super(server, {
|
||||||
|
name: 'users',
|
||||||
|
path: '/users'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.methods.push([ 'get', this.getUsers.bind(this), [ server.auth.createAuthoriser('administrator', 10) ]]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUsers (req, res) {
|
||||||
|
const { query } = req;
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = UsersEndpoint;
|
@ -20,7 +20,7 @@ class Util {
|
|||||||
static checkPermissions (perms, perm, level = 1) {
|
static checkPermissions (perms, perm, level = 1) {
|
||||||
|
|
||||||
if (!perms || typeof perms !== 'object') throw new Error('Missing perms object');
|
if (!perms || typeof perms !== 'object') throw new Error('Missing perms object');
|
||||||
if (!perm || typeof perms !== 'string') throw new Error('Missing perm string');
|
if (!perm || typeof perm !== 'string') throw new Error('Missing perm string');
|
||||||
|
|
||||||
// Allow for checking of nested permissions, e.g. administrator:createUser
|
// Allow for checking of nested permissions, e.g. administrator:createUser
|
||||||
const resolveables = perm.split(':');
|
const resolveables = perm.split(':');
|
||||||
|
Loading…
Reference in New Issue
Block a user