pos login edited with phone number
This commit is contained in:
@@ -47,7 +47,7 @@ func (r *posRepository) PosLogin(req models.PosLoginRequest) (*models.PosSession
|
||||
return nil, fmt.Errorf("an email or mobile number is required")
|
||||
}
|
||||
|
||||
rows, err := r.posLoginCandidates(field, value, req.Configid)
|
||||
rows, err := r.posLoginCandidates(field, value, req.Configid, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -55,6 +55,21 @@ func (r *posRepository) PosLogin(req models.PosLoginRequest) (*models.PosSession
|
||||
// One message for "no such account" and for "wrong password", on purpose.
|
||||
// Distinguishing them turns the login into a directory of who banks here.
|
||||
if len(rows) == 0 {
|
||||
// Nothing eligible under that credential. Before answering with the
|
||||
// deliberately vague rejection, look again without the role filter — a
|
||||
// back-office account typing its own password at a till deserves to be
|
||||
// told that is the problem, rather than sent hunting for a password
|
||||
// that was never wrong.
|
||||
//
|
||||
// Only ever reached after that account's own password verifies, so it
|
||||
// discloses nothing the caller has not just proved. An ambiguous match
|
||||
// falls through to the vague answer rather than naming anything.
|
||||
if others, oerr := r.posLoginCandidates(field, value, req.Configid, false); oerr == nil &&
|
||||
len(others) == 1 &&
|
||||
strings.TrimSpace(others[0].Password) != "" &&
|
||||
constantTimeEqual(others[0].Password, req.Password) {
|
||||
return nil, errPosRoleIneligible
|
||||
}
|
||||
return nil, errPosLoginRejected
|
||||
}
|
||||
|
||||
@@ -205,7 +220,7 @@ func posRoleLabel(roleID int) string {
|
||||
// demanding a number they have never seen would make the login unusable. So it
|
||||
// is honoured when sent and inferred when not — and inference that finds more
|
||||
// than one candidate is reported, never guessed.
|
||||
func (r *posRepository) posLoginCandidates(field, value string, configID int) ([]posLoginRow, error) {
|
||||
func (r *posRepository) posLoginCandidates(field, value string, configID int, tillOnly bool) ([]posLoginRow, error) {
|
||||
rows := make([]posLoginRow, 0, 2)
|
||||
|
||||
query := fmt.Sprintf(`
|
||||
@@ -223,6 +238,25 @@ func (r *posRepository) posLoginCandidates(field, value string, configID int) ([
|
||||
params = append(params, configID)
|
||||
}
|
||||
|
||||
// Only till accounts are candidates.
|
||||
//
|
||||
// This matters most for signing in by phone. `contactno` is not unique in
|
||||
// this schema — 34 numbers are shared by 104 active accounts, one of them
|
||||
// by eleven — and the caller refuses any lookup returning more than one
|
||||
// row, because choosing between them could bill into the wrong tenant's
|
||||
// books. Without this clause a cashier whose number also sits on a tenant
|
||||
// admin's record simply cannot log in.
|
||||
//
|
||||
// Narrowing here means a till phone number only has to be unique among
|
||||
// till accounts, not across all 608 users. An eligible-but-wrong-role
|
||||
// account still gets the specific errPosRoleIneligible answer, because the
|
||||
// caller checks the role again after the password verifies — this clause
|
||||
// removes ambiguity, it does not replace that check.
|
||||
if tillOnly {
|
||||
query += fmt.Sprintf(` AND COALESCE(roleid, 0) IN (%d, %d)`,
|
||||
models.PosRoleSupervisor, models.PosRoleCashier)
|
||||
}
|
||||
|
||||
// Inactive accounts are excluded from the match rather than matched and
|
||||
// then refused. A deactivated duplicate would otherwise make a working
|
||||
// login ambiguous, which turns "this person left" into "nobody can open
|
||||
|
||||
Reference in New Issue
Block a user