pos login with the ph number and pin

This commit is contained in:
2026-08-12 17:10:27 +05:30
parent ff72af9a8a
commit d566ca5591
9 changed files with 1007 additions and 91 deletions

View File

@@ -226,24 +226,41 @@ type PosCatalogueResponse struct {
// PosLoginRequest is what a till sends to sign in.
//
// Authname or Contactno, matching the web console's own login — a shop should
// not need a second set of credentials just because the screen is a till.
// A mobile number and a four-digit PIN. That is what a person standing at a
// counter can actually type between customers, and it is the pair the console
// issues them — anything longer gets written on the side of the terminal, which
// is worse than a short credential.
//
// Locationid is optional and only means anything for a user entitled to more
// than one outlet: it says which of theirs this terminal is standing in. It is
// checked against what they may reach, never trusted on its own.
type PosLoginRequest struct {
Authname string `json:"authname"`
Contactno string `json:"contactno"`
Password string `json:"password"`
Configid int `json:"configid"`
Locationid int `json:"location_id"`
// The mobile number this person signs in with. Sent in whatever form they
// typed it — "+91 98765 43210", "098765-43210", "9876543210" — and reduced
// to ten digits by the server before it is matched.
Contactno string `json:"contactno"`
// A PIN, for signing on at a terminal a supervisor has already opened. Only
// honoured by the PIN route, which requires an existing session — four
// digits is no barrier to an anonymous caller.
// A four-digit PIN, and the credential this endpoint now checks.
//
// Four digits is ten thousand guesses, which would be no barrier at all on
// its own — it is a barrier here only because it is checked against one
// mobile number, and a mobile number is unique among a tenant's till
// accounts. Rate limiting at the edge is what stands between that and a
// patient attacker; this endpoint cannot supply it.
Pin string `json:"pin"`
// A username and password, the way in before PINs.
//
// Kept working, not deprecated in place, because every till account on the
// platform predates the mobile number it now signs in with. Removing this
// before the back office has filled those in would close every shop on the
// same morning. See docs/POS_PHONE_PIN_LOGIN_HANDOVER.md §5.
Authname string `json:"authname,omitempty"`
Password string `json:"password,omitempty"`
Configid int `json:"configid"`
Locationid int `json:"location_id"`
// Which physical till is asking. Recorded on the session so a stolen token
// can be told apart from the terminal it was issued to.
Terminalid string `json:"terminal_id"`
@@ -319,24 +336,25 @@ type PosSession struct {
// what gets stamped on a bill as `cashiername` and settled against at the end
// of a shift.
//
// The PIN travels in the clear, over TLS, and that is a considered choice
// rather than an oversight. A four-digit PIN is brute-forceable in microseconds
// whatever it is wrapped in, so hashing it here would buy the appearance of
// strength and not the substance. What it would cost is real: the terminal
// salts every PIN with its own random salt before storing it, so a hash
// computed here could never be verified there without inventing a shared
// scheme and keeping two codebases agreeing about it for ever.
// The PIN used to travel down with this list, on the reasoning that a PIN was
// *shift attribution* rather than a security boundary: the token decided which
// books a till could reach, and the PIN only decided which of the people
// already inside a shop got credited with a sale.
//
// The honest framing is that a PIN is *shift attribution*, not a security
// boundary. The boundary is the session token — which is what stops a till
// reaching another tenant's books at all. The PIN decides which of the people
// already inside a shop gets credited with a sale, and the terminal still
// stores it hashed at rest.
// That reasoning ended when the PIN became half of the sign-in. A list of PINs
// is now a list of working credentials for the outlet — including the
// supervisor's, which carries `can_manage_staff` — so a cashier handed this
// array could sign back in as their own manager. Hence `json:"-"`: the field is
// still read from the database, because the query needs it to drop two people
// who share a PIN, but it cannot reach the wire from here.
//
// Switching operator at an open terminal goes through `POST /pos/login/pin`,
// which checks the PIN against the outlet the caller's token already names.
type PosStaffMember struct {
Userid int `json:"user_id"`
Fullname string `json:"full_name"`
Role string `json:"role"`
Pin string `json:"pin,omitempty"`
Pin string `json:"-"`
Status string `json:"status,omitempty"`
}