fix(shard): restrict staff in-game location to admins/moderators
The public "Staff online" list on the Shard page exposed each staff member's in-game location (map + coordinates) to everyone, including logged-in players and unauthenticated visitors. Location is now privileged data: - Server: getOnline inspects the caller's role via getUserFromRequest (the same non-rejecting helper siteMode uses on public routes) and only includes map/x/y/z for admin/moderator callers. For everyone else the fields are omitted from the JSON entirely, so they can't be read from the network tab. serial + name (online status) still shown. - Client: Shard.jsx gates the location span on the viewer's role from useAuth() (same pattern as RoleGate); non-privileged viewers see who is online but no location field is rendered. Tests: publicShardOnline.test.js covers admin + moderator (location included), player + unauthenticated + editor (location omitted). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XmHdsbnLzDMAVQkAoTQSBe
This commit is contained in:
@@ -13,6 +13,7 @@ const shardEvents = require('../../../model/shardEvents/shardEvents.model')
|
||||
const shardState = require('../../../model/shardState/shardState.model')
|
||||
const uoLinkConfig = require('../../../model/uoLinkConfig/uoLinkConfig.model')
|
||||
const broadcast = require('../../../utils/shardBroadcast')
|
||||
const auth = require('../../../utils/auth')
|
||||
|
||||
const log = require('../../../utils/logger')('public-shard')
|
||||
|
||||
@@ -70,12 +71,31 @@ async function getEconomy(req, res) {
|
||||
}
|
||||
|
||||
// GET /public/shard/online — players online now whose account is linked to a
|
||||
// STAFF website user (admin/editor/moderator). Shows name + location (map +
|
||||
// coordinates); no vitals or account. Non-staff players are never listed.
|
||||
// STAFF website user (admin/editor/moderator). Everyone sees that a staff member
|
||||
// is online (name + serial); their in-game location (map + coordinates) is only
|
||||
// included for privileged viewers (admin/moderator) so it is never exposed to
|
||||
// players or the public via the network tab. Non-staff players are never listed.
|
||||
function canSeeStaffLocation(req) {
|
||||
const viewer = auth.getUserFromRequest(req)
|
||||
return !!viewer && (viewer.role === 'admin' || viewer.role === 'moderator')
|
||||
}
|
||||
|
||||
async function getOnline(req, res) {
|
||||
try {
|
||||
const rows = await shardState.listOnlineLinked()
|
||||
return res.json(rows.map((r) => ({ serial: r.serial, name: r.name, map: r.map, x: r.x, y: r.y, z: r.z })))
|
||||
const showLocation = canSeeStaffLocation(req)
|
||||
return res.json(
|
||||
rows.map((r) => {
|
||||
const entry = { serial: r.serial, name: r.name }
|
||||
if (showLocation) {
|
||||
entry.map = r.map
|
||||
entry.x = r.x
|
||||
entry.y = r.y
|
||||
entry.z = r.z
|
||||
}
|
||||
return entry
|
||||
}),
|
||||
)
|
||||
} catch (err) {
|
||||
log.error('shard.getOnline', err)
|
||||
return res.status(500).json({ message: 'Internal Server Error' })
|
||||
|
||||
Reference in New Issue
Block a user