BREAKING CHANGE(db): replace StorageManager and CacheDb with a unified smartdata-backed database layer
This commit is contained in:
106
ts/db/documents/classes.accounting-session.doc.ts
Normal file
106
ts/db/documents/classes.accounting-session.doc.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class AccountingSessionDoc extends plugins.smartdata.SmartDataDbDoc<AccountingSessionDoc, AccountingSessionDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public sessionId!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public username!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public macAddress!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public nasIpAddress!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public nasPort!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public nasPortType!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public nasIdentifier!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public vlanId!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public framedIpAddress!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public calledStationId!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public callingStationId!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public startTime!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public endTime!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public lastUpdateTime!: number;
|
||||
|
||||
@plugins.smartdata.index()
|
||||
@plugins.smartdata.svDb()
|
||||
public status!: 'active' | 'stopped' | 'terminated';
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public terminateCause!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public inputOctets!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public outputOctets!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public inputPackets!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public outputPackets!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public sessionTime!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public serviceType!: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findBySessionId(sessionId: string): Promise<AccountingSessionDoc | null> {
|
||||
return await AccountingSessionDoc.getInstance({ sessionId });
|
||||
}
|
||||
|
||||
public static async findActive(): Promise<AccountingSessionDoc[]> {
|
||||
return await AccountingSessionDoc.getInstances({ status: 'active' });
|
||||
}
|
||||
|
||||
public static async findByUsername(username: string): Promise<AccountingSessionDoc[]> {
|
||||
return await AccountingSessionDoc.getInstances({ username });
|
||||
}
|
||||
|
||||
public static async findByNas(nasIpAddress: string): Promise<AccountingSessionDoc[]> {
|
||||
return await AccountingSessionDoc.getInstances({ nasIpAddress });
|
||||
}
|
||||
|
||||
public static async findByVlan(vlanId: number): Promise<AccountingSessionDoc[]> {
|
||||
return await AccountingSessionDoc.getInstances({ vlanId });
|
||||
}
|
||||
|
||||
public static async findStoppedBefore(cutoffTime: number): Promise<AccountingSessionDoc[]> {
|
||||
return await AccountingSessionDoc.getInstances({
|
||||
status: { $in: ['stopped', 'terminated'] } as any,
|
||||
endTime: { $lt: cutoffTime, $gt: 0 } as any,
|
||||
});
|
||||
}
|
||||
}
|
||||
41
ts/db/documents/classes.acme-cert.doc.ts
Normal file
41
ts/db/documents/classes.acme-cert.doc.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class AcmeCertDoc extends plugins.smartdata.SmartDataDbDoc<AcmeCertDoc, AcmeCertDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public domainName!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public id!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public created!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public privateKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public publicKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public csr!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public validUntil!: number;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findByDomain(domainName: string): Promise<AcmeCertDoc | null> {
|
||||
return await AcmeCertDoc.getInstance({ domainName });
|
||||
}
|
||||
|
||||
public static async findAll(): Promise<AcmeCertDoc[]> {
|
||||
return await AcmeCertDoc.getInstances({});
|
||||
}
|
||||
}
|
||||
56
ts/db/documents/classes.api-token.doc.ts
Normal file
56
ts/db/documents/classes.api-token.doc.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
import type { TApiTokenScope } from '../../../ts_interfaces/data/route-management.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class ApiTokenDoc extends plugins.smartdata.SmartDataDbDoc<ApiTokenDoc, ApiTokenDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public id!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public name: string = '';
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public tokenHash!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public scopes!: TApiTokenScope[];
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public createdAt!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public expiresAt!: number | null;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public lastUsedAt!: number | null;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public createdBy!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public enabled!: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findById(id: string): Promise<ApiTokenDoc | null> {
|
||||
return await ApiTokenDoc.getInstance({ id });
|
||||
}
|
||||
|
||||
public static async findByTokenHash(tokenHash: string): Promise<ApiTokenDoc | null> {
|
||||
return await ApiTokenDoc.getInstance({ tokenHash });
|
||||
}
|
||||
|
||||
public static async findAll(): Promise<ApiTokenDoc[]> {
|
||||
return await ApiTokenDoc.getInstances({});
|
||||
}
|
||||
|
||||
public static async findEnabled(): Promise<ApiTokenDoc[]> {
|
||||
return await ApiTokenDoc.getInstances({ enabled: true });
|
||||
}
|
||||
}
|
||||
240
ts/db/documents/classes.cached.email.ts
Normal file
240
ts/db/documents/classes.cached.email.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { CachedDocument, TTL } from '../classes.cached.document.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
/**
|
||||
* Email status in the cache
|
||||
*/
|
||||
export type TCachedEmailStatus = 'pending' | 'processing' | 'delivered' | 'failed' | 'deferred';
|
||||
|
||||
/**
|
||||
* Helper to get the smartdata database instance
|
||||
*/
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
/**
|
||||
* CachedEmail - Stores email queue items in the cache
|
||||
*
|
||||
* Used for persistent email queue storage, tracking delivery status,
|
||||
* and maintaining email history for the configured TTL period.
|
||||
*/
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class CachedEmail extends CachedDocument<CachedEmail> {
|
||||
// TTL fields from base class (decorators required on concrete class)
|
||||
@plugins.smartdata.svDb()
|
||||
public createdAt: Date = new Date();
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public expiresAt: Date = new Date(Date.now() + TTL.DAYS_30);
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public lastAccessedAt: Date = new Date();
|
||||
|
||||
/**
|
||||
* Unique identifier for this email
|
||||
*/
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public id!: string;
|
||||
|
||||
/**
|
||||
* Email message ID (RFC 822 Message-ID header)
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public messageId!: string;
|
||||
|
||||
/**
|
||||
* Sender email address (envelope from)
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public from!: string;
|
||||
|
||||
/**
|
||||
* Recipient email addresses
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public to!: string[];
|
||||
|
||||
/**
|
||||
* CC recipients
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public cc!: string[];
|
||||
|
||||
/**
|
||||
* BCC recipients
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public bcc!: string[];
|
||||
|
||||
/**
|
||||
* Email subject
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public subject!: string;
|
||||
|
||||
/**
|
||||
* Raw RFC822 email content
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public rawContent!: string;
|
||||
|
||||
/**
|
||||
* Current status of the email
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public status!: TCachedEmailStatus;
|
||||
|
||||
/**
|
||||
* Number of delivery attempts
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public attempts: number = 0;
|
||||
|
||||
/**
|
||||
* Maximum number of delivery attempts
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public maxAttempts: number = 3;
|
||||
|
||||
/**
|
||||
* Timestamp for next delivery attempt
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public nextAttempt!: Date;
|
||||
|
||||
/**
|
||||
* Last error message if delivery failed
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public lastError!: string;
|
||||
|
||||
/**
|
||||
* Timestamp when the email was successfully delivered
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public deliveredAt!: Date;
|
||||
|
||||
/**
|
||||
* Sender domain (for querying/filtering)
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public senderDomain!: string;
|
||||
|
||||
/**
|
||||
* Priority level (higher = more important)
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public priority: number = 0;
|
||||
|
||||
/**
|
||||
* JSON-serialized route data
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public routeData!: string;
|
||||
|
||||
/**
|
||||
* DKIM signature status
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public dkimSigned: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.setTTL(TTL.DAYS_30); // Default 30-day TTL
|
||||
this.status = 'pending';
|
||||
this.to = [];
|
||||
this.cc = [];
|
||||
this.bcc = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CachedEmail with a unique ID
|
||||
*/
|
||||
public static createNew(): CachedEmail {
|
||||
const email = new CachedEmail();
|
||||
email.id = plugins.uuid.v4();
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an email by ID
|
||||
*/
|
||||
public static async findById(id: string): Promise<CachedEmail | null> {
|
||||
return await CachedEmail.getInstance({
|
||||
id,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all emails with a specific status
|
||||
*/
|
||||
public static async findByStatus(status: TCachedEmailStatus): Promise<CachedEmail[]> {
|
||||
return await CachedEmail.getInstances({
|
||||
status,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all emails pending delivery (status = pending and nextAttempt <= now)
|
||||
*/
|
||||
public static async findPendingForDelivery(): Promise<CachedEmail[]> {
|
||||
const now = new Date();
|
||||
return await CachedEmail.getInstances({
|
||||
status: 'pending',
|
||||
nextAttempt: { $lte: now },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find emails by sender domain
|
||||
*/
|
||||
public static async findBySenderDomain(domain: string): Promise<CachedEmail[]> {
|
||||
return await CachedEmail.getInstances({
|
||||
senderDomain: domain,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark as delivered
|
||||
*/
|
||||
public markDelivered(): void {
|
||||
this.status = 'delivered';
|
||||
this.deliveredAt = new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark as failed with error
|
||||
*/
|
||||
public markFailed(error: string): void {
|
||||
this.status = 'failed';
|
||||
this.lastError = error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment attempt counter and schedule next attempt
|
||||
*/
|
||||
public scheduleRetry(delayMs: number = 5 * 60 * 1000): void {
|
||||
this.attempts++;
|
||||
this.status = 'deferred';
|
||||
this.nextAttempt = new Date(Date.now() + delayMs);
|
||||
|
||||
// If max attempts reached, mark as failed
|
||||
if (this.attempts >= this.maxAttempts) {
|
||||
this.status = 'failed';
|
||||
this.lastError = `Max attempts (${this.maxAttempts}) reached`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract sender domain from email address
|
||||
*/
|
||||
public updateSenderDomain(): void {
|
||||
if (this.from) {
|
||||
const match = this.from.match(/@([^>]+)>?$/);
|
||||
if (match) {
|
||||
this.senderDomain = match[1].toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
247
ts/db/documents/classes.cached.ip.reputation.ts
Normal file
247
ts/db/documents/classes.cached.ip.reputation.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { CachedDocument, TTL } from '../classes.cached.document.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
/**
|
||||
* Helper to get the smartdata database instance
|
||||
*/
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
/**
|
||||
* IP reputation result data
|
||||
*/
|
||||
export interface IIPReputationData {
|
||||
score: number;
|
||||
isSpam: boolean;
|
||||
isProxy: boolean;
|
||||
isTor: boolean;
|
||||
isVPN: boolean;
|
||||
country?: string;
|
||||
asn?: string;
|
||||
org?: string;
|
||||
blacklists?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* CachedIPReputation - Stores IP reputation lookup results
|
||||
*
|
||||
* Caches the results of IP reputation checks to avoid repeated
|
||||
* external API calls. Default TTL is 24 hours.
|
||||
*/
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class CachedIPReputation extends CachedDocument<CachedIPReputation> {
|
||||
// TTL fields from base class (decorators required on concrete class)
|
||||
@plugins.smartdata.svDb()
|
||||
public createdAt: Date = new Date();
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public expiresAt: Date = new Date(Date.now() + TTL.HOURS_24);
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public lastAccessedAt: Date = new Date();
|
||||
|
||||
/**
|
||||
* IP address (unique identifier)
|
||||
*/
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public ipAddress!: string;
|
||||
|
||||
/**
|
||||
* Reputation score (0-100, higher = better)
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public score!: number;
|
||||
|
||||
/**
|
||||
* Whether the IP is flagged as spam source
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public isSpam!: boolean;
|
||||
|
||||
/**
|
||||
* Whether the IP is a known proxy
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public isProxy!: boolean;
|
||||
|
||||
/**
|
||||
* Whether the IP is a Tor exit node
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public isTor!: boolean;
|
||||
|
||||
/**
|
||||
* Whether the IP is a VPN endpoint
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public isVPN!: boolean;
|
||||
|
||||
/**
|
||||
* Country code (ISO 3166-1 alpha-2)
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public country!: string;
|
||||
|
||||
/**
|
||||
* Autonomous System Number
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public asn!: string;
|
||||
|
||||
/**
|
||||
* Organization name
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public org!: string;
|
||||
|
||||
/**
|
||||
* List of blacklists the IP appears on
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public blacklists!: string[];
|
||||
|
||||
/**
|
||||
* Number of times this IP has been checked
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public checkCount: number = 0;
|
||||
|
||||
/**
|
||||
* Number of connections from this IP
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public connectionCount: number = 0;
|
||||
|
||||
/**
|
||||
* Number of emails received from this IP
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public emailCount: number = 0;
|
||||
|
||||
/**
|
||||
* Number of spam emails from this IP
|
||||
*/
|
||||
@plugins.smartdata.svDb()
|
||||
public spamCount: number = 0;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.setTTL(TTL.HOURS_24); // Default 24-hour TTL
|
||||
this.blacklists = [];
|
||||
this.score = 50; // Default neutral score
|
||||
this.isSpam = false;
|
||||
this.isProxy = false;
|
||||
this.isTor = false;
|
||||
this.isVPN = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create from reputation data
|
||||
*/
|
||||
public static fromReputationData(ipAddress: string, data: IIPReputationData): CachedIPReputation {
|
||||
const cached = new CachedIPReputation();
|
||||
cached.ipAddress = ipAddress;
|
||||
cached.score = data.score;
|
||||
cached.isSpam = data.isSpam;
|
||||
cached.isProxy = data.isProxy;
|
||||
cached.isTor = data.isTor;
|
||||
cached.isVPN = data.isVPN;
|
||||
cached.country = data.country || '';
|
||||
cached.asn = data.asn || '';
|
||||
cached.org = data.org || '';
|
||||
cached.blacklists = data.blacklists || [];
|
||||
cached.checkCount = 1;
|
||||
return cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to reputation data object
|
||||
*/
|
||||
public toReputationData(): IIPReputationData {
|
||||
this.touch();
|
||||
return {
|
||||
score: this.score,
|
||||
isSpam: this.isSpam,
|
||||
isProxy: this.isProxy,
|
||||
isTor: this.isTor,
|
||||
isVPN: this.isVPN,
|
||||
country: this.country,
|
||||
asn: this.asn,
|
||||
org: this.org,
|
||||
blacklists: this.blacklists,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Find by IP address
|
||||
*/
|
||||
public static async findByIP(ipAddress: string): Promise<CachedIPReputation | null> {
|
||||
return await CachedIPReputation.getInstance({
|
||||
ipAddress,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all IPs flagged as spam
|
||||
*/
|
||||
public static async findSpamIPs(): Promise<CachedIPReputation[]> {
|
||||
return await CachedIPReputation.getInstances({
|
||||
isSpam: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Find IPs with score below threshold
|
||||
*/
|
||||
public static async findLowScoreIPs(threshold: number): Promise<CachedIPReputation[]> {
|
||||
return await CachedIPReputation.getInstances({
|
||||
score: { $lt: threshold },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a connection from this IP
|
||||
*/
|
||||
public recordConnection(): void {
|
||||
this.connectionCount++;
|
||||
this.touch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Record an email from this IP
|
||||
*/
|
||||
public recordEmail(isSpam: boolean = false): void {
|
||||
this.emailCount++;
|
||||
if (isSpam) {
|
||||
this.spamCount++;
|
||||
}
|
||||
this.touch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the reputation data
|
||||
*/
|
||||
public updateReputation(data: IIPReputationData): void {
|
||||
this.score = data.score;
|
||||
this.isSpam = data.isSpam;
|
||||
this.isProxy = data.isProxy;
|
||||
this.isTor = data.isTor;
|
||||
this.isVPN = data.isVPN;
|
||||
this.country = data.country || this.country;
|
||||
this.asn = data.asn || this.asn;
|
||||
this.org = data.org || this.org;
|
||||
this.blacklists = data.blacklists || this.blacklists;
|
||||
this.checkCount++;
|
||||
this.touch();
|
||||
// Refresh TTL on update
|
||||
this.setTTL(TTL.HOURS_24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this IP should be blocked
|
||||
*/
|
||||
public shouldBlock(): boolean {
|
||||
return this.isSpam || this.score < 20 || this.blacklists.length > 2;
|
||||
}
|
||||
}
|
||||
35
ts/db/documents/classes.cert-backoff.doc.ts
Normal file
35
ts/db/documents/classes.cert-backoff.doc.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class CertBackoffDoc extends plugins.smartdata.SmartDataDbDoc<CertBackoffDoc, CertBackoffDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public domain!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public failures!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public lastFailure!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public retryAfter!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public lastError!: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findByDomain(domain: string): Promise<CertBackoffDoc | null> {
|
||||
return await CertBackoffDoc.getInstance({ domain });
|
||||
}
|
||||
|
||||
public static async findAll(): Promise<CertBackoffDoc[]> {
|
||||
return await CertBackoffDoc.getInstances({});
|
||||
}
|
||||
}
|
||||
38
ts/db/documents/classes.proxy-cert.doc.ts
Normal file
38
ts/db/documents/classes.proxy-cert.doc.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class ProxyCertDoc extends plugins.smartdata.SmartDataDbDoc<ProxyCertDoc, ProxyCertDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public domain!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public publicKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public privateKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public ca!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public validUntil!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public validFrom!: number;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findByDomain(domain: string): Promise<ProxyCertDoc | null> {
|
||||
return await ProxyCertDoc.getInstance({ domain });
|
||||
}
|
||||
|
||||
public static async findAll(): Promise<ProxyCertDoc[]> {
|
||||
return await ProxyCertDoc.getInstances({});
|
||||
}
|
||||
}
|
||||
54
ts/db/documents/classes.remote-ingress-edge.doc.ts
Normal file
54
ts/db/documents/classes.remote-ingress-edge.doc.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class RemoteIngressEdgeDoc extends plugins.smartdata.SmartDataDbDoc<RemoteIngressEdgeDoc, RemoteIngressEdgeDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public id!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public name: string = '';
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public secret!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public listenPorts!: number[];
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public listenPortsUdp!: number[];
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public enabled!: boolean;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public autoDerivePorts!: boolean;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public tags!: string[];
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public createdAt!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public updatedAt!: number;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findById(id: string): Promise<RemoteIngressEdgeDoc | null> {
|
||||
return await RemoteIngressEdgeDoc.getInstance({ id });
|
||||
}
|
||||
|
||||
public static async findAll(): Promise<RemoteIngressEdgeDoc[]> {
|
||||
return await RemoteIngressEdgeDoc.getInstances({});
|
||||
}
|
||||
|
||||
public static async findEnabled(): Promise<RemoteIngressEdgeDoc[]> {
|
||||
return await RemoteIngressEdgeDoc.getInstances({ enabled: true });
|
||||
}
|
||||
}
|
||||
32
ts/db/documents/classes.route-override.doc.ts
Normal file
32
ts/db/documents/classes.route-override.doc.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class RouteOverrideDoc extends plugins.smartdata.SmartDataDbDoc<RouteOverrideDoc, RouteOverrideDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public routeName!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public enabled!: boolean;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public updatedAt!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public updatedBy!: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findByRouteName(routeName: string): Promise<RouteOverrideDoc | null> {
|
||||
return await RouteOverrideDoc.getInstance({ routeName });
|
||||
}
|
||||
|
||||
public static async findAll(): Promise<RouteOverrideDoc[]> {
|
||||
return await RouteOverrideDoc.getInstances({});
|
||||
}
|
||||
}
|
||||
38
ts/db/documents/classes.stored-route.doc.ts
Normal file
38
ts/db/documents/classes.stored-route.doc.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class StoredRouteDoc extends plugins.smartdata.SmartDataDbDoc<StoredRouteDoc, StoredRouteDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public id!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public route!: plugins.smartproxy.IRouteConfig;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public enabled!: boolean;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public createdAt!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public updatedAt!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public createdBy!: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findById(id: string): Promise<StoredRouteDoc | null> {
|
||||
return await StoredRouteDoc.getInstance({ id });
|
||||
}
|
||||
|
||||
public static async findAll(): Promise<StoredRouteDoc[]> {
|
||||
return await StoredRouteDoc.getInstances({});
|
||||
}
|
||||
}
|
||||
32
ts/db/documents/classes.vlan-mappings.doc.ts
Normal file
32
ts/db/documents/classes.vlan-mappings.doc.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
export interface IMacVlanMapping {
|
||||
mac: string;
|
||||
vlan: number;
|
||||
description?: string;
|
||||
enabled: boolean;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
}
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class VlanMappingsDoc extends plugins.smartdata.SmartDataDbDoc<VlanMappingsDoc, VlanMappingsDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public configId: string = 'vlan-mappings';
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public mappings!: IMacVlanMapping[];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.mappings = [];
|
||||
}
|
||||
|
||||
public static async load(): Promise<VlanMappingsDoc | null> {
|
||||
return await VlanMappingsDoc.getInstance({ configId: 'vlan-mappings' });
|
||||
}
|
||||
}
|
||||
57
ts/db/documents/classes.vpn-client.doc.ts
Normal file
57
ts/db/documents/classes.vpn-client.doc.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class VpnClientDoc extends plugins.smartdata.SmartDataDbDoc<VpnClientDoc, VpnClientDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public clientId!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public enabled!: boolean;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public serverDefinedClientTags?: string[];
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public description?: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public assignedIp?: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public noisePublicKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public wgPublicKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public wgPrivateKey?: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public createdAt!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public updatedAt!: number;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public expiresAt?: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async findByClientId(clientId: string): Promise<VpnClientDoc | null> {
|
||||
return await VpnClientDoc.getInstance({ clientId });
|
||||
}
|
||||
|
||||
public static async findAll(): Promise<VpnClientDoc[]> {
|
||||
return await VpnClientDoc.getInstances({});
|
||||
}
|
||||
|
||||
public static async findEnabled(): Promise<VpnClientDoc[]> {
|
||||
return await VpnClientDoc.getInstances({ enabled: true });
|
||||
}
|
||||
}
|
||||
31
ts/db/documents/classes.vpn-server-keys.doc.ts
Normal file
31
ts/db/documents/classes.vpn-server-keys.doc.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { DcRouterDb } from '../classes.dcrouter-db.js';
|
||||
|
||||
const getDb = () => DcRouterDb.getInstance().getDb();
|
||||
|
||||
@plugins.smartdata.Collection(() => getDb())
|
||||
export class VpnServerKeysDoc extends plugins.smartdata.SmartDataDbDoc<VpnServerKeysDoc, VpnServerKeysDoc> {
|
||||
@plugins.smartdata.unI()
|
||||
@plugins.smartdata.svDb()
|
||||
public configId: string = 'vpn-server-keys';
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public noisePrivateKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public noisePublicKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public wgPrivateKey!: string;
|
||||
|
||||
@plugins.smartdata.svDb()
|
||||
public wgPublicKey!: string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static async load(): Promise<VpnServerKeysDoc | null> {
|
||||
return await VpnServerKeysDoc.getInstance({ configId: 'vpn-server-keys' });
|
||||
}
|
||||
}
|
||||
24
ts/db/documents/index.ts
Normal file
24
ts/db/documents/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// Cached/TTL document classes
|
||||
export * from './classes.cached.email.js';
|
||||
export * from './classes.cached.ip.reputation.js';
|
||||
|
||||
// Config document classes
|
||||
export * from './classes.stored-route.doc.js';
|
||||
export * from './classes.route-override.doc.js';
|
||||
export * from './classes.api-token.doc.js';
|
||||
|
||||
// VPN document classes
|
||||
export * from './classes.vpn-server-keys.doc.js';
|
||||
export * from './classes.vpn-client.doc.js';
|
||||
|
||||
// Certificate document classes
|
||||
export * from './classes.acme-cert.doc.js';
|
||||
export * from './classes.proxy-cert.doc.js';
|
||||
export * from './classes.cert-backoff.doc.js';
|
||||
|
||||
// Remote ingress document classes
|
||||
export * from './classes.remote-ingress-edge.doc.js';
|
||||
|
||||
// RADIUS document classes
|
||||
export * from './classes.vlan-mappings.doc.js';
|
||||
export * from './classes.accounting-session.doc.js';
|
||||
Reference in New Issue
Block a user