Skip to content

Commit ed5f067

Browse files
committed
release 3.0.24
1 parent 0e789b3 commit ed5f067

31 files changed

Lines changed: 1218 additions & 151 deletions

RELEASE_NOTES.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,3 +2072,66 @@
20722072
| ➕ dodane | 0 |
20732073
| 🔧 zmienione | 6 |
20742074
| ➖ usunięte | 0 |
2075+
2076+
2077+
# Changelog zmian - `## 3.0.24 (2026-04-22)`- `API: 2.4.0`
2078+
2079+
## 1. ksef-client
2080+
2081+
### 1.1 api.client.model
2082+
- **exceptions/TooManyRequestsApiException.java**: ➕ dodanie klasy
2083+
- **exceptions/TooManyRequestsProblemDetails.java**: ➕ dodanie klasy
2084+
- **exceptions/BadRequestApiError.java**: ➕ dodanie klasy
2085+
- **exceptions/BadRequestApiException.java**: ➕ dodanie klasy
2086+
- **exceptions/BadRequestProblemDetails.java**: ➕ dodanie klasy
2087+
- **exceptions/GoneApiException.java**: ➕ dodanie klasy
2088+
- **exceptions/GoneProblemDetails.java**: ➕ dodanie klasy
2089+
- **exceptions/UnauthorizedProblemDetails.java**: 🔧 dodanie pola `String timestamp`
2090+
- **exceptions/ForbiddenProblemDetails.java**: 🔧 dodanie pola `String timestamp`
2091+
- **exceptions/GetRateLimitIntegrationTest.java**: 🔧 aktualizacja testu
2092+
- **HttpStatus.java**: 🔧 dodanie enuma `GONE(410)`
2093+
2094+
### 1.2 client
2095+
- **Headers.java**: 🔧 dodanie pól `X_ERROR_FORMAT = "X-Error-Format"` i `X_ERROR_FORMAT_PROBLEM_DETAILS = "problem-details"`
2096+
2097+
### 1.3 system
2098+
- **ExceptionHandler.java**: ➕ dodanie klasy odpowiedzialnej za parsowanie błedów odpowiedzi http, dodano obsługę dla http 400, 410, 429 zgodnie z propozycją API KSeF ([#764](https://github.com/CIRFMF/ksef-docs/issues/764)) - najpierw próba zdekodowania odpowiedzi w nowym modelu, a następnie cofa się do dotychczasowego formatu.
2099+
2100+
### 1.4 api
2101+
- **DefaultKsefClient.java**: 🔧 parsowanie błedów odpowiedzi http przeniesiono do `ExceptionHandler`
2102+
2103+
### 1.5 api.services
2104+
- **DefaultSignatureService.java**: 🔧 - dodano obsługę podpisywania dokumentów dla kluczy eksportowalnych
2105+
2106+
### 1.6 sign
2107+
- **CertUtil.java**: 🔧 rozbudowa metod o sprawdzanie algorytmów kluczy
2108+
- **LocalSigningContext.java**: 🔧 dodano przeciążone metody `SignatureValue createSignatureValue` pod podpisywanie dla kluczy eksportowalnych, jedna oznaczona jako Deprecated
2109+
- **SignContextProvider.java**: 🔧 zgodnie z `LocalSigningContext`
2110+
2111+
## 2. demo-web-app
2112+
2113+
### 2.1 integrationTest
2114+
- **AuthorizationIntegrationTest.java**: 🔧 dodano test pod podpisywanie dla kluczy eksportowalnych
2115+
- **BatchIntegrationTest.java**: 🔧 aktualizacja testów po przejściu na nowy model dla błedów http (nagłówek `X-Error-Format: "problem-details"`)
2116+
- **QueryInvoiceIntegrationTest.java**: 🔧 aktualizacja testów po przejściu na nowy model dla błedów http (nagłówek `X-Error-Format: "problem-details"`)
2117+
- **SessionIntegrationTest.java**: 🔧 aktualizacja testów po przejściu na nowy model dla błedów http (nagłówek `X-Error-Format: "problem-details"`)
2118+
- **PeppolInvoiceIntegrationTest.java**: 🔧 zmiany związane z dodaniem placeholderów w `invoice_template_pef_correction.xml`
2119+
- **ExceptionsApiIntegrationTest.java**: 🔧 dodanie testów o obsługę kolejnych typów błedów http zwracanych z API
2120+
2121+
### 2.2 integrationTest.resources
2122+
- **xml/invoices/sample/invoice_template_pef_correction.xml**: 🔧 dodanie placeholderów dla numeru KSeF i daty faktury korygowanej
2123+
2124+
### 2.3 resources
2125+
- **application.yaml**: 🔧 dodanie domyślnie nagłówka `X-Error-Format: "problem-details"`
2126+
- **application-demo.yaml**: 🔧 dodanie domyślnie nagłówka `X-Error-Format: "problem-details"`
2127+
- **application-prod.yaml**: 🔧 dodanie domyślnie nagłówka `X-Error-Format: "problem-details"`
2128+
2129+
---
2130+
## 3. Podsumowanie
2131+
2132+
| Typ zmiany | Liczba plików |
2133+
|-------------|---------------|
2134+
| ➕ dodane | 8 |
2135+
| 🔧 zmienione | 20 |
2136+
| ➖ usunięte | 0 |
2137+

demo-web-app/build.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ plugins {
88
}
99

1010
group = "pl.akmf.ksef"
11-
version = "3.0.23"
11+
version = "3.0.24"
1212

1313
java {
1414
toolchain {
@@ -44,6 +44,7 @@ val testcontainersVersion = "1.21.3"
4444
val awaitilityVersion = "4.2.0"
4545
val googleZxing = "3.5.3"
4646
val reflectionsVersion = "0.10.2"
47+
val xadesVersion = "6.3"
4748

4849
dependencies {
4950
implementation(project(":ksef-client"))
@@ -79,6 +80,10 @@ dependencies {
7980
implementation("org.awaitility:awaitility:${awaitilityVersion}")
8081

8182
testImplementation("org.reflections:reflections:${reflectionsVersion}")
83+
84+
// weryfikacje podpisu
85+
integrationTestImplementation("eu.europa.ec.joinup.sd-dss:dss-validation:${xadesVersion}")
86+
integrationTestImplementation("eu.europa.ec.joinup.sd-dss:dss-policy-jaxb:${xadesVersion}")
8287
}
8388

8489
sourceSets {

demo-web-app/src/integrationTest/java/pl/akmf/ksef/sdk/AuthorizationIntegrationTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
package pl.akmf.ksef.sdk;
22

3+
import eu.europa.esig.dss.detailedreport.DetailedReport;
4+
import eu.europa.esig.dss.model.DSSDocument;
5+
import eu.europa.esig.dss.model.InMemoryDocument;
6+
import eu.europa.esig.dss.simplereport.SimpleReport;
7+
import eu.europa.esig.dss.spi.validation.CommonCertificateVerifier;
8+
import eu.europa.esig.dss.validation.SignedDocumentValidator;
9+
import eu.europa.esig.dss.validation.reports.Reports;
310
import jakarta.xml.bind.JAXBException;
411
import org.junit.jupiter.api.Assertions;
512
import org.junit.jupiter.api.Test;
@@ -29,7 +36,10 @@
2936
import pl.akmf.ksef.sdk.util.IdentifierGeneratorUtils;
3037

3138
import java.io.IOException;
39+
import java.nio.charset.StandardCharsets;
40+
import java.security.KeyStore;
3241
import java.security.PrivateKey;
42+
import java.security.cert.Certificate;
3343
import java.security.cert.X509Certificate;
3444
import java.time.Duration;
3545
import java.time.OffsetDateTime;
@@ -114,6 +124,54 @@ void authorizeByKSeFCertificateWithECDSaEncoding() throws Exception {
114124
Assertions.assertNotNull(tokenResponse);
115125
}
116126

127+
// @Test
128+
void signExportableKeysTest() throws Exception {
129+
String alias = "ec-key-alias"; // your alias
130+
131+
String contextNip = IdentifierGeneratorUtils.generateRandomNIP();
132+
AuthenticationChallengeResponse challenge = ksefClient.getAuthChallenge();
133+
AuthTokenRequest authTokenRequest = new AuthTokenRequestBuilder()
134+
.withChallenge(challenge.getChallenge())
135+
.withContextNip(contextNip)
136+
.withSubjectType(SubjectIdentifierTypeEnum.CERTIFICATE_SUBJECT)
137+
.build();
138+
139+
String xml = AuthTokenRequestSerializer.authTokenRequestSerializer(authTokenRequest);
140+
141+
KeyStore ks = KeyStore.getInstance("Windows-MY");
142+
ks.load(null, null);
143+
144+
if (ks.containsAlias(alias)) {
145+
PrivateKey privateKey = (PrivateKey) ks.getKey(alias, null);
146+
Certificate cert = ks.getCertificate(alias);
147+
148+
String signedXml = signatureService.sign(xml.getBytes(), (X509Certificate) cert, privateKey);
149+
System.out.println("----");
150+
System.out.println("signedXml: " + signedXml);
151+
System.out.println("----");
152+
153+
byte[] bytes = signedXml.getBytes(StandardCharsets.UTF_8);
154+
DSSDocument document = new InMemoryDocument(bytes);
155+
SignedDocumentValidator validator = SignedDocumentValidator.fromDocument(document);
156+
validator.setCertificateVerifier(new CommonCertificateVerifier());
157+
Reports reports = validator.validateDocument();
158+
SimpleReport simpleReport = reports.getSimpleReport();
159+
List<String> simpleSignatureIds = simpleReport.getSignatureIdList();
160+
161+
for (String id : simpleSignatureIds) {
162+
boolean valid = simpleReport.isValid(id);
163+
System.out.println("Simple signature " + id + " - valid: " + valid);
164+
}
165+
166+
DetailedReport detailedReport = reports.getDetailedReport();
167+
boolean valid = detailedReport.isCertificateValidation();
168+
System.out.println("Detailed report - valid: " + valid);
169+
170+
} else {
171+
Assertions.fail("Could not find alias: " + alias + "in KeyStore.");
172+
}
173+
}
174+
117175
@Test
118176
void authorizeByKSeFCertificateWithRSaEncoding() throws Exception {
119177
String contextNip = IdentifierGeneratorUtils.generateRandomNIP();

demo-web-app/src/integrationTest/java/pl/akmf/ksef/sdk/BatchIntegrationTest.java

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import org.springframework.beans.factory.annotation.Autowired;
77
import pl.akmf.ksef.sdk.api.builders.batch.OpenBatchSessionRequestBuilder;
88
import pl.akmf.ksef.sdk.api.services.DefaultCryptographyService;
9-
import pl.akmf.ksef.sdk.client.ExceptionDetails;
109
import pl.akmf.ksef.sdk.client.model.ApiException;
11-
import pl.akmf.ksef.sdk.client.model.ExceptionResponse;
1210
import pl.akmf.ksef.sdk.client.model.UpoVersion;
11+
import pl.akmf.ksef.sdk.client.model.exceptions.BadRequestApiError;
12+
import pl.akmf.ksef.sdk.client.model.exceptions.BadRequestApiException;
13+
import pl.akmf.ksef.sdk.client.model.exceptions.BadRequestProblemDetails;
1314
import pl.akmf.ksef.sdk.client.model.session.EncryptionData;
1415
import pl.akmf.ksef.sdk.client.model.session.EncryptionInfo;
1516
import pl.akmf.ksef.sdk.client.model.session.FileMetadata;
@@ -187,12 +188,13 @@ void shouldThrowWhileSendWithExceededTotalPackageSize() throws JAXBException, IO
187188
// API KSeF powinno odrzucić żądanie ze względu na przekroczony limit fileSize
188189
ApiException apiException = assertThrows(ApiException.class, () ->
189190
ksefClient.openBatchSession(request, UpoVersion.UPO_4_3, accessToken));
190-
ExceptionResponse exceptionResponse = apiException.getExceptionResponse();
191-
Assertions.assertFalse(exceptionResponse.getException().getExceptionDetailList().isEmpty());
192-
ExceptionDetails details = exceptionResponse.getException().getExceptionDetailList().getFirst();
193-
Assertions.assertEquals(21405, details.getExceptionCode());
194-
Assertions.assertEquals("Błąd walidacji danych wejściowych.", details.getExceptionDescription());
195-
Assertions.assertEquals("'fileSize' must be less than or equal to '5000000000'.", details.getDetails().getFirst());
191+
BadRequestApiException badRequestApiException = (BadRequestApiException) apiException;
192+
BadRequestProblemDetails exceptionResponse = badRequestApiException.getBadRequestProblemDetails();
193+
Assertions.assertFalse(exceptionResponse.getErrors().isEmpty());
194+
BadRequestApiError error = exceptionResponse.getErrors().getFirst();
195+
Assertions.assertEquals(21405, error.getCode());
196+
Assertions.assertEquals("Błąd walidacji danych wejściowych.", error.getDescription());
197+
Assertions.assertEquals("'fileSize' must be less than or equal to '5000000000'.", error.getDetails().getFirst());
196198
}
197199

198200
// Weryfikuje odrzucenie paczki przekraczającej limit rozmiaru 100 MiB (przed szyfrowaniem).
@@ -287,12 +289,13 @@ void shouldThrowWhileCloseSessionWithoutAllParts() throws JAXBException, IOExcep
287289

288290
ApiException apiException = assertThrows(ApiException.class, () ->
289291
closeSession(sessionReferenceNumber, accessToken));
290-
ExceptionResponse exceptionResponse = apiException.getExceptionResponse();
291-
Assertions.assertFalse(exceptionResponse.getException().getExceptionDetailList().isEmpty());
292-
ExceptionDetails details = exceptionResponse.getException().getExceptionDetailList().getFirst();
293-
Assertions.assertEquals(21205, details.getExceptionCode());
294-
Assertions.assertEquals("Pakiet nie może być pusty.", details.getExceptionDescription());
295-
Assertions.assertEquals("Nie przesłano zadeklarowanej '2' części pliku.", details.getDetails().getFirst());
292+
BadRequestApiException badRequestApiException = (BadRequestApiException) apiException;
293+
BadRequestProblemDetails exceptionResponse = badRequestApiException.getBadRequestProblemDetails();
294+
Assertions.assertFalse(exceptionResponse.getErrors().isEmpty());
295+
BadRequestApiError error = exceptionResponse.getErrors().getFirst();
296+
Assertions.assertEquals(21205, error.getCode());
297+
Assertions.assertEquals("Pakiet nie może być pusty.", error.getDescription());
298+
Assertions.assertEquals("Nie przesłano zadeklarowanej '2' części pliku.", error.getDetails().getFirst());
296299
}
297300

298301
// Weryfikuje odrzucenie paczki z liczbą części przekraczającą maksymalny limit 50.
@@ -325,12 +328,13 @@ void shouldThrowWhileSendWithExceededPartCount() throws JAXBException, IOExcepti
325328
// API KSeF odrzuca żądanie z przekroczoną liczbą części
326329
ApiException apiException = assertThrows(ApiException.class, () ->
327330
ksefClient.openBatchSession(request, UpoVersion.UPO_4_3, accessToken));
328-
ExceptionResponse exceptionResponse = apiException.getExceptionResponse();
329-
Assertions.assertFalse(exceptionResponse.getException().getExceptionDetailList().isEmpty());
330-
ExceptionDetails details = exceptionResponse.getException().getExceptionDetailList().getFirst();
331-
Assertions.assertEquals(21161, details.getExceptionCode());
332-
Assertions.assertEquals("Przekroczono dozwoloną liczbę części pakietów.", details.getExceptionDescription());
333-
Assertions.assertEquals("Liczba części pliku musi być mniejsza lub równa niż 50.", details.getDetails().getFirst());
331+
BadRequestApiException badRequestApiException = (BadRequestApiException) apiException;
332+
BadRequestProblemDetails exceptionResponse = badRequestApiException.getBadRequestProblemDetails();
333+
Assertions.assertFalse(exceptionResponse.getErrors().isEmpty());
334+
BadRequestApiError error = exceptionResponse.getErrors().getFirst();
335+
Assertions.assertEquals(21161, error.getCode());
336+
Assertions.assertEquals("Przekroczono dozwoloną liczbę części pakietów.", error.getDescription());
337+
Assertions.assertEquals("Liczba części pliku musi być mniejsza lub równa niż 50.", error.getDetails().getFirst());
334338
}
335339

336340
// Weryfikuje wykrycie nieprawidłowo zaszyfrowanego klucza symetrycznego.

0 commit comments

Comments
 (0)