cipher-shield 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Adaptive DEFCON Threat Escalation System v2.1
3
+ *
4
+ * Intelligent threat level management system that automatically escalates security
5
+ * measures based on detected malicious activity. Implements a cooldown-based
6
+ * system to prevent persistent high-security states while maintaining protection.
7
+ *
8
+ * DEFCON States:
9
+ * - GREEN: Normal operation, all security features active but not aggressive
10
+ * - RED: High alert, conservative security measures (may skip resource-intensive checks)
11
+ *
12
+ * Features:
13
+ * - Automatic escalation based on threat patterns
14
+ * - Configurable thresholds and cooldown periods
15
+ * - Thread-safe operations for concurrent requests
16
+ * - Performance monitoring and logging
17
+ *
18
+ * @module defconSystem
19
+ * @version 1.0.0
20
+ * @author Omindu Dissanayaka
21
+ * @license MIT
22
+ */
23
+
24
+ /**
25
+ * DEFCON security states enumeration
26
+ * @readonly
27
+ * @enum {string}
28
+ */
29
+ const DEFCON_STATES = Object.freeze({
30
+ GREEN: 'GREEN',
31
+ RED: 'RED'
32
+ });
33
+
34
+ /**
35
+ * Default configuration constants
36
+ * These can be overridden for custom deployments
37
+ */
38
+ const DEFAULT_CONFIG = Object.freeze({
39
+ ESCALATION_TIMEOUT: 300000,
40
+ ESCALATION_THRESHOLD: 3,
41
+ MAX_ESCALATION_COUNT: 100
42
+ });
43
+
44
+ /**
45
+ * Internal state management
46
+ * @private
47
+ */
48
+ let currentState = DEFCON_STATES.GREEN;
49
+ let escalationCount = 0;
50
+ let cooldownTimer = null;
51
+ let lastEscalationTime = null;
52
+ let threatHistory = [];
53
+
54
+ /**
55
+ * Initializes the DEFCON system to default state
56
+ *
57
+ * Resets all internal counters, clears any active timers, and prepares
58
+ * the system for fresh threat monitoring. Should be called during
59
+ * application startup or when manually resetting security state.
60
+ *
61
+ * @function initialize
62
+ * @returns {void}
63
+ *
64
+ * @example
65
+ * ```javascript
66
+ * const defconSystem = require('./defconSystem');
67
+ * defconSystem.initialize(); // Reset to GREEN state
68
+ * ```
69
+ */
70
+ function initialize() {
71
+ currentState = DEFCON_STATES.GREEN;
72
+ escalationCount = 0;
73
+ lastEscalationTime = null;
74
+ threatHistory = [];
75
+
76
+ if (cooldownTimer) {
77
+ clearTimeout(cooldownTimer);
78
+ cooldownTimer = null;
79
+ }
80
+
81
+ if (process.env.NODE_ENV === 'development') {
82
+ console.log('[DEFCON] System initialized to GREEN state');
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Retrieves the current DEFCON security state
88
+ *
89
+ * @function getState
90
+ * @returns {string} Current DEFCON state ('GREEN' or 'RED')
91
+ *
92
+ * @example
93
+ * ```javascript
94
+ * const state = defconSystem.getState();
95
+ * if (state === 'RED') {
96
+ * // Apply conservative security measures
97
+ * }
98
+ * ```
99
+ */
100
+ function getState() {
101
+ return currentState;
102
+ }
103
+
104
+ /**
105
+ * Escalates the threat level based on detected malicious activity
106
+ *
107
+ * Increments the escalation counter and automatically transitions to RED state
108
+ * when the threshold is reached. Implements cooldown-based auto-reset to
109
+ * prevent indefinite high-security states.
110
+ *
111
+ * @function escalate
112
+ * @param {string} reason - Description of the threat that triggered escalation
113
+ * @returns {boolean} True if escalation occurred, false if threshold not met
114
+ *
115
+ * @example
116
+ * ```javascript
117
+ * defconSystem.escalate('Multiple failed login attempts');
118
+ * defconSystem.escalate('Suspicious payload detected');
119
+ * ```
120
+ */
121
+ function escalate(reason) {
122
+ if (!reason || typeof reason !== 'string') {
123
+ reason = 'Unknown threat';
124
+ }
125
+
126
+ if (escalationCount >= DEFAULT_CONFIG.MAX_ESCALATION_COUNT) {
127
+ if (process.env.NODE_ENV === 'development') {
128
+ console.warn('[DEFCON] Escalation count at maximum, maintaining current state');
129
+ }
130
+ return false;
131
+ }
132
+
133
+ escalationCount++;
134
+ lastEscalationTime = Date.now();
135
+
136
+ threatHistory.push({
137
+ timestamp: lastEscalationTime,
138
+ reason: reason,
139
+ count: escalationCount
140
+ });
141
+
142
+ if (threatHistory.length > 100) {
143
+ threatHistory = threatHistory.slice(-100);
144
+ }
145
+
146
+ if (escalationCount >= DEFAULT_CONFIG.ESCALATION_THRESHOLD && currentState === DEFCON_STATES.GREEN) {
147
+ currentState = DEFCON_STATES.RED;
148
+
149
+ if (cooldownTimer) {
150
+ clearTimeout(cooldownTimer);
151
+ }
152
+
153
+ cooldownTimer = setTimeout(() => {
154
+ currentState = DEFCON_STATES.GREEN;
155
+ escalationCount = Math.floor(escalationCount / 2);
156
+ cooldownTimer = null;
157
+
158
+ if (process.env.NODE_ENV === 'development') {
159
+ console.log(`[DEFCON] Auto-reset to GREEN after ${DEFAULT_CONFIG.ESCALATION_TIMEOUT / 1000}s cooldown`);
160
+ }
161
+ }, DEFAULT_CONFIG.ESCALATION_TIMEOUT);
162
+
163
+ if (process.env.NODE_ENV === 'development') {
164
+ console.warn(`[DEFCON] 🚨 ESCALATED to RED state: ${reason} (${escalationCount}/${DEFAULT_CONFIG.ESCALATION_THRESHOLD})`);
165
+ }
166
+
167
+ return true;
168
+ }
169
+
170
+ if (process.env.NODE_ENV === 'development') {
171
+ console.log(`[DEFCON] Threat detected: ${reason} (${escalationCount}/${DEFAULT_CONFIG.ESCALATION_THRESHOLD})`);
172
+ }
173
+
174
+ return false;
175
+ }
176
+
177
+ /**
178
+ * Manually sets the DEFCON state (for testing or administrative override)
179
+ *
180
+ * Allows direct state manipulation, useful for testing, maintenance, or
181
+ * administrative security controls. Automatically handles timer cleanup
182
+ * and counter resets.
183
+ *
184
+ * @function setState
185
+ * @param {string} state - Target state ('GREEN' or 'RED')
186
+ * @returns {boolean} True if state was changed, false if invalid state provided
187
+ *
188
+ * @example
189
+ * ```javascript
190
+ * defconSystem.setState('RED'); // Force high alert
191
+ * defconSystem.setState('GREEN'); // Reset to normal
192
+ * ```
193
+ */
194
+ function setState(state) {
195
+ if (state !== DEFCON_STATES.GREEN && state !== DEFCON_STATES.RED) {
196
+ if (process.env.NODE_ENV === 'development') {
197
+ console.error(`[DEFCON] Invalid state: ${state}. Must be 'GREEN' or 'RED'`);
198
+ }
199
+ return false;
200
+ }
201
+
202
+ const previousState = currentState;
203
+ currentState = state;
204
+
205
+ if (state === DEFCON_STATES.GREEN) {
206
+ escalationCount = 0;
207
+ lastEscalationTime = null;
208
+
209
+ if (cooldownTimer) {
210
+ clearTimeout(cooldownTimer);
211
+ cooldownTimer = null;
212
+ }
213
+ }
214
+
215
+ if (process.env.NODE_ENV === 'development') {
216
+ console.log(`[DEFCON] Manual state change: ${previousState} → ${state}`);
217
+ }
218
+
219
+ return true;
220
+ }
221
+
222
+ /**
223
+ * Retrieves current system status and statistics
224
+ *
225
+ * Provides comprehensive information about the current DEFCON state,
226
+ * escalation history, and system health for monitoring and debugging.
227
+ *
228
+ * @function getStatus
229
+ * @returns {Object} System status information
230
+ * @property {string} state - Current DEFCON state
231
+ * @property {number} escalationCount - Current escalation counter
232
+ * @property {number} threshold - Escalation threshold
233
+ * @property {number|null} lastEscalationTime - Timestamp of last escalation
234
+ * @property {number} cooldownRemaining - Milliseconds until auto-reset (0 if not in RED)
235
+ * @property {Array} recentThreats - Last 10 threats detected
236
+ *
237
+ * @example
238
+ * ```javascript
239
+ * const status = defconSystem.getStatus();
240
+ * console.log(`State: ${status.state}, Threats: ${status.escalationCount}`);
241
+ * ```
242
+ */
243
+ function getStatus() {
244
+ const now = Date.now();
245
+ let cooldownRemaining = 0;
246
+
247
+ if (currentState === DEFCON_STATES.RED && cooldownTimer) {
248
+ const elapsed = now - (lastEscalationTime || now);
249
+ cooldownRemaining = Math.max(0, DEFAULT_CONFIG.ESCALATION_TIMEOUT - elapsed);
250
+ }
251
+
252
+ return {
253
+ state: currentState,
254
+ escalationCount,
255
+ threshold: DEFAULT_CONFIG.ESCALATION_THRESHOLD,
256
+ lastEscalationTime,
257
+ cooldownRemaining,
258
+ recentThreats: threatHistory.slice(-10),
259
+ config: {
260
+ escalationTimeout: DEFAULT_CONFIG.ESCALATION_TIMEOUT,
261
+ maxEscalationCount: DEFAULT_CONFIG.MAX_ESCALATION_COUNT
262
+ }
263
+ };
264
+ }
265
+
266
+ /**
267
+ * Resets escalation counter without changing state
268
+ *
269
+ * Useful for gradual cooldown or manual intervention while maintaining
270
+ * current security posture.
271
+ *
272
+ * @function resetCounter
273
+ * @returns {number} Previous escalation count
274
+ *
275
+ * @example
276
+ * ```javascript
277
+ * const previousCount = defconSystem.resetCounter();
278
+ * console.log(`Reset counter from ${previousCount} to 0`);
279
+ * ```
280
+ */
281
+ function resetCounter() {
282
+ const previousCount = escalationCount;
283
+ escalationCount = 0;
284
+
285
+ if (process.env.NODE_ENV === 'development') {
286
+ console.log(`[DEFCON] Escalation counter reset from ${previousCount} to 0`);
287
+ }
288
+
289
+ return previousCount;
290
+ }
291
+
292
+ module.exports = {
293
+ initialize,
294
+ getState,
295
+ escalate,
296
+ setState,
297
+ getStatus,
298
+ resetCounter,
299
+ DEFCON_STATES,
300
+ DEFAULT_CONFIG
301
+ };
@@ -0,0 +1,272 @@
1
+ /**
2
+ * MagicAuth - Secure JWT Authentication Wrapper
3
+ *
4
+ * A simplified and secure JWT authentication utility with automatic secret management,
5
+ * secure defaults, and Express middleware integration.
6
+ *
7
+ * @module MagicAuth
8
+ * @version 1.0.0
9
+ * @author Omindu Dissanayaka
10
+ * @license MIT
11
+ */
12
+
13
+ const jwt = require('jsonwebtoken');
14
+
15
+ class MagicAuth {
16
+ /**
17
+ * Creates a MagicAuth instance
18
+ *
19
+ * @param {Object} [options] - Configuration options
20
+ * @param {string} [options.secret] - JWT secret (defaults to process.env.JWT_SECRET)
21
+ * @param {string} [options.algorithm='HS256'] - JWT algorithm
22
+ * @param {string|number} [options.expiresIn='1h'] - Default token expiration
23
+ * @param {string} [options.issuer] - JWT issuer
24
+ * @param {string} [options.audience] - JWT audience
25
+ * @param {boolean} [options.requireSecret=true] - Require secret to be set
26
+ */
27
+ constructor(options = {}) {
28
+ this.options = {
29
+ secret: options.secret || process.env.JWT_SECRET,
30
+ algorithm: options.algorithm || 'HS256',
31
+ expiresIn: options.expiresIn || '1h',
32
+ issuer: options.issuer,
33
+ audience: options.audience,
34
+ requireSecret: options.requireSecret !== false,
35
+ ...options
36
+ };
37
+
38
+ this._validateSecret();
39
+
40
+ this.defaultSignOptions = {
41
+ algorithm: this.options.algorithm,
42
+ expiresIn: this.options.expiresIn,
43
+ ...(this.options.issuer && { issuer: this.options.issuer }),
44
+ ...(this.options.audience && { audience: this.options.audience })
45
+ };
46
+
47
+ this.defaultVerifyOptions = {
48
+ algorithms: [this.options.algorithm],
49
+ ...(this.options.issuer && { issuer: this.options.issuer }),
50
+ ...(this.options.audience && { audience: this.options.audience })
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Validate JWT secret configuration
56
+ *
57
+ * @private
58
+ * @throws {Error} If secret is required but not provided
59
+ */
60
+ _validateSecret() {
61
+ if (this.options.requireSecret && !this.options.secret) {
62
+ const isProduction = process.env.NODE_ENV === 'production';
63
+ const message = 'JWT_SECRET environment variable is required for MagicAuth. ' +
64
+ 'Set process.env.JWT_SECRET or pass secret in options.';
65
+
66
+ if (isProduction) {
67
+ throw new Error(message);
68
+ } else {
69
+ console.warn(`[MagicAuth] ⚠️ WARNING: ${message}`);
70
+ this.options.secret = this._generateDevSecret();
71
+ console.warn(`[MagicAuth] 🔧 Using temporary development secret. DO NOT USE IN PRODUCTION!`);
72
+ }
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Generate a temporary secret for development
78
+ *
79
+ * @private
80
+ * @returns {string} Temporary secret
81
+ */
82
+ _generateDevSecret() {
83
+ return require('crypto').randomBytes(32).toString('hex');
84
+ }
85
+
86
+ /**
87
+ * Sign a JWT token
88
+ *
89
+ * @param {Object} payload - Payload to encode in the token
90
+ * @param {Object} [options] - Additional sign options
91
+ * @returns {string} JWT token
92
+ * @throws {Error} If signing fails
93
+ */
94
+ sign(payload, options = {}) {
95
+ try {
96
+ if (!payload || typeof payload !== 'object') {
97
+ throw new Error('Payload must be a non-null object');
98
+ }
99
+
100
+ const signOptions = {
101
+ ...this.defaultSignOptions,
102
+ ...options
103
+ };
104
+
105
+ if (options.expiresIn === null) {
106
+ delete signOptions.expiresIn;
107
+ }
108
+
109
+ return jwt.sign(payload, this.options.secret, signOptions);
110
+ } catch (error) {
111
+ throw new Error(`JWT signing failed: ${error.message}`);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Verify and decode a JWT token
117
+ *
118
+ * @param {string} token - JWT token to verify
119
+ * @param {Object} [options] - Additional verify options
120
+ * @returns {Object} Decoded payload
121
+ * @throws {Error} If verification fails
122
+ */
123
+ verify(token, options = {}) {
124
+ try {
125
+ if (!token || typeof token !== 'string') {
126
+ throw new Error('Token must be a non-empty string');
127
+ }
128
+
129
+ const verifyOptions = {
130
+ ...this.defaultVerifyOptions,
131
+ ...options
132
+ };
133
+
134
+ return jwt.verify(token, this.options.secret, verifyOptions);
135
+ } catch (error) {
136
+ if (error.name === 'TokenExpiredError') {
137
+ throw new Error('Token has expired');
138
+ } else if (error.name === 'JsonWebTokenError') {
139
+ throw new Error('Invalid token');
140
+ } else if (error.name === 'NotBeforeError') {
141
+ throw new Error('Token not active');
142
+ } else {
143
+ throw new Error(`Token verification failed: ${error.message}`);
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Express middleware for automatic JWT authentication
150
+ *
151
+ * Checks Authorization header for Bearer token, verifies it,
152
+ * and attaches payload to req.user
153
+ *
154
+ * @returns {Function} Express middleware function
155
+ */
156
+ middleware() {
157
+ return (req, res, next) => {
158
+ try {
159
+ const authHeader = req.headers.authorization;
160
+
161
+ if (!authHeader) {
162
+ return res.status(401).json({
163
+ error: 'Authentication required',
164
+ message: 'Authorization header is missing',
165
+ code: 'AUTH_MISSING'
166
+ });
167
+ }
168
+
169
+ if (!authHeader.startsWith('Bearer ')) {
170
+ return res.status(401).json({
171
+ error: 'Invalid authentication format',
172
+ message: 'Authorization header must start with "Bearer "',
173
+ code: 'AUTH_INVALID_FORMAT'
174
+ });
175
+ }
176
+
177
+ const token = authHeader.substring(7);
178
+
179
+ if (!token) {
180
+ return res.status(401).json({
181
+ error: 'Authentication required',
182
+ message: 'Bearer token is empty',
183
+ code: 'AUTH_EMPTY_TOKEN'
184
+ });
185
+ }
186
+
187
+ const payload = this.verify(token);
188
+
189
+ req.user = payload;
190
+
191
+ next();
192
+ } catch (error) {
193
+ const statusCode = error.message.includes('expired') ? 401 : 401;
194
+ const errorCode = error.message.includes('expired') ? 'AUTH_TOKEN_EXPIRED' : 'AUTH_TOKEN_INVALID';
195
+
196
+ return res.status(statusCode).json({
197
+ error: 'Authentication failed',
198
+ message: error.message,
199
+ code: errorCode
200
+ });
201
+ }
202
+ };
203
+ }
204
+
205
+ /**
206
+ * Refresh a token (create new token with same payload)
207
+ *
208
+ * @param {string} token - Existing token to refresh
209
+ * @param {Object} [options] - New sign options
210
+ * @returns {string} New JWT token
211
+ */
212
+ refresh(token, options = {}) {
213
+ const payload = this.verify(token);
214
+
215
+ const { iat, exp, ...cleanPayload } = payload;
216
+
217
+ return this.sign(cleanPayload, options);
218
+ }
219
+
220
+ /**
221
+ * Decode a token without verification (for debugging)
222
+ *
223
+ * @param {string} token - JWT token to decode
224
+ * @param {boolean} [complete=false] - Return complete decoded token
225
+ * @returns {Object|null} Decoded payload or null if invalid
226
+ */
227
+ decode(token, complete = false) {
228
+ try {
229
+ return jwt.decode(token, { complete });
230
+ } catch {
231
+ return null;
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Get token expiration time
237
+ *
238
+ * @param {string} token - JWT token
239
+ * @returns {Date|null} Expiration date or null if invalid
240
+ */
241
+ getExpiration(token) {
242
+ try {
243
+ const decoded = jwt.decode(token);
244
+ if (decoded && decoded.exp) {
245
+ return new Date(decoded.exp * 1000);
246
+ }
247
+ return null;
248
+ } catch {
249
+ return null;
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Check if token is expired
255
+ *
256
+ * @param {string} token - JWT token
257
+ * @returns {boolean} True if expired or invalid
258
+ */
259
+ isExpired(token) {
260
+ try {
261
+ const decoded = jwt.decode(token);
262
+ if (!decoded || !decoded.exp) {
263
+ return true;
264
+ }
265
+ return Date.now() >= decoded.exp * 1000;
266
+ } catch {
267
+ return true;
268
+ }
269
+ }
270
+ }
271
+
272
+ module.exports = MagicAuth;