openvibers/openvibe.live Commits

Pastes: request your own unlisted pastes when viewing your own page

OP OpenVibers committed 19 Aug 2026 · 6d3fde7c3f · 1 file, +12 −3

/pastes/by-user/:username had no auth at all, so it could never tell the owner
from a visitor and always asked Media for public pastes only. Your own unlisted
pastes were therefore missing from your own paste list.

Add optionalAuth and send include_unlisted when the requester IS that user
(matching either the local id or the linked network id, since browser-created
pastes carry the network id while migrated rows carry the local one). Media
re-checks ownership, so the flag alone cannot leak someone else's pastes.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Xw6Sf5zzSALw8m93XNu5JE

Changes

ddiff --git a/server/media-proxy/pastes.js b/server/media-proxy/pastes.js
iindex 9ab2f6c0..58b91025 100644
---- a/server/media-proxy/pastes.js
++++ b/server/media-proxy/pastes.js
@@@ -134,7 +134,7 @@ router.post('/bulk', requireAdmin, forwardAsApp('/bulk'));
// Media doesn't know usernames — resolve locally, then list by user id.
// Browser-JWT-created pastes carry the NETWORK id while migrated/app-key rows
// carry the LOCAL id, so query both id spaces and merge.
--router.get('/by-user/:username', async (req, res) => {
++router.get('/by-user/:username', optionalAuth, async (req, res) => {
try {
const user = db.getUserByUsername(req.params.username);
if (!user) return res.status(404).json({ error: 'User not found' });
@@@ -145,10 +145,19 @@ router.get('/by-user/:username', async (req, res) => {
} catch { /* */ }
const limit = Math.min(Math.max(parseInt(req.query.limit || '30', 10), 1), 100);
const sort = req.query.sort === 'oldest' ? 'oldest' : 'newest';
++ // Viewing your OWN paste list includes your unlisted/private ones — otherwise an
++ // unlisted paste is invisible everywhere and looks like it was never created.
++ // Anyone else viewing this user's page still sees public pastes only. Media
++ // re-checks this, so the flag alone cannot leak another user's pastes.
++ const viewingSelf = !!(req.user && (
++ String(req.user.id) === String(user.id) ||
++ (networkId != null && String(req.user.id) === String(networkId))
++ ));
++ const mine = viewingSelf ? { include_unlisted: 1 } : {};
const lists = await Promise.all([
-- media.listPastes({ user_id: user.id, limit, sort }).catch(() => null),
++ media.listPastes({ user_id: user.id, limit, sort, ...mine }).catch(() => null),
networkId != null && String(networkId) !== String(user.id)
-- ? media.listPastes({ user_id: networkId, limit, sort }).catch(() => null)
++ ? media.listPastes({ user_id: networkId, limit, sort, ...mine }).catch(() => null)
: null,
]);
const seen = new Set();