diff --git a/hkp-java/src/main/kotlin/pgp/hkp/HKPApi.kt b/hkp-java/src/main/kotlin/pgp/hkp/HKPApi.kt new file mode 100644 index 0000000..a2489f5 --- /dev/null +++ b/hkp-java/src/main/kotlin/pgp/hkp/HKPApi.kt @@ -0,0 +1,28 @@ +package pgp.hkp + +import pgp.hkp.operation.Get +import java.net.http.HttpClient + + +open class HKPApi( + val http: HttpClient, + val service: HKPServerInfo, + val openpgp: OpenPgpImplementation +) { + companion object { + const val REQUEST_PATH_PREFIX = "/pks" + const val REQUEST_PATH_LOOKUP = "${Companion.REQUEST_PATH_PREFIX}/lookup" + const val REQUEST_PATH_ADD = "${Companion.REQUEST_PATH_PREFIX}/add" + + const val VAR_OP = "op" + const val VAR_SEARCH = "search" + + const val OP_GET = "get" + const val OP_INDEX = "index" + const val OP_VINDEX = "vindex" + const val OP_STATS = "stats" + const val OP_HGET = "hget" + } + + fun get() = Get(http, service, openpgp) +} \ No newline at end of file diff --git a/hkp-java/src/main/kotlin/pgp/hkp/HKPServerInfo.kt b/hkp-java/src/main/kotlin/pgp/hkp/HKPServerInfo.kt new file mode 100644 index 0000000..348ee6b --- /dev/null +++ b/hkp-java/src/main/kotlin/pgp/hkp/HKPServerInfo.kt @@ -0,0 +1,8 @@ +package pgp.hkp + +import java.net.URI + +data class HKPServerInfo( + val serviceUri: URI, +) { +} \ No newline at end of file diff --git a/hkp-java/src/main/kotlin/pgp/hkp/HockeypuckApi.kt b/hkp-java/src/main/kotlin/pgp/hkp/HockeypuckApi.kt new file mode 100644 index 0000000..8a2494e --- /dev/null +++ b/hkp-java/src/main/kotlin/pgp/hkp/HockeypuckApi.kt @@ -0,0 +1,14 @@ +package pgp.hkp + +import java.net.http.HttpClient + +class HockeypuckApi( + http: HttpClient, + service: HKPServerInfo, + openpgp: OpenPgpImplementation +) : HKPApi(http, service, openpgp) { + companion object { + const val REQUEST_PATH_DELETE = "$REQUEST_PATH_PREFIX/delete" + const val REQUEST_PATH_REPLACE = "$REQUEST_PATH_PREFIX/replace" + } +} \ No newline at end of file diff --git a/hkp-java/src/main/kotlin/pgp/hkp/OpenPgpImplementation.kt b/hkp-java/src/main/kotlin/pgp/hkp/OpenPgpImplementation.kt new file mode 100644 index 0000000..17f8f3d --- /dev/null +++ b/hkp-java/src/main/kotlin/pgp/hkp/OpenPgpImplementation.kt @@ -0,0 +1,8 @@ +package pgp.hkp + +abstract class OpenPgpImplementation { + + abstract fun hexKeyId(keyId: Long): CharSequence + + abstract fun hexFingerprint(fingerprint: ByteArray): CharSequence +} \ No newline at end of file diff --git a/hkp-java/src/main/kotlin/pgp/hkp/SKSApi.kt b/hkp-java/src/main/kotlin/pgp/hkp/SKSApi.kt new file mode 100644 index 0000000..b46e2ef --- /dev/null +++ b/hkp-java/src/main/kotlin/pgp/hkp/SKSApi.kt @@ -0,0 +1,13 @@ +package pgp.hkp + +import java.net.http.HttpClient + +class SKSApi( + http: HttpClient, + service: HKPServerInfo, + openpgp: OpenPgpImplementation +) : HKPApi(http, service, openpgp) { + companion object { + const val REQUEST_PATH_HASHQUERY = "$REQUEST_PATH_PREFIX/hashquery" + } +} \ No newline at end of file diff --git a/hkp-java/src/main/kotlin/pgp/hkp/operation/Get.kt b/hkp-java/src/main/kotlin/pgp/hkp/operation/Get.kt new file mode 100644 index 0000000..ce3e91a --- /dev/null +++ b/hkp-java/src/main/kotlin/pgp/hkp/operation/Get.kt @@ -0,0 +1,30 @@ +package pgp.hkp.operation + +import pgp.hkp.HKPApi.Companion.OP_GET +import pgp.hkp.HKPServerInfo +import pgp.hkp.OpenPgpImplementation +import java.net.http.HttpClient + +class Get(val http: HttpClient, + val service: HKPServerInfo, + val openpgp: OpenPgpImplementation) { + + fun byKeyId(keyId: Long): LookupRequest { + return LookupRequest(http, service, OP_GET, "0x${openpgp.hexKeyId(keyId)}") + } + + fun byFingerprint(fingerprint: ByteArray): LookupRequest { + return byFingerprint(openpgp.hexFingerprint(fingerprint)) + } + + fun byFingerprint(fingerprint: CharSequence): LookupRequest { + require(fingerprint.length in listOf(32, 40, 64)) { + "Fingerprint strings are either 32 (v3), 40 (v4) or 64 (v6) hexadecimal digits." + } + return LookupRequest(http, service, OP_GET, "0x$fingerprint") + } + + fun byUserId(userId: CharSequence): LookupRequest { + return LookupRequest(http, service, OP_GET, userId.toString()) + } +} \ No newline at end of file diff --git a/hkp-java/src/main/kotlin/pgp/hkp/operation/LookupRequest.kt b/hkp-java/src/main/kotlin/pgp/hkp/operation/LookupRequest.kt new file mode 100644 index 0000000..5d7a6e8 --- /dev/null +++ b/hkp-java/src/main/kotlin/pgp/hkp/operation/LookupRequest.kt @@ -0,0 +1,34 @@ +package pgp.hkp.operation + +import pgp.hkp.HKPApi.Companion.REQUEST_PATH_LOOKUP +import pgp.hkp.HKPApi.Companion.VAR_OP +import pgp.hkp.HKPApi.Companion.VAR_SEARCH +import pgp.hkp.HKPServerInfo +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse +import java.net.http.HttpResponse.BodySubscribers + +class LookupRequest( + val http: HttpClient, + val service: HKPServerInfo, + val op: CharSequence, + val search: CharSequence +) { + + val path: CharSequence + get() = "$REQUEST_PATH_LOOKUP?search=$search&op=$op" + + fun execute() { + val request = HttpRequest.newBuilder(URIBuilder()URI.create("${service.serviceUri}$REQUEST_PATH_LOOKUP")) + .GET() + .(VAR_SEARCH, search.toString()) + .header(VAR_OP, op.toString()) + .build() + + println(request.toString()) + + http.send(request, HttpResponse.BodyHandler {it -> BodySubscribers.ofByteArray()}) + } +} \ No newline at end of file diff --git a/hkp-java/src/test/kotlin/pgp/hkp/HKPApiTest.kt b/hkp-java/src/test/kotlin/pgp/hkp/HKPApiTest.kt new file mode 100644 index 0000000..f73763d --- /dev/null +++ b/hkp-java/src/test/kotlin/pgp/hkp/HKPApiTest.kt @@ -0,0 +1,27 @@ +package pgp.hkp + +import org.junit.jupiter.api.Test +import java.net.URI +import java.net.http.HttpClient +import java.util.HexFormat + +class HKPApiTest { + + @Test + fun test() { + val api = HKPApi(HttpClient.newHttpClient(), + HKPServerInfo(URI.create("http://keys.example.com:11371")), + object : OpenPgpImplementation() { + override fun hexKeyId(keyId: Long): CharSequence { + return keyId.toString(16) + } + + override fun hexFingerprint(fingerprint: ByteArray): CharSequence { + return HexFormat.of().formatHex(fingerprint) + } + } + ) + + api.get().byUserId("Alice").execute() + } +} \ No newline at end of file