Raporty retrospektywne
Endpoint POST /v1/reports służy do zlecenia asynchronicznego wygenerowania raportu retrospektywnego. Przyjmuje zlecenie i zwraca 202 Accepted — faktyczne generowanie odbywa się w tle.
Endpoint
Nagłówki
| Nagłówek | Wymagany | Opis |
|---|---|---|
Authorization |
tak | Bearer <access_token> — token OAuth 2.0, podpisany kluczem prywatnym aplikacji |
ks-system-identification |
tak | Identyfikator systemu w formacie D.D.NNNNNN.YYYY |
Content-Type |
tak | application/json |
Struktura żądania
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
format |
string | tak | Format wynikowy: parquet lub csv. |
publicKeyPem |
string (PEM) | tak | Publiczny klucz RSA integratora do szyfrowania wyniku. Zobacz Szyfrowanie. |
runAt |
DateTime (ISO 8601, UTC) |
tak | Czas wykonania. Wartość w przeszłości lub teraźniejszości oznacza wykonanie natychmiastowe. |
storage |
obiekt | tak | Docelowe Azure Storage klienta, do którego trafi zaszyfrowany wynik. |
reportId |
string | nie* | Identyfikator konkretnego raportu. Wymagany jeśli groupId nie jest podany. |
groupId |
string | nie* | Identyfikator grupy raportów — generuje wszystkie raporty z grupy. Wymagany jeśli reportId nie jest podany. |
compression |
bool | nie | Włączenie kompresji przed szyfrowaniem. Domyślnie false. |
obfuscationToken |
string | nie | Token do obfuskacji danych osobowych. |
pseudonymizationToken |
string | nie | Token do pseudonimizacji danych osobowych. |
parameters |
object |
nie | Parametry specyficzne dla raportu (np. zakres dat, NIP). Zależne od reportId. |
* Dokładnie jedno z pól reportId lub groupId musi być podane.
storage
{
"storage": {
"type": "AzureBlob",
"connectionString": "BlobEndpoint=https://<account>.blob.core.windows.net/;SharedAccessSignature=..."
}
}
Magazyn jest własnością integratora. KAMSOFT zapisuje do niego zaszyfrowany artefakt i nie przechowuje kopii wyniku.
parameters — raporty EOD
Dla raportów kalkulacji kosztów (cost-calculation, product-level-cost-calculation) wymagane parametry:
| Klucz | Opis |
|---|---|
CompanyTaxNo |
NIP firmy |
Year |
Rok (liczba całkowita) |
Month |
Miesiąc (liczba całkowita, 1–12) |
Szyfrowanie
Wynik raportu jest szyfrowany algorytmem hybrydowym RSA/AESG/SHA256 (AES-GCM + RSA-OAEP).
Algorytm
Dla każdego raportu KAMSOFT:
- Generuje losowy klucz AES-256 (32 bajty) i nonce (12 bajtów) — łącznie 44 bajty klucza sesyjnego.
- Szyfruje dane raportu algorytmem AES-256-GCM — wynikiem są zaszyfrowane dane i 16-bajtowy tag autentyczności (GCM).
- Szyfruje klucz sesyjny (44 bajty) algorytmem RSA-OAEP-SHA256 używając klucza publicznego z pola
publicKeyPem. - Zwraca zaszyfrowany klucz sesyjny w odpowiedzi
202jako poleencryptedSessionKey(base64). - Zapisuje zaszyfrowany plik raportu do Azure Storage klienta.
Format artefaktu w blob storage
Artefakt to czyste dane AES-256-GCM (dane + 16-bajtowy GCM tag na końcu). Klucz i nonce są zwracane osobno w odpowiedzi HTTP — nie są osadzone w pliku.
| Segment | Rozmiar | Zawartość |
|---|---|---|
| Zaszyfrowane dane | N bajtów | Dane raportu zaszyfrowane AES-256-GCM |
| GCM tag | 16 bajtów | Tag autentyczności |
Generowanie pary kluczy
# Klucz 4096-bit — zalecany
openssl genrsa -out rsr-data.key 4096
openssl rsa -in rsr-data.key -pubout -out rsr-data.pub.pem
rsr-data.pub.pem— trafia do polapublicKeyPemw żądaniu (format PEM,BEGIN PUBLIC KEYlubBEGIN RSA PUBLIC KEY).rsr-data.key— przechowywany wyłącznie po stronie integratora do odszyfrowania wyniku.
Odszyfrowanie wyniku
Schemat deszyfrowania:
- Z odpowiedzi
202odczytaj poleencryptedSessionKey(base64) i zapisz je. - Odszyfruj
encryptedSessionKeykluczem prywatnym RSA (OAEP-SHA256) — otrzymujesz 44 bajty: pierwsze 32 B to klucz AES, kolejne 12 B to nonce. - Pobierz zaszyfrowany plik z Azure Blob Storage.
- Odszyfruj plik AES-256-GCM używając klucza i nonce z kroku 2 (weryfikacja tagu GCM jest obowiązkowa — odrzuć artefakt jeśli tag nie pasuje).
Do kroków 2–4 możesz użyć gotowego skryptu decrypt_report.py:
# Instalacja zależności
pip install cryptography
# Zapisanie klucza AES z odpowiedzi endpointu
curl -s -X POST https://<host>/v1/reports \
-H "Authorization: Bearer <token>" \
-H "ks-system-identification: 1.2.123456.2026" \
-H "Content-Type: application/json" \
-d @request.json | python3 -c "import sys,json; print(json.load(sys.stdin)['encryptedSessionKey'])" > aes_key.b64
# Pobranie zaszyfrowanego pliku z blob storage
az storage blob download \
--connection-string "<sas-connection-string>" \
--container-name rsr-output \
--name <ścieżka-do-pliku> \
--file report.enc
# Odszyfrowanie
python3 decrypt_report.py \
--private-key rsr-data.key \
--aes-key aes_key.b64 \
--input report.enc \
--output report.parquet
Klucze jednorazowe
Generuj nową parę RSA na każde zlecenie. Nie używaj ponownie kluczy z poprzednich żądań ani certyfikatu uwierzytelniającego do szyfrowania danych.
Przykład żądania
POST /v1/reports HTTP/1.1
Host: api.kamsoft.example
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIs...
ks-system-identification: 1.2.123456.2026
Content-Type: application/json
{
"format": "parquet",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A...\n-----END PUBLIC KEY-----",
"runAt": "2026-05-01T02:00:00Z",
"storage": {
"type": "AzureBlob",
"connectionString": "BlobEndpoint=https://integratorstorage.blob.core.windows.net/;SharedAccessSignature=sv=2024-11-04&..."
},
"reportId": "cost-calculation",
"parameters": {
"CompanyTaxNo": "1234567890",
"Year": "2026",
"Month": "4"
}
}
Odpowiedź 202 Accepted:
executionId— identyfikator zlecenia do celów diagnostycznych.encryptedSessionKey— klucz sesyjny AES zaszyfrowany kluczem publicznym RSA z polapublicKeyPem. Zachowaj go — jest potrzebny do odszyfrowania pliku po jego pojawieniu się wstorageConfig.
Kody odpowiedzi
| Kod | Znaczenie |
|---|---|
202 Accepted |
Zlecenie przyjęte. |
400 Bad Request |
Błędne body, brakujący publicKeyPem, niepoprawny zakres dat. |
401 Unauthorized |
Brak lub nieważny token Bearer. |
403 Forbidden |
Brak nadanego pola eksploatacji RSR. |
429 Too Many Requests |
Przekroczony limit bramki — zastosuj backoff wg Retry-After. |
5xx |
Awaria po stronie KAMSOFT. |
Cykl życia zlecenia
sequenceDiagram
participant I as Integrator
participant K as KAMSOFT API
participant S as Azure Storage (integratora)
I->>I: Generuje parę kluczy RSA
I->>K: POST /v1/reports (publicKeyPem)
K-->>I: 202 Accepted + encryptedSessionKey
I->>I: Zapisuje encryptedSessionKey
K->>K: Generuje raport
K->>K: Szyfruje dane AES-256-GCM
K->>S: Zapisuje zaszyfrowany plik
I->>S: Pobiera zaszyfrowany plik
I->>I: Odszyfrowuje encryptedSessionKey kluczem prywatnym RSA
I->>I: Odszyfrowuje plik AES-256-GCM