Browse Source
Nostr-Signature: d7ee36680a38fac493b27fba26d6e1c496dee9a3099db68a4352f7709a41e860 573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc 071cc8031940590785e5566a45159e5324e36e8a06023282ab1d50b608902d3b06d95efc03d0a4da861a88f12381f7b64999c09a49dfe5f36fbd8ec6aefd8aebmain
10 changed files with 518 additions and 235 deletions
@ -1,19 +0,0 @@
@@ -1,19 +0,0 @@
|
||||
{"kind":1,"created_at":1771510311,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"0975c5cb65ed1189c9979026c13b93d3c2a40a21eb0bf43f6ca8bdccf7f7712f","sig":"e3309b47df9ccba4ce46722399d8d670abd8e847cf7d940188c67d5e8aee9e7d8498c9fb984174667c9ee71086fbf5a97377c713bee76f109fd212d478d88d75"} |
||||
{"kind":1,"created_at":1771510473,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"34181f7b81d8b7861b7a560862835103325debb8c29ef77985a2f0e56d0c5262","sig":"38a5c7fd3d294bee72bc9c3b81d13ff6e578cb9c0ebf892df37f8123174c854b4b823ae6fd7b3b877db9b7d6232361117c6a6f487016850cbe83a89508cbb524"} |
||||
{"kind":1,"created_at":1771510682,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"5e1268762622dc55284555b29b5615d85daac2d4cd501be4e350b5b67131f24b","sig":"ef3b6aff41ccf54631d0f4df3b82822bc7d2448b0b5a4a0b341407068750348a510ec89f9f93de5134598655adb8d061d1ae16fa129f66c2c9b7d8ef164e89b8"} |
||||
{"kind":1,"created_at":1771511465,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"56a1cb556357f061c6fc0796b2e94adcc7d7765150788a08c71757a267be3350","sig":"6c6c5cfbdcf5d992c690960928a1498bd0d778370d27bed72bac5c543cf53966a13eeeb2c1d61998f877076745f3defecf0f91eed84bcdbd2fa7ee0f24b9840c"} |
||||
{"kind":1,"created_at":1771511472,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"0abdba9ee73550f9c72b001977b07a71883100b73761f685575b090f41fb51bc","sig":"25a1f5849e94b33e06e2f90740efe92d4a8338b275d0ff6ad723e51018b2bbeeb16dd7da8c30b38f6205d3836aaf1006cdd21a88d73dfea5a78ab91f88cf0d33"} |
||||
{"kind":1,"created_at":1771511567,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"b7d48b0da85b481a8b3511988112a3cc55b32676e5e54f73f11d4204d1867ddd","sig":"675f23a0fab00bb89c37f35171e314d8550917c871309ef29529866bab2d64ecfbfcea5f2e3e84ff9819a44b1ecbb98624479ec9012c059dc4b72ca25c8f1bd0"} |
||||
{"kind":1,"created_at":1771512222,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"be185e7ee45a6651cba2586c1dbea1f82e1c656175a58619e9f252e997c66cd6","sig":"adf7cd122f65dbe0a505d35d536ca488d39367ad0bdbb154c73b909182183e0e207b6be470e79fb2ea72a0834b74dcc96697c7c7845726cdab06c6f8bf5cc5ce"} |
||||
{"kind":1,"created_at":1771512397,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"f8198dba67d77e0ea99edcc54164a3b05c624588643189626fb54a66073971dd","sig":"f240f5c6cb0497010e6da38cb0771c1b161e10c6126ba4e47820e2838b273fedf91bbd91558e172e3a1be94e868a75ff4e5139aac66d25220ab4083cbe9bda63"} |
||||
{"kind":1,"created_at":1771512543,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"56b95e20d0d89c4e04f2ce970d982a3cf4eb843c7c494d5c3363d13474eae98f","sig":"46d0d0de245ecc98b54da628bd850369d06a16a9ef7f48cdada086192e0e3e7453e2bf98244b21ab78d1446478f442c3697c87d025713c79555c7332a8158d3d"} |
||||
{"kind":1,"created_at":1771512613,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"559c879a68c63bf1257950b8bdc118b8b30647c192292a044afa1efe48497d4e","sig":"b7ddfaef7f7630583c84b6c2b17768b9899dd44c54482d8bca9a11a78e9ede78e02cce3bc119754951d8c962c24b5a2481977f7ebb9f1a720c3d1f9f225c0111"} |
||||
{"kind":1,"created_at":1771512886,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"e733144129fbe2cabbfee223d3b908d7411bcbe2a43cb8e60e77a14b5035aa0a","sig":"1bc994286b401b6ee5fc91ce5819048b5b5980ced9519cafee53c99011f1bcc6c47072eb548005ec87131d49cd13a2dbeca333230fff778ab266badc231f2c33"} |
||||
{"kind":1,"created_at":1771512960,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"cafa43b36d5301c1cfc744f9b7e01a95cd695c43c0d54f1a6fc2aef81befb115","sig":"3a5f95f21bae716556697d12710f28f73f1dad27b6be48ae1f6d12f7983c03fa1aa1adbdafe96dbf0b716621443deb686bb5f9775319ad132b55859a258d8533"} |
||||
{"kind":1,"created_at":1771513111,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"ea0d419686ffcd3cdb41f16c184abd4d83bb8ee24452828bac8fda4b4df2ba80","sig":"96292550f3d375d906a495fd84f9465c059296aacaede47cd4dadee26c9a74b627c996c608f8d00a5c0238b6c744319f2920f1afd55d07dde0abf662c598aa82"} |
||||
{"kind":1,"created_at":1771513431,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"d8584d4c8acf886a8d6bbd4426364e4a4aeefcfb6cb0a6ed1424c1dfb1faabc8","sig":"246f2c15c26ce811a6ecda27d3a48e6e82a27de232752187795aca46b01ae158e1d24e2902fe65201f47224b16905d71abdd20ff5846fd0fd6ae8f1ecf6bc52e"} |
||||
{"kind":1,"created_at":1771513536,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"70eff91c6f1842c2e8de975ee8286c2da9cbf1c00d61a886c37340ed2511912b","sig":"9a20af5c64b6092f44f58a8e2814a3a79da5fe9770397927e86b3f8fa100a24061388274530014dcbc26b4672c33a88792cd0a52c6926ef08e11ccef7d0fcffe"} |
||||
{"kind":1,"created_at":1771513628,"tags":[["client","gitrepublic-cli"]],"content":"Published from gitrepublic CLI.","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"8b5565bf6d15f8e0ed551fd42fe1ae3c7edf02a6053d1b52aad379c63d609b27","sig":"ac513f9262e69c5b51a92efa4ebd49806f3af8db2621cb4aaf97a9b4c6bb270e8ea8d2f20e03471b3834433699e68477ce7e7fc7e8787137440f38656c5314f7"} |
||||
{"kind":1,"created_at":1771514350,"tags":[["client","gitrepublic-cli"]],"content":"After refactor","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"fb1dc615ba763665868d9c99ee1c3dc332e4628e527879b74c80e4ef567a4c6f","sig":"f17c7815431b16d0273524d37e66f0ccf93c7107cd931fe8fe3c2ab3a3421cb82c07c165efeccea5bfa927ff000087ab503ee4669f1324a3acee74b2c51786e7"} |
||||
{"kind":1,"created_at":1771514466,"tags":[["client","gitrepublic-cli"]],"content":"After refactor","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"55c904f2a2b03363f456cb3fcacf3a3e37fe42119228f1c221bcf45ff55746fc","sig":"40a7840007c4b4d538be853f22ae431296bd01929d25a3110508a6f601648c7a4b1f60cebf77bd58632edaf903a47f736ef145ae83d40947532636215f3edee3"} |
||||
{"kind":1,"created_at":1771514648,"tags":[["client","gitrepublic-cli"]],"content":"After refactor","pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","id":"1f450a0aa75cdfded2452febd6b389a22e18fc55054a67a7792ade5fbccdf821","sig":"b1eab9ad0a04694c465c22141b28d841badec8bf220a1fb2bd1dcfb24e47d1fbdd1eaa46d8916c7c9d7c703e5e44dd117092c7ae6949d4a7e2736711112958dd"} |
||||
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
/** |
||||
* API endpoint for validating repository announcements |
||||
* Checks if repo has valid announcement in nostr/repo-events.jsonl and on relays |
||||
*/ |
||||
|
||||
import { json, error } from '@sveltejs/kit'; |
||||
import type { RequestHandler } from './$types'; |
||||
import { createRepoGetHandler } from '$lib/utils/api-handlers.js'; |
||||
import type { RepoRequestContext } from '$lib/utils/api-context.js'; |
||||
import { fileManager, nostrClient } from '$lib/services/service-registry.js'; |
||||
import { validateAnnouncementEvent } from '$lib/services/nostr/repo-verification.js'; |
||||
import { KIND } from '$lib/types/nostr.js'; |
||||
import { requireNpubHex } from '$lib/utils/npub-utils.js'; |
||||
import type { NostrEvent } from '$lib/types/nostr.js'; |
||||
import logger from '$lib/services/logger.js'; |
||||
|
||||
/** |
||||
* GET - Validate repository announcement |
||||
* Checks: |
||||
* - Announcement exists in repo (nostr/repo-events.jsonl) |
||||
* - Announcement exists on relays |
||||
* - Announcement signature is valid |
||||
* - Announcement matches repo (d-tag matches repo name) |
||||
*/ |
||||
export const GET: RequestHandler = createRepoGetHandler( |
||||
async (context: RepoRequestContext) => { |
||||
const { npub, repo } = context; |
||||
const repoOwnerPubkey = requireNpubHex(npub); |
||||
|
||||
// Check if repo exists
|
||||
if (!fileManager.repoExists(npub, repo)) { |
||||
return json({ |
||||
valid: false, |
||||
error: 'Repository not found', |
||||
inRepo: false, |
||||
onRelays: false |
||||
}); |
||||
} |
||||
|
||||
let inRepo = false; |
||||
let onRelays = false; |
||||
let repoAnnouncement: NostrEvent | null = null; |
||||
let relayAnnouncement: NostrEvent | null = null; |
||||
let validationError: string | undefined; |
||||
|
||||
// Check announcement in repo (nostr/repo-events.jsonl)
|
||||
try { |
||||
const repoEventsFile = await fileManager.getFileContent(npub, repo, 'nostr/repo-events.jsonl', 'HEAD'); |
||||
const lines = repoEventsFile.content.trim().split('\n').filter(Boolean); |
||||
let latestTimestamp = 0; |
||||
|
||||
for (const line of lines) { |
||||
try { |
||||
const entry = JSON.parse(line); |
||||
if (entry.type === 'announcement' && entry.event && entry.timestamp) { |
||||
if (entry.timestamp > latestTimestamp) { |
||||
latestTimestamp = entry.timestamp; |
||||
repoAnnouncement = entry.event; |
||||
} |
||||
} |
||||
} catch { |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
if (repoAnnouncement) { |
||||
inRepo = true; |
||||
} |
||||
} catch (err) { |
||||
logger.debug({ error: err, npub, repo }, 'Failed to read announcement from repo'); |
||||
} |
||||
|
||||
// Check announcement on relays
|
||||
try { |
||||
const events = await nostrClient.fetchEvents([ |
||||
{ |
||||
kinds: [KIND.REPO_ANNOUNCEMENT], |
||||
authors: [repoOwnerPubkey], |
||||
'#d': [repo], |
||||
limit: 1 |
||||
} |
||||
]); |
||||
|
||||
if (events.length > 0) { |
||||
relayAnnouncement = events[0]; |
||||
onRelays = true; |
||||
} |
||||
} catch (err) { |
||||
logger.debug({ error: err, npub, repo }, 'Failed to fetch announcement from relays'); |
||||
} |
||||
|
||||
// Use repo announcement if available, otherwise use relay announcement
|
||||
const announcement = repoAnnouncement || relayAnnouncement; |
||||
|
||||
if (!announcement) { |
||||
return json({ |
||||
valid: false, |
||||
error: 'No announcement found in repo or on relays', |
||||
inRepo: false, |
||||
onRelays: false |
||||
}); |
||||
} |
||||
|
||||
// Validate the announcement
|
||||
const validation = validateAnnouncementEvent(announcement, repo); |
||||
if (!validation.valid) { |
||||
validationError = validation.error; |
||||
} |
||||
|
||||
// Check if announcements match (if both exist)
|
||||
let announcementsMatch = true; |
||||
if (repoAnnouncement && relayAnnouncement) { |
||||
announcementsMatch = repoAnnouncement.id === relayAnnouncement.id; |
||||
} |
||||
|
||||
return json({ |
||||
valid: validation.valid && announcementsMatch, |
||||
error: validationError || (announcementsMatch ? undefined : 'Announcements in repo and on relays do not match'), |
||||
inRepo, |
||||
onRelays, |
||||
announcementsMatch: repoAnnouncement && relayAnnouncement ? announcementsMatch : undefined, |
||||
announcementId: announcement.id, |
||||
announcementPubkey: announcement.pubkey, |
||||
announcementCreatedAt: announcement.created_at, |
||||
repoAnnouncementId: repoAnnouncement?.id, |
||||
relayAnnouncementId: relayAnnouncement?.id |
||||
}); |
||||
}, |
||||
{ operation: 'validateRepo', requireRepoAccess: false } // Validation is public
|
||||
); |
||||
Loading…
Reference in new issue