Check bare RIDs against already seeded repos

The seed form accepts a RID without the rad: prefix but compared it as
typed against lists that have the prefix, so duplicates got through.
This commit is contained in:
Rūdolfs Ošiņš
2026-10-01 18:20:24 +02:00
parent 56e495ba8d
commit 5b3bc10a06
3 changed files with 71 additions and 25 deletions
+17 -25
View File
@@ -9,8 +9,9 @@
import { nodeRunning } from "@app/lib/events";
import { invoke } from "@app/lib/invoke";
import { seedTarget } from "@app/lib/seedRepo";
import useLocalStorage from "@app/lib/useLocalStorage.svelte";
import { parseRepositoryId, twemoji } from "@app/lib/utils";
import { twemoji } from "@app/lib/utils";
import { announce } from "@app/components/AnnounceSwitch.svelte";
import Button from "@app/components/Button.svelte";
@@ -56,20 +57,25 @@
);
async function submit() {
const trimmedRid = rid.trim();
if (trimmedRid === "") {
if (rid.trim() === "") {
return;
}
validationMessage = validate(trimmedRid);
if (validationMessage === undefined) {
await seed(trimmedRid);
await reload();
rid = "";
closeFocused();
const target = seedTarget(
rid,
seededNotReplicated,
repos.map(r => r.rid),
);
if ("error" in target) {
validationMessage = target.error;
return;
}
validationMessage = undefined;
await seed(target.rid);
await reload();
rid = "";
closeFocused();
}
async function seed(rid: string) {
@@ -82,20 +88,6 @@
console.error("Seeding failed", error);
}
}
function validate(rid: string): string | undefined {
const parsedRid = parseRepositoryId(rid);
if (parsedRid === undefined) {
return "RID is not valid";
}
if (seededNotReplicated.includes(rid)) {
return "This repo is already queued for fetching";
}
if (repos.map(r => r.rid).includes(rid)) {
return "This repo is already seeded";
}
}
</script>
<style>
+23
View File
@@ -0,0 +1,23 @@
import { parseRepositoryId } from "@app/lib/utils";
// Validates a RID typed into the "Seed a repo" form. The form accepts a bare
// `z…` id as well as `rad:z…`, so the result is the RID in the `rad:` form the
// seeded and queued lists use.
export function seedTarget(
input: string,
queued: string[],
seeded: string[],
): { rid: string } | { error: string } {
const parsed = parseRepositoryId(input.trim());
if (parsed === undefined) {
return { error: "RID is not valid" };
}
const rid = `${parsed.prefix}${parsed.pubkey}`;
if (queued.includes(rid)) {
return { error: "This repo is already queued for fetching" };
}
if (seeded.includes(rid)) {
return { error: "This repo is already seeded" };
}
return { rid };
}
+31
View File
@@ -0,0 +1,31 @@
import { describe, expect, test } from "vitest";
import { seedTarget } from "@app/lib/seedRepo";
const rid = "rad:z3fpY7nttPPa6MBnAv2DccHzQJnqe";
const bare = "z3fpY7nttPPa6MBnAv2DccHzQJnqe";
describe("seedTarget", () => {
test.each([rid, bare, ` ${rid} `])("accepts %j as %j", input => {
expect(seedTarget(input, [], [])).toEqual({ rid });
});
test.each(["", "rad:", "rad:z0OIl", "not a rid", "rad:zabc"])(
"rejects %j",
input => {
expect(seedTarget(input, [], [])).toEqual({ error: "RID is not valid" });
},
);
test.each([rid, bare])("reports %j as already queued", input => {
expect(seedTarget(input, [rid], [])).toEqual({
error: "This repo is already queued for fetching",
});
});
test.each([rid, bare])("reports %j as already seeded", input => {
expect(seedTarget(input, [], [rid])).toEqual({
error: "This repo is already seeded",
});
});
});