Authenticates with the pin.
(self, request: Request)
| 472 | time.sleep(5.0 if count > 5 else 0.5) |
| 473 | |
| 474 | def pin_auth(self, request: Request) -> Response: |
| 475 | """Authenticates with the pin.""" |
| 476 | if not self.check_host_trust(request.environ): |
| 477 | return SecurityError() # type: ignore[return-value] |
| 478 | |
| 479 | exhausted = False |
| 480 | auth = False |
| 481 | trust = self.check_pin_trust(request.environ) |
| 482 | pin = t.cast(str, self.pin) |
| 483 | |
| 484 | # If the trust return value is `None` it means that the cookie is |
| 485 | # set but the stored pin hash value is bad. This means that the |
| 486 | # pin was changed. In this case we count a bad auth and unset the |
| 487 | # cookie. This way it becomes harder to guess the cookie name |
| 488 | # instead of the pin as we still count up failures. |
| 489 | bad_cookie = False |
| 490 | if trust is None: |
| 491 | self._fail_pin_auth() |
| 492 | bad_cookie = True |
| 493 | |
| 494 | # If we're trusted, we're authenticated. |
| 495 | elif trust: |
| 496 | auth = True |
| 497 | |
| 498 | # If we failed too many times, then we're locked out. |
| 499 | elif self._failed_pin_auth.value >= 10: |
| 500 | exhausted = True |
| 501 | |
| 502 | # Otherwise go through pin based authentication |
| 503 | else: |
| 504 | entered_pin = request.args["pin"] |
| 505 | |
| 506 | if entered_pin.strip().replace("-", "") == pin.replace("-", ""): |
| 507 | self._failed_pin_auth.value = 0 |
| 508 | auth = True |
| 509 | else: |
| 510 | self._fail_pin_auth() |
| 511 | |
| 512 | rv = Response( |
| 513 | json.dumps({"auth": auth, "exhausted": exhausted}), |
| 514 | mimetype="application/json", |
| 515 | ) |
| 516 | if auth: |
| 517 | rv.set_cookie( |
| 518 | self.pin_cookie_name, |
| 519 | f"{int(time.time())}|{hash_pin(pin)}", |
| 520 | httponly=True, |
| 521 | samesite="Strict", |
| 522 | secure=request.is_secure, |
| 523 | ) |
| 524 | elif bad_cookie: |
| 525 | rv.delete_cookie(self.pin_cookie_name) |
| 526 | return rv |
| 527 | |
| 528 | def log_pin_request(self, request: Request) -> Response: |
| 529 | """Log the pin if needed.""" |
no test coverage detected