diff --git a/cameleer-license-minter/src/main/java/com/cameleer/license/minter/cli/LicenseMinterCli.java b/cameleer-license-minter/src/main/java/com/cameleer/license/minter/cli/LicenseMinterCli.java index 334f1fbd..927cd5e7 100644 --- a/cameleer-license-minter/src/main/java/com/cameleer/license/minter/cli/LicenseMinterCli.java +++ b/cameleer-license-minter/src/main/java/com/cameleer/license/minter/cli/LicenseMinterCli.java @@ -98,6 +98,23 @@ public final class LicenseMinterCli { } else { out.println(token); } + if (bool.contains("--verify")) { + String pubPath = flags.get("--public-key"); + if (pubPath == null) { + err.println("--verify requires --public-key"); + if (outPath != null) Files.deleteIfExists(Path.of(outPath)); + return 2; + } + try { + String pubB64 = Files.readString(Path.of(pubPath)).trim(); + new com.cameleer.server.core.license.LicenseValidator(pubB64, tenant).validate(token); + out.println("verified ok"); + } catch (Exception ve) { + err.println("VERIFY FAILED: " + ve.getMessage()); + if (outPath != null) Files.deleteIfExists(Path.of(outPath)); + return 3; + } + } return 0; } catch (Exception e) { err.println("ERROR: " + e.getMessage()); diff --git a/cameleer-license-minter/src/test/java/com/cameleer/license/minter/cli/LicenseMinterCliTest.java b/cameleer-license-minter/src/test/java/com/cameleer/license/minter/cli/LicenseMinterCliTest.java index 3978fa4e..36f3dd2f 100644 --- a/cameleer-license-minter/src/test/java/com/cameleer/license/minter/cli/LicenseMinterCliTest.java +++ b/cameleer-license-minter/src/test/java/com/cameleer/license/minter/cli/LicenseMinterCliTest.java @@ -48,4 +48,65 @@ class LicenseMinterCliTest { int code = LicenseMinterCli.run(new String[]{"--frobnicate=yes"}); assertThat(code).isNotZero(); } + + @Test + void verify_happyPath_succeeds() throws Exception { + KeyPair kp = KeyPairGenerator.getInstance("Ed25519").generateKeyPair(); + Path priv = tmp.resolve("priv.b64"); + Path pub = tmp.resolve("pub.b64"); + Files.writeString(priv, Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded())); + Files.writeString(pub, Base64.getEncoder().encodeToString(kp.getPublic().getEncoded())); + Path out = tmp.resolve("license.tok"); + + int code = LicenseMinterCli.run(new String[]{ + "--private-key=" + priv, + "--public-key=" + pub, + "--tenant=acme", + "--expires=2099-12-31", + "--output=" + out, + "--verify" + }); + + assertThat(code).isEqualTo(0); + assertThat(out).exists(); + } + + @Test + void verify_wrongPublicKey_deletesOutputAndExitsNonZero() throws Exception { + KeyPair signing = KeyPairGenerator.getInstance("Ed25519").generateKeyPair(); + KeyPair other = KeyPairGenerator.getInstance("Ed25519").generateKeyPair(); + Path priv = tmp.resolve("priv.b64"); + Path pub = tmp.resolve("pub.b64"); + Files.writeString(priv, Base64.getEncoder().encodeToString(signing.getPrivate().getEncoded())); + Files.writeString(pub, Base64.getEncoder().encodeToString(other.getPublic().getEncoded())); + Path out = tmp.resolve("license.tok"); + + int code = LicenseMinterCli.run(new String[]{ + "--private-key=" + priv, + "--public-key=" + pub, + "--tenant=acme", + "--expires=2099-12-31", + "--output=" + out, + "--verify" + }); + + assertThat(code).isNotZero(); + assertThat(out).doesNotExist(); + } + + @Test + void verify_withoutPublicKey_fails() throws Exception { + KeyPair kp = KeyPairGenerator.getInstance("Ed25519").generateKeyPair(); + Path priv = tmp.resolve("priv.b64"); + Files.writeString(priv, Base64.getEncoder().encodeToString(kp.getPrivate().getEncoded())); + + int code = LicenseMinterCli.run(new String[]{ + "--private-key=" + priv, + "--tenant=acme", + "--expires=2099-12-31", + "--verify" + }); + + assertThat(code).isNotZero(); + } }