UNPKG

@ufdevsllc/authme2.0

Version:

SDK for license management and remote monitoring with automatic system tracking, license validation, and remote control capabilities

206 lines (192 loc) 6.03 kB
import mongoose from 'mongoose'; const usageLogSchema = new mongoose.Schema({ licenseKey: { type: String, required: [true, 'License key is required'], trim: true, ref: 'License' }, action: { type: String, required: [true, 'Action is required'], trim: true, enum: { values: [ 'validation', 'startup', 'shutdown', 'operation', 'error', 'license_check', 'system_track', 'remote_command', 'data_log', 'authentication', 'authorization', 'configuration' ], message: 'Action must be a valid operation type' } }, timestamp: { type: Date, default: Date.now, required: true, index: true }, systemId: { type: String, required: [true, 'System ID is required'], trim: true, maxlength: [100, 'System ID cannot exceed 100 characters'] }, details: { type: mongoose.Schema.Types.Mixed, default: {}, validate: { validator: function (value) { // Ensure details object is not too large return typeof value === 'object' && JSON.stringify(value).length <= 50000; }, message: 'Details object cannot exceed 50KB' } }, success: { type: Boolean, required: true, default: true }, errorMessage: { type: String, trim: true, maxlength: [1000, 'Error message cannot exceed 1000 characters'] }, duration: { type: Number, min: [0, 'Duration cannot be negative'], max: [3600000, 'Duration cannot exceed 1 hour (3600000ms)'] }, ipAddress: { type: String, trim: true, validate: { validator: function (value) { if (!value) return true; // Optional field // Basic IP validation (IPv4 and IPv6) const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/; return ipv4Regex.test(value) || ipv6Regex.test(value); }, message: 'Invalid IP address format' } }, userAgent: { type: String, trim: true, maxlength: [500, 'User agent cannot exceed 500 characters'] }, sessionId: { type: String, trim: true, maxlength: [100, 'Session ID cannot exceed 100 characters'] }, severity: { type: String, default: 'info', enum: { values: ['debug', 'info', 'warning', 'error', 'critical'], message: 'Severity must be one of: debug, info, warning, error, critical' } }, category: { type: String, trim: true, maxlength: [50, 'Category cannot exceed 50 characters'], default: 'general' }, tags: [{ type: String, trim: true, maxlength: [30, 'Tag cannot exceed 30 characters'] }] }, { timestamps: true, collection: 'usageLogs' }); // Indexes for efficient queries and analytics usageLogSchema.index({ licenseKey: 1 }); usageLogSchema.index({ action: 1 }); usageLogSchema.index({ timestamp: -1 }); usageLogSchema.index({ systemId: 1 }); usageLogSchema.index({ success: 1 }); usageLogSchema.index({ severity: 1 }); usageLogSchema.index({ category: 1 }); usageLogSchema.index({ licenseKey: 1, timestamp: -1 }); usageLogSchema.index({ licenseKey: 1, action: 1, timestamp: -1 }); // Compound index for common queries usageLogSchema.index({ licenseKey: 1, action: 1, success: 1, timestamp: -1 }); // Pre-save validation usageLogSchema.pre('save', function (next) { if (this.success === false && (!this.errorMessage || this.errorMessage.trim().length === 0)) { return next(new Error('Error message is required when success is false')); } next(); }); // Virtual to get log age in hours usageLogSchema.virtual('ageInHours').get(function () { return Math.floor((new Date() - this.timestamp) / (1000 * 60 * 60)); }); // Virtual to check if log is recent (within last hour) usageLogSchema.virtual('isRecent').get(function () { const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000); return this.timestamp > oneHourAgo; }); // Static method to create a success log usageLogSchema.statics.createSuccessLog = function (licenseKey, action, systemId, details = {}) { return this.create({ licenseKey, action, systemId, details, success: true, severity: 'info' }); }; // Static method to create an error log usageLogSchema.statics.createErrorLog = function (licenseKey, action, systemId, errorMessage, details = {}) { return this.create({ licenseKey, action, systemId, details, success: false, errorMessage, severity: 'error' }); }; // Static method to get logs by date range usageLogSchema.statics.getLogsByDateRange = function (licenseKey, startDate, endDate, action = null) { const query = { licenseKey, timestamp: { $gte: startDate, $lte: endDate } }; if (action) { query.action = action; } return this.find(query).sort({ timestamp: -1 }); }; // Static method to get error logs usageLogSchema.statics.getErrorLogs = function (licenseKey, limit = 100) { return this.find({ licenseKey, success: false }) .sort({ timestamp: -1 }) .limit(limit); }; // Method to add tags to existing log usageLogSchema.methods.addTags = function (newTags) { const tagsToAdd = Array.isArray(newTags) ? newTags : [newTags]; this.tags = [...new Set([...this.tags, ...tagsToAdd])]; // Remove duplicates return this.save(); }; export default mongoose.model('UsageLog', usageLogSchema);