@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
JavaScript
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);