Skip to content

Commit d88821e

Browse files
committed
System Touch
1 parent 522eeb4 commit d88821e

2 files changed

Lines changed: 87 additions & 49 deletions

File tree

.idea/dictionaries/project.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

source/server/nitro/NitroWebExpress.java

Lines changed: 86 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -447,12 +447,18 @@ public void run()
447447
while (!Thread.currentThread().isInterrupted())
448448
{
449449
Socket client = SERVER_SOCKET.accept();
450+
450451
Thread h = new Thread(() -> handle(client));
452+
451453
h.setDaemon(true);
454+
452455
h.start();
453456
}
454457
}
455-
catch (Exception e) { ExceptionHandler.dispatch(e); }
458+
catch (Exception e)
459+
{
460+
ExceptionHandler.dispatch(e);
461+
}
456462
}
457463

458464
/** Per-connection session state. */
@@ -486,28 +492,33 @@ private void handle(final Socket CLIENT)
486492
while ((line = in.readLine()) != null)
487493
{
488494
line = line.trim();
495+
489496
if (line.isEmpty()) continue;
497+
490498
if (line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("exit")) break;
491499

492-
CommonRails.printSystemComponent(this, this.hashCode(),
493-
". ModuleInstallationService [" + session.remoteIp + "] cmd: " + line + " .");
500+
CommonRails.printSystemComponent(this, this.hashCode(), ". ModuleInstallationService [" + session.remoteIp + "] cmd: " + line + " .");
494501

495502
String response = dispatch(line, CLIENT.getInputStream(), out, session);
503+
496504
if (response != null) writeLine(out, response);
497505
}
498506
}
499-
catch (Exception e) { ExceptionHandler.dispatch(e); }
507+
catch (Exception e)
508+
{
509+
ExceptionHandler.dispatch(e);
510+
}
500511
finally
501512
{
502513
if (session.adminToken != null) admin.ModuleAdmin.logout(session.adminToken);
503514
try { CLIENT.close(); } catch (Exception ignored) {}
504515
}
505516
}
506517

507-
private String dispatch(final String CMD, final InputStream RAW,
508-
final BufferedWriter OUT, final Session SESSION)
518+
private String dispatch(final String CMD, final InputStream RAW, final BufferedWriter OUT, final Session SESSION)
509519
{
510520
String[] parts = CMD.split("\\s+", 4);
521+
511522
switch (parts[0].toLowerCase())
512523
{
513524
case "identify":
@@ -554,146 +565,172 @@ private String identify(final String NATIONAL_ID_STR, final Session SESSION)
554565
try
555566
{
556567
long id = Long.parseLong(NATIONAL_ID_STR);
568+
557569
national.NationalFinanceID r = db.N21Store.loadNationalFinanceID(id);
570+
558571
if (r == null) return "[identify] National ID " + id + " not found.";
572+
559573
SESSION.nationalId = id;
560-
db.N21Store.storeModuleAction(id, "", "identify", SESSION.remoteIp,
561-
"", 0, "", "", "identified");
562-
CommonRails.printSystemComponent(this, this.hashCode(),
563-
". ModuleInstallationService identified National ID " + id + " .");
574+
575+
db.N21Store.storeModuleAction(id, "", "identify", SESSION.remoteIp, "", 0, "", "", "identified");
576+
577+
CommonRails.printSystemComponent(this, this.hashCode(), ". ModuleInstallationService identified National ID " + id + " .");
578+
564579
return "[identify] National ID " + id + " recognised. Welcome.";
565580
}
566-
catch (NumberFormatException e) { return "[identify] Invalid National ID."; }
581+
catch (NumberFormatException e)
582+
{
583+
return "[identify] Invalid National ID.";
584+
}
567585
}
568586

569587
private String adminLogin(final String PASSWORD, final Session SESSION)
570588
{
571589
if (SESSION.nationalId < 0) return "[admin] Identify yourself first.";
590+
572591
String token = admin.ModuleAdmin.login(PASSWORD, SESSION.nationalId);
592+
573593
if (token == null)
574594
{
575-
db.N21Store.storeModuleAction(SESSION.nationalId, "", "admin-login-fail",
576-
SESSION.remoteIp, "", 0, "", "", "failed");
595+
db.N21Store.storeModuleAction(SESSION.nationalId, "", "admin-login-fail", SESSION.remoteIp, "", 0, "", "", "failed");
596+
577597
return "[admin] Authentication failed.";
578598
}
599+
579600
SESSION.adminToken = token;
580-
db.N21Store.storeModuleAction(SESSION.nationalId, "", "admin-login",
581-
SESSION.remoteIp, "", 0, "", token, "success");
601+
602+
db.N21Store.storeModuleAction(SESSION.nationalId, "", "admin-login", SESSION.remoteIp, "", 0, "", token, "success");
603+
582604
return "[admin] Authenticated. You may now unload modules and grant signatories.";
583605
}
584606

585-
private String installModule(final String NAME, final String SIG_HEX,
586-
final String BYTE_COUNT_STR, final InputStream RAW,
587-
final BufferedWriter OUT, final Session SESSION)
607+
private String installModule(final String NAME, final String SIG_HEX, final String BYTE_COUNT_STR, final InputStream RAW, final BufferedWriter OUT, final Session SESSION)
588608
{
589609
try
590610
{
591611
int byteCount = Integer.parseInt(BYTE_COUNT_STR);
612+
592613
if (byteCount <= 0 || byteCount > 50 * 1024 * 1024)
593614
return "[install] Invalid byte count: " + byteCount;
594615

595616
writeLine(OUT, "[install] Ready to receive " + byteCount + " bytes for '" + NAME + "'.");
596617

597618
byte[] data = new byte[byteCount];
619+
598620
new DataInputStream(RAW).readFully(data);
599621

600622
// Security check 1: SHA-256
601623
String actualHex = sha256hex(data);
624+
602625
if (!actualHex.equalsIgnoreCase(SIG_HEX))
603626
{
604627
String result = "sig-mismatch expected=" + SIG_HEX + " got=" + actualHex;
605-
db.N21Store.storeModuleAction(SESSION.nationalId, NAME, "install-reject",
606-
SESSION.remoteIp, "", byteCount, SIG_HEX, "", result);
607-
CommonRails.printSystemComponent(this, this.hashCode(),
608-
". ModuleInstallationService SECURITY FAIL sig mismatch [" + NAME + "] .");
628+
629+
db.N21Store.storeModuleAction(SESSION.nationalId, NAME, "install-reject", SESSION.remoteIp, "", byteCount, SIG_HEX, "", result);
630+
631+
CommonRails.printSystemComponent(this, this.hashCode(), ". ModuleInstallationService SECURITY FAIL sig mismatch [" + NAME + "] .");
632+
609633
return "[install] REJECTED — signature mismatch.";
610634
}
611635

612636
// Security check 2: file type
613637
String detectedType = detectType(data);
638+
614639
if (detectedType == null)
615640
{
616-
db.N21Store.storeModuleAction(SESSION.nationalId, NAME, "install-reject",
617-
SESSION.remoteIp, "unknown", byteCount, SIG_HEX, "", "bad-type");
618-
CommonRails.printSystemComponent(this, this.hashCode(),
619-
". ModuleInstallationService SECURITY FAIL unsupported type [" + NAME + "] .");
641+
db.N21Store.storeModuleAction(SESSION.nationalId, NAME, "install-reject", SESSION.remoteIp, "unknown", byteCount, SIG_HEX, "", "bad-type");
642+
643+
CommonRails.printSystemComponent(this, this.hashCode(), ". ModuleInstallationService SECURITY FAIL unsupported type [" + NAME + "] .");
644+
620645
return "[install] REJECTED — unsupported file type (must be .jar, .zip, or .java).";
621646
}
622647

623-
CommonRails.printSystemComponent(this, this.hashCode(),
624-
". ModuleInstallationService security passed [" + NAME + "] type=" + detectedType + " .");
648+
CommonRails.printSystemComponent(this, this.hashCode(), ". ModuleInstallationService security passed [" + NAME + "] type=" + detectedType + " .");
625649

626650
// Heuristics check — score the module before writing to disk
627651
try
628652
{
629653
Path tmp = Files.createTempFile("nwe-heuristic-", "." + detectedType);
654+
630655
Files.write(tmp, data);
656+
631657
heuristics.ModuleHeuristics.Result hr = heuristics.ModuleHeuristics.evaluate(tmp);
658+
632659
Files.deleteIfExists(tmp);
633660

634-
CommonRails.printSystemComponent(this, this.hashCode(),
635-
". ModuleInstallationService heuristics [" + NAME + "] score=" + hr.score + " suitable=" + hr.suitable + " .");
661+
CommonRails.printSystemComponent(this, this.hashCode(), ". ModuleInstallationService heuristics [" + NAME + "] score=" + hr.score + " suitable=" + hr.suitable + " .");
662+
636663
writeLine(OUT, "[heuristics] " + hr.summary());
637664

638665
if (!hr.suitable)
639666
{
640-
db.N21Store.storeModuleAction(SESSION.nationalId, NAME, "install-reject",
641-
SESSION.remoteIp, detectedType, byteCount, SIG_HEX, "", "heuristics-fail score=" + hr.score);
642-
return "[install] REJECTED — heuristics score " + hr.score + "/100 is below threshold ("
643-
+ heuristics.ModuleHeuristics.PASS_THRESHOLD + "). See findings above.";
667+
db.N21Store.storeModuleAction(SESSION.nationalId, NAME, "install-reject", SESSION.remoteIp, detectedType, byteCount, SIG_HEX, "", "heuristics-fail score=" + hr.score);
668+
669+
return "[install] REJECTED — heuristics score " + hr.score + "/100 is below threshold (" + heuristics.ModuleHeuristics.PASS_THRESHOLD + "). See findings above.";
644670
}
645671
}
646672
catch (Exception hEx)
647673
{
648674
// Heuristics failure must not block install — log and continue
649-
CommonRails.printSystemComponent(this, this.hashCode(),
650-
". ModuleInstallationService heuristics error [" + NAME + "]: " + hEx.getMessage() + " — proceeding .");
675+
CommonRails.printSystemComponent(this, this.hashCode(), ". ModuleInstallationService heuristics error [" + NAME + "]: " + hEx.getMessage() + " — proceeding .");
651676
}
652677

653678
String filename = NAME.replaceAll("[^a-zA-Z0-9._-]", "_") + "." + detectedType;
679+
654680
Path dest = INSTALL_DIR.resolve(filename);
681+
655682
Files.write(dest, data);
656683

657684
URLClassLoader loader = null;
685+
658686
if (detectedType.equals("jar"))
659687
{
660-
loader = new URLClassLoader(new URL[]{ dest.toUri().toURL() },
661-
Thread.currentThread().getContextClassLoader());
688+
loader = new URLClassLoader(new URL[]{ dest.toUri().toURL() }, Thread.currentThread().getContextClassLoader());
662689
}
663690
else if (detectedType.equals("zip"))
664691
{
665692
Path unzipDir = INSTALL_DIR.resolve(NAME);
693+
666694
Files.createDirectories(unzipDir);
695+
667696
unzip(data, unzipDir);
668-
loader = new URLClassLoader(new URL[]{ unzipDir.toUri().toURL() },
669-
Thread.currentThread().getContextClassLoader());
697+
698+
loader = new URLClassLoader(new URL[]{ unzipDir.toUri().toURL() }, Thread.currentThread().getContextClassLoader());
670699
}
671700
else
672701
{
673702
javax.tools.JavaCompiler compiler = javax.tools.ToolProvider.getSystemJavaCompiler();
703+
674704
if (compiler == null) return "[install] No system compiler available (JDK required).";
705+
675706
Path srcFile = INSTALL_DIR.resolve(NAME + ".java");
707+
676708
Files.write(srcFile, data);
709+
677710
if (compiler.run(null, null, null, srcFile.toString()) != 0)
678711
return "[install] Compilation failed for " + NAME + ".java";
679-
loader = new URLClassLoader(new URL[]{ INSTALL_DIR.toUri().toURL() },
680-
Thread.currentThread().getContextClassLoader());
712+
713+
loader = new URLClassLoader(new URL[]{ INSTALL_DIR.toUri().toURL() }, Thread.currentThread().getContextClassLoader());
681714
}
682715

683716
ModuleRegistry.register(new InstalledModule(NAME, dest, loader));
684717

685718
String result = "installed " + detectedType + " " + byteCount + "B";
686-
db.N21Store.storeModuleAction(SESSION.nationalId, NAME, "install",
687-
SESSION.remoteIp, detectedType, byteCount, SIG_HEX, "", result);
688719

689-
CommonRails.printSystemComponent(this, this.hashCode(),
690-
". ModuleInstallationService installed [" + NAME + "] for National ID "
691-
+ SESSION.nationalId + " .");
720+
db.N21Store.storeModuleAction(SESSION.nationalId, NAME, "install", SESSION.remoteIp, detectedType, byteCount, SIG_HEX, "", result);
721+
722+
CommonRails.printSystemComponent(this, this.hashCode(), ". ModuleInstallationService installed [" + NAME + "] for National ID " + SESSION.nationalId + " .");
692723

693724
return "[install] Module '" + NAME + "' installed (" + detectedType + ", " + byteCount + " bytes).";
694725
}
695-
catch (NumberFormatException e) { return "[install] Invalid byte count."; }
696-
catch (Exception e) { ExceptionHandler.dispatch(e); return "[install] Error: " + e.getMessage(); }
726+
catch (NumberFormatException e)
727+
{
728+
return "[install] Invalid byte count.";
729+
}
730+
catch (Exception e)
731+
{
732+
ExceptionHandler.dispatch(e); return "[install] Error: " + e.getMessage();
733+
}
697734
}
698735

699736
private String unloadModule(final String NAME, final Session SESSION)

0 commit comments

Comments
 (0)