diff --git a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsFuseIT.java b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsFuseIT.java index 40c0c1ae..3d516373 100644 --- a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsFuseIT.java +++ b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsFuseIT.java @@ -67,14 +67,14 @@ public class DhfsFuseIT { var c1curl = container1.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c2uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c2uuid); var c2curl = container2.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c1uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c1uuid); waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); diff --git a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsFusex3IT.java b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsFusex3IT.java index 717d11f2..2a91513a 100644 --- a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsFusex3IT.java +++ b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsFusex3IT.java @@ -93,26 +93,26 @@ public class DhfsFusex3IT { var c1curl = container1.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c2uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c2uuid); var c2curl1 = container2.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c1uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c1uuid); var c2curl3 = container2.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c3uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c3uuid); var c3curl = container3.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c2uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c2uuid); waitingConsumer3.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS, 2); waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS, 2); diff --git a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsImage.java b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsImage.java index a4ae3054..9fa434f7 100644 --- a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsImage.java +++ b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/DhfsImage.java @@ -78,6 +78,7 @@ public class DhfsImage implements Future { "-Ddhfs.objects.sync.timeout=30", "-Ddhfs.objects.sync.ping.timeout=5", "-Ddhfs.objects.reconnect_interval=1s", + "-Ddhfs.sync.cert-check=false", "-Dquarkus.log.category.\"com.usatiuk\".level=TRACE", "-Dquarkus.log.category.\"com.usatiuk.dhfs\".level=TRACE", "-Dquarkus.log.category.\"com.usatiuk.objects.transaction\".level=INFO", diff --git a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/KillIT.java b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/KillIT.java index 01eb29ae..93bdf7b8 100644 --- a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/KillIT.java +++ b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/KillIT.java @@ -81,14 +81,14 @@ public class KillIT { var c1curl = container1.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c2uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c2uuid); var c2curl = container2.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c1uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c1uuid); waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); diff --git a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/LazyFsIT.java b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/LazyFsIT.java index f4825cb1..1ed5fd20 100644 --- a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/LazyFsIT.java +++ b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/LazyFsIT.java @@ -93,14 +93,14 @@ public class LazyFsIT { var c1curl = container1.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c2uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/"+c2uuid); var c2curl = container2.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c1uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/"+c1uuid); waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); diff --git a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/ResyncIT.java b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/ResyncIT.java index 398c37cd..ca7871a4 100644 --- a/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/ResyncIT.java +++ b/dhfs-parent/dhfs-app/src/test/java/com/usatiuk/dhfsapp/integration/ResyncIT.java @@ -75,14 +75,14 @@ public class ResyncIT { var c1curl = container1.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c2uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c2uuid); var c2curl = container2.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c1uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c1uuid); waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); @@ -115,14 +115,14 @@ public class ResyncIT { var c1curl = container1.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c2uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c2uuid); var c2curl = container2.execInContainer("/bin/sh", "-c", "curl --header \"Content-Type: application/json\" " + " --request PUT " + - " --data '{\"uuid\":\"" + c1uuid + "\"}' " + - " http://localhost:8080/peers-manage/known-peers"); + " --data '{}' " + + " http://localhost:8080/peers-manage/known-peers/" + c1uuid); waitingConsumer2.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); waitingConsumer1.waitUntil(frame -> frame.getUtf8String().contains("Connected"), 60, TimeUnit.SECONDS); diff --git a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/peersync/PeerManager.java b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/peersync/PeerManager.java index a0788716..a3eafbe6 100644 --- a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/peersync/PeerManager.java +++ b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/peersync/PeerManager.java @@ -2,6 +2,7 @@ package com.usatiuk.dhfs.peersync; import com.usatiuk.dhfs.peerdiscovery.PeerAddress; import com.usatiuk.dhfs.peerdiscovery.PeerDiscoveryDirectory; +import com.usatiuk.dhfs.peersync.api.ApiPeerInfo; import com.usatiuk.dhfs.peersync.api.PeerSyncApiClientDynamic; import com.usatiuk.dhfs.peertrust.PeerTrustManager; import com.usatiuk.dhfs.remoteobj.SyncHandler; @@ -13,11 +14,13 @@ import io.quarkus.logging.Log; import io.quarkus.runtime.StartupEvent; import io.quarkus.scheduler.Scheduled; import io.smallrye.common.annotation.Blocking; +import jakarta.annotation.Nullable; import jakarta.annotation.Priority; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; +import org.apache.commons.lang3.tuple.Pair; import org.eclipse.microprofile.config.inject.ConfigProperty; import java.io.IOException; @@ -47,6 +50,8 @@ public class PeerManager { PeerTrustManager peerTrustManager; @ConfigProperty(name = "dhfs.objects.sync.ping.timeout") long pingTimeout; + @ConfigProperty(name = "dhfs.sync.cert-check", defaultValue = "true") + boolean certCheck; @Inject PeerDiscoveryDirectory peerDiscoveryDirectory; @Inject @@ -185,24 +190,39 @@ public class PeerManager { return peerDiscoveryDirectory.getForPeer(host).stream().min(Comparator.comparing(PeerAddress::type)); } - public void addRemoteHost(PeerId host) { - transactionManager.run(() -> { + private ApiPeerInfo getInfo(PeerId host) { + return transactionManager.run(() -> { if (peerInfoService.getPeerInfo(host).isPresent()) throw new IllegalStateException("Host " + host + " is already added"); var addr = selectBestAddress(host).orElseThrow(() -> new IllegalStateException("Host " + host + " is unreachable")); var info = peerSyncApiClient.getSelfInfo(addr); - var cert = Base64.getDecoder().decode(info.cert()); - peerInfoService.putPeer(host, cert); + return info; + }); + } + + public void addRemoteHost(PeerId host, @Nullable String cert) { + transactionManager.run(() -> { + var info = getInfo(host); + + var certGot = Base64.getDecoder().decode(info.cert()); + if (certCheck) { + var certApi = Base64.getDecoder().decode(cert); + if (!Arrays.equals(certGot, certApi)) + throw new IllegalStateException("Host " + host + " has different cert"); + } + peerInfoService.putPeer(host, certGot); }); peerTrustManager.reloadTrustManagerHosts(transactionManager.run(() -> peerInfoService.getPeers().stream().toList())); //FIXME: } - public Collection getSeenButNotAddedHosts() { + + public Collection> getSeenButNotAddedHosts() { return transactionManager.run(() -> { - return peerDiscoveryDirectory.getReachablePeers().stream().filter(p -> !peerInfoService.getPeerInfo(p).isPresent()).toList(); + return peerDiscoveryDirectory.getReachablePeers().stream().filter(p -> !peerInfoService.getPeerInfo(p).isPresent()) + .map(p -> Pair.of(p, getInfo(p))).toList(); }); } diff --git a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerDelete.java b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerDelete.java deleted file mode 100644 index 735effd7..00000000 --- a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerDelete.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.usatiuk.dhfs.webapi; - -public record KnownPeerDelete(String uuid) { -} diff --git a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerInfo.java b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerInfo.java deleted file mode 100644 index 7b53252c..00000000 --- a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerInfo.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.usatiuk.dhfs.webapi; - -import jakarta.annotation.Nullable; - -public record KnownPeerInfo(String uuid, @Nullable String knownAddress) { -} diff --git a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerPut.java b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerPut.java index 42e33040..7d56b194 100644 --- a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerPut.java +++ b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeerPut.java @@ -1,4 +1,6 @@ package com.usatiuk.dhfs.webapi; -public record KnownPeerPut(String uuid) { +import jakarta.annotation.Nullable; + +public record KnownPeerPut(@Nullable String cert) { } diff --git a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeers.java b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeers.java deleted file mode 100644 index e90a7a93..00000000 --- a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/KnownPeers.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.usatiuk.dhfs.webapi; - -import java.util.List; - -public record KnownPeers(List peers, String selfUuid) { -} diff --git a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/PeerInfo.java b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/PeerInfo.java index c9e7292c..de62ecb7 100644 --- a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/PeerInfo.java +++ b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/PeerInfo.java @@ -1,4 +1,6 @@ package com.usatiuk.dhfs.webapi; -public record PeerInfo(String uuid, String address) { +import jakarta.annotation.Nullable; + +public record PeerInfo(String uuid, String cert, @Nullable String knownAddress) { } diff --git a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/PeerManagementApi.java b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/PeerManagementApi.java index 66a60915..ec74090a 100644 --- a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/PeerManagementApi.java +++ b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/PeerManagementApi.java @@ -5,14 +5,9 @@ import com.usatiuk.dhfs.peersync.PeerInfoService; import com.usatiuk.dhfs.peersync.PeerManager; import com.usatiuk.dhfs.peersync.PersistentPeerDataService; import jakarta.inject.Inject; -import jakarta.ws.rs.DELETE; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.PUT; -import jakarta.ws.rs.Path; +import jakarta.ws.rs.*; -import java.util.Collection; -import java.util.Objects; -import java.util.Optional; +import java.util.*; @Path("/peers-manage") public class PeerManagementApi { @@ -25,43 +20,30 @@ public class PeerManagementApi { @Path("known-peers") @GET - public KnownPeers knownPeers() { - return new KnownPeers(peerInfoService.getPeers().stream().map(peerInfo -> new KnownPeerInfo(peerInfo.id().toString(), - Optional.ofNullable(peerManager.getAddress(peerInfo.id())).map(Objects::toString).orElse(null))).toList(), - persistentPeerDataService.getSelfUuid().toString()); + public List knownPeers() { + return peerInfoService.getPeers().stream().map( + peerInfo -> new PeerInfo(peerInfo.id().toString(), Base64.getEncoder().encodeToString(peerInfo.cert().toByteArray()), + Optional.ofNullable(peerManager.getAddress(peerInfo.id())).map(Objects::toString).orElse(null))).toList(); } - @Path("known-peers") + @Path("known-peers/{peerId}") @PUT - public void addPeer(KnownPeerPut knownPeerPut) { - peerManager.addRemoteHost(PeerId.of(knownPeerPut.uuid())); + public void addPeer(@PathParam("peerId") String peerId, KnownPeerPut knownPeerPut) { + peerManager.addRemoteHost(PeerId.of(peerId), knownPeerPut.cert()); } - @Path("known-peers") + @Path("known-peers/{peerId}") @DELETE - public void deletePeer(KnownPeerDelete knownPeerDelete) { - peerManager.removeRemoteHost(PeerId.of(knownPeerDelete.uuid())); + public void deletePeer(@PathParam("peerId") String peerId) { + peerManager.removeRemoteHost(PeerId.of(peerId)); } @Path("available-peers") @GET - public Collection availablePeers() { + public Collection availablePeers() { return peerManager.getSeenButNotAddedHosts().stream() - .map(p -> new KnownPeerInfo(p.toString(), - peerManager.selectBestAddress(p).map(Objects::toString).orElse(null))) + .map(p -> new PeerInfo(p.getLeft().toString(), p.getRight().cert(), + peerManager.selectBestAddress(p.getLeft()).map(Objects::toString).orElse(null))) .toList(); } - - @Path("peer-state") - @GET - public Collection peerInfos(Collection peerIdStrings) { - return peerIdStrings.stream().map(PeerId::of).map( - peerId -> { - return new PeerInfo( - peerId.toString(), - peerManager.getAddress(peerId).toString() - ); - } - ).toList(); - } } diff --git a/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/SelfInfo.java b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/SelfInfo.java new file mode 100644 index 00000000..1eff4e1f --- /dev/null +++ b/dhfs-parent/sync-base/src/main/java/com/usatiuk/dhfs/webapi/SelfInfo.java @@ -0,0 +1,4 @@ +package com.usatiuk.dhfs.webapi; + +public record SelfInfo(String uuid, String cert) { +} diff --git a/webui/src/PeerAvailableCard.tsx b/webui/src/PeerAvailableCard.tsx index 22a9fe1d..9a5f4cd0 100644 --- a/webui/src/PeerAvailableCard.tsx +++ b/webui/src/PeerAvailableCard.tsx @@ -2,6 +2,7 @@ import { TAvailablePeerInfoTo } from "./api/dto"; import { useFetcher } from "react-router-dom"; import "./PeerAvailableCard.scss"; +import { hashCert } from "./hash"; export interface TPeerAvailableCardProps { peerInfo: TAvailablePeerInfoTo; @@ -16,6 +17,9 @@ export function PeerAvailableCard({ peerInfo }: TPeerAvailableCardProps) { UUID: {peerInfo.uuid} +
+ Cert: {hashCert(peerInfo.cert)} +
connect + ); diff --git a/webui/src/PeerKnownCard.tsx b/webui/src/PeerKnownCard.tsx index cc5764f8..b963fa80 100644 --- a/webui/src/PeerKnownCard.tsx +++ b/webui/src/PeerKnownCard.tsx @@ -4,6 +4,7 @@ import "./PeerKnownCard.scss"; import { useFetcher, useLoaderData } from "react-router-dom"; import { LoaderToType } from "./commonPlumbing"; import { peerStateLoader } from "./PeerStatePlumbing"; +import { hashCert } from "./hash"; export interface TPeerKnownCardProps { peerInfo: TKnownPeerInfoTo; @@ -32,6 +33,9 @@ export function PeerKnownCard({ peerInfo }: TPeerKnownCardProps) { : "not connected"} +
+ Cert: {hashCert(peerInfo.cert)} +
diff --git a/webui/src/PeerState.tsx b/webui/src/PeerState.tsx index bc1517bc..cc135f6b 100644 --- a/webui/src/PeerState.tsx +++ b/webui/src/PeerState.tsx @@ -4,12 +4,13 @@ import { LoaderToType } from "./commonPlumbing"; import { peerStateLoader } from "./PeerStatePlumbing"; import { PeerAvailableCard } from "./PeerAvailableCard"; import { PeerKnownCard } from "./PeerKnownCard"; +import { hashCert } from "./hash"; export function PeerState() { const loaderData = useLoaderData() as LoaderToType; - const knownPeers = loaderData.knownPeers.peers - ?.filter((p) => p.uuid !== loaderData.knownPeers.selfUuid) + const knownPeers = loaderData.knownPeers + ?.filter((p) => p.uuid !== loaderData.selfInfo.selfUuid) ?.map((p) => ); const availablePeers = loaderData.availablePeers.map((p) => ( @@ -18,7 +19,8 @@ export function PeerState() { return (
-
Self UUID: {loaderData.knownPeers.selfUuid}
+
UUID: {loaderData.selfInfo.selfUuid}
+
Certificate: {hashCert(loaderData.selfInfo.cert)}
Known peers
{knownPeers}
diff --git a/webui/src/PeerStatePlumbing.ts b/webui/src/PeerStatePlumbing.ts index b864ffca..96d9d5e0 100644 --- a/webui/src/PeerStatePlumbing.ts +++ b/webui/src/PeerStatePlumbing.ts @@ -2,6 +2,7 @@ import { getAvailablePeers, getKnownPeers, getPeerAddresses, + getSelfInfo, putKnownPeer, putPeerAddress, removeKnownPeer, @@ -10,6 +11,7 @@ import { ActionFunctionArgs } from "react-router-dom"; export async function peerStateLoader() { return { + selfInfo: await getSelfInfo(), availablePeers: await getAvailablePeers(), knownPeers: await getKnownPeers(), peerAddresses: await getPeerAddresses(), @@ -26,7 +28,10 @@ export async function peerStateAction({ request }: ActionFunctionArgs) { const formData = await request.formData(); const intent = formData.get("intent") as PeerStateActionType; if (intent === "add_peer") { - return await putKnownPeer(formData.get("uuid") as string); + return await putKnownPeer( + formData.get("uuid") as string, + formData.get("cert") as string, + ); } else if (intent === "remove_peer") { return await removeKnownPeer(formData.get("uuid") as string); } else if (intent === "save_addr") { diff --git a/webui/src/api/PeerState.ts b/webui/src/api/PeerState.ts index 3c5bb399..1ccaf0fc 100644 --- a/webui/src/api/PeerState.ts +++ b/webui/src/api/PeerState.ts @@ -4,15 +4,26 @@ import { KnownPeersToResp, NoContentToResp, PeerAddressInfoToResp, + SelfInfoToResp, TAvailablePeerInfoArrTo, TAvailablePeerInfoToResp, - TKnownPeerInfoArrTo, TKnownPeersTo, + TKnownPeersTo, TKnownPeersToResp, TNoContentToResp, TPeerAddressInfoArrTo, TPeerAddressInfoToResp, + TSelfInfoTo, + TSelfInfoToResp, } from "./dto"; +export async function getSelfInfo(): Promise { + return fetchJSON_throws( + "/peer-info/self", + "GET", + SelfInfoToResp, + ); +} + export async function getAvailablePeers(): Promise { return fetchJSON_throws< TAvailablePeerInfoToResp, @@ -28,16 +39,27 @@ export async function getKnownPeers(): Promise { ); } -export async function putKnownPeer(uuid: string): Promise { - return fetchJSON("/peers-manage/known-peers", "PUT", NoContentToResp, { - uuid, - }); +export async function putKnownPeer( + uuid: string, + cert: string, +): Promise { + return fetchJSON( + `/peers-manage/known-peers/${uuid}`, + "PUT", + NoContentToResp, + { + cert, + }, + ); } export async function removeKnownPeer(uuid: string): Promise { - return fetchJSON("/peers-manage/known-peers", "DELETE", NoContentToResp, { - uuid, - }); + return fetchJSON( + `/peers-manage/known-peers/${uuid}`, + "DELETE", + NoContentToResp, + {}, + ); } export async function getPeerAddresses(): Promise { diff --git a/webui/src/api/dto.ts b/webui/src/api/dto.ts index f893a623..39c1d81b 100644 --- a/webui/src/api/dto.ts +++ b/webui/src/api/dto.ts @@ -36,13 +36,28 @@ export type TTokenTo = z.infer; export const TokenToResp = CreateAPIResponse(TokenTo); export type TTokenToResp = z.infer; -// AvailablePeerInfo -export const AvailablePeerInfoTo = z.object({ +// SelfInfo + +export const SelfInfoTo = z.object({ + selfUuid: z.string(), + cert: z.string(), +}); +export type TSelfInfoTo = z.infer; + +export const SelfInfoToResp = CreateAPIResponse(SelfInfoTo); +export type TSelfInfoToResp = z.infer; + +// PeerInfo + +export const PeerInfoTo = z.object({ uuid: z.string(), knownAddress: z.string().optional(), - // addr: z.string(), - // port: z.number(), + cert: z.string(), }); +export type TPeerInfoTo = z.infer; + +// AvailablePeerInfo +export const AvailablePeerInfoTo = PeerInfoTo; export type TAvailablePeerInfoTo = z.infer; export const AvailablePeerInfoArrTo = z.array(AvailablePeerInfoTo); @@ -54,19 +69,13 @@ export const AvailablePeerInfoToResp = CreateAPIResponse( export type TAvailablePeerInfoToResp = z.infer; // KnownPeerInfo -export const KnownPeerInfoTo = z.object({ - uuid: z.string(), - knownAddress: z.string().optional(), -}); +export const KnownPeerInfoTo = PeerInfoTo; export type TKnownPeerInfoTo = z.infer; export const KnownPeerInfoArrTo = z.array(KnownPeerInfoTo); export type TKnownPeerInfoArrTo = z.infer; -export const KnownPeersTo = z.object({ - selfUuid: z.string(), - peers: KnownPeerInfoArrTo, -}); +export const KnownPeersTo = KnownPeerInfoArrTo; export type TKnownPeersTo = z.infer; export const KnownPeersToResp = CreateAPIResponse(KnownPeersTo); @@ -86,9 +95,9 @@ export const PeerAddressInfoToResp = CreateAPIResponse(PeerAddressInfoArrTo); export type TPeerAddressInfoToResp = z.infer; // KnownPeerPut -export const KnownPeerPutTo = z.object({ uuid: z.string() }); +export const KnownPeerPutTo = z.object({ cert: z.string() }); export type TKnownPeerPutTo = z.infer; // KnownPeerDelete -export const KnownPeerDeleteTo = z.object({ uuid: z.string() }); +export const KnownPeerDeleteTo = NoContentTo; export type TKnownPeerDeleteTo = z.infer; diff --git a/webui/src/hash.ts b/webui/src/hash.ts new file mode 100644 index 00000000..2894edf0 --- /dev/null +++ b/webui/src/hash.ts @@ -0,0 +1,7 @@ +export async function hashCert(cert: string) { + const hash = await crypto.subtle.digest( + "SHA-1", + new TextEncoder().encode(cert), + ); + return btoa(String.fromCharCode(...new Uint8Array(hash))); +}