Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
- Сервер: Employee.PinHash (PBKDF2, миграция Phase36); POST
/api/organization/employees/{id}/pin — админ задаёт/снимает PIN (4–6 цифр,
уникален среди активных сотрудников на пересекающихся точках). Кастомный
OpenIddict-грант grant_type=pin (retail_point_id + pin): находит кассира,
привязанного к точке, по PIN и выдаёт токены. Брутфорс-защита — in-memory по
точке (5 неверных → блок 5 мин). Клиент-сидер досоздаёт gt:pin существующим
клиентам (без пересоздания). Пароль остаётся запасным.
- Касса: PIN-пад на зарегистрированном устройстве (маскированный ввод, 0–9/⌫/
Войти), переключение на вход по логину; AuthService.PinLoginAsync.
- Тесты: unit PinHasher (9), integration (3): вход по PIN выдаёт рабочий токен;
5 неверных → блок; дубль PIN на точке → 409. + скриншот PIN-пада в галерее.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
41 lines
1.1 KiB
C#
41 lines
1.1 KiB
C#
using FluentAssertions;
|
|
using foodmarket.Application.Common;
|
|
using Xunit;
|
|
|
|
namespace foodmarket.UnitTests;
|
|
|
|
public class PinHasherTests
|
|
{
|
|
[Fact]
|
|
public void Hash_then_verify_roundtrips()
|
|
{
|
|
var hash = PinHasher.Hash("1234");
|
|
PinHasher.Verify("1234", hash).Should().BeTrue();
|
|
PinHasher.Verify("1235", hash).Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void Hash_is_salted_different_each_time()
|
|
{
|
|
PinHasher.Hash("4321").Should().NotBe(PinHasher.Hash("4321"));
|
|
}
|
|
|
|
[Fact]
|
|
public void Verify_handles_null_and_garbage()
|
|
{
|
|
PinHasher.Verify("1234", null).Should().BeFalse();
|
|
PinHasher.Verify("1234", "").Should().BeFalse();
|
|
PinHasher.Verify("1234", "not-a-hash").Should().BeFalse();
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("1234", true)]
|
|
[InlineData("123456", true)]
|
|
[InlineData("123", false)]
|
|
[InlineData("1234567", false)]
|
|
[InlineData("12a4", false)]
|
|
[InlineData(null, false)]
|
|
public void IsValidPin_rules(string? pin, bool expected)
|
|
=> PinHasher.IsValidPin(pin).Should().Be(expected);
|
|
}
|