Skip to content

CIRFMF/ksef-client-csharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KSeF Client

Wstęp – Struktura projektu i technologie

Repozytorium zawiera:

  • Implementacja klienta KSeF 2.0

    • KSeF.Client - główna biblioteka klienta z logiką biznesową
    • KSeF.Client.Core - modele, interfejsy i wyjątki (wydzielone dla zgodności z .NET Standard 2.0)
    • KSeF.Client.ClientFactory - dodatkowa biblioteka klienta która umożliwia korzystanie z KSeFClient, CertificateFetcherServices oraz CryptographyServices w formie fabryk dla 3 niezależnych środowisk.
  • Testy

    • KSeF.Client.Tests - testy jednostkowe i funkcjonalne
    • KSeF.Client.Tests.Core - testy E2E i integracyjne
    • KSeF.Client.Tests.ClientFactory - testy dla fabryk KSeFClient, CryptographyServices i CertificateFetcherServices
    • KSeF.Client.Tests.Utils - narzędzia pomocnicze do testów
    • KSeF.Client.Tests.CertTestApp - aplikacja konsolowa dla zobrazowania tworzenia przykładowego, testowego certyfikatu oraz podpisu XAdES
  • Przykładowa aplikacja

    • KSeF.DemoWebApp - aplikacja demonstracyjna ASP.NET

Całość napisana jest w języku C# z wykorzystaniem platformy .NET 8/9 (lub nowszej). Do komunikacji HTTP wykorzystywany jest RestClient, a rejestracja i konfiguracja klienta KSeF odbywa się przez mechanizm Dependency Injection (Microsoft.Extensions.DependencyInjection).

Struktura projektu

KSeF.Client

Zawiera implementację komunikacji z API KSeF oraz logikę biznesową:

  • Api/

    • Builders/ - buildery do konstrukcji requestów API (Auth, Certificates, Permissions, Sessions, itp.)
    • Services/ - serwisy biznesowe (AuthCoordinator, CryptographyService, SignatureService, TokenService, QrCodeService, VerificationLinkService)
  • Clients/
    Implementacje klientów specjalizowanych (CryptographyClient, KSeFClient)

  • DI/
    Konfiguracja Dependency Injection i opcje klienta (KSeFClientOptions, CryptographyClientOptions, ServiceCollectionExtensions)

  • Extensions/
    Metody rozszerzające (Base64UrlExtensions)

  • Http/
    Implementacja komunikacji HTTP (KSeFClient, RestClient, JsonUtil)

KSeF.Client.Core

Biblioteka zawierająca wspólne typy i interfejsy:

  • Exceptions/
    Wyjątki specyficzne dla KSeF (KsefApiException, KsefRateLimitException)

  • Interfaces/
    Interfejsy usług i klientów (IKSeFClient, ICryptographyService, ISignatureService, IAuthCoordinator, IQrCodeService, IVerificationLinkService)

  • Models/
    Modele danych odpowiadające strukturom API KSeF (Authorization, Certificates, Invoices, Sessions, Permissions, Token, QRCode, Peppol)

  • KsefNumberValidator.cs
    Walidator numerów faktury nadawanych przez KSeF

Instalacja i konfiguracja

Aby użyć biblioteki KSeF.Client w swoim projekcie, dodaj referencję do projektu KSeF.Client (zawiera on już referencję do KSeF.Client.Core).

Pakiety Nuget

Projekty KSeF.Client i KSeF.Client.Core są dostępne jako pakiety nuget w GitHub Packages organizacji CIRFMF.

Opis paczek:

  • KSeF.Client - główna biblioteka klienta z logiką biznesową
  • KSeF.Client.Core - modele, interfejsy i wyjątki

Należy najpierw skonfigurować dostęp do paczek NuGet opublikowanych w GitHub Packages organizacji CIRFMF. Wymaga to autoryzacji przy pomocy osobistego tokena dostępu (Personal Access Token – PAT) z uprawnieniem read:packages. Dokładny poradnik jest dostępny w pliku nuget-package.md.

Przykładowa rejestracja klienta KSeF w kontenerze DI

Minimalna konfiguracja

using KSeF.Client.DI;

WebApplicationBuilder builder = Microsoft.AspNetCore.Builder.WebApplication.CreateBuilder(args);

// Rejestracja klienta KSeF
builder.Services.AddKSeFClient(options =>
{
    options.BaseUrl = KsefEnvironmentsUris.TEST; // lub PRODUCTION, DEMO
});

// Rejestracja serwisu kryptograficznego (wymagane dla operacji wymagających szyfrowania)
builder.Services.AddCryptographyClient();

Pełna konfiguracja z dodatkowymi opcjami

Konfiguracja może być wczytana z pliku appsettings.json:

{
  "ApiSettings": {
    "BaseUrl": "https://ksef-test.mf.gov.pl",
    "CustomHeaders": { 
      "X-Custom-Header": "value"
    }
  }
}
using KSeF.Client.DI;
using KSeF.Client.Core.Interfaces.Clients;

WebApplicationBuilder builder = Microsoft.AspNetCore.Builder.WebApplication.CreateBuilder(args);

// Wczytanie konfiguracji z appsettings.json
KSeFClientOptions? apiSettings = builder.Configuration.GetSection("ApiSettings").Get<KSeFClientOptions>();

// Rejestracja klienta KSeF z konfiguracją z appsettings
builder.Services.AddKSeFClient(options =>
{
    options.BaseUrl = apiSettings?.BaseUrl ?? KsefEnvironmentsUris.TEST;
    options.WebProxy = apiSettings?.WebProxy; // opcjonalnie: konfiguracja proxy
    options.CustomHeaders = apiSettings?.CustomHeaders ?? new Dictionary<string, string>();
});
// Rejestracja własnej implementacji ICertificateFetcher.
builder.Services.AddSingleton<ICertificateFetcher, MyCertificateFetcher>();
// Rejestracja klienta kryptograficznego KSeF w trybie NonBlocking.
// (automatycznie użyje powyższego MyCertificateFetcher).
builder.Services.AddCryptographyClient(CryptographyServiceWarmupMode.NonBlocking);

Uwaga: AddCryptographyClient jest wymagany dla operacji wymagających szyfrowania (np. sesje wsadowe, eksport faktur).

Uwaga: AddCryptographyClient rejestruje serwis kryptograficzny CryptographyService oraz zapewnia dodanie algorytmu kryptograficznego dla ECDSA z SHA-256 do klasy CryptoConfig.

Użycie AddCryptographyClient z przekazaniem własnego delegata (np. GetCertificates()) z własnego serwisu (np. MyCertificateService); Ten sposób inicjalizacji nie jest polecany.

// Rejestracja serwisu w kontenerze DI
builder.Services.AddSingleton<IMyCCertificateService, MyCertificateService>();

// Przekazanie delegata do AddCryptographyClient
builder.Services.AddCryptographyClient(
    pemCertificatesFetcher: async (cancellationToken) =>
    {
        // Pobranie serwisu z kontenera DI
        using var scope = builder.Services.BuildServiceProvider().CreateScope();
        var myFetcher = scope.ServiceProvider.GetRequiredService<IMyCertificateService>();
        
        // Wywołanie metody z pobranego serwisu
        return await myFetcher.GetCertificates(cancellationToken);
    },
    warmupMode: CryptographyServiceWarmupMode.NonBlocking
);

Uwaga: Sygnatura metody GetCertificates() musi zwracać Task<ICollection<PemCertificateInfo>> i przyjmować CancellationToken jako parametr. Tworzenie scope'a jest konieczne, ponieważ delegat będzie wywołany później, a nie od razu podczas konfiguracji.

Przykład użycia

// Wstrzyknięcie klienta przez DI
public class InvoiceService
{
    private readonly IKSeFClient _ksefClient;
    private readonly ICryptographyService _cryptographyService;

    public InvoiceService(IKSeFClient ksefClient, ICryptographyService cryptographyService)
    {
        _ksefClient = ksefClient;
        _cryptographyService = cryptographyService;
    }

    // pełna implementacja np. WebApplication.Controllers.OnlineSessionController
    // Wysłanie faktury w sesji interaktywnej
    public async Task<string> SendInvoiceAsync(string invoiceXml, string sessionReferenceNumber, string accessToken)
    {
        // ...
        SendInvoiceResponse response = await _ksefClient.SendOnlineSessionInvoiceAsync(
            request,
            sessionReferenceNumber,
            accessToken,
            CancellationToken.None);
        
        return response.ReferenceNumber;
    }
}

Testowanie

Projekt zawiera rozbudowany zestaw testów:

  • Testy E2E i integracyjne (KSeF.Client.Tests.Core)
  • Testy jednostkowe i funkcjonalne (KSeF.Client.Tests)
  • Narzędzia testowe (KSeF.Client.Tests.Utils)

Uruchomienie testów

dotnet test KSeF.Client.sln

Rozwiązywanie problemów (Troubleshooting)

Błąd: "The password may be incorrect" na IIS / Azure

Jeśli podczas ładowania certyfikatu z kluczem prywatnym otrzymujesz wyjątek:

System.Security.Cryptography.CryptographicException: The EncryptedPrivateKeyInfo structure was decoded but was not successfully interpreted, the password may be incorrect.

Oznacza to zazwyczaj problem środowiskowy (brak załadowanego profilu użytkownika na IIS/Azure), a nie błędne hasło. System Windows próbuje zapisać tymczasowy klucz na dysku, ale nie ma do tego uprawnień.

Rozwiązanie

Zamiast standardowego X509Certificate2.CreateFromEncryptedPem, użyj metody rozszerzającej X509Certificate2.MergeWithPemKey dostępnej w bibliotece, która ładuje klucz w pamięci (Ephemeral Key):

using System.Security.Cryptography.X509Certificates;
using KSeF.Client.Extensions;

// 1. Wczytaj certyfikat publiczny i treść klucza PEM
X509Certificate2 publicCert = new X509Certificate2("cert.cer");
string privateKeyPem = File.ReadAllText("key.pem");

// 2. Połącz bezpiecznie (działa na Azure/IIS bez LoadUserProfile)
X509Certificate2 cert = publicCert.MergeWithPemKey(privateKeyPem, "TwojeHaslo");

Więcej informacji

Szczegółowe przykłady użycia i dokumentacja API dostępne są w repozytorium dokumentacji.

About

No description, website, or topics provided.

Resources

License

Contributing

Stars

Watchers

Forks

Packages