ksef-rb 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -0
- data/README.md +25 -2
- data/lib/ksef/internal/connection.rb +9 -2
- data/lib/ksef/internal/token_encryptor.rb +12 -5
- data/lib/ksef/invoice_header.rb +3 -2
- data/lib/ksef/version.rb +1 -1
- data/lib/ksef-rb.rb +6 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f0036e4b7913536223a5b778902fa2bd69f334494b76772df2cf74dc7a2219d
|
|
4
|
+
data.tar.gz: 3bf943a76ccb8504b13475b7c0783b5571e46191a94e2f999253d5ebe54fa9d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c99c25e305544ff19f78829e1aa696711b8b19d8439c29f5577b03a4e4e6a0ebe81e225452f094ccc75edb1556234a6654970d5c5136090a4d7fed0986c038f
|
|
7
|
+
data.tar.gz: 642c4bedf0387bc6591b2132f457324b08f413127cba53dca6360d5317b68457fd93622b6fbc6107e0a9f4178ef17e26f16eb066b15aa16a8a45c5eeae9b96f8
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.3] - 2026-07-13
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Retry middleware: `Faraday::RetriableResponse` was missing from
|
|
14
|
+
`Connection::RETRY_OPTIONS[:exceptions]`. Because that key overrides the
|
|
15
|
+
faraday-retry default (which includes it), its absence silently disabled the
|
|
16
|
+
`retry_statuses: [502, 503, 504]` retries **and** leaked the raw synthetic
|
|
17
|
+
`Faraday::RetriableResponse` up the stack instead of mapping it to a typed
|
|
18
|
+
`Ksef::ServerError`. Observed in production as an unretried gateway blip on
|
|
19
|
+
`POST /auth/challenge` surfacing as `Faraday::RetriableResponse` rather than
|
|
20
|
+
being absorbed. The class is now included, so 502/503/504 are retried up to
|
|
21
|
+
`max` and, if still failing, raised as `Ksef::ServerError`. Added regression
|
|
22
|
+
specs covering both retry-then-recover and retry-then-exhaust paths.
|
|
23
|
+
|
|
24
|
+
## [0.1.2] - 2026-05-19
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- `/security/public-key-certificates` returns a DER-encoded X.509 certificate,
|
|
28
|
+
not a bare SPKI. The previous `Internal::TokenEncryptor.normalize_public_key`
|
|
29
|
+
fed the DER straight into `OpenSSL::PKey::RSA.new`, which raised
|
|
30
|
+
`OpenSSL::PKey::PKeyError: Neither PUB key nor PRIV key` against the live
|
|
31
|
+
production endpoint. The normaliser now parses the bytes as an X.509
|
|
32
|
+
certificate and extracts the public key, falling back to the bare-key code
|
|
33
|
+
path for backwards compatibility. The spec-helper fixture was updated to
|
|
34
|
+
return a real self-signed X.509 cert (matching the real KSeF response shape)
|
|
35
|
+
so the entire session lifecycle exercises this path.
|
|
36
|
+
- `Ksef::InvoiceHeader` now `require`s `"time"` explicitly. It calls
|
|
37
|
+
`Time.iso8601` to parse `acquisitionDate` / `permanentStorageDate`; the spec
|
|
38
|
+
suite happened to load `time` transitively via `webmock`, but a bare
|
|
39
|
+
consumer that only required `"ksef"` got `NoMethodError: undefined method
|
|
40
|
+
'iso8601' for class Time` the first time they pulled invoice metadata.
|
|
41
|
+
|
|
42
|
+
## [0.1.1] - 2026-05-19
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
- `lib/ksef-rb.rb` shim so `gem "ksef-rb"` works in any Gemfile without
|
|
46
|
+
the `require: "ksef"` option. Consumers who already use the explicit
|
|
47
|
+
`require:` form keep working unchanged.
|
|
48
|
+
|
|
10
49
|
## [0.1.0] - 2025-05-18
|
|
11
50
|
|
|
12
51
|
### Added
|
data/README.md
CHANGED
|
@@ -15,7 +15,7 @@ but additions are expected as more KSeF features land.
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
17
17
|
```ruby
|
|
18
|
-
gem "ksef-rb"
|
|
18
|
+
gem "ksef-rb"
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Quick start
|
|
@@ -37,7 +37,8 @@ client.sessions.with_interactive do |_session|
|
|
|
37
37
|
headers = client.invoices.query(
|
|
38
38
|
subject_type: :recipient,
|
|
39
39
|
date_from: Time.now.utc - (7 * 24 * 3600),
|
|
40
|
-
date_to: Time.now.utc
|
|
40
|
+
date_to: Time.now.utc,
|
|
41
|
+
date_type: :issue # :permanent_storage (default), :invoicing, or :issue
|
|
41
42
|
)
|
|
42
43
|
|
|
43
44
|
headers.each do |h|
|
|
@@ -49,6 +50,28 @@ client.sessions.with_interactive do |_session|
|
|
|
49
50
|
end
|
|
50
51
|
```
|
|
51
52
|
|
|
53
|
+
`#query` returns at most `page_size` headers per call (default 100, max 250).
|
|
54
|
+
Paginate by bumping `page_offset` until a short page comes back:
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
all = []
|
|
58
|
+
offset = 0
|
|
59
|
+
loop do
|
|
60
|
+
page = client.invoices.query(
|
|
61
|
+
subject_type: :recipient,
|
|
62
|
+
date_from: Date.new(2026, 4, 1),
|
|
63
|
+
date_to: Date.new(2026, 5, 31),
|
|
64
|
+
date_type: :issue,
|
|
65
|
+
page_size: 250,
|
|
66
|
+
page_offset: offset
|
|
67
|
+
)
|
|
68
|
+
all.concat(page)
|
|
69
|
+
break if page.size < 250
|
|
70
|
+
|
|
71
|
+
offset += 1
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
52
75
|
`Ksef::InvoiceHeader` exposes (among others):
|
|
53
76
|
`ksef_reference_number`, `invoice_number`, `issuer_nip`, `issuer_name`,
|
|
54
77
|
`recipient_nip`, `recipient_name`, `issued_on`, `gross_amount`, `net_amount`,
|
|
@@ -18,10 +18,17 @@ module Ksef
|
|
|
18
18
|
backoff_factor: 2,
|
|
19
19
|
retry_statuses: [502, 503, 504],
|
|
20
20
|
methods: %i[get head post delete put patch],
|
|
21
|
+
# `Faraday::RetriableResponse` MUST stay in this list: faraday-retry
|
|
22
|
+
# raises it internally to trigger a `retry_statuses` retry. Because we
|
|
23
|
+
# override `exceptions` (rather than inheriting the middleware default,
|
|
24
|
+
# which includes it), omitting it silently disables 502/503/504 retries
|
|
25
|
+
# *and* leaks the raw synthetic exception past `check!` instead of
|
|
26
|
+
# mapping it to a typed `Ksef::ServerError`.
|
|
21
27
|
exceptions: [
|
|
22
28
|
Errno::ETIMEDOUT,
|
|
23
29
|
Faraday::TimeoutError,
|
|
24
|
-
Faraday::ConnectionFailed
|
|
30
|
+
Faraday::ConnectionFailed,
|
|
31
|
+
Faraday::RetriableResponse
|
|
25
32
|
]
|
|
26
33
|
}.freeze
|
|
27
34
|
|
|
@@ -134,7 +141,7 @@ module Ksef
|
|
|
134
141
|
end
|
|
135
142
|
|
|
136
143
|
def parse_retry_after(value)
|
|
137
|
-
return
|
|
144
|
+
return if value.nil?
|
|
138
145
|
|
|
139
146
|
Integer(value)
|
|
140
147
|
rescue ArgumentError, TypeError
|
|
@@ -34,13 +34,20 @@ module Ksef
|
|
|
34
34
|
Base64.strict_encode64(ciphertext)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
37
|
+
# Normalizes whatever `/security/public-key-certificates` hands us into a
|
|
38
|
+
# PEM-encoded RSA public key suitable for {.encrypt}.
|
|
39
|
+
#
|
|
40
|
+
# KSeF returns the `certificate` field as a base64-encoded DER X.509
|
|
41
|
+
# certificate (not a bare public key), so we parse it as a cert first
|
|
42
|
+
# and extract the SPKI. PEM-armored inputs and bare-key DER blobs are
|
|
43
|
+
# also accepted as a courtesy.
|
|
40
44
|
def normalize_public_key(raw)
|
|
41
|
-
|
|
45
|
+
text = raw.to_s
|
|
46
|
+
return text if text.include?("BEGIN")
|
|
42
47
|
|
|
43
|
-
der = Base64.decode64(
|
|
48
|
+
der = Base64.decode64(text)
|
|
49
|
+
OpenSSL::X509::Certificate.new(der).public_key.to_pem
|
|
50
|
+
rescue OpenSSL::X509::CertificateError
|
|
44
51
|
OpenSSL::PKey::RSA.new(der).to_pem
|
|
45
52
|
end
|
|
46
53
|
end
|
data/lib/ksef/invoice_header.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "date"
|
|
4
|
+
require "time"
|
|
4
5
|
|
|
5
6
|
module Ksef
|
|
6
7
|
# Lightweight value object describing an invoice as returned by
|
|
@@ -56,7 +57,7 @@ module Ksef
|
|
|
56
57
|
private
|
|
57
58
|
|
|
58
59
|
def parse_date(value)
|
|
59
|
-
return
|
|
60
|
+
return if value.nil? || value.empty?
|
|
60
61
|
|
|
61
62
|
Date.iso8601(value)
|
|
62
63
|
rescue ArgumentError
|
|
@@ -64,7 +65,7 @@ module Ksef
|
|
|
64
65
|
end
|
|
65
66
|
|
|
66
67
|
def parse_time(value)
|
|
67
|
-
return
|
|
68
|
+
return if value.nil? || value.empty?
|
|
68
69
|
|
|
69
70
|
Time.iso8601(value)
|
|
70
71
|
rescue ArgumentError
|
data/lib/ksef/version.rb
CHANGED
data/lib/ksef-rb.rb
ADDED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ksef-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michał Siwek
|
|
@@ -91,6 +91,7 @@ files:
|
|
|
91
91
|
- CHANGELOG.md
|
|
92
92
|
- LICENSE.txt
|
|
93
93
|
- README.md
|
|
94
|
+
- lib/ksef-rb.rb
|
|
94
95
|
- lib/ksef.rb
|
|
95
96
|
- lib/ksef/client.rb
|
|
96
97
|
- lib/ksef/configuration.rb
|