xypriss-security
Version:
XyPriss Security is an advanced JavaScript security library designed for enterprise applications. It provides military-grade encryption, secure data structures, quantum-resistant cryptography, and comprehensive security utilities for modern web applicatio
393 lines (389 loc) • 12 kB
JavaScript
'use strict';
var hashCore = require('../core/hash/hash-core.js');
require('../core/hash/hash-types.js');
require('crypto');
var encoding = require('../utils/encoding.js');
require('../core/hash/hash-security.js');
require('../core/hash/hash-advanced.js');
require('../algorithms/hash-algorithms.js');
var randomCore = require('../core/random/random-core.js');
require('../core/random/random-types.js');
require('../core/random/random-sources.js');
require('nehonix-uri-processor');
require('../utils/memory/index.js');
require('../types.js');
require('../core/random/random-security.js');
/* ---------------------------------------------------------------------------------------------
* Copyright (c) NEHONIX INC. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
* -------------------------------------------------------------------------------------------
*/
/**
* @author NEHONIX INC.
* @version 1.0.0
* @license MIT
* @description Tamper-Evident Logging Module
*
* This module provides secure logging functionality with tamper detection.
* It creates a cryptographically linked chain of log entries that can detect
* if any entries have been modified, deleted, or inserted.
*
* This is useful for security-critical applications where log integrity
* is important, such as audit logs, security events, or financial transactions.
*/
/**
* Log level
*/
exports.LogLevel = void 0;
(function (LogLevel) {
LogLevel["DEBUG"] = "DEBUG";
LogLevel["INFO"] = "INFO";
LogLevel["WARNING"] = "WARNING";
LogLevel["ERROR"] = "ERROR";
LogLevel["CRITICAL"] = "CRITICAL";
})(exports.LogLevel || (exports.LogLevel = {}));
/**
* Tamper-evident logger
*/
class TamperEvidentLogger {
/**
* Creates a new tamper-evident logger
*
* @param key - Secret key for hashing
* @param storageKey - Key for storing logs in localStorage (if available)
*/
constructor(key, storageKey) {
this.entries = [];
this.lastHash = "";
this.sequence = 0;
this.key = key || encoding.bufferToHex(randomCore.SecureRandom.getRandomBytes(32));
this.storageKey = storageKey;
// Initialize with a genesis entry if storage is empty
if (this.entries.length === 0) {
this.addGenesisEntry();
}
// Load from storage if available
this.loadFromStorage();
}
/**
* Adds a genesis entry to the log
*/
addGenesisEntry() {
const timestamp = Date.now();
const id = this.generateId();
const genesisEntry = {
id,
timestamp,
level: exports.LogLevel.INFO,
message: "Genesis entry",
previousHash: "0000000000000000000000000000000000000000000000000000000000000000",
hash: "",
sequence: 0,
};
// Calculate the hash
genesisEntry.hash = this.calculateHash(genesisEntry);
// Add to entries
this.entries.push(genesisEntry);
this.lastHash = genesisEntry.hash;
this.sequence = 1;
// Save to storage
this.saveToStorage();
}
/**
* Generates a unique ID for a log entry
*
* @returns Unique ID
*/
generateId() {
return encoding.bufferToHex(randomCore.SecureRandom.getRandomBytes(16));
}
/**
* Calculates the hash of a log entry
*
* @param entry - Log entry to hash
* @returns Hash of the log entry
*/
calculateHash(entry) {
// Create a string representation of the entry without the hash
const entryString = JSON.stringify({
id: entry.id,
timestamp: entry.timestamp,
level: entry.level,
message: entry.message,
data: entry.data,
previousHash: entry.previousHash,
sequence: entry.sequence,
});
// Calculate the hash
return hashCore.Hash.create(entryString, {
salt: this.key,
algorithm: "sha256",
iterations: 1,
outputFormat: "hex",
});
}
/**
* Loads logs from storage
*/
loadFromStorage() {
if (!this.storageKey || typeof localStorage === "undefined") {
return;
}
try {
const storedData = localStorage.getItem(this.storageKey);
if (storedData) {
const parsed = JSON.parse(storedData);
if (Array.isArray(parsed)) {
this.entries = parsed;
if (this.entries.length > 0) {
const lastEntry = this.entries[this.entries.length - 1];
this.lastHash = lastEntry.hash;
this.sequence = lastEntry.sequence + 1;
}
else {
this.addGenesisEntry();
}
}
}
}
catch (e) {
console.error("Failed to load logs from storage:", e);
this.addGenesisEntry();
}
}
/**
* Saves logs to storage
*/
saveToStorage() {
if (!this.storageKey || typeof localStorage === "undefined") {
return;
}
try {
localStorage.setItem(this.storageKey, JSON.stringify(this.entries));
}
catch (e) {
console.error("Failed to save logs to storage:", e);
}
}
/**
* Adds a log entry
*
* @param level - Log level
* @param message - Log message
* @param data - Additional data
* @returns The created log entry
*/
log(level, message, data) {
const timestamp = Date.now();
const id = this.generateId();
const entry = {
id,
timestamp,
level,
message,
data,
previousHash: this.lastHash,
hash: "",
sequence: this.sequence,
};
// Calculate the hash
entry.hash = this.calculateHash(entry);
// Add to entries
this.entries.push(entry);
this.lastHash = entry.hash;
this.sequence++;
// Save to storage
this.saveToStorage();
return entry;
}
/**
* Logs a debug message
*
* @param message - Log message
* @param data - Additional data
* @returns The created log entry
*/
debug(message, data) {
return this.log(exports.LogLevel.DEBUG, message, data);
}
/**
* Logs an info message
*
* @param message - Log message
* @param data - Additional data
* @returns The created log entry
*/
info(message, data) {
return this.log(exports.LogLevel.INFO, message, data);
}
/**
* Logs a warning message
*
* @param message - Log message
* @param data - Additional data
* @returns The created log entry
*/
warning(message, data) {
return this.log(exports.LogLevel.WARNING, message, data);
}
/**
* Logs an error message
*
* @param message - Log message
* @param data - Additional data
* @returns The created log entry
*/
error(message, data) {
return this.log(exports.LogLevel.ERROR, message, data);
}
/**
* Logs a critical message
*
* @param message - Log message
* @param data - Additional data
* @returns The created log entry
*/
critical(message, data) {
return this.log(exports.LogLevel.CRITICAL, message, data);
}
/**
* Gets all log entries
*
* @returns All log entries
*/
getEntries() {
return [...this.entries];
}
/**
* Gets log entries by level
*
* @param level - Log level
* @returns Log entries with the specified level
*/
getEntriesByLevel(level) {
return this.entries.filter((entry) => entry.level === level);
}
/**
* Gets log entries by time range
*
* @param startTime - Start time
* @param endTime - End time
* @returns Log entries within the specified time range
*/
getEntriesByTimeRange(startTime, endTime) {
return this.entries.filter((entry) => entry.timestamp >= startTime && entry.timestamp <= endTime);
}
/**
* Verifies the integrity of the log chain
*
* @returns Verification result
*/
verify() {
const result = {
valid: true,
invalidEntries: [],
missingEntries: [],
tamperedEntries: [],
};
if (this.entries.length === 0) {
return result;
}
// Check the genesis entry
const genesisEntry = this.entries[0];
if (genesisEntry.previousHash !==
"0000000000000000000000000000000000000000000000000000000000000000") {
result.valid = false;
result.tamperedEntries.push(0);
}
// Verify each entry
for (let i = 0; i < this.entries.length; i++) {
const entry = this.entries[i];
// Verify the hash
const calculatedHash = this.calculateHash(entry);
if (calculatedHash !== entry.hash) {
result.valid = false;
result.tamperedEntries.push(i);
}
// Verify the previous hash (except for genesis)
if (i > 0) {
const previousEntry = this.entries[i - 1];
if (entry.previousHash !== previousEntry.hash) {
result.valid = false;
result.tamperedEntries.push(i);
}
}
// Verify the sequence
if (entry.sequence !== i) {
result.valid = false;
result.invalidEntries.push(i);
}
}
// Check for missing entries
for (let i = 1; i < this.entries.length; i++) {
const entry = this.entries[i];
const previousEntry = this.entries[i - 1];
if (entry.sequence - previousEntry.sequence > 1) {
result.valid = false;
for (let j = previousEntry.sequence + 1; j < entry.sequence; j++) {
result.missingEntries.push(j);
}
}
}
return result;
}
/**
* Exports the logs to a string
*
* @returns Exported logs
*/
export() {
return JSON.stringify(this.entries);
}
/**
* Imports logs from a string
*
* @param data - Exported logs
* @param verify - Whether to verify the logs after importing
* @returns Verification result if verify is true
*/
import(data, verify = true) {
try {
const parsed = JSON.parse(data);
if (!Array.isArray(parsed)) {
throw new Error("Invalid log data");
}
this.entries = parsed;
if (this.entries.length > 0) {
const lastEntry = this.entries[this.entries.length - 1];
this.lastHash = lastEntry.hash;
this.sequence = lastEntry.sequence + 1;
}
else {
this.addGenesisEntry();
}
// Save to storage
this.saveToStorage();
// Verify if requested
if (verify) {
return this.verify();
}
}
catch (e) {
console.error("Failed to import logs:", e);
this.addGenesisEntry();
}
return undefined;
}
/**
* Clears all logs
*/
clear() {
this.entries = [];
this.lastHash = "";
this.sequence = 0;
// Add genesis entry
this.addGenesisEntry();
}
}
exports.TamperEvidentLogger = TamperEvidentLogger;
//# sourceMappingURL=tamper-evident-logging.js.map