icynet-auth-server/src/modules/objects/audit/audit.service.ts

147 lines
3.5 KiB
TypeScript

import { Inject, Injectable } from '@nestjs/common';
import { Request } from 'express';
import { Repository } from 'typeorm';
import { User } from '../user/user.entity';
import { AuditLog } from './audit.entity';
import { AuditAction } from './audit.enum';
import { lookup, Lookup } from 'geoip-lite';
import { parse, Details } from 'express-useragent';
import { FormUtilityService } from 'src/modules/utility/services/form-utility.service';
export interface UserLoginEntry {
login_at: Date;
current: boolean;
location: Partial<Lookup>;
user_agent: Partial<Details>;
}
@Injectable()
export class AuditService {
constructor(
@Inject('AUDIT_REPOSITORY')
private readonly audit: Repository<AuditLog>,
private readonly form: FormUtilityService,
) {}
public async insertAudit(
action: AuditAction,
comment?: string,
user?: User,
ip?: string,
ua?: string,
) {
const audit = new AuditLog();
audit.action = action as string;
audit.content = comment;
audit.actor_ip = ip;
audit.actor_ua = ua;
audit.actor = user;
if (
action === AuditAction.MALICIOUS_REQUEST ||
action === AuditAction.THROTTLE
) {
audit.flagged = true;
// TODO: email administrator
}
await this.updateAudit(audit);
return audit;
}
public async auditRequest(
req: Request,
type: AuditAction,
comment?: string,
user?: User,
) {
return this.insertAudit(
type,
comment,
user || req.user || null,
req.ip,
req.header('user-agent'),
);
}
public getIPLocation(ip: string) {
return lookup(ip);
}
public getUserAgentInfo(ua: string) {
return parse(ua);
}
public async getUserLogins(
user: User,
sessid?: string,
): Promise<UserLoginEntry[]> {
const userLogins: UserLoginEntry[] = [];
const auditEntries = await this.audit.find({
where: { actor: { id: user.id }, action: AuditAction.LOGIN },
order: { created_at: 'DESC' },
take: 10,
});
auditEntries.forEach((entry) => {
userLogins.push({
login_at: entry.created_at,
current: sessid === entry.content,
location: entry.actor_ip
? this.form.pluckObject(this.getIPLocation(entry.actor_ip), [
'country',
'city',
'timezone',
'll',
])
: null,
user_agent: entry.actor_ua
? this.form.pluckObject(this.getUserAgentInfo(entry.actor_ua), [
'browser',
'version',
'os',
'platform',
])
: null,
});
});
return userLogins;
}
public async getUserAccountCreation(user: User) {
const auditEntry = await this.audit.findOne({
where: { actor: { id: user.id }, action: AuditAction.REGISTRATION },
});
if (!auditEntry) {
return null;
}
return {
created_at: auditEntry.created_at,
ip: auditEntry.actor_ip,
location: auditEntry.actor_ip
? this.form.pluckObject(this.getIPLocation(auditEntry.actor_ip), [
'country',
'city',
'timezone',
'll',
])
: null,
user_agent: auditEntry.actor_ua
? this.form.pluckObject(this.getUserAgentInfo(auditEntry.actor_ua), [
'browser',
'version',
'os',
'platform',
])
: null,
};
}
public async updateAudit(audit: AuditLog): Promise<void> {
await this.audit.save(audit);
}
}