openvibers/openvibe.community Commits
Pastes: the guarded screenshot address, never Media's private object URL (broken images) (#273)
Changes
@@@ -313,7 +313,7 @@ function createForumService({ db, network = null, pulse = null, relay = null, vifor (const r of rows) {const lines = String(r.content || '').split('\n');if (!out.has(r.post_id)) out.set(r.post_id, []);-- out.get(r.post_id).push({ slug: r.slug, title: r.title, language: r.language || 'text', type: r.type, url: `/p/${r.slug}`, screenshot_url: r.type === 'screenshot' ? r.screenshot_url : null,++ out.get(r.post_id).push({ slug: r.slug, title: r.title, language: r.language || 'text', type: r.type, url: `/p/${r.slug}`, screenshot_url: r.type === 'screenshot' && r.screenshot_url ? `/p/${encodeURIComponent(r.slug)}/screenshot` : null,lines: r.content ? lines.length : 0, excerpt: r.type === 'screenshot' ? null : lines.slice(0, 12).join('\n').slice(0, 1500) });}return out;@@@ -252,7 +252,10 @@ function createPasteService({ db, network = null, media = null, config = {}, limenvelope_url: locked ? `/p/${encodeURIComponent(p.slug)}/raw` : null,stream_id: streamIdOf(ref),stream_ref: ref,-- screenshot_url: p.screenshot_url || null,++ // The guarded address, never Media's own object URL: screenshots are stored private in Media (the share++ // rules decide who sees one), so /o/<id> is a 404 to every browser. /p/<slug>/screenshot checks the paste's++ // audience and streams the bytes (2026-11-07: every image paste and AI moment on openvibe.live was broken).++ screenshot_url: p.screenshot_url && !locked ? `${site || ''}/p/${encodeURIComponent(p.slug)}/screenshot` : null,metadata: metadataFor(p.metadata, isOwner(v, p) || isService(v)),burn_after_read: !!p.burn_after_read,forked_from: p.forked_from || null,@@@ -273,7 +273,9 @@ const { boot, check, done } = require('./helpers/app');assert.strictEqual(p.owner_subject, alex.subject_id);assert.ok(up.v2 && up.kind === 'screenshot' && up.visibility === 'private', 'a v2 Media object: private screenshot');assert.strictEqual(up.owner, alex.subject_id, 'owned by the person');-- assert.strictEqual(p.screenshot_url, `https://openvibe.media/o/${up.key}`);++ // The object is private in Media, so the answer names the guarded address, never Media's /o/<id> (a 404 to a browser).++ assert.ok(/\/p\/[a-z0-9-]+\/screenshot$/.test(p.screenshot_url) && p.screenshot_url.endsWith(`/p/${p.slug}/screenshot`), p.screenshot_url);++ assert.ok(!p.screenshot_url.includes('/o/'), 'never the Media object URL');assert.strictEqual(p.title, 'My desk');assert.strictEqual(p.content, 'look');const meta = JSON.parse(p.metadata);
@@ -313,7 +313,7 @@ function createForumService({ db, network = null, pulse = null, relay = null, vi
@@ -313,7 +313,7 @@ function createForumService({ db, network = null, pulse = null, relay = null, vi
for (const r of rows) {
for (const r of rows) {
const lines = String(r.content || '').split('\n');
const lines = String(r.content || '').split('\n');
if (!out.has(r.post_id)) out.set(r.post_id, []);
if (!out.has(r.post_id)) out.set(r.post_id, []);
- out.get(r.post_id).push({ slug: r.slug, title: r.title, language: r.language || 'text', type: r.type, url: `/p/${r.slug}`, screenshot_url: r.type === 'screenshot' ? r.screenshot_url : null,
+ out.get(r.post_id).push({ slug: r.slug, title: r.title, language: r.language || 'text', type: r.type, url: `/p/${r.slug}`, screenshot_url: r.type === 'screenshot' && r.screenshot_url ? `/p/${encodeURIComponent(r.slug)}/screenshot` : null,
lines: r.content ? lines.length : 0, excerpt: r.type === 'screenshot' ? null : lines.slice(0, 12).join('\n').slice(0, 1500) });
lines: r.content ? lines.length : 0, excerpt: r.type === 'screenshot' ? null : lines.slice(0, 12).join('\n').slice(0, 1500) });
}
}
return out;
return out;
@@ -252,7 +252,10 @@ function createPasteService({ db, network = null, media = null, config = {}, lim
@@ -252,7 +252,10 @@ function createPasteService({ db, network = null, media = null, config = {}, lim
envelope_url: locked ? `/p/${encodeURIComponent(p.slug)}/raw` : null,
envelope_url: locked ? `/p/${encodeURIComponent(p.slug)}/raw` : null,
stream_id: streamIdOf(ref),
stream_id: streamIdOf(ref),
stream_ref: ref,
stream_ref: ref,
- screenshot_url: p.screenshot_url || null,
+ // The guarded address, never Media's own object URL: screenshots are stored private in Media (the share
+ // rules decide who sees one), so /o/<id> is a 404 to every browser. /p/<slug>/screenshot checks the paste's
+ // audience and streams the bytes (2026-11-07: every image paste and AI moment on openvibe.live was broken).
+ screenshot_url: p.screenshot_url && !locked ? `${site || ''}/p/${encodeURIComponent(p.slug)}/screenshot` : null,
metadata: metadataFor(p.metadata, isOwner(v, p) || isService(v)),
metadata: metadataFor(p.metadata, isOwner(v, p) || isService(v)),
burn_after_read: !!p.burn_after_read,
burn_after_read: !!p.burn_after_read,
forked_from: p.forked_from || null,
forked_from: p.forked_from || null,
@@ -273,7 +273,9 @@ const { boot, check, done } = require('./helpers/app');
@@ -273,7 +273,9 @@ const { boot, check, done } = require('./helpers/app');
assert.strictEqual(p.owner_subject, alex.subject_id);
assert.strictEqual(p.owner_subject, alex.subject_id);
assert.ok(up.v2 && up.kind === 'screenshot' && up.visibility === 'private', 'a v2 Media object: private screenshot');
assert.ok(up.v2 && up.kind === 'screenshot' && up.visibility === 'private', 'a v2 Media object: private screenshot');
assert.strictEqual(up.owner, alex.subject_id, 'owned by the person');
assert.strictEqual(up.owner, alex.subject_id, 'owned by the person');
- assert.strictEqual(p.screenshot_url, `https://openvibe.media/o/${up.key}`);
+ // The object is private in Media, so the answer names the guarded address, never Media's /o/<id> (a 404 to a browser).
+ assert.ok(/\/p\/[a-z0-9-]+\/screenshot$/.test(p.screenshot_url) && p.screenshot_url.endsWith(`/p/${p.slug}/screenshot`), p.screenshot_url);
+ assert.ok(!p.screenshot_url.includes('/o/'), 'never the Media object URL');
assert.strictEqual(p.title, 'My desk');
assert.strictEqual(p.title, 'My desk');
assert.strictEqual(p.content, 'look');
assert.strictEqual(p.content, 'look');
const meta = JSON.parse(p.metadata);
const meta = JSON.parse(p.metadata);