core: oplog: better logging

This commit is contained in:
undefined committed 2021-12-21 21:34:49 +08:00
1 parent 92c1a41585
commit ead0d54a55
8 files changed
+74 -60

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hydrooj",
"version": "3.2.27",
"version": "3.2.28",
"bin": "bin/hydrooj.js",
"main": "src/loader",
"module": "src/loader",
+8 -8
View File
@@ -100,10 +100,10 @@ class BlogEditHandler extends BlogHandler {
@param('content', Types.Content)
async postUpdate(domainId: string, did: ObjectID, title: string, content: string) {
if (!this.user.own(this.ddoc)) this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
await blog.edit(did, title, content);
await oplog.add({
...this.ddoc, operator: this.user._id, type: 'edit',
});
await Promise.all([
blog.edit(did, title, content),
oplog.log(this, 'blog.edit', this.ddoc),
]);
this.response.body = { did };
this.response.redirect = this.url('blog_detail', { uid: this.user._id, did });
}
@@ -111,10 +111,10 @@ class BlogEditHandler extends BlogHandler {
@param('did', Types.ObjectID)
async postDelete(domainId: string, did: ObjectID) {
if (!this.user.own(this.ddoc)) this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
await blog.del(did);
await oplog.add({
...this.ddoc, operator: this.user._id, operateIp: this.request.ip, type: 'delete',
});
await Promise.all([
blog.del(did),
oplog.log(this, 'blog.delete', this.ddoc),
]);
this.response.redirect = this.url('blog_main', { uid: this.ddoc.owner });
}
}
+24 -25
View File
@@ -251,10 +251,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
async postEditReply(domainId: string, drid: ObjectID, content: string) {
this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
if (!this.user.own(this.drdoc)) throw new PermissionError(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
await discussion.editReply(domainId, drid, content);
await oplog.add({
...this.drdoc, operator: this.user._id, operateIp: this.request.ip, type: 'edit',
});
await Promise.all([
discussion.editReply(domainId, drid, content),
oplog.log(this, 'discussion.reply.edit', this.drdoc),
]);
this.back();
}
@@ -266,10 +266,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
this.checkPerm(PERM.PERM_DELETE_DISCUSSION_REPLY);
} else this.checkPerm(PERM.PERM_DELETE_DISCUSSION_SELF);
}
await discussion.delReply(domainId, drid);
await oplog.add({
...this.drdoc, operator: this.user._id, operateIp: this.request.ip, type: 'delete',
});
await Promise.all([
discussion.delReply(domainId, drid),
oplog.log(this, 'discussion.reply.delete', this.drdoc),
]);
this.back();
}
@@ -279,11 +279,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
async postEditTailReply(domainId: string, drid: ObjectID, drrid: ObjectID, content: string) {
this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
if (!this.user.own(this.drrdoc)) throw new PermissionError(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
await discussion.editTailReply(domainId, drid, drrid, content);
// TODO: history?
await oplog.add({
...this.drrdoc, operator: this.user._id, operateIp: this.request.ip, type: 'edit',
});
await Promise.all([
discussion.editTailReply(domainId, drid, drrid, content),
oplog.log(this, 'discussion.tailReply.edit', this.drrdoc),
]);
this.back();
}
@@ -291,10 +290,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
@param('drrid', Types.ObjectID)
async postDeleteTailReply(domainId: string, drid: ObjectID, drrid: ObjectID) {
if (!this.user.own(this.drrdoc)) this.checkPerm(PERM.PERM_DELETE_DISCUSSION_REPLY);
await discussion.delTailReply(domainId, drid, drrid);
await oplog.add({
...this.drrdoc, operator: this.user._id, operateIp: this.request.ip, type: 'delete',
});
await Promise.all([
discussion.delTailReply(domainId, drid, drrid),
oplog.log(this, 'discussion.tailReply.delete', this.drrdoc),
]);
this.back();
}
@@ -346,10 +345,10 @@ class DiscussionEditHandler extends DiscussionHandler {
else this.checkPerm(PERM.PERM_EDIT_DISCUSSION_SELF);
if (!this.user.hasPerm(PERM.PERM_HIGHLIGHT_DISCUSSION)) highlight = this.ddoc.highlight;
if (!this.user.hasPerm(PERM.PERM_PIN_DISCUSSION)) pin = this.ddoc.pin;
await discussion.edit(domainId, did, title, content, highlight, pin);
await oplog.add({
...this.ddoc, operator: this.user._id, type: 'edit',
});
await Promise.all([
discussion.edit(domainId, did, title, content, highlight, pin),
oplog.log(this, 'discussion.edit', this.ddoc),
]);
this.response.body = { did };
this.response.redirect = this.url('discussion_detail', { did });
}
@@ -358,10 +357,10 @@ class DiscussionEditHandler extends DiscussionHandler {
async postDelete(domainId: string, did: ObjectID) {
if (!this.user.own(this.ddoc)) this.checkPerm(PERM.PERM_DELETE_DISCUSSION);
else this.checkPerm(PERM.PERM_DELETE_DISCUSSION_SELF);
await discussion.del(domainId, did);
await oplog.add({
...this.ddoc, operator: this.user._id, operateIp: this.request.ip, type: 'delete',
});
await Promise.all([
oplog.log(this, 'discussion.delete', this.ddoc),
discussion.del(domainId, did),
]);
this.response.body = { type: this.ddoc.parentType, parent: this.ddoc.parentId };
this.response.redirect = this.url('discussion_node', {
type: discussion.typeDisplay[this.ddoc.parentType],
+13 -3
View File
@@ -11,6 +11,7 @@ import paginate from '../lib/paginate';
import { PERM, PERMS_BY_FAMILY, PRIV } from '../model/builtin';
import * as discussion from '../model/discussion';
import domain from '../model/domain';
import * as oplog from '../model/oplog';
import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
import * as system from '../model/system';
import user from '../model/user';
@@ -114,14 +115,20 @@ class DomainUserHandler extends ManageHandler {
@post('uid', Types.Int)
@post('role', Types.Name)
async postSetUser(domainId: string, uid: number, role: string) {
await domain.setUserRole(domainId, uid, role);
await Promise.all([
domain.setUserRole(domainId, uid, role),
oplog.log(this, 'domain.setRole', { uid, role }),
]);
this.back();
}
@param('uid', Types.NumericArray)
@param('role', Types.Name)
async postSetUsers(domainId: string, uid: number[], role: string) {
await domain.setUserRole(domainId, uid, role);
await Promise.all([
domain.setUserRole(domainId, uid, role),
oplog.log(this, 'domain.setRole', { uid, role }),
]);
this.back();
}
}
@@ -242,7 +249,10 @@ class DomainJoinHandler extends Handler {
throw new InvalidJoinInvitationCodeError(this.domain._id);
}
}
await domain.setUserRole(this.domain._id, this.user._id, this.joinSettings.role);
await Promise.all([
domain.setUserRole(this.domain._id, this.user._id, this.joinSettings.role),
oplog.log(this, 'domain.join', {}),
]);
this.response.redirect = this.url('homepage', { query: { notification: 'Successfully joined domain.' } });
}
}
+1 -7
View File
@@ -91,14 +91,8 @@ export class FSDownloadHandler extends Handler {
this.response.addHeader('Cache-Control', 'public');
const target = `user/${uid}/${filename}`;
const file = await storage.getMeta(target);
await oplog.add({
type: 'download',
time: new Date(),
uid: this.user._id,
ip: this.request.ip,
fileType: 'user',
await oplog.log(this, 'download.file.user', {
target,
referer: this.request.referer,
size: file?.size || 0,
});
if (!file) {
+2 -14
View File
@@ -514,14 +514,8 @@ export class ProblemFilesHandler extends ProblemDetailHandler {
?.filter((i) => files.has(i.name))
?.map((i) => i.size),
) || 0;
await oplog.add({
type: 'bulkDownload',
time: new Date(),
uid: this.user._id,
ip: this.request.ip,
fileType: 'problem',
await oplog.log(this, 'download.problem.bulk', {
target: Array.from(files).map((file) => `problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${file}`),
referer: this.request.referer,
size,
});
for (const file of files) {
@@ -618,14 +612,8 @@ export class ProblemFileDownloadHandler extends ProblemDetailHandler {
}
const target = `problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${filename}`;
const file = await storage.getMeta(target);
await oplog.add({
type: 'download',
time: new Date(),
uid: this.user._id,
ip: this.request.ip,
fileType: 'problem',
await oplog.log(this, 'download.problem.single', {
target,
referer: this.request.referer,
size: file?.size || 0,
});
if (!file) {
+5 -1
View File
@@ -14,6 +14,7 @@ import BlackListModel from '../model/blacklist';
import { PERM, PRIV, STATUS } from '../model/builtin';
import domain from '../model/domain';
import oauth from '../model/oauth';
import * as oplog from '../model/oplog';
import problem, { ProblemDoc } from '../model/problem';
import * as system from '../model/system';
import task from '../model/task';
@@ -118,7 +119,10 @@ class UserLoginHandler extends Handler {
let udoc = await user.getByEmail(domainId, uname);
if (!udoc) udoc = await user.getByUname(domainId, uname);
if (!udoc) throw new UserNotFoundError(uname);
await this.limitRate('user_login', 60, 5);
await Promise.all([
this.limitRate('user_login', 60, 5),
oplog.log(this, 'user.login', { redirect }),
]);
if (udoc._tfa && !verifyToken(udoc._tfa, tfa)) throw new InvalidTokenError('2FA token invalid.');
udoc.checkPassword(password);
await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip });
+20 -1
View File
@@ -1,6 +1,7 @@
import { ObjectID } from 'mongodb';
import { OplogDoc } from '../interface';
import db from '../service/db';
import type { Handler } from '../service/server';
export const coll = db.collection('oplog');
@@ -14,8 +15,26 @@ export async function add(data: Partial<OplogDoc> & { type: string }): Promise<O
return res.insertedId;
}
export async function log<T extends Handler>(handler: T, type: string, data: any) {
const res = await coll.insertOne({
...data,
_id: new ObjectID(),
type,
time: new Date(),
domainId: handler.domainId,
ua: handler.request.headers?.['user-agent'],
referer: handler.request.headers?.referer,
args: handler.args,
operator: handler.user?.id,
operateIp: handler.request.ip,
});
return res.insertedId;
}
export async function get(id: ObjectID): Promise<OplogDoc | null> {
return await coll.findOne({ _id: id });
}
global.Hydro.model.oplog = { coll, add, get };
global.Hydro.model.oplog = {
coll, add, get, log,
};