// Kotlin/JVM. Paired transport-free scaffold; production ports are intentionally abstract. // beginVerified performs ALL verification inside a transaction. close rolls back // unless committed. See examples/README.md for crypto, freshness and authority rules. package bringpass.draft import java.io.Closeable enum class Op { REGISTER, USE, REVOKE, RETRACT } data class Envelope(val fields: List, val signature: String) data class Result(val receipt: Envelope, val fresh: Boolean) interface Tx : Closeable { val operation: Op fun cached(): Envelope? fun registerNewKey() fun requireCurrentEntitlement() fun revokeTarget() fun retractRelationship() fun signResult(): Envelope fun commitOnce(result: Envelope) } interface Ports { fun challenge(op: Op, rid: String, target: String, trustedContext: String): Envelope fun verifyProviderAndApprove(challenge: Envelope) fun signProof(challenge: Envelope): Envelope fun verifyResultAndApply(result: Envelope) fun beginVerified(proof: Envelope, trustedContext: String): Tx fun recoverRevoke(rid: String, target: String, trustedContext: String): Envelope } class TokenSide(private val ports: Ports) { fun respond(challenge: Envelope): Envelope { ports.verifyProviderAndApprove(challenge) return ports.signProof(challenge) } fun accept(result: Envelope) = ports.verifyResultAndApply(result) } class ProviderSide(private val ports: Ports) { fun start(op: Op, rid: String, target: String, context: String) = ports.challenge(op, rid, target, context) fun finish(proof: Envelope, trustedContext: String): Result = ports.beginVerified(proof, trustedContext).use { tx -> val cached = tx.cached() if (cached != null) Result(cached, false) else { when (tx.operation) { Op.REGISTER -> tx.registerNewKey() Op.USE -> tx.requireCurrentEntitlement() Op.REVOKE -> tx.revokeTarget() Op.RETRACT -> tx.retractRelationship() } val result = tx.signResult() tx.commitOnce(result) Result(result, true) } } fun lost(rid: String, target: String, context: String) = ports.recoverRevoke(rid, target, context) } fun legacyValue(value: String, approved: Boolean, selected: Boolean): String { require(approved && selected && value.isNotEmpty()) return value // No new message reaches the legacy reader. }