Repository navigation
Conversation
…ints with temp wifi
…sk routes, and wifi controllers
…, and extract kiosk lookback constant
…nd 401 on bad admin tokens
feat: decouple gate checkin and add self checkin-checkout kiosk endpo…
|
Claude finished @vvshk's task in 2m 9s —— View job PR #486 review complete
Main concern: kiosk security. A Behavior change to confirm: gate entry no longer checks in Nit: an unused The full summary is in this comment. I did not run lint or tests, because |
| ['GET', /^\/stay\/kiosk\/bookings\/[^/]+$/], | ||
| ['POST', /^\/stay\/kiosk\/wifi\/generate_temp_code$/], | ||
| ['GET', /^\/stay\/kiosk\/wifi\/fetch_temp_codes\/[^/]+$/], | ||
| ['PUT', /^\/stay\/(flat_)?check(in|out)\/[^/]+$/] |
There was a problem hiding this comment.
Security: a kiosk token can check in or check out any booking, not just the scanned guest's.
This allowlist entry lets a kioskAdmin call PUT /stay/checkin/:bookingid, /checkout/:bookingid, /flat_checkin/:bookingid and /flat_checkout/:bookingid. Those handlers only look up the booking by bookingid. Nothing ties the request to the card scanned at the kiosk. On top of that, req.kioskRoute = true skips every authorizeRoles check.
Kiosks are unattended, shared devices, and their token can be pulled from the client. Anyone who has it can:
- Loop over card numbers with
GET /stay/kiosk/bookings/:cardnoto collect names andbookingids. - Call
PUT /stay/checkout/:bookingidon anycheckedinstay. An early checkout runshandleEarlyCheckout: it cancels the booking, refunds the transaction as credits and creates a new one.
Suggested fixes:
- Add kiosk-specific checkin and checkout handlers, or a guard on these routes, that require the scanned
cardnoand reject the request whenbooking.cardno !== cardno. - Rate-limit the
/stay/kiosk/*routes, and logreq.user.usernameon each kiosk action so it can be audited.
| }); | ||
| }; | ||
|
|
||
| export const fetchTempCodesForAdmin = async (req, res) => { |
There was a problem hiding this comment.
Security: WiFi passwords can be read for any card number.
fetchTempCodesForAdmin returns the WiFi passwords for whatever :cardno is in the URL. Any office, room or super admin can call it, and so can a kiosk-only token, because req.kioskRoute skips authorizeRoles. The kiosk has no proof that the guest is actually at the device. Anyone with the kiosk token can loop over card numbers and collect the passwords of every checked-in guest. generateTempCodeForAdmin has the same problem, and it also uses up the guest's single code (MAX_WIFI_PASS_LIMIT = 1).
If card numbers are sequential or easy to guess, this is easy to exploit. Consider:
- Requiring a second factor from the guest, such as the last 4 digits of their mobile number or a scanned QR or NFC payload, rather than the bare card number.
- Rate-limiting these routes per kiosk account.
| let decoded; | ||
| try { | ||
| decoded = jwt.verify(token, process.env.SECRET); | ||
| } catch (err) { |
There was a problem hiding this comment.
Nit: err is never used. Also, ApiError treats its third argument as data, and when data is set it skips Error.captureStackTrace. If these strings are only for the client, that's fine. Otherwise, consider logging the real reason (expired or malformed) with req.log before throwing.
| } catch (err) { | |
| } catch { |
Review summaryThis PR adds self-service kiosk endpoints (booking lookup with a checkout preview, and WiFi code generation and lookup), a Main concern: kiosk security (see the inline comments). A Behavior change to confirm: removing the hooks from
Stays now stay in those states until staff or the kiosk acts. The new overdue report covers part of this. The shared business docs in Minor:
I did not run lint or tests: per 🤖 Generated with Claude Code |
No description provided.