From ad6b52f5fa271e52427a4a486614545177c596ac Mon Sep 17 00:00:00 2001 From: fontvielle Date: Thu, 22 Oct 2026 12:09:04 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D1=80=D0=BE=D0=BA=D0=B8=20=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D1=82=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82=D0=BE=D0=B2=20?= =?UTF-8?q?=E2=80=94=20=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=BF=D0=BE?= =?UTF-8?q?=20=D0=BD=D0=B0=D1=88=D0=B5=D0=B9=20=D0=BE=D1=80=D0=B3=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В справочнике ИШ — сертификаты всех участников обмена (на 9 — 351: ВТБ, Сбербанк, ТБанк…). «Свой» был любой не НРД/биржа/НКЦ/УЦ, и приходило «Сертификат ключа организации истекает сегодня» по сотруднику Сбербанка. Теперь свой — ИНН в subject равен ИНН нашей организации; уведомления о сроках — только по своим (сертификаты НРД приезжают с обновлением bj); чужие сертификаты не показываются в шаге «Сертификаты». Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn --- internal/lkgateway/certexpiry.go | 39 +++++++++++++++++---------- internal/lkgateway/onboarding_test.go | 9 +++++-- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/internal/lkgateway/certexpiry.go b/internal/lkgateway/certexpiry.go index 9503729..600f54d 100644 --- a/internal/lkgateway/certexpiry.go +++ b/internal/lkgateway/certexpiry.go @@ -2,11 +2,12 @@ package lkgateway // Сроки сертификатов в справочнике ИШ (05.10.2026). Своих сертификатов bj напрямую не видит (ключи — в // Валидате и ИШ), но знает содержимое справочника активного профиля ИШ: его раз в 6 часов читает сверка -// сертификатов НРД (nsdcerts.go, NSDCerts.LastStore). Свой сертификат — тот, что не из комплекта НРД, -// не самоподписанный (не УЦ) и выдан не НРД, бирже или НКЦ. По нему же отмечается шаг «Сертификаты». +// сертификатов НРД (nsdcerts.go, NSDCerts.LastStore). В справочнике — сертификаты всех участников +// обмена (на 9 — 351: ВТБ, Сбербанк, ТБанк…). Свой — ИНН в subject равен ИНН нашей организации (22.10.2026; +// раньше «своим» был любой не НРД/биржа/НКЦ/УЦ). По нему же отмечается шаг «Сертификаты». // -// Уведомления: за 30, 14, 7, 3 и 1 день до окончания и в день окончания — для своего сертификата и для -// сертификатов НРД, если им нет замены с более поздним сроком. +// Уведомления: за 30, 14, 7, 3 и 1 день до окончания и в день окончания — только по сертификатам нашей +// организации (сертификаты НРД приезжают с обновлением bj). import ( "encoding/json" @@ -65,26 +66,35 @@ func bundleSerials() map[string]bool { return out } -// storeCertKind — own (свой), counterpart (НРД/биржа/НКЦ), ca (УЦ) или "" (не сертификат). -func storeCertKind(c NSDStoreCert, bundle map[string]bool) string { +// storeCertKind — own (нашей организации), counterpart (НРД/биржа/НКЦ), other (другие участники обмена), +// ca (УЦ) или "" (не сертификат). ourINN — ИНН нашей организации; пусто (ещё не задан) — своим +// считается любой, кроме НРД/биржи/НКЦ/УЦ, как до 22.10.2026. +func storeCertKind(c NSDStoreCert, bundle map[string]bool, ourINN string) string { if c.Kind != "x509" { return "" } if c.SelfSigned || strings.Contains(c.SubjectCN, "УЦ") { return "ca" } - if bundle[normSerial(c.Serial)] || counterpartINN[subjectINN(c.Subject)] != "" { + inn := subjectINN(c.Subject) + if bundle[normSerial(c.Serial)] || counterpartINN[inn] != "" { return "counterpart" } + if ourINN = strings.TrimLeft(strings.TrimSpace(ourINN), "0"); ourINN != "" && inn != ourINN { + return "other" + } return "own" } +// ourOrgINN — ИНН нашей организации для отбора своих сертификатов. +func ourOrgINN(s Settings) string { return orgINN(s) } + // ownStoreCerts — свои сертификаты в справочнике ИШ. func ownStoreCerts(s Settings) []NSDStoreCert { - bundle := bundleSerials() + bundle, our := bundleSerials(), ourOrgINN(s) var out []NSDStoreCert for _, c := range s.NSDCerts.LastStore { - if storeCertKind(c, bundle) == "own" { + if storeCertKind(c, bundle, our) == "own" { out = append(out, c) } } @@ -93,12 +103,12 @@ func ownStoreCerts(s Settings) []NSDStoreCert { // storeCertsForUI — сертификаты справочника ИШ (кроме УЦ) для шага «Сертификаты»: свой — с отметкой «ключ есть». func storeCertsForUI(s Settings) []cryptocli.Certificate { - bundle := bundleSerials() + bundle, our := bundleSerials(), ourOrgINN(s) var out []cryptocli.Certificate seen := map[string]bool{} for _, c := range s.NSDCerts.LastStore { - k := storeCertKind(c, bundle) - if k == "" || k == "ca" || seen[c.Serial] { + k := storeCertKind(c, bundle, our) + if k == "" || k == "ca" || k == "other" || seen[c.Serial] { // чужие сертификаты участников — не наши continue } seen[c.Serial] = true @@ -136,9 +146,10 @@ func certExpiryTick(rc *RuntimeConfig) { } } changed := false + our := ourOrgINN(s) for _, c := range s.NSDCerts.LastStore { - kind := storeCertKind(c, bundle) - if kind != "own" && kind != "counterpart" { + kind := storeCertKind(c, bundle, our) + if kind != "own" { // только сертификаты нашей организации continue } until := storeNotAfter(c) diff --git a/internal/lkgateway/onboarding_test.go b/internal/lkgateway/onboarding_test.go index bf37ca6..da8de81 100644 --- a/internal/lkgateway/onboarding_test.go +++ b/internal/lkgateway/onboarding_test.go @@ -45,11 +45,16 @@ func TestStoreCertKindAndExpiry(t *testing.T) { own := NSDStoreCert{Kind: "x509", Subject: "O=Предприятие 1046,CN=Сотрудник 1046,INN=078000001046", SubjectCN: "Сотрудник 1046", IssuerCN: "Тестовый УЦ", Serial: "AA01"} nsd := NSDStoreCert{Kind: "x509", Subject: "O=НКО АО НРД,CN=Петров,INN=007702165310", SubjectCN: "Петров", IssuerCN: "Тестовый УЦ", Serial: "BB02"} ca := NSDStoreCert{Kind: "x509", SubjectCN: "Тестовый УЦ", SelfSigned: true} - for c, want := range map[*NSDStoreCert]string{&own: "own", &nsd: "counterpart", &ca: "ca"} { - if got := storeCertKind(*c, bundle); got != want { + // сотрудник другого участника обмена (в справочнике ИШ их сотни) — не наш сертификат + sber := NSDStoreCert{Kind: "x509", Subject: "O=ПАО Сбербанк,CN=Исакова,INN=007707083893", SubjectCN: "Исакова", IssuerCN: "Корневой УЦ", Serial: "CC03"} + for c, want := range map[*NSDStoreCert]string{&own: "own", &nsd: "counterpart", &ca: "ca", &sber: "other"} { + if got := storeCertKind(*c, bundle, "078000001046"); got != want { t.Errorf("%s: %s, want %s", c.SubjectCN, got, want) } } + if storeCertKind(sber, bundle, "") != "own" { + t.Error("ИНН организации не задан — как раньше, свой любой не НРД") + } if subjectINN(nsd.Subject) != "7702165310" { t.Errorf("subjectINN: %q", subjectINN(nsd.Subject)) }