Restrict public presence to staff + let admins view any character
Public "Online now" now lists only players whose game account is linked to a STAFF website user (admin/editor/moderator) — linked players are no longer exposed publicly with their name and location. listOnlineLinked joins through to users and filters on role; the section is relabeled "Staff online". Character/roster/vendor reads gain an admin bypass: admins may view any character's data, while players (and editor/moderator staff) stay limited to accounts they have personally linked. The bypass lives in the shared player controller and only ever widens access for genuine admins. Also finalizes the uo-link character/vendor front end (player + admin character sheets, VendorSales component, ShardChar removed) and regenerates swagger-output.json. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018kj5s1QCKobuFPYmqxjy1q
This commit is contained in:
@@ -1415,7 +1415,7 @@
|
||||
"tags": [
|
||||
"Public · Shard"
|
||||
],
|
||||
"summary": "Players online now (name + serial + map only)",
|
||||
"summary": "Staff online now (linked staff accounts; name + serial + map only)",
|
||||
"description": "",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -1464,75 +1464,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/public/shard/char/{serial}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Public · Shard"
|
||||
],
|
||||
"summary": "Live character sheet by serial (cached; degrades on shard restart)",
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "serial",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Mobile serial, e.g. 0x24C."
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Character profile",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid serial",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Character not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error"
|
||||
},
|
||||
"502": {
|
||||
"description": "Bad Gateway"
|
||||
},
|
||||
"503": {
|
||||
"description": "Shard restarting — retry",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/public/shard/stream": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -1984,7 +1915,7 @@
|
||||
"tags": [
|
||||
"Admin · Account"
|
||||
],
|
||||
"summary": "Character roster for a linked account (self)",
|
||||
"summary": "Character roster for an account (self; admins: any account)",
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -2038,7 +1969,7 @@
|
||||
"tags": [
|
||||
"Admin · Account"
|
||||
],
|
||||
"summary": "Player vendors for a linked account (self)",
|
||||
"summary": "Player vendors for an account (self; admins: any account)",
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -2087,6 +2018,107 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/admin/shard/char/{serial}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Admin · Account"
|
||||
],
|
||||
"summary": "Character sheet (self-linked characters; admins: any character)",
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "serial",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Mobile serial, e.g. 0x24C."
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Character profile",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request"
|
||||
},
|
||||
"403": {
|
||||
"description": "Character not on an account linked to the caller",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error"
|
||||
},
|
||||
"502": {
|
||||
"description": "Bad Gateway"
|
||||
},
|
||||
"503": {
|
||||
"description": "Service Unavailable"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"cookieAuth": []
|
||||
},
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/admin/shard/sales": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Admin · Account"
|
||||
],
|
||||
"summary": "Recent player-vendor sales for the caller’s linked accounts (self)",
|
||||
"description": "",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Vendor sales",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ShardVendorSale"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"cookieAuth": []
|
||||
},
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/admin/dashboard": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -7002,6 +7034,123 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/player/shard/char/{serial}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Player · Shard"
|
||||
],
|
||||
"summary": "Character sheet — only for a character on the caller’s linked account",
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "serial",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Mobile serial, e.g. 0x24C."
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Character profile",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request"
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
},
|
||||
"403": {
|
||||
"description": "Character not on an account linked to the caller",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error"
|
||||
},
|
||||
"502": {
|
||||
"description": "Bad Gateway"
|
||||
},
|
||||
"503": {
|
||||
"description": "Shard unavailable — retry",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"cookieAuth": []
|
||||
},
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/player/shard/sales": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Player · Shard"
|
||||
],
|
||||
"summary": "Recent player-vendor sales for the caller’s linked accounts",
|
||||
"description": "",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Vendor sales",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ShardVendorSale"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden"
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"cookieAuth": []
|
||||
},
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
@@ -10544,7 +10693,7 @@
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"example": "A player online now (redacted for the public list)."
|
||||
"example": "A LINKED player online now (only accounts linked to a website user are listed)."
|
||||
},
|
||||
"properties": {
|
||||
"type": "object",
|
||||
@@ -10591,6 +10740,161 @@
|
||||
"example": "Trammel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "integer"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"example": {
|
||||
"type": "number",
|
||||
"example": 1402
|
||||
}
|
||||
}
|
||||
},
|
||||
"y": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "integer"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"example": {
|
||||
"type": "number",
|
||||
"example": 1604
|
||||
}
|
||||
}
|
||||
},
|
||||
"z": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "integer"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"example": {
|
||||
"type": "number",
|
||||
"example": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ShardVendorSale": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "object"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"example": "A player-vendor sale (visible only to the linked owner)."
|
||||
},
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"t": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "integer"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"example": "Sale time, epoch ms."
|
||||
},
|
||||
"example": {
|
||||
"type": "number",
|
||||
"example": 1783720195626
|
||||
}
|
||||
}
|
||||
},
|
||||
"itemType": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "string"
|
||||
},
|
||||
"example": {
|
||||
"type": "string",
|
||||
"example": "Longsword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"amount": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "integer"
|
||||
},
|
||||
"example": {
|
||||
"type": "number",
|
||||
"example": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"price": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "integer"
|
||||
},
|
||||
"example": {
|
||||
"type": "number",
|
||||
"example": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
"commission": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "integer"
|
||||
},
|
||||
"nullable": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"example": {
|
||||
"type": "number",
|
||||
"example": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"ownerAcct": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "string"
|
||||
},
|
||||
"example": {
|
||||
"type": "string",
|
||||
"example": "whitlocktech"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,11 +546,26 @@ const doc = {
|
||||
},
|
||||
ShardOnlinePlayer: {
|
||||
type: 'object',
|
||||
description: 'A player online now (redacted for the public list).',
|
||||
description: 'A LINKED player online now (only accounts linked to a website user are listed).',
|
||||
properties: {
|
||||
serial: { type: 'string', example: '0x24C' },
|
||||
name: { type: 'string', example: 'Darrow' },
|
||||
map: { type: 'string', nullable: true, example: 'Trammel' },
|
||||
x: { type: 'integer', nullable: true, example: 1402 },
|
||||
y: { type: 'integer', nullable: true, example: 1604 },
|
||||
z: { type: 'integer', nullable: true, example: 0 },
|
||||
},
|
||||
},
|
||||
ShardVendorSale: {
|
||||
type: 'object',
|
||||
description: 'A player-vendor sale (visible only to the linked owner).',
|
||||
properties: {
|
||||
t: { type: 'integer', description: 'Sale time, epoch ms.', example: 1783720195626 },
|
||||
itemType: { type: 'string', example: 'Longsword' },
|
||||
amount: { type: 'integer', example: 1 },
|
||||
price: { type: 'integer', example: 100 },
|
||||
commission: { type: 'integer', nullable: true, example: 5 },
|
||||
ownerAcct: { type: 'string', example: 'whitlocktech' },
|
||||
},
|
||||
},
|
||||
ShardHouse: {
|
||||
|
||||
Reference in New Issue
Block a user