Shut the parts kiosk behind a device token, and stop the health probe leaking

This commit is contained in:
2026-09-02 17:45:05 -04:00
parent bb733f1332
commit 2f90419ceb
8 changed files with 295 additions and 44 deletions

View File

@@ -1501,6 +1501,17 @@ export const measuringtoolsApi = {
}
// 3D printed parts (printedparts plugin)
// Device token for the parts kiosk, provisioned once per screen and kept in
// that browser. Absent means the routes answer 404, which is what an
// unprovisioned browser should see.
export const KIOSK_TOKEN_KEY = 'printedparts-kiosk-token'
function kioskHeaders() {
let token = ''
try { token = localStorage.getItem(KIOSK_TOKEN_KEY) || '' } catch { token = '' }
return token ? { 'X-Kiosk-Token': token } : {}
}
export const printedpartsApi = {
list(params = {}) {
return api.get('/printedparts/items', { params })
@@ -1541,11 +1552,17 @@ export const printedpartsApi = {
adjust(printeditemid, data) {
return api.post(`/printedparts/items/${printeditemid}/adjust`, data)
},
// The kiosk routes are the only unauthenticated write in the product, so they
// are gated on a per-DEVICE token rather than on the page. It lives in this
// browser's localStorage, put there once by an admin opening the kiosk with
// ?token=... - see PartsKiosk.vue. A token shipped inside the page would be
// readable by anyone who could load it, which is not a gate.
kioskItem(itemcode) {
return api.get(`/printedparts/kiosk/item/${encodeURIComponent(itemcode)}`)
return api.get(`/printedparts/kiosk/item/${encodeURIComponent(itemcode)}`,
{ headers: kioskHeaders() })
},
kioskTake(data) {
return api.post('/printedparts/kiosk/take', data)
return api.post('/printedparts/kiosk/take', data, { headers: kioskHeaders() })
},
listFiles(printeditemid) {
return api.get(`/printedparts/items/${printeditemid}/files`)