mojic 1.1.0 → 1.2.4

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.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Mojic v1.1.0
1
+ # Mojic v1.2.4
2
2
 
3
3
  > **Operation Polymorphic Chaos: Obfuscate C source code into a randomized, password-seeded stream of emojis.**
4
4
 
package/bin/mojic.js CHANGED
@@ -12,7 +12,7 @@ import { CipherEngine } from '../lib/CipherEngine.js';
12
12
  program
13
13
  .name('mojic')
14
14
  .description('Obfuscate C source code into emojis')
15
- .version('1.1.0')
15
+ .version('1.2.4')
16
16
  .addHelpCommand('help [command]', 'Display help for command')
17
17
  .showHelpAfterError();
18
18
 
@@ -78,7 +78,6 @@ const createHeaderSkipper = () => {
78
78
  });
79
79
  };
80
80
 
81
- // --- FLATTENING (Minifier) ---
82
81
  const createMinifier = () => {
83
82
  return new Transform({
84
83
  transform(chunk, encoding, cb) {
@@ -91,11 +90,8 @@ const createMinifier = () => {
91
90
  });
92
91
  };
93
92
 
94
- // --- Recursive Logic ---
95
-
96
93
  async function traverseDirectory(currentPath, extension, callback) {
97
94
  const entries = fs.readdirSync(currentPath, { withFileTypes: true });
98
-
99
95
  for (const entry of entries) {
100
96
  const fullPath = path.join(currentPath, entry.name);
101
97
  if (entry.isDirectory()) {
@@ -123,7 +119,7 @@ program
123
119
  throw new Error(`'${targetPath}' is a directory. Use -r to process recursively.`);
124
120
  }
125
121
 
126
- console.log(chalk.blue('Initiating Mojic Encryption v1.1...'));
122
+ console.log(chalk.blue('Initiating Mojic Encryption v1.2...'));
127
123
  if (options.flat) console.log(chalk.yellow(' -> Structural Flattening Enabled'));
128
124
 
129
125
  const password = await promptPassword('Create password for file(s):');
@@ -142,10 +138,7 @@ program
142
138
 
143
139
  await new Promise((resolve, reject) => {
144
140
  let pipeline = readStream;
145
-
146
- if (options.flat) {
147
- pipeline = pipeline.pipe(createMinifier());
148
- }
141
+ if (options.flat) pipeline = pipeline.pipe(createMinifier());
149
142
 
150
143
  pipeline
151
144
  .pipe(engine.getEncryptStream())
@@ -193,10 +186,7 @@ program
193
186
 
194
187
  const headerStr = await getStreamHeader(filePath);
195
188
  const metadata = CipherEngine.decodeHeader(headerStr);
196
-
197
189
  const engine = new CipherEngine(password);
198
-
199
- // Pass the Auth Check Hex (if available in new format)
200
190
  await engine.init(metadata.saltHex, metadata.authCheckHex);
201
191
 
202
192
  const readStream = fs.createReadStream(filePath);
@@ -204,8 +194,9 @@ program
204
194
 
205
195
  await new Promise((resolve, reject) => {
206
196
  const decryptStream = engine.getDecryptStream();
207
-
208
197
  decryptStream.on('error', (err) => {
198
+ readStream.destroy(); // Stop reading
199
+ writeStream.destroy(); // Stop writing
209
200
  reject(err);
210
201
  });
211
202
 
@@ -216,19 +207,12 @@ program
216
207
  .on('finish', resolve)
217
208
  .on('error', reject);
218
209
  });
219
-
220
- return true; // Success
210
+ return true;
221
211
  } catch (e) {
222
212
  const outputName = filePath.replace(/\.mojic$/, '') + '.restored.c';
213
+ // Wait for stream handles to release
214
+ setTimeout(() => { if (fs.existsSync(outputName)) try { fs.unlinkSync(outputName); } catch(ign){} }, 100);
223
215
 
224
- // Cleanup output file on error
225
- setTimeout(() => {
226
- if (fs.existsSync(outputName)) {
227
- try { fs.unlinkSync(outputName); } catch(ign){}
228
- }
229
- }, 100);
230
-
231
- // Specific Error Messaging (No Emojis)
232
216
  if (e.message === "WRONG_PASSWORD") {
233
217
  console.log(chalk.red(` Error: Incorrect Password`));
234
218
  } else if (e.message === "FILE_TAMPERED") {
@@ -236,8 +220,7 @@ program
236
220
  } else {
237
221
  console.log(chalk.red(` Error: ${e.message}`));
238
222
  }
239
-
240
- return false; // Failure
223
+ return false;
241
224
  }
242
225
  };
243
226
 
@@ -247,9 +230,7 @@ program
247
230
  console.log(chalk.green('Batch decryption complete.'));
248
231
  } else {
249
232
  const success = await processFile(targetPath);
250
- if (success) {
251
- console.log(chalk.green(`Restored.`));
252
- }
233
+ if (success) console.log(chalk.green(`Restored.`));
253
234
  }
254
235
 
255
236
  } catch (err) {
@@ -258,7 +239,6 @@ program
258
239
  });
259
240
 
260
241
  // --- SRT ---
261
-
262
242
  const rotatePassword = async (file) => {
263
243
  try {
264
244
  if (!fs.existsSync(file)) throw new Error('File not found');
@@ -283,16 +263,8 @@ const rotatePassword = async (file) => {
283
263
 
284
264
  await new Promise((resolve, reject) => {
285
265
  const decryptStream = oldEngine.getDecryptStream();
286
-
287
- decryptStream.on('error', (err) => reject(err));
288
-
289
- readStream
290
- .pipe(createHeaderSkipper())
291
- .pipe(decryptStream)
292
- .pipe(newEngine.getEncryptStream())
293
- .pipe(writeStream)
294
- .on('finish', resolve)
295
- .on('error', reject);
266
+ decryptStream.on('error', reject);
267
+ readStream.pipe(createHeaderSkipper()).pipe(decryptStream).pipe(newEngine.getEncryptStream()).pipe(writeStream).on('finish', resolve).on('error', reject);
296
268
  });
297
269
 
298
270
  fs.renameSync(tempFile, file);
@@ -300,11 +272,8 @@ const rotatePassword = async (file) => {
300
272
 
301
273
  } catch (err) {
302
274
  if (fs.existsSync(file + '.tmp')) fs.unlinkSync(file + '.tmp');
303
- if (err.message === "WRONG_PASSWORD") {
304
- console.error(chalk.red('Error: Incorrect Current Password'));
305
- } else {
306
- console.error(chalk.red('Error:'), err.message);
307
- }
275
+ if (err.message === "WRONG_PASSWORD") console.error(chalk.red('Error: Incorrect Current Password'));
276
+ else console.error(chalk.red('Error:'), err.message);
308
277
  }
309
278
  };
310
279
 
@@ -331,15 +300,8 @@ const reEncrypt = async (file) => {
331
300
 
332
301
  await new Promise((resolve, reject) => {
333
302
  const decryptStream = oldEngine.getDecryptStream();
334
- decryptStream.on('error', (err) => reject(err));
335
-
336
- readStream
337
- .pipe(createHeaderSkipper())
338
- .pipe(decryptStream)
339
- .pipe(newEngine.getEncryptStream())
340
- .pipe(writeStream)
341
- .on('finish', resolve)
342
- .on('error', reject);
303
+ decryptStream.on('error', reject);
304
+ readStream.pipe(createHeaderSkipper()).pipe(decryptStream).pipe(newEngine.getEncryptStream()).pipe(writeStream).on('finish', resolve).on('error', reject);
343
305
  });
344
306
 
345
307
  fs.renameSync(tempFile, file);
@@ -347,28 +309,15 @@ const reEncrypt = async (file) => {
347
309
 
348
310
  } catch (err) {
349
311
  if (fs.existsSync(file + '.tmp')) fs.unlinkSync(file + '.tmp');
350
- if (err.message === "WRONG_PASSWORD") {
351
- console.error(chalk.red('Error: Incorrect Password'));
352
- } else {
353
- console.error(chalk.red('Error:'), err.message);
354
- }
312
+ if (err.message === "WRONG_PASSWORD") console.error(chalk.red('Error: Incorrect Password'));
313
+ else console.error(chalk.red('Error:'), err.message);
355
314
  }
356
315
  };
357
316
 
358
- program
359
- .command('srt')
360
- .description('Security and Rotation Tools')
361
- .option('--pass <file>', 'Update the password for an existing file')
362
- .option('--re <file>', 'Re-encrypt with new random seed (Same password)')
363
- .action(async (options) => {
364
- if (options.pass) {
365
- await rotatePassword(options.pass);
366
- } else if (options.re) {
367
- await reEncrypt(options.re);
368
- } else {
369
- console.log(chalk.yellow('Please specify an option: --pass <file> or --re <file>'));
370
- program.commands.find(c => c.name() === 'srt').help();
371
- }
372
- });
317
+ program.command('srt').description('Security and Rotation Tools').option('--pass <file>', 'Update password').option('--re <file>', 'Re-encrypt').action(async (options) => {
318
+ if (options.pass) await rotatePassword(options.pass);
319
+ else if (options.re) await reEncrypt(options.re);
320
+ else { console.log(chalk.yellow('Please specify an option: --pass <file> or --re <file>')); program.commands.find(c => c.name() === 'srt').help(); }
321
+ });
373
322
 
374
323
  program.parse(process.argv);
@@ -3,15 +3,11 @@ import { Transform } from 'stream';
3
3
  import { StringDecoder } from 'string_decoder';
4
4
 
5
5
  /**
6
- * MOJIC v1.1.0 CIPHER ENGINE
6
+ * MOJIC v1.2.4 CIPHER ENGINE
7
7
  * "Operation Polymorphic Chaos"
8
- * * Features:
9
- * - Xoshiro256** PRNG (256-bit State)
10
- * - Base-1024 Compression (5 bytes -> 4 emojis)
11
- * - Polymorphic Keyword Encryption (Rolling Cipher)
12
- * - HMAC-SHA256 Integrity Footer
13
- * - Line Wrapping (New: Prevents lag in editors)
14
- * - Instant Password Verification (New: Header Auth Check)
8
+ * * Fixes:
9
+ * - Word Boundaries: Prevents splitting variables like 'secretCode'
10
+ * - Regex: correctly handles #directives vs keywords
15
11
  */
16
12
 
17
13
  // --- EMOJI UNIVERSE GENERATION ---
@@ -158,7 +154,7 @@ export class CipherEngine {
158
154
 
159
155
  _encodeHeader() {
160
156
  const saltHex = this.salt.toString('hex');
161
- const authCheck = this.authKey.subarray(0, 4).toString('hex'); // 4 bytes check
157
+ const authCheck = this.authKey.subarray(0, 4).toString('hex');
162
158
 
163
159
  let headerStr = '';
164
160
  for (const char of (saltHex + authCheck)) {
@@ -196,9 +192,14 @@ export class CipherEngine {
196
192
  transform(chunk, encoding, callback) {
197
193
  const str = chunk.toString('utf8');
198
194
 
199
- const sortedKeywords = [...C_KEYWORDS].sort((a, b) => b.length - a.length);
200
- const keywordPattern = sortedKeywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
201
- const regex = new RegExp(`(${keywordPattern})`, 'g');
195
+ // --- FIXED REGEX LOGIC ---
196
+ // Separate alpha keywords (int, void) from symbols (#include)
197
+ const alphaKeywords = C_KEYWORDS.filter(k => /^\w+$/.test(k)).sort((a,b)=>b.length-a.length).join('|');
198
+ const symKeywords = C_KEYWORDS.filter(k => !/^\w+$/.test(k)).map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
199
+
200
+ // Match: \b(int|void)\b OR (#include)
201
+ // This ensures 'secretCode' isn't matched as 'Code' containing 'do' or 'int'
202
+ const regex = new RegExp(`(\\b(?:${alphaKeywords})\\b|(?:${symKeywords}))`, 'g');
202
203
 
203
204
  const parts = str.split(regex);
204
205
 
@@ -218,8 +219,6 @@ export class CipherEngine {
218
219
 
219
220
  const outBuf = Buffer.from(polyEmoji);
220
221
  engine.hmac.update(outBuf);
221
-
222
- // Emit wrapped
223
222
  this.push(engine._wrapOutput(outBuf));
224
223
 
225
224
  } else {
@@ -256,7 +255,6 @@ export class CipherEngine {
256
255
  footerStr += HEADER_ALPHABET[val];
257
256
  }
258
257
  }
259
- // Push footer (always starts on a new line or wrapped)
260
258
  this.push(Buffer.from('\n' + footerStr));
261
259
  callback();
262
260
  }
@@ -289,7 +287,6 @@ export class CipherEngine {
289
287
 
290
288
  _flushDataBuffer(buf) {
291
289
  if (buf.length === 0) return Buffer.alloc(0);
292
-
293
290
  const padded = Buffer.alloc(5);
294
291
  buf.copy(padded);
295
292
  const enc = this._encodeBase1024(padded);
@@ -313,8 +310,7 @@ export class CipherEngine {
313
310
  const segments = [...segmenter.segment(str)];
314
311
 
315
312
  for (const { segment } of segments) {
316
- // Filter out whitespace/newlines used for wrapping
317
- if (segment.match(/\s/)) continue;
313
+ if (segment.match(/\s/)) continue; // Skip wraps
318
314
 
319
315
  emojiBuffer.push(segment);
320
316
 
@@ -349,13 +345,9 @@ export class CipherEngine {
349
345
  }
350
346
 
351
347
  if (footerHex !== calcDigest) {
352
- // Critical security failure
353
348
  this.emit('error', new Error("FILE_TAMPERED"));
354
349
  return;
355
350
  }
356
-
357
- if (engine.decodeDataBuf.length > 0) {
358
- }
359
351
  callback();
360
352
  }
361
353
  });
@@ -388,8 +380,6 @@ export class CipherEngine {
388
380
  const cleanChunk = chunk.filter(b => b !== 0x00);
389
381
  stream.push(cleanChunk);
390
382
  }
391
- } else {
392
- // Unknown emojis are ignored now
393
383
  }
394
384
  }
395
385
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mojic",
3
- "version": "1.1.0",
3
+ "version": "1.2.4",
4
4
  "description": "Obfuscate C source code into encrypted, password-seeded emoji streams.",
5
5
  "main": "bin/mojic.js",
6
6
  "bin": {
@@ -15,6 +15,10 @@
15
15
  "type": "git",
16
16
  "url": "git+https://github.com/notamitgamer/mojic.git"
17
17
  },
18
+ "publishConfig": {
19
+ "registry": "https://registry.npmjs.org/",
20
+ "access": "public"
21
+ },
18
22
  "dependencies": {
19
23
  "chalk": "^5.3.0",
20
24
  "commander": "^11.1.0",
@@ -50,4 +54,4 @@
50
54
  ],
51
55
  "outputPath": "dist"
52
56
  }
53
- }
57
+ }