// JDK 17+. Paired protocol scaffold, NOT a cryptographic verifier. // Ports must implement the verification/transaction contract in examples/README.md. // No request method, URL, reader SDK or fictitious published library is used. public final class Protocol { public enum Op { REGISTER, USE, REVOKE, RETRACT } public record Envelope(String[] fields, String signature) {} public record Result(Envelope receipt, boolean fresh) {} public interface Tx extends AutoCloseable { Op operation(); Envelope cached(); void registerNewKey(); void requireCurrentEntitlement(); void revokeTarget(); void retractRelationship(); Envelope signResult(); void commitOnce(Envelope result); void close(); // Rollback unless committed; release transaction lock. } public interface Ports { Envelope challenge(Op op, String rid, String target, String trustedContext); void verifyProviderAndApprove(Envelope challenge); Envelope signProof(Envelope challenge); void verifyResultAndApply(Envelope result); Tx beginVerified(Envelope proof, String trustedContext); Envelope recoverRevoke(String rid, String target, String trustedContext); } public static final class TokenSide { private final Ports ports; public TokenSide(Ports ports) { this.ports = ports; } public Envelope respond(Envelope challenge) { ports.verifyProviderAndApprove(challenge); return ports.signProof(challenge); } public void accept(Envelope result) { ports.verifyResultAndApply(result); } } public static final class ProviderSide { private final Ports ports; public ProviderSide(Ports ports) { this.ports = ports; } public Envelope start(Op op, String rid, String target, String context) { return ports.challenge(op, rid, target, context); } public Result finish(Envelope proof, String trustedContext) { try (Tx tx = ports.beginVerified(proof, trustedContext)) { Envelope cached = tx.cached(); if (cached != null) return new Result(cached, false); switch (tx.operation()) { case REGISTER -> tx.registerNewKey(); case USE -> tx.requireCurrentEntitlement(); case REVOKE -> tx.revokeTarget(); case RETRACT -> tx.retractRelationship(); } Envelope result = tx.signResult(); tx.commitOnce(result); return new Result(result, true); } } public Envelope lost(String rid, String target, String context) { return ports.recoverRevoke(rid, target, context); } } public static String legacyValue(String value, boolean approved, boolean selected) { if (!approved || !selected || value == null || value.isEmpty()) throw new IllegalArgumentException("Local approval/selection required"); return value; // Only an agreed barcode/QR value or input to an existing NFC driver. } }