Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions src/app/api/index/plot/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,24 +74,31 @@ export async function POST(req: Request) {
decoded.args;

// 4. Fetch content from IPFS (with fallback)
let content: string;
let content: string | null = null;
try {
const ipfsRes = await fetch(`${IPFS_GATEWAY}${contentCID}`, {
signal: AbortSignal.timeout(IPFS_TIMEOUT_MS),
});
if (!ipfsRes.ok) throw new Error(`IPFS status ${ipfsRes.status}`);
content = await ipfsRes.text();
const ipfsContent = await ipfsRes.text();
// Verify IPFS content hash matches on-chain hash
if (hashContent(ipfsContent) === contentHash) {
content = ipfsContent;
}
// If hash mismatches, fall through to fallback content below
} catch {
if (!fallbackContent) {
return error("IPFS fetch failed and no fallback content provided", 502);
// IPFS fetch failed — fall through to fallback content below
}

// 5. Try fallback content if IPFS content was unavailable or hash-mismatched
if (!content && fallbackContent) {
if (hashContent(fallbackContent) === contentHash) {
content = fallbackContent;
}
content = fallbackContent;
}

// 5. Verify content hash
const computedHash = hashContent(content);
if (computedHash !== contentHash) {
return error("Content hash mismatch");
if (!content) {
return error("Content hash mismatch (IPFS and fallback both failed)");
}

// 6. Get block timestamp
Expand Down
28 changes: 16 additions & 12 deletions src/app/api/index/storyline/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,27 +100,31 @@ export async function POST(req: Request) {
const writerType = await detectWriterType(writer);

// 6. Fetch genesis plot content from IPFS (with fallback)
let genesisContent: string;
let genesisContent: string | null = null;
try {
const ipfsRes = await fetch(`${IPFS_GATEWAY}${openingCID}`, {
signal: AbortSignal.timeout(IPFS_TIMEOUT_MS),
});
if (!ipfsRes.ok) throw new Error(`IPFS status ${ipfsRes.status}`);
genesisContent = await ipfsRes.text();
const ipfsContent = await ipfsRes.text();
// Verify IPFS content hash matches on-chain hash
if (hashContent(ipfsContent) === openingHash) {
genesisContent = ipfsContent;
}
// If hash mismatches, fall through to fallback content below
} catch {
if (!fallbackContent) {
return error(
"IPFS fetch failed and no fallback content provided",
502
);
// IPFS fetch failed — fall through to fallback content below
}

// 7. Try fallback content if IPFS content was unavailable or hash-mismatched
if (!genesisContent && fallbackContent) {
if (hashContent(fallbackContent) === openingHash) {
genesisContent = fallbackContent;
}
genesisContent = fallbackContent;
}

// 7. Verify genesis content hash
const computedHash = hashContent(genesisContent);
if (computedHash !== openingHash) {
return error("Genesis content hash mismatch");
if (!genesisContent) {
return error("Genesis content hash mismatch (IPFS and fallback both failed)");
}

// 8. Upsert storyline to Supabase
Expand Down
Loading