feat(crypto-service): gRPC-каркас сервиса криптографии (КриптоПро JCP)

- services/crypto-service/proto/crypto.proto — protobuf-контракт VerifyXMLDSig/SignXMLDSig/Health, package ru.zetit.bridgeandjoins.crypto.v1
- services/crypto-service/build.gradle.kts — Gradle Java 21 + protobuf-плагин + shadowJar
- services/crypto-service/src/main/java/.../CryptoServer.java — точка входа на UDS (Netty Epoll)
- services/crypto-service/src/main/java/.../CryptoServiceImpl.java — gRPC-биндинг
- services/crypto-service/src/main/java/.../{Verify,Sign,Health}Handler.java — заглушки операций
- services/crypto-service/src/main/java/.../KeystoreProvider.java — абстракция cryptopro/validata/vipnet/stub
- services/crypto-service/Dockerfile — Liberica JDK 21 → shadowJar → slim
- internal/cryptocli/client.go — Go-клиент по UDS, реализует m2mcore.CryptoVerifier (M1 stub)
- internal/cryptocli/client_test.go — тесты на доступность сокета и ErrNotImplemented
- deploy/docker-compose/docker-compose.yml — добавлен сервис crypto-service с UDS-volume

Реальная криптография КриптоПро JCP подключается после получения
лицензии и jar (положить в services/crypto-service/libs/jcp.jar) и
открытия Maven Central через прокси zetit (для grpc-java/santuario).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
fontvielle
2026-05-14 00:58:10 +03:00
parent a8cdeeb838
commit 1cf069b55b
15 changed files with 666 additions and 18 deletions
+61
View File
@@ -0,0 +1,61 @@
// Package cryptocli — Go-клиент crypto-service по UDS. На M1 — заглушка,
// возвращает ErrNotImplemented. Реальная реализация — после
// генерации gRPC-стабов из proto (когда прокси откроет proto-tooling
// и Go-зависимости).
package cryptocli
import (
"context"
"errors"
"net"
"time"
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2mcore"
)
// ErrNotImplemented возвращается клиентом до подключения реального gRPC.
var ErrNotImplemented = errors.New("cryptocli: не реализовано (ждём gRPC-стабы из proto)")
// Client — клиент crypto-service по Unix Domain Socket.
type Client struct {
socketPath string
dialer net.Dialer
timeout time.Duration
}
// Option настраивает Client.
type Option func(*Client)
// WithTimeout задаёт таймаут на одну операцию.
func WithTimeout(t time.Duration) Option {
return func(c *Client) { c.timeout = t }
}
// NewClient создаёт клиента к UDS. На M1 — без реального gRPC.
// Используется как заглушка, реализующая m2mcore.CryptoVerifier.
func NewClient(socketPath string, opts ...Option) *Client {
c := &Client{socketPath: socketPath, timeout: 5 * time.Second}
for _, o := range opts {
o(c)
}
return c
}
// VerifyXMLDSig вызывает CryptoService.VerifyXMLDSig. На M1 — stub.
func (c *Client) VerifyXMLDSig(ctx context.Context, _ []byte) (m2mcore.CertInfo, error) {
// На M1 проверяем только доступность сокета и возвращаем
// ErrNotImplemented. Это позволяет m2m-core логировать «crypto-service
// доступен, но криптография ещё не подключена» отдельно от «сокета
// нет совсем».
dctx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()
conn, err := c.dialer.DialContext(dctx, "unix", c.socketPath)
if err != nil {
return m2mcore.CertInfo{}, err
}
_ = conn.Close()
return m2mcore.CertInfo{}, ErrNotImplemented
}
// Ensure Client реализует m2mcore.CryptoVerifier.
var _ m2mcore.CryptoVerifier = (*Client)(nil)