@ahmedhegazee/nestjs-telescope
Version:
Advanced observability and monitoring solution for NestJS applications with ML-powered analytics, enterprise features, and production-ready scaling
210 lines • 7.5 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var DataMaskingService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataMaskingService = void 0;
const common_1 = require("@nestjs/common");
let DataMaskingService = DataMaskingService_1 = class DataMaskingService {
constructor() {
this.logger = new common_1.Logger(DataMaskingService_1.name);
this.defaultPatterns = [
/\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
/\b\d{3}-\d{2}-\d{4}\b/g,
/\b\d{9}\b/g,
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
/Bearer\s+[A-Za-z0-9\-\._~\+\/]+=*/g,
/\b\d{3}-?\d{3}-?\d{4}\b/g,
/\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
/https?:\/\/[^\s]*(?:token|key|secret|password)=[^\s&]*/g,
/['\"]?(?:api[_-]?key|access[_-]?token|secret[_-]?key)['\"]?\s*[:=]\s*['\"]?[A-Za-z0-9\-_]{8,}['\"]?/gi,
/\b\d{8,17}\b/g,
/\b[A-Z]{1,2}\d{6,9}\b/g
];
this.sensitiveKeyPatterns = [
/password/i,
/passwd/i,
/secret/i,
/token/i,
/key/i,
/auth/i,
/credential/i,
/pin/i,
/ssn/i,
/social/i,
/card/i,
/account/i,
/bank/i
];
}
maskSensitiveData(data, config = {}) {
const finalConfig = {
enabled: true,
preserveLength: true,
maskingChar: '*',
customPatterns: [],
sensitiveKeys: [],
...config
};
if (!finalConfig.enabled) {
return data;
}
try {
return this.maskData(data, finalConfig);
}
catch (error) {
this.logger.error('Error masking sensitive data:', error);
return data;
}
}
detectSensitiveData(data, config = {}) {
const finalConfig = {
enabled: true,
preserveLength: true,
maskingChar: '*',
customPatterns: [],
sensitiveKeys: [],
...config
};
if (!finalConfig.enabled || !data) {
return false;
}
try {
const dataStr = this.convertToString(data);
const allPatterns = [...this.defaultPatterns, ...finalConfig.customPatterns];
for (const pattern of allPatterns) {
if (pattern.test(dataStr)) {
return true;
}
}
if (typeof data === 'object' && data !== null) {
return this.hasSensitiveKeys(data, finalConfig);
}
return false;
}
catch (error) {
this.logger.error('Error detecting sensitive data:', error);
return false;
}
}
maskData(data, config) {
if (data === null || data === undefined) {
return data;
}
if (typeof data === 'string') {
return this.maskString(data, config);
}
if (typeof data === 'number' || typeof data === 'boolean') {
return data;
}
if (Array.isArray(data)) {
return data.map(item => this.maskData(item, config));
}
if (typeof data === 'object') {
return this.maskObject(data, config);
}
return data;
}
maskString(str, config) {
let maskedStr = str;
const allPatterns = [...this.defaultPatterns, ...config.customPatterns];
for (const pattern of allPatterns) {
maskedStr = maskedStr.replace(pattern, (match) => {
return config.preserveLength
? config.maskingChar.repeat(match.length)
: '***MASKED***';
});
}
return maskedStr;
}
maskObject(obj, config) {
const maskedObj = {};
for (const [key, value] of Object.entries(obj)) {
const lowerKey = key.toLowerCase();
const isSensitiveKey = this.sensitiveKeyPatterns.some(pattern => pattern.test(lowerKey)) ||
config.sensitiveKeys.some(sensitiveKey => lowerKey.includes(sensitiveKey.toLowerCase()));
if (isSensitiveKey) {
maskedObj[key] = this.maskSensitiveValue(value, config);
}
else {
maskedObj[key] = this.maskData(value, config);
}
}
return maskedObj;
}
maskSensitiveValue(value, config) {
if (typeof value === 'string') {
return config.preserveLength
? config.maskingChar.repeat(value.length)
: '***MASKED***';
}
if (typeof value === 'number') {
return config.preserveLength
? config.maskingChar.repeat(value.toString().length)
: '***MASKED***';
}
return '***MASKED***';
}
hasSensitiveKeys(obj, config) {
for (const key of Object.keys(obj)) {
const lowerKey = key.toLowerCase();
if (this.sensitiveKeyPatterns.some(pattern => pattern.test(lowerKey))) {
return true;
}
if (config.sensitiveKeys.some(sensitiveKey => lowerKey.includes(sensitiveKey.toLowerCase()))) {
return true;
}
if (typeof obj[key] === 'object' && obj[key] !== null) {
if (this.hasSensitiveKeys(obj[key], config)) {
return true;
}
}
}
return false;
}
convertToString(data) {
try {
if (typeof data === 'string') {
return data;
}
return JSON.stringify(data);
}
catch (error) {
return String(data);
}
}
createSafeSummary(data, config = {}) {
const finalConfig = {
enabled: true,
preserveLength: false,
maskingChar: '*',
customPatterns: [],
sensitiveKeys: [],
...config
};
try {
const maskedData = this.maskSensitiveData(data, finalConfig);
const summary = JSON.stringify(maskedData);
if (summary.length > 500) {
return summary.substring(0, 497) + '...';
}
return summary;
}
catch (error) {
return '[Data masking failed]';
}
}
};
exports.DataMaskingService = DataMaskingService;
exports.DataMaskingService = DataMaskingService = DataMaskingService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [])
], DataMaskingService);
//# sourceMappingURL=data-masking.service.js.map