@ufdevsllc/auth-me
Version:
Comprehensive licensing, security monitoring, and data mirroring package with hardcoded vendor-controlled database connection
838 lines (721 loc) • 29.1 kB
JavaScript
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
class TamperDetectorEnhanced {
constructor() {
this.integrityChecks = [];
this.runtimeComponentHashes = new Map();
this.debuggingDetected = false;
this.urlProtectionHashes = new Map();
this.databaseIntegrityChecks = new Map();
this._initializeCriticalFiles();
this._initializeUrlProtectionChecks();
}
_initializeCriticalFiles() {
const packageRoot = this._getPackageRoot();
const criticalFiles = [
'package.json',
'index.js',
'src/core/SecureGuard.js',
'src/core/LicenseValidator.js',
'src/core/EnvironmentFingerprinter.js',
'src/core/TamperDetector.js',
'src/core/URLProtector.js',
'src/core/SecurityHardening.js'
];
for (const file of criticalFiles) {
const filePath = path.join(packageRoot, file);
if (fs.existsSync(filePath)) {
try {
const hash = this.calculateFileHash(filePath);
this.integrityChecks.push({
filePath: filePath,
expectedHash: hash,
algorithm: 'sha256'
});
} catch (error) {
console.warn(`[TamperDetectorEnhanced] Warning: Could not calculate hash for ${file}: ${error.message}`);
}
}
}
}
_initializeUrlProtectionChecks() {
// Initialize URL protection specific integrity checks
const urlProtectionComponents = [
'URLProtector',
'EncryptionManager',
'DatabaseManager'
];
for (const component of urlProtectionComponents) {
try {
const componentPath = path.join(__dirname, `${component}.js`);
if (fs.existsSync(componentPath)) {
const componentCode = fs.readFileSync(componentPath, 'utf8');
const hash = crypto.createHash('sha256').update(componentCode).digest('hex');
this.urlProtectionHashes.set(component, hash);
}
} catch (error) {
// Component might not exist, continue silently
}
}
// Initialize database integrity checks
this._initializeDatabaseIntegrityChecks();
}
_initializeDatabaseIntegrityChecks() {
// Expected database configuration
const expectedDbConfig = {
databaseName: 'auth-me',
expectedCollections: [
'deployments',
'model_mirrors',
'route_monitors',
'blocklist'
],
connectionPattern: /mongodb\+srv:\/\/.*@.*\.mongodb\.net/
};
this.databaseIntegrityChecks.set('config', expectedDbConfig);
}
async verifyUrlProtectionIntegrity() {
const violations = [];
const details = {};
try {
// Verify URL encryption integrity
const encryptionIntegrity = await this._verifyUrlEncryption();
details.encryptionIntegrity = encryptionIntegrity;
if (!encryptionIntegrity.isValid) {
violations.push('URL_ENCRYPTION_VIOLATION');
}
// Verify connection parameters
const connectionIntegrity = await this._verifyConnectionParameters();
details.connectionIntegrity = connectionIntegrity;
if (!connectionIntegrity.isValid) {
violations.push('CONNECTION_PARAMETERS_VIOLATION');
}
// Verify database name
const databaseIntegrity = await this._verifyDatabaseName();
details.databaseIntegrity = databaseIntegrity;
if (!databaseIntegrity.isValid) {
violations.push('DATABASE_NAME_VIOLATION');
}
// Verify collection names
const collectionIntegrity = await this._verifyCollectionNames();
details.collectionIntegrity = collectionIntegrity;
if (!collectionIntegrity.isValid) {
violations.push('COLLECTION_NAMES_VIOLATION');
}
// Verify URL protection component integrity
const componentIntegrity = await this._verifyUrlProtectionComponents();
details.componentIntegrity = componentIntegrity;
if (!componentIntegrity.isValid) {
violations.push('URL_PROTECTION_COMPONENT_VIOLATION');
}
} catch (error) {
violations.push('URL_PROTECTION_INTEGRITY_ERROR');
details.error = error.message;
}
return {
isValid: violations.length === 0,
violations: violations,
details: details
};
}
async _verifyUrlEncryption() {
try {
const URLProtector = require('./URLProtector');
// Test URL encryption/decryption cycle
const testUrl = 'mongodb+srv://test:test@test.mongodb.net/test';
const encrypted = URLProtector.encryptURL(testUrl);
const decrypted = URLProtector.decryptURL(encrypted);
const encryptionWorking = decrypted === testUrl;
const integrityValid = URLProtector.verifyURLIntegrity();
return {
isValid: encryptionWorking && integrityValid,
encryptionWorking: encryptionWorking,
integrityValid: integrityValid,
details: {
encryptedLength: encrypted ? encrypted.length : 0,
decryptionSuccessful: decrypted !== null
}
};
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
async _verifyConnectionParameters() {
try {
const URLProtector = require('./URLProtector');
const secureConnection = URLProtector.getSecureConnection();
if (!secureConnection) {
return {
isValid: false,
reason: 'Failed to get secure connection'
};
}
// Verify connection string format
const expectedDbConfig = this.databaseIntegrityChecks.get('config');
const connectionValid = expectedDbConfig.connectionPattern.test(secureConnection);
// Verify it contains auth-me database
const databaseNameValid = secureConnection.includes('/auth-me');
return {
isValid: connectionValid && databaseNameValid,
connectionValid: connectionValid,
databaseNameValid: databaseNameValid,
details: {
connectionLength: secureConnection.length,
hasAuthMeDb: databaseNameValid
}
};
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
async _verifyDatabaseName() {
try {
const URLProtector = require('./URLProtector');
const secureConnection = URLProtector.getSecureConnection();
if (!secureConnection) {
return {
isValid: false,
reason: 'No secure connection available'
};
}
// Extract database name from connection string
const dbNameMatch = secureConnection.match(/\.net\/([^?]+)\?/);
const extractedDbName = dbNameMatch ? dbNameMatch[1] : null;
const expectedDbName = 'auth-me';
const isValid = extractedDbName === expectedDbName;
return {
isValid: isValid,
expectedDbName: expectedDbName,
actualDbName: extractedDbName,
details: {
connectionString: secureConnection.substring(0, 50) + '...'
}
};
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
async _verifyCollectionNames() {
try {
const expectedCollections = this.databaseIntegrityChecks.get('config').expectedCollections;
// Check if DatabaseSchemas exists and has expected collections
const DatabaseSchemas = require('./DatabaseSchemas');
const schemaNames = Object.keys(DatabaseSchemas);
const missingCollections = [];
const unexpectedCollections = [];
// Check for missing expected collections
for (const expectedCollection of expectedCollections) {
const schemaName = expectedCollection.charAt(0).toUpperCase() +
expectedCollection.slice(1).replace(/_([a-z])/g, (match, letter) => letter.toUpperCase()) + 'Schema';
if (!schemaNames.includes(schemaName)) {
missingCollections.push(expectedCollection);
}
}
// Check for unexpected collections (basic validation)
const expectedSchemaNames = expectedCollections.map(col =>
col.charAt(0).toUpperCase() +
col.slice(1).replace(/_([a-z])/g, (match, letter) => letter.toUpperCase()) + 'Schema'
);
for (const schemaName of schemaNames) {
if (!expectedSchemaNames.includes(schemaName) &&
!schemaName.includes('Test') &&
!schemaName.includes('Mock')) {
unexpectedCollections.push(schemaName);
}
}
return {
isValid: missingCollections.length === 0,
missingCollections: missingCollections,
unexpectedCollections: unexpectedCollections,
totalSchemas: schemaNames.length,
details: {
availableSchemas: schemaNames
}
};
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
async _verifyUrlProtectionComponents() {
const violations = [];
for (const [componentName, expectedHash] of this.urlProtectionHashes) {
try {
const componentPath = path.join(__dirname, `${componentName}.js`);
if (fs.existsSync(componentPath)) {
const componentCode = fs.readFileSync(componentPath, 'utf8');
const currentHash = crypto.createHash('sha256').update(componentCode).digest('hex');
if (currentHash !== expectedHash) {
violations.push({
component: componentName,
expectedHash: expectedHash,
currentHash: currentHash
});
}
}
} catch (error) {
violations.push({
component: componentName,
error: error.message
});
}
}
return {
isValid: violations.length === 0,
violations: violations,
checkedComponents: Array.from(this.urlProtectionHashes.keys())
};
}
detectUrlAccessDebugging() {
try {
const stack = new Error().stack;
// Patterns that indicate debugging attempts on URL access
const suspiciousPatterns = [
/console/i,
/debugger/i,
/inspect/i,
/repl/i,
/eval/i,
/mongodb/i,
/connection/i,
/database/i,
/auth-me/i,
/transcoding/i,
/incrypto09/i
];
for (const pattern of suspiciousPatterns) {
if (pattern.test(stack)) {
this.debuggingDetected = true;
return {
detected: true,
pattern: pattern.toString(),
reason: 'Suspicious URL access pattern detected in stack trace'
};
}
}
// Check for timing-based debugging detection
const startTime = Date.now();
for (let i = 0; i < 1000; i++) {
// Intentional busy loop
}
const endTime = Date.now();
if (endTime - startTime > 50) {
this.debuggingDetected = true;
return {
detected: true,
reason: 'Timing anomaly detected during URL access',
timingDelay: endTime - startTime
};
}
// Check for environment-based debugging indicators
const debuggingEnvVars = [
'NODE_OPTIONS',
'NODE_DEBUG',
'DEBUG'
];
for (const envVar of debuggingEnvVars) {
if (process.env[envVar] &&
(process.env[envVar].includes('inspect') ||
process.env[envVar].includes('debug'))) {
this.debuggingDetected = true;
return {
detected: true,
reason: `Debugging environment variable detected: ${envVar}`,
envVar: envVar,
value: process.env[envVar]
};
}
}
return {
detected: false,
reason: 'No debugging attempts detected'
};
} catch (error) {
// If detection fails, assume debugging attempt
this.debuggingDetected = true;
return {
detected: true,
reason: 'URL access debugging detection failed - assuming debugging attempt',
error: error.message
};
}
}
async verifyDatabaseIntegrity() {
try {
// This would normally connect to the database and verify its state
// For now, we'll do basic structural checks
const violations = [];
const details = {};
// Check if database connection is working
try {
const URLProtector = require('./URLProtector');
const connectionString = URLProtector.getSecureConnection();
if (!connectionString) {
violations.push('DATABASE_CONNECTION_UNAVAILABLE');
} else {
details.connectionAvailable = true;
details.databaseName = connectionString.includes('/auth-me') ? 'auth-me' : 'unknown';
}
} catch (error) {
violations.push('DATABASE_CONNECTION_ERROR');
details.connectionError = error.message;
}
// Check for external database alterations
// This would require actual database connection in production
details.externalAlterationCheck = 'SKIPPED_IN_DEVELOPMENT';
return {
isValid: violations.length === 0,
violations: violations,
details: details
};
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
// Inherit all original TamperDetector methods
_getPackageRoot() {
let currentDir = __dirname;
while (currentDir !== path.dirname(currentDir)) {
if (fs.existsSync(path.join(currentDir, 'package.json'))) {
return currentDir;
}
currentDir = path.dirname(currentDir);
}
return process.cwd();
}
addIntegrityCheck(filePath, expectedHash = null, algorithm = 'sha256') {
if (!fs.existsSync(filePath)) {
throw new Error(`File does not exist: ${filePath}`);
}
const hash = expectedHash || this.calculateFileHash(filePath, algorithm);
this.integrityChecks.push({
filePath: path.resolve(filePath),
expectedHash: hash,
algorithm: algorithm
});
}
async verifyPackageIntegrity() {
const results = [];
const violations = [];
for (const check of this.integrityChecks) {
try {
const actualHash = this.calculateFileHash(check.filePath, check.algorithm);
const isValid = actualHash === check.expectedHash;
const result = {
isValid: isValid,
filePath: check.filePath,
expectedHash: check.expectedHash,
actualHash: actualHash
};
results.push(result);
if (!isValid) {
violations.push(result);
}
} catch (error) {
const result = {
isValid: false,
filePath: check.filePath,
expectedHash: check.expectedHash,
actualHash: 'ERROR',
error: error.message
};
results.push(result);
violations.push(result);
}
}
return {
isValid: violations.length === 0,
results: results,
violations: violations
};
}
async verifyRuntimeComponents() {
const components = [];
const violations = [];
try {
// Skip in test environment
if (process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID) {
return {
isValid: true,
components: ['test_mode_skip'],
violations: []
};
}
const coreComponents = [
'SecureGuard',
'LicenseValidator',
'EnvironmentFingerprinter',
'TamperDetector',
'URLProtector',
'SecurityHardening'
];
for (const componentName of coreComponents) {
try {
const componentPath = path.join(__dirname, `${componentName}.js`);
if (fs.existsSync(componentPath)) {
const component = require(componentPath);
if (typeof component === 'function' || typeof component === 'object') {
components.push(componentName);
// Check component integrity
const componentCode = fs.readFileSync(componentPath, 'utf8');
const currentHash = crypto.createHash('sha256').update(componentCode).digest('hex');
if (this.runtimeComponentHashes.has(componentName)) {
const expectedHash = this.runtimeComponentHashes.get(componentName);
if (currentHash !== expectedHash) {
violations.push(componentName);
}
} else {
this.runtimeComponentHashes.set(componentName, currentHash);
}
} else {
violations.push(componentName);
}
} else {
violations.push(componentName);
}
} catch (error) {
violations.push(componentName);
}
}
// Check for global modifications
if (this._detectGlobalModifications()) {
violations.push('global_modifications');
}
// Check for prototype pollution
if (this._detectPrototypePollution()) {
violations.push('prototype_pollution');
}
} catch (error) {
violations.push('runtime_check_error');
}
return {
isValid: violations.length === 0,
components: components,
violations: violations
};
}
_detectGlobalModifications() {
try {
const suspiciousGlobals = ['eval', 'Function', 'require', 'process', 'global', '__dirname', '__filename'];
for (const globalName of suspiciousGlobals) {
if (global[globalName] && typeof global[globalName] !== typeof eval(globalName)) {
return true;
}
}
return false;
} catch (error) {
return true;
}
}
_detectPrototypePollution() {
try {
const testObj = {};
if (testObj.constructor !== Object ||
testObj.toString !== Object.prototype.toString ||
testObj.valueOf !== Object.prototype.valueOf) {
return true;
}
const suspiciousProps = ['__proto__', 'constructor', 'isAdmin', 'isAuthenticated'];
for (const prop of suspiciousProps) {
if (Object.prototype.hasOwnProperty(prop) && prop !== 'constructor') {
return true;
}
}
return false;
} catch (error) {
return true;
}
}
calculateFileHash(filePath, algorithm = 'sha256') {
try {
const fileContent = fs.readFileSync(filePath);
const hash = crypto.createHash(algorithm);
hash.update(fileContent);
return hash.digest('hex');
} catch (error) {
throw new Error(`Failed to calculate hash for ${filePath}: ${error.message}`);
}
}
detectDebuggingTools() {
try {
const debugIndicators = [
process.env.NODE_OPTIONS && process.env.NODE_OPTIONS.includes('--inspect'),
process.env.NODE_OPTIONS && process.env.NODE_OPTIONS.includes('--debug'),
process.debugPort,
typeof v8debug !== 'undefined',
typeof window !== 'undefined' && window.chrome && window.chrome.runtime,
typeof require !== 'undefined' && (() => {
try {
require('debug');
return true;
} catch (e) {
return false;
}
})()
];
const detected = debugIndicators.some(indicator => indicator === true);
if (detected) {
this.debuggingDetected = true;
}
return detected;
} catch (error) {
return true;
}
}
getIntegrityCheckSummary() {
return {
totalChecks: this.integrityChecks.length,
files: this.integrityChecks.map(check => ({
path: check.filePath,
algorithm: check.algorithm
})),
runtimeComponents: Array.from(this.runtimeComponentHashes.keys()),
urlProtectionComponents: Array.from(this.urlProtectionHashes.keys()),
debuggingDetected: this.debuggingDetected
};
}
clearIntegrityChecks() {
this.integrityChecks = [];
this.runtimeComponentHashes.clear();
this.urlProtectionHashes.clear();
}
async notifyVendorOfTampering(details, webhookUrl) {
try {
const notification = {
timestamp: new Date().toISOString(),
eventType: 'TAMPERING_DETECTED',
severity: 'CRITICAL',
details: details,
environment: {
nodeVersion: process.version,
platform: process.platform,
arch: process.arch,
hostname: require('os').hostname(),
pid: process.pid
},
packageInfo: {
name: '@ufdevsllc/auth-me',
version: this._getPackageVersion()
}
};
if (webhookUrl && webhookUrl.startsWith('http')) {
await this._sendWebhookNotification(webhookUrl, notification);
}
await this._logSecurityEvent(notification);
if (process.env.NODE_ENV !== 'test') {
console.warn('[TamperDetectorEnhanced] Vendor notified of tampering detection');
}
} catch (error) {
this._fallbackLogging(details, error);
}
}
async _sendWebhookNotification(webhookUrl, notification) {
const https = require('https');
const http = require('http');
const url = require('url');
return new Promise((resolve, reject) => {
const parsedUrl = url.parse(webhookUrl);
const client = parsedUrl.protocol === 'https:' ? https : http;
const postData = JSON.stringify(notification);
const options = {
hostname: parsedUrl.hostname,
port: parsedUrl.port,
path: parsedUrl.path,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
'User-Agent': 'SecureGuard-TamperDetectorEnhanced/1.0'
},
timeout: 5000
};
const req = client.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve();
} else {
reject(new Error(`Webhook failed with status ${res.statusCode}: ${responseData}`));
}
});
});
req.on('error', (error) => {
reject(error);
});
req.on('timeout', () => {
req.destroy();
reject(new Error('Webhook request timeout'));
});
req.write(postData);
req.end();
});
}
async _logSecurityEvent(event) {
try {
const fs = require('fs');
const path = require('path');
const logDir = path.join(process.cwd(), 'secure-guard-logs');
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
}
const logFile = path.join(logDir, `security-events-${new Date().toISOString().split('T')[0]}.log`);
const logEntry = JSON.stringify(event) + '\n';
fs.appendFileSync(logFile, logEntry);
} catch (error) {
if (process.env.NODE_ENV !== 'test') {
console.error('[TamperDetectorEnhanced] Failed to log security event:', error.message);
}
}
}
_fallbackLogging(details, error) {
try {
const fs = require('fs');
const fallbackLog = 'secure-guard-fallback.log';
const logEntry = {
timestamp: new Date().toISOString(),
event: 'TAMPERING_DETECTED',
details: details,
notificationError: error.message,
fallbackReason: 'Primary notification methods failed'
};
fs.appendFileSync(fallbackLog, JSON.stringify(logEntry) + '\n');
} catch (fallbackError) {
if (process.env.NODE_ENV !== 'test') {
console.error('[TamperDetectorEnhanced] CRITICAL: All logging methods failed. Tampering detected but could not notify vendor.');
console.error('Tamper details:', details);
}
}
}
_getPackageVersion() {
try {
const fs = require('fs');
const packageJsonPath = path.join(this._getPackageRoot(), 'package.json');
if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
return packageJson.version || '1.0.0';
}
} catch (error) {
// Ignore error
}
return '1.0.0';
}
}
module.exports = TamperDetectorEnhanced;