mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
private rover security! and styling updaes
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -78,8 +78,8 @@
|
||||
<script defer src="https://analytics.otter.land/script.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land"></script>
|
||||
<script defer src="https://analytics.otter.land/recorder.js" data-website-id="82dd56a5-db44-4279-bd1e-a4d9fee39af7" data-domains="rover.otter.land" data-sample-rate="0.15" data-mask-level="moderate" data-max-duration="300000"></script>
|
||||
<title>Roomba Rover</title>
|
||||
<script type="module" crossorigin src="/assets/index-qmfprxrq.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-CjRD7Org.css">
|
||||
<script type="module" crossorigin src="/assets/index-_MGdcdqA.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-LIjDMlbF.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -137,11 +137,26 @@ function buildRoomCameraInfo(camera) {
|
||||
};
|
||||
}
|
||||
|
||||
function isClosedPrivateRover(rover) {
|
||||
return Boolean(rover?.private?.enabled && !rover?.private?.open);
|
||||
}
|
||||
|
||||
function getPublicRoster() {
|
||||
return roverManager
|
||||
.getRoster()
|
||||
/*
|
||||
Closed private rovers are intentionally absent from the public
|
||||
inter-instance contract. If a rover is private and closed, other servers
|
||||
should not see its row or receive any derived snapshot URL for it.
|
||||
*/
|
||||
.filter((rover) => !isClosedPrivateRover(rover));
|
||||
}
|
||||
|
||||
function buildLocalInfo() {
|
||||
const mode = getMode();
|
||||
const lockdown = isLockdownMode();
|
||||
const features = getFeatureFlags();
|
||||
const roster = roverManager.getRoster().map((rover) => (lockdown ? rover : addRoverSnapshotLinks(rover)));
|
||||
const roster = getPublicRoster().map((rover) => (lockdown ? rover : addRoverSnapshotLinks(rover)));
|
||||
const roomCameras = lockdown || !features.roomCameras ? [] : getRoomCameras().map(buildRoomCameraInfo);
|
||||
return {
|
||||
instance: {
|
||||
@@ -184,6 +199,16 @@ app.get('/api/inter-instance/rover-snapshots/:roverId/latest', (req, res) => {
|
||||
return;
|
||||
}
|
||||
const roverId = String(req.params.roverId || '');
|
||||
const publicRover = getPublicRoster().find((rover) => String(rover.id) === roverId);
|
||||
if (!publicRover) {
|
||||
/*
|
||||
Do not rely on "not advertising the URL" as the privacy boundary. Public
|
||||
snapshot hosting must also reject direct requests for closed-private or
|
||||
unknown rovers because old URLs, logs, or guesses can outlive roster state.
|
||||
*/
|
||||
res.status(404).json({ error: 'Rover snapshot unavailable' });
|
||||
return;
|
||||
}
|
||||
sendJpegState(res, getRoverSnapshotState(roverId), 'Rover snapshot unavailable');
|
||||
});
|
||||
|
||||
|
||||
@@ -94,29 +94,13 @@ function InstanceMetadata({ remote }) {
|
||||
}
|
||||
|
||||
function RemoteMediaStrip({ remote }) {
|
||||
const roverSnapshots = (remote.roster || [])
|
||||
.map((rover) => ({
|
||||
id: rover.id,
|
||||
name: rover.name || rover.id,
|
||||
url: rover.snapshots?.latestUrl,
|
||||
updatedAt: rover.snapshots?.updatedAt,
|
||||
}))
|
||||
.filter((entry) => entry.url);
|
||||
const roomCameras = Array.isArray(remote.roomCameras) ? remote.roomCameras.filter((camera) => camera.snapshotUrl) : [];
|
||||
const items = [
|
||||
...roverSnapshots.map((entry) => ({ ...entry, kind: 'Rover' })),
|
||||
...roomCameras.map((entry) => ({ ...entry, name: entry.name || entry.id, url: entry.snapshotUrl, kind: 'Room' })),
|
||||
];
|
||||
if (!items.length) return null;
|
||||
if (!roomCameras.length) return null;
|
||||
return (
|
||||
<div className="grid grid-cols-2 gap-0.5 md:grid-cols-3">
|
||||
{items.map((item) => (
|
||||
<div key={`${item.kind}-${item.id}`} className="surface-muted overflow-hidden text-xs">
|
||||
<img src={item.url} alt={item.name} className="aspect-video w-full bg-black object-cover" loading="lazy" />
|
||||
<div className="flex items-center justify-between gap-0.5 p-0.5">
|
||||
<span className="truncate text-slate-200">{item.name}</span>
|
||||
<span className="text-[0.65rem] text-slate-500">{item.kind}</span>
|
||||
</div>
|
||||
<div className="flex gap-0.5 overflow-x-auto pb-0.5">
|
||||
{roomCameras.map((camera) => (
|
||||
<div key={camera.id} className="surface-muted w-28 shrink-0 overflow-hidden">
|
||||
<img src={camera.snapshotUrl} alt={camera.name || camera.id} className="h-14 w-full bg-black object-cover" loading="lazy" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -229,6 +229,14 @@ export default function RoverQueuesPanel({
|
||||
handleRequest(rover.id);
|
||||
}}
|
||||
>
|
||||
{externalMode && rover?.snapshots?.latestUrl ? (
|
||||
<img
|
||||
src={rover.snapshots.latestUrl}
|
||||
alt=""
|
||||
className="h-8 w-10 shrink-0 rounded border border-slate-700 bg-black object-cover"
|
||||
loading="lazy"
|
||||
/>
|
||||
) : null}
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-0.5">
|
||||
<div className="flex items-center justify-between gap-0.5">
|
||||
<div className="flex min-w-0 items-center gap-0.5">
|
||||
|
||||
Reference in New Issue
Block a user