pdnd-ruby-client 0.1.1
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 +7 -0
- data/.env.sample +6 -0
- data/.rspec +1 -0
- data/.rubocop.yml +291 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +21 -0
- data/README.md +251 -0
- data/Rakefile +4 -0
- data/configs/sample.json +16 -0
- data/lib/pdnd-ruby-client/client.rb +116 -0
- data/lib/pdnd-ruby-client/config_loader.rb +21 -0
- data/lib/pdnd-ruby-client/errors.rb +33 -0
- data/lib/pdnd-ruby-client/jwt_generator.rb +165 -0
- data/lib/pdnd-ruby-client/token_manager.rb +35 -0
- data/lib/pdnd-ruby-client/version.rb +7 -0
- data/lib/pdnd-ruby-client.rb +8 -0
- data/sig/pdnd-ruby-client.rbs +6 -0
- data/tmp/.gitkeep +0 -0
- data/tmp/pdnd_token.json +1 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c13a6f6c53adb114f00fb2e5a8c3a1678ac18e674b69cb120f39d9770d923946
|
4
|
+
data.tar.gz: 36806f273b1e1cf8c75e811f55d7e7a6151cecf5b094bab6451bb05e7dc8811c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 652a135f762aef625ecc67fbeab5c12491c719614c74ba220a70673b34073a288d3ecb9554e7c16d0443ac301fa5525f69a613acb0d319214340722ffe61af2c
|
7
|
+
data.tar.gz: ec24d9ffcfc9ac7bab1e1d7e39400ed0bc7dd75e835be58f953275e41865fa69b6d5a74dce3a4c441b9175516d03e272ad906db9afc0c0d724f2fea27943afb8
|
data/.env.sample
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
AllCops:
|
2
|
+
NewCops: enable
|
3
|
+
SuggestExtensions: false
|
4
|
+
Exclude:
|
5
|
+
- 'bin/console'
|
6
|
+
|
7
|
+
|
8
|
+
Gemspec/AddRuntimeDependency: # new in 1.65
|
9
|
+
Enabled: true
|
10
|
+
Gemspec/AttributeAssignment: # new in 1.77
|
11
|
+
Enabled: true
|
12
|
+
Gemspec/DeprecatedAttributeAssignment: # new in 1.30
|
13
|
+
Enabled: true
|
14
|
+
Gemspec/DevelopmentDependencies: # new in 1.44
|
15
|
+
Enabled: true
|
16
|
+
Gemspec/RequireMFA: # new in 1.23
|
17
|
+
Enabled: true
|
18
|
+
Layout/EmptyLinesAfterModuleInclusion: # new in 1.79
|
19
|
+
Enabled: true
|
20
|
+
Layout/LineContinuationLeadingSpace: # new in 1.31
|
21
|
+
Enabled: true
|
22
|
+
Layout/LineContinuationSpacing: # new in 1.31
|
23
|
+
Enabled: true
|
24
|
+
Layout/LineEndStringConcatenationIndentation: # new in 1.18
|
25
|
+
Enabled: true
|
26
|
+
Layout/SpaceBeforeBrackets: # new in 1.7
|
27
|
+
Enabled: true
|
28
|
+
Lint/AmbiguousAssignment: # new in 1.7
|
29
|
+
Enabled: true
|
30
|
+
Lint/AmbiguousOperatorPrecedence: # new in 1.21
|
31
|
+
Enabled: true
|
32
|
+
Lint/AmbiguousRange: # new in 1.19
|
33
|
+
Enabled: true
|
34
|
+
Lint/ArrayLiteralInRegexp: # new in 1.71
|
35
|
+
Enabled: true
|
36
|
+
Lint/ConstantOverwrittenInRescue: # new in 1.31
|
37
|
+
Enabled: true
|
38
|
+
Lint/ConstantReassignment: # new in 1.70
|
39
|
+
Enabled: true
|
40
|
+
Lint/CopDirectiveSyntax: # new in 1.72
|
41
|
+
Enabled: true
|
42
|
+
Lint/DeprecatedConstants: # new in 1.8
|
43
|
+
Enabled: true
|
44
|
+
Lint/DuplicateBranch: # new in 1.3
|
45
|
+
Enabled: true
|
46
|
+
Lint/DuplicateMagicComment: # new in 1.37
|
47
|
+
Enabled: true
|
48
|
+
Lint/DuplicateMatchPattern: # new in 1.50
|
49
|
+
Enabled: true
|
50
|
+
Lint/DuplicateRegexpCharacterClassElement: # new in 1.1
|
51
|
+
Enabled: true
|
52
|
+
Lint/DuplicateSetElement: # new in 1.67
|
53
|
+
Enabled: true
|
54
|
+
Lint/EmptyBlock: # new in 1.1
|
55
|
+
Enabled: true
|
56
|
+
Lint/EmptyClass: # new in 1.3
|
57
|
+
Enabled: true
|
58
|
+
Lint/EmptyInPattern: # new in 1.16
|
59
|
+
Enabled: true
|
60
|
+
Lint/HashNewWithKeywordArgumentsAsDefault: # new in 1.69
|
61
|
+
Enabled: true
|
62
|
+
Lint/IncompatibleIoSelectWithFiberScheduler: # new in 1.21
|
63
|
+
Enabled: true
|
64
|
+
Lint/ItWithoutArgumentsInBlock: # new in 1.59
|
65
|
+
Enabled: true
|
66
|
+
Lint/LambdaWithoutLiteralBlock: # new in 1.8
|
67
|
+
Enabled: true
|
68
|
+
Lint/LiteralAssignmentInCondition: # new in 1.58
|
69
|
+
Enabled: true
|
70
|
+
Lint/MixedCaseRange: # new in 1.53
|
71
|
+
Enabled: true
|
72
|
+
Lint/NoReturnInBeginEndBlocks: # new in 1.2
|
73
|
+
Enabled: true
|
74
|
+
Lint/NonAtomicFileOperation: # new in 1.31
|
75
|
+
Enabled: true
|
76
|
+
Lint/NumberedParameterAssignment: # new in 1.9
|
77
|
+
Enabled: true
|
78
|
+
Lint/NumericOperationWithConstantResult: # new in 1.69
|
79
|
+
Enabled: true
|
80
|
+
Lint/OrAssignmentToConstant: # new in 1.9
|
81
|
+
Enabled: true
|
82
|
+
Lint/RedundantDirGlobSort: # new in 1.8
|
83
|
+
Enabled: true
|
84
|
+
Lint/RedundantRegexpQuantifiers: # new in 1.53
|
85
|
+
Enabled: true
|
86
|
+
Lint/RedundantTypeConversion: # new in 1.72
|
87
|
+
Enabled: true
|
88
|
+
Lint/RefinementImportMethods: # new in 1.27
|
89
|
+
Enabled: true
|
90
|
+
Lint/RequireRangeParentheses: # new in 1.32
|
91
|
+
Enabled: true
|
92
|
+
Lint/RequireRelativeSelfPath: # new in 1.22
|
93
|
+
Enabled: true
|
94
|
+
Lint/SharedMutableDefault: # new in 1.70
|
95
|
+
Enabled: true
|
96
|
+
Lint/SuppressedExceptionInNumberConversion: # new in 1.72
|
97
|
+
Enabled: true
|
98
|
+
Lint/SymbolConversion: # new in 1.9
|
99
|
+
Enabled: true
|
100
|
+
Lint/ToEnumArguments: # new in 1.1
|
101
|
+
Enabled: true
|
102
|
+
Lint/TripleQuotes: # new in 1.9
|
103
|
+
Enabled: true
|
104
|
+
Lint/UnescapedBracketInRegexp: # new in 1.68
|
105
|
+
Enabled: true
|
106
|
+
Lint/UnexpectedBlockArity: # new in 1.5
|
107
|
+
Enabled: true
|
108
|
+
Lint/UnmodifiedReduceAccumulator: # new in 1.1
|
109
|
+
Enabled: true
|
110
|
+
Lint/UselessConstantScoping: # new in 1.72
|
111
|
+
Enabled: true
|
112
|
+
Lint/UselessDefaultValueArgument: # new in 1.76
|
113
|
+
Enabled: true
|
114
|
+
Lint/UselessDefined: # new in 1.69
|
115
|
+
Enabled: true
|
116
|
+
Lint/UselessNumericOperation: # new in 1.66
|
117
|
+
Enabled: true
|
118
|
+
Lint/UselessOr: # new in 1.76
|
119
|
+
Enabled: true
|
120
|
+
Lint/UselessRescue: # new in 1.43
|
121
|
+
Enabled: true
|
122
|
+
Lint/UselessRuby2Keywords: # new in 1.23
|
123
|
+
Enabled: true
|
124
|
+
Metrics/CollectionLiteralLength: # new in 1.47
|
125
|
+
Enabled: true
|
126
|
+
Metrics/AbcSize:
|
127
|
+
Enabled: false
|
128
|
+
Naming/FileName:
|
129
|
+
Enabled: false
|
130
|
+
Naming/BlockForwarding: # new in 1.24
|
131
|
+
Enabled: true
|
132
|
+
Naming/PredicateMethod: # new in 1.76
|
133
|
+
Enabled: true
|
134
|
+
Security/CompoundHash: # new in 1.28
|
135
|
+
Enabled: true
|
136
|
+
Security/IoMethods: # new in 1.22
|
137
|
+
Enabled: true
|
138
|
+
Style/AmbiguousEndlessMethodDefinition: # new in 1.68
|
139
|
+
Enabled: true
|
140
|
+
Style/ArgumentsForwarding: # new in 1.1
|
141
|
+
Enabled: true
|
142
|
+
Style/ArrayIntersect: # new in 1.40
|
143
|
+
Enabled: true
|
144
|
+
Style/BitwisePredicate: # new in 1.68
|
145
|
+
Enabled: true
|
146
|
+
Style/CollectionCompact: # new in 1.2
|
147
|
+
Enabled: true
|
148
|
+
Style/CollectionQuerying: # new in 1.77
|
149
|
+
Enabled: true
|
150
|
+
Style/CombinableDefined: # new in 1.68
|
151
|
+
Enabled: true
|
152
|
+
Style/ComparableBetween: # new in 1.74
|
153
|
+
Enabled: true
|
154
|
+
Style/ComparableClamp: # new in 1.44
|
155
|
+
Enabled: true
|
156
|
+
Style/ConcatArrayLiterals: # new in 1.41
|
157
|
+
Enabled: true
|
158
|
+
Style/DataInheritance: # new in 1.49
|
159
|
+
Enabled: true
|
160
|
+
Style/DigChain: # new in 1.69
|
161
|
+
Enabled: true
|
162
|
+
Style/DirEmpty: # new in 1.48
|
163
|
+
Enabled: true
|
164
|
+
Style/DocumentDynamicEvalDefinition: # new in 1.1
|
165
|
+
Enabled: true
|
166
|
+
Style/EmptyHeredoc: # new in 1.32
|
167
|
+
Enabled: true
|
168
|
+
Style/EmptyStringInsideInterpolation: # new in 1.76
|
169
|
+
Enabled: true
|
170
|
+
Style/EndlessMethod: # new in 1.8
|
171
|
+
Enabled: true
|
172
|
+
Style/EnvHome: # new in 1.29
|
173
|
+
Enabled: true
|
174
|
+
Style/ExactRegexpMatch: # new in 1.51
|
175
|
+
Enabled: true
|
176
|
+
Style/FetchEnvVar: # new in 1.28
|
177
|
+
Enabled: true
|
178
|
+
Style/FileEmpty: # new in 1.48
|
179
|
+
Enabled: true
|
180
|
+
Style/FileNull: # new in 1.69
|
181
|
+
Enabled: true
|
182
|
+
Style/FileRead: # new in 1.24
|
183
|
+
Enabled: true
|
184
|
+
Style/FileTouch: # new in 1.69
|
185
|
+
Enabled: true
|
186
|
+
Style/FileWrite: # new in 1.24
|
187
|
+
Enabled: true
|
188
|
+
Style/HashConversion: # new in 1.10
|
189
|
+
Enabled: true
|
190
|
+
Style/HashExcept: # new in 1.7
|
191
|
+
Enabled: true
|
192
|
+
Style/HashFetchChain: # new in 1.75
|
193
|
+
Enabled: true
|
194
|
+
Style/HashSlice: # new in 1.71
|
195
|
+
Enabled: true
|
196
|
+
Style/IfWithBooleanLiteralBranches: # new in 1.9
|
197
|
+
Enabled: true
|
198
|
+
Style/InPatternThen: # new in 1.16
|
199
|
+
Enabled: true
|
200
|
+
Style/ItAssignment: # new in 1.70
|
201
|
+
Enabled: true
|
202
|
+
Style/ItBlockParameter: # new in 1.75
|
203
|
+
Enabled: true
|
204
|
+
Style/KeywordArgumentsMerging: # new in 1.68
|
205
|
+
Enabled: true
|
206
|
+
Style/MagicCommentFormat: # new in 1.35
|
207
|
+
Enabled: true
|
208
|
+
Style/MapCompactWithConditionalBlock: # new in 1.30
|
209
|
+
Enabled: true
|
210
|
+
Style/MapIntoArray: # new in 1.63
|
211
|
+
Enabled: true
|
212
|
+
Style/MapToHash: # new in 1.24
|
213
|
+
Enabled: true
|
214
|
+
Style/MapToSet: # new in 1.42
|
215
|
+
Enabled: true
|
216
|
+
Style/MinMaxComparison: # new in 1.42
|
217
|
+
Enabled: true
|
218
|
+
Style/MultilineInPatternThen: # new in 1.16
|
219
|
+
Enabled: true
|
220
|
+
Style/NegatedIfElseCondition: # new in 1.2
|
221
|
+
Enabled: true
|
222
|
+
Style/NestedFileDirname: # new in 1.26
|
223
|
+
Enabled: true
|
224
|
+
Style/NilLambda: # new in 1.3
|
225
|
+
Enabled: true
|
226
|
+
Style/NumberedParameters: # new in 1.22
|
227
|
+
Enabled: true
|
228
|
+
Style/NumberedParametersLimit: # new in 1.22
|
229
|
+
Enabled: true
|
230
|
+
Style/ObjectThen: # new in 1.28
|
231
|
+
Enabled: true
|
232
|
+
Style/OpenStructUse: # new in 1.23
|
233
|
+
Enabled: true
|
234
|
+
Style/OperatorMethodCall: # new in 1.37
|
235
|
+
Enabled: true
|
236
|
+
Style/QuotedSymbols: # new in 1.16
|
237
|
+
Enabled: true
|
238
|
+
Style/RedundantArgument: # new in 1.4
|
239
|
+
Enabled: true
|
240
|
+
Style/RedundantArrayConstructor: # new in 1.52
|
241
|
+
Enabled: true
|
242
|
+
Style/RedundantArrayFlatten: # new in 1.76
|
243
|
+
Enabled: true
|
244
|
+
Style/RedundantConstantBase: # new in 1.40
|
245
|
+
Enabled: true
|
246
|
+
Style/RedundantCurrentDirectoryInPath: # new in 1.53
|
247
|
+
Enabled: true
|
248
|
+
Style/RedundantDoubleSplatHashBraces: # new in 1.41
|
249
|
+
Enabled: true
|
250
|
+
Style/RedundantEach: # new in 1.38
|
251
|
+
Enabled: true
|
252
|
+
Style/RedundantFilterChain: # new in 1.52
|
253
|
+
Enabled: true
|
254
|
+
Style/RedundantFormat: # new in 1.72
|
255
|
+
Enabled: true
|
256
|
+
Style/RedundantHeredocDelimiterQuotes: # new in 1.45
|
257
|
+
Enabled: true
|
258
|
+
Style/RedundantInitialize: # new in 1.27
|
259
|
+
Enabled: true
|
260
|
+
Style/RedundantInterpolationUnfreeze: # new in 1.66
|
261
|
+
Enabled: true
|
262
|
+
Style/RedundantLineContinuation: # new in 1.49
|
263
|
+
Enabled: true
|
264
|
+
Style/RedundantRegexpArgument: # new in 1.53
|
265
|
+
Enabled: true
|
266
|
+
Style/RedundantRegexpConstructor: # new in 1.52
|
267
|
+
Enabled: true
|
268
|
+
Style/RedundantSelfAssignmentBranch: # new in 1.19
|
269
|
+
Enabled: true
|
270
|
+
Style/RedundantStringEscape: # new in 1.37
|
271
|
+
Enabled: true
|
272
|
+
Style/ReturnNilInPredicateMethodDefinition: # new in 1.53
|
273
|
+
Enabled: true
|
274
|
+
Style/SafeNavigationChainLength: # new in 1.68
|
275
|
+
Enabled: true
|
276
|
+
Style/SelectByRegexp: # new in 1.22
|
277
|
+
Enabled: true
|
278
|
+
Style/SendWithLiteralMethodName: # new in 1.64
|
279
|
+
Enabled: true
|
280
|
+
Style/SingleLineDoEndBlock: # new in 1.57
|
281
|
+
Enabled: true
|
282
|
+
Style/StringChars: # new in 1.12
|
283
|
+
Enabled: true
|
284
|
+
Style/SuperArguments: # new in 1.64
|
285
|
+
Enabled: true
|
286
|
+
Style/SuperWithArgsParentheses: # new in 1.58
|
287
|
+
Enabled: true
|
288
|
+
Style/SwapValues: # new in 1.1
|
289
|
+
Enabled: true
|
290
|
+
Style/YAMLFileRead: # new in 1.53
|
291
|
+
Enabled: true
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Istituto Superiore per la Protezione e la Ricerca Ambientale (ISPRA)
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
# pdnd-ruby-client   
|
2
|
+
|
3
|
+
Client Ruby per autenticazione e interazione con le API della Piattaforma Digitale Nazionale Dati (PDND).
|
4
|
+
|
5
|
+
## Licenza
|
6
|
+
|
7
|
+
MIT
|
8
|
+
|
9
|
+
## Requisiti
|
10
|
+
|
11
|
+
- Ruby >= 3.2 (versioni precedenti sono [EOL](https://endoflife.date/ruby))
|
12
|
+
|
13
|
+
## Installazione
|
14
|
+
|
15
|
+
1. Installa la libreria al tuo Gemfile:
|
16
|
+
```bash
|
17
|
+
gem 'pdnd-ruby-client'
|
18
|
+
```
|
19
|
+
|
20
|
+
2. Configura il file JSON con i parametri richiesti (esempio in `configs/sample.json`):
|
21
|
+
```json
|
22
|
+
{
|
23
|
+
"collaudo": {
|
24
|
+
"kid": "kid",
|
25
|
+
"issuer": "issuer",
|
26
|
+
"clientId": "clientId",
|
27
|
+
"purposeId": "purposeId",
|
28
|
+
"privKeyPath": "/tmp/key.priv"
|
29
|
+
},
|
30
|
+
"produzione": {
|
31
|
+
"kid": "kid",
|
32
|
+
"issuer": "issuer",
|
33
|
+
"clientId": "clientId",
|
34
|
+
"purposeId": "purposeId",
|
35
|
+
"privKeyPath": "/tmp/key.priv"
|
36
|
+
}
|
37
|
+
}
|
38
|
+
```
|
39
|
+
## Istruzioni base
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require "pdnd-ruby-client"
|
43
|
+
|
44
|
+
# Inizializza la configurazione
|
45
|
+
# Load the configuration from the specified JSON file and environment key.
|
46
|
+
config = PDND::ConfigLoader.load("configs/sample.json")
|
47
|
+
jwt = PDND::JWTGenerator.new(config)
|
48
|
+
token, exp = jwt.generate_token
|
49
|
+
client = PDND::Client.new(config)
|
50
|
+
client.token = token
|
51
|
+
client.token_exp = exp
|
52
|
+
client.api_url="https://www.tuogateway.example.it/indirizzo/della/api"
|
53
|
+
client.filters="id=1234"
|
54
|
+
code, body = client.request_api
|
55
|
+
|
56
|
+
# Stampa il risultato
|
57
|
+
puts body
|
58
|
+
|
59
|
+
```
|
60
|
+
|
61
|
+
## Leggi e Salva il token
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
|
65
|
+
require "pdnd-ruby-client"
|
66
|
+
|
67
|
+
# Inizializza la configurazione
|
68
|
+
# Load the configuration from the specified JSON file and environment key.
|
69
|
+
config = PDND::ConfigLoader.load("configs/sample.json")
|
70
|
+
# Inizializza il TokenManager per caricare o salvare i token su file esterno
|
71
|
+
token_mgr = PDND::TokenManager.new
|
72
|
+
# Carica il file salvato
|
73
|
+
token, exp = token_mgr.load
|
74
|
+
# Verifica se il token è stato precedentemente salvato ed è valido
|
75
|
+
if token.nil? || !token_mgr.valid?(exp)
|
76
|
+
# Se non è valido, genera un nuovo token
|
77
|
+
jwt = PDND::JWTGenerator.new(config)
|
78
|
+
token, exp = jwt.generate_token
|
79
|
+
# Salva il nuovo token
|
80
|
+
token_mgr.save(token, exp)
|
81
|
+
end
|
82
|
+
# Inizializza il client passando il token e la dada e ora di scadenza
|
83
|
+
client = PDND::Client.new(config)
|
84
|
+
client.token = token
|
85
|
+
client.token_exp = exp
|
86
|
+
# Imposta l'url dell'API
|
87
|
+
client.api_url="https://www.tuogateway.example.it/indirizzo/della/api"
|
88
|
+
# Imposta i paramentri per filtrare
|
89
|
+
# I parametri possono essere:
|
90
|
+
# - Stringa: "parametro1=1¶metro2=test&..."
|
91
|
+
# - Array: ["parametro1=1", "parametro2=test", ...]
|
92
|
+
# - Hash: {"parametro1" => 1, "parametro2" => "test", ... }
|
93
|
+
# sarà la funzione a verificare la tipologia e a convertire i filtri nel formato corretto.
|
94
|
+
# se il formato non fosse corretto, la funzione "request_api" restituisce errore.
|
95
|
+
client.filters="id=1234"
|
96
|
+
# Richiama la api
|
97
|
+
# @return code Number
|
98
|
+
# @return body Json
|
99
|
+
code, body = client.request_api
|
100
|
+
|
101
|
+
# Stampa il risultato
|
102
|
+
puts body
|
103
|
+
|
104
|
+
```
|
105
|
+
|
106
|
+
### Funzionalità aggiuntive
|
107
|
+
|
108
|
+
**Disabilita verifica certificato SSL**
|
109
|
+
|
110
|
+
La funzione `client.verify_ssl = false` Disabilita verifica SSL per ambiente impostato (es. collaudo).
|
111
|
+
Default: true
|
112
|
+
|
113
|
+
**Salva il token**
|
114
|
+
|
115
|
+
La funzione `token_mgr.save(token, exp)` consente a PDND::TokenManager di memorizzare il token e la scadenza e non doverlo richiedere a ogni chiamata.
|
116
|
+
|
117
|
+
**Carica il token salvato**
|
118
|
+
|
119
|
+
La funzione `token_mgr.load()` consente a PDND::TokenManager di richiamare il token precedentemente salvato.
|
120
|
+
|
121
|
+
**Valida il token salvato**
|
122
|
+
|
123
|
+
La funzione `token_mgr.valid?` PDND::TokenManager verifica la validità del token salvato.
|
124
|
+
|
125
|
+
**Imposta nome al token file**
|
126
|
+
|
127
|
+
La funzione `token_mgr.path("tmp/tuofile.json")` PDND::TokenManager imposta un nome personalizzato al file.
|
128
|
+
|
129
|
+
## Utilizzo da CLI
|
130
|
+
|
131
|
+
Esegui il client dalla cartella principale:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
ruby bin/pdnd_client.rb --api-url "https://api.pdnd.example.it/resource" --config /configs/sample.json
|
135
|
+
```
|
136
|
+
|
137
|
+
### Opzioni disponibili
|
138
|
+
|
139
|
+
- `--env` : Specifica l'ambiente da usare (es. collaudo, produzione). Default: `produzione`
|
140
|
+
- `--config` : Specifica il percorso completo del file di configurazione (es: `--config /configs/sample.json`)
|
141
|
+
- `--debug` : Abilita output dettagliato
|
142
|
+
- `--api-url` : URL dell’API da chiamare dopo la generazione del token
|
143
|
+
- `--api-url-filters` : Filtri da applicare all'API (es. ?parametro=valore)
|
144
|
+
- `--status-url` : URL dell’API di status per verificare la validità del token
|
145
|
+
- `--json`: Stampa le risposte delle API in formato JSON
|
146
|
+
- `--save`: Salva il token per evitare di richiederlo a ogni chiamata
|
147
|
+
- `--no-verify-ssl`: Disabilita la verifica SSL (utile per ambienti di collaudo)
|
148
|
+
- `--help`: Mostra questa schermata di aiuto
|
149
|
+
|
150
|
+
### Esempi
|
151
|
+
|
152
|
+
**Chiamata API generica:**
|
153
|
+
```bash
|
154
|
+
ruby bin/pdnd_client.rb --api-url="https://api.pdnd.example.it/resource" --config /configs/sample.json
|
155
|
+
```
|
156
|
+
|
157
|
+
**Verifica validità token:**
|
158
|
+
```bash
|
159
|
+
ruby bin/pdnd_client.rb --status-url="https://api.pdnd.example.it/status" --config /configs/sample.json
|
160
|
+
```
|
161
|
+
|
162
|
+
**Debug attivo:**
|
163
|
+
```bash
|
164
|
+
ruby bin/pdnd_client.rb --debug --api-url="https://api.pdnd.example.it/resource"
|
165
|
+
```
|
166
|
+
|
167
|
+
### Opzione di aiuto
|
168
|
+
|
169
|
+
Se esegui il comando con `--help` oppure senza parametri, viene mostrata una descrizione delle opzioni disponibili e alcuni esempi di utilizzo:
|
170
|
+
|
171
|
+
```bash
|
172
|
+
ruby bin/pdnd_client.rb --help
|
173
|
+
```
|
174
|
+
|
175
|
+
**Output di esempio:**
|
176
|
+
```
|
177
|
+
Utilizzo:
|
178
|
+
ruby bin/pdnd_client.rb -c /percorso/config.json [opzioni]
|
179
|
+
|
180
|
+
Opzioni:
|
181
|
+
--env Specifica l'ambiente da usare (es. collaudo, produzione)
|
182
|
+
Default: produzione
|
183
|
+
--config Specifica il percorso completo del file di configurazione
|
184
|
+
--debug Abilita output dettagliato
|
185
|
+
--api-url URL dell’API da chiamare dopo la generazione del token
|
186
|
+
--api-url-filters Filtri da applicare all'API (es. ?parametro=valore)
|
187
|
+
--status-url URL dell’API di status per verificare la validità del token
|
188
|
+
--json Stampa le risposte delle API in formato JSON
|
189
|
+
--save Salva il token per evitare di richiederlo a ogni chiamata
|
190
|
+
--no-verify-ssl Disabilita la verifica SSL (utile per ambienti di collaudo)
|
191
|
+
--help Mostra questa schermata di aiuto
|
192
|
+
|
193
|
+
Esempi:
|
194
|
+
ruby bin/pdnd_client.rb --api-url="https://api.pdnd.example.it/resource" --config /percorso/config.json
|
195
|
+
ruby bin/pdnd_client.rb --status-url="https://api.pdnd.example.it/status" --config /percorso/config.json
|
196
|
+
ruby bin/pdnd_client.rb --debug --api-url="https://api.pdnd.example.it/resource"
|
197
|
+
```
|
198
|
+
|
199
|
+
## Variabili di ambiente supportate
|
200
|
+
|
201
|
+
Se un parametro non è presente nel file di configurazione, puoi definirlo come variabile di ambiente:
|
202
|
+
|
203
|
+
- `PDND_KID`
|
204
|
+
- `PDND_ISSUER`
|
205
|
+
- `PDND_CLIENT_ID`
|
206
|
+
- `PDND_PURPOSE_ID`
|
207
|
+
- `PDND_PRIVKEY_PATH`
|
208
|
+
|
209
|
+
## Note
|
210
|
+
|
211
|
+
- Il token viene salvato in un file temporaneo e riutilizzato finché è valido.
|
212
|
+
- Gli errori specifici vengono gestiti tramite la classe `PdndException`.
|
213
|
+
|
214
|
+
## Esempio di configurazione minima
|
215
|
+
|
216
|
+
```json
|
217
|
+
{
|
218
|
+
"produzione": {
|
219
|
+
"kid": "kid",
|
220
|
+
"issuer": "issuer",
|
221
|
+
"clientId": "clientId",
|
222
|
+
"purposeId": "purposeId",
|
223
|
+
"privKeyPath": "/tmp/key.pem"
|
224
|
+
}
|
225
|
+
}
|
226
|
+
```
|
227
|
+
## Esempio di configurazione per collaudo e prosuzione
|
228
|
+
|
229
|
+
```json
|
230
|
+
{
|
231
|
+
"collaudo": {
|
232
|
+
"kid": "kid",
|
233
|
+
"issuer": "issuer",
|
234
|
+
"clientId": "clientId",
|
235
|
+
"purposeId": "purposeId",
|
236
|
+
"privKeyPath": "/tmp/key.pem"
|
237
|
+
},
|
238
|
+
"produzione": {
|
239
|
+
"kid": "kid",
|
240
|
+
"issuer": "issuer",
|
241
|
+
"clientId": "clientId",
|
242
|
+
"purposeId": "purposeId",
|
243
|
+
"privKeyPath": "/tmp/key.pem"
|
244
|
+
}
|
245
|
+
}
|
246
|
+
```
|
247
|
+
---
|
248
|
+
|
249
|
+
## Contribuire
|
250
|
+
|
251
|
+
Le pull request sono benvenute! Per problemi o suggerimenti, apri una issue.
|
data/Rakefile
ADDED
data/configs/sample.json
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"collaudo": {
|
3
|
+
"kid": "kid",
|
4
|
+
"issuer": "issuer",
|
5
|
+
"clientId": "clientId",
|
6
|
+
"purposeId": "purposeId",
|
7
|
+
"privKeyPath": "/tmp/key.pem"
|
8
|
+
},
|
9
|
+
"produzione": {
|
10
|
+
"kid": "kid",
|
11
|
+
"issuer": "issuer",
|
12
|
+
"clientId": "clientId",
|
13
|
+
"purposeId": "purposeId",
|
14
|
+
"privKeyPath": "/tmp/key.pem"
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# La classe PDND::Client è responsabile dell'invio di richieste HTTP all'API PDND.
|
4
|
+
# Gestisce autenticazione via token JWT, invio di richieste GET, parsing dei filtri,
|
5
|
+
# gestione dello stato, opzioni di debug e verifica del certificato SSL.
|
6
|
+
|
7
|
+
require 'net/http'
|
8
|
+
require 'json'
|
9
|
+
require 'faraday'
|
10
|
+
|
11
|
+
module PDND
|
12
|
+
# @!group PDND Client
|
13
|
+
# Questa classe gestisce le operazioni di comunicazione con il back-end PDND.
|
14
|
+
# @example
|
15
|
+
# client = PDND::Client.new(config)
|
16
|
+
# client.request_api
|
17
|
+
#
|
18
|
+
# @attr [String] token Il token di autenticazione JWT
|
19
|
+
# @attr [Boolean] debug Flag per attivare il logging in console
|
20
|
+
class Client
|
21
|
+
attr_accessor :token, :token_exp, :debug, :verify_ssl,
|
22
|
+
:api_url, :api_search, :status_url, :filters
|
23
|
+
|
24
|
+
def initialize(config)
|
25
|
+
@config = config
|
26
|
+
@verify_ssl = true
|
27
|
+
@debug = false
|
28
|
+
@api_url = ''
|
29
|
+
@api_search = ''
|
30
|
+
@status_url = ''
|
31
|
+
@filters = []
|
32
|
+
@token = ''
|
33
|
+
@token_exp = ''
|
34
|
+
end
|
35
|
+
|
36
|
+
def request_api
|
37
|
+
validate_api_config
|
38
|
+
build_api_uri
|
39
|
+
log_api_search
|
40
|
+
|
41
|
+
response = perform_request(@api_search.to_s)
|
42
|
+
|
43
|
+
raise PDND::APIError.new(response.status, response.body.force_encoding('UTF-8')) unless response.success?
|
44
|
+
|
45
|
+
puts "📡 Response: #{response.body}" if @debug
|
46
|
+
[response.status, JSON.parse(response.body)]
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_status
|
50
|
+
validate_status_config
|
51
|
+
|
52
|
+
response = perform_request(@status_url)
|
53
|
+
|
54
|
+
puts "📡 Status response: #{response.body}" if @debug
|
55
|
+
[response.status, JSON.parse(response.body)]
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def validate_api_config
|
61
|
+
raise PDND::APIError.new(0, 'URL dell\'API assente!') if @api_url.to_s.strip.empty?
|
62
|
+
raise PDND::APIError.new(0, 'Token assente!') if @token.to_s.strip.empty?
|
63
|
+
end
|
64
|
+
|
65
|
+
def validate_status_config
|
66
|
+
raise PDND::APIError.new(0, 'URL per controllare lo stato della API assente!') if @status_url.to_s.strip.empty?
|
67
|
+
raise PDND::APIError.new(0, 'Token assente!') if @token.to_s.strip.empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_api_uri
|
71
|
+
parse_filters
|
72
|
+
@api_search = URI(@api_url + (@filters ? "?#{@filters}" : ''))
|
73
|
+
end
|
74
|
+
|
75
|
+
def log_api_search
|
76
|
+
puts "📡 API SEARCH: #{@api_search}" if @debug
|
77
|
+
end
|
78
|
+
|
79
|
+
def perform_request(url)
|
80
|
+
conn = Faraday.new(url: url) do |faraday|
|
81
|
+
faraday.ssl.verify = false unless @verify_ssl
|
82
|
+
faraday.adapter Faraday.default_adapter
|
83
|
+
end
|
84
|
+
|
85
|
+
conn.get do |req|
|
86
|
+
req.headers['Authorization'] = "Bearer #{@token}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def parse_filters
|
91
|
+
case @filters
|
92
|
+
when String
|
93
|
+
@filters
|
94
|
+
when Hash
|
95
|
+
URI.encode_www_form(flatten_filter_hash(@filters))
|
96
|
+
when Array
|
97
|
+
@filters.join('&')
|
98
|
+
else
|
99
|
+
raise ArgumentError, '❌ I filtri devono essere una stringa, un hash o un array.'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def flatten_filter_hash(hash)
|
104
|
+
hash.each_with_object({}) do |(key, val), acc|
|
105
|
+
if val.is_a?(Array)
|
106
|
+
val.each do |v|
|
107
|
+
acc["#{key}[]"] ||= []
|
108
|
+
acc["#{key}[]"] << v
|
109
|
+
end
|
110
|
+
else
|
111
|
+
acc[key] = val
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/pdnd_ruby_client/config_loader.rb
|
4
|
+
|
5
|
+
require 'json'
|
6
|
+
require 'dotenv/load'
|
7
|
+
|
8
|
+
# La classe Config viene inizializzata con un percorso verso un file di configurazione e una chiave di ambiente.
|
9
|
+
# Legge la configurazione dal file e la memorizza Hash.
|
10
|
+
module PDND
|
11
|
+
# Carica la configurazione da un file JSON e restituisce i parametri per l'ambiente specificato.
|
12
|
+
# Utilizzato per inizializzare i client PDND con le credenziali corrette.
|
13
|
+
class ConfigLoader
|
14
|
+
def self.load(path, env = 'produzione')
|
15
|
+
config = JSON.parse(File.read(path))
|
16
|
+
raise "❌ Ambiente '#{env}' non trovato" unless config[env]
|
17
|
+
|
18
|
+
config[env].transform_keys(&:to_sym)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# 📎 Modulo contenente le classi di errore personalizzate per PDND Ruby Client.
|
4
|
+
module PDND
|
5
|
+
# Errore generico
|
6
|
+
class Error < StandardError
|
7
|
+
def initialize(msg = 'Errore generico PDND')
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Errore specifico per token scaduti o non validi
|
13
|
+
class TokenExpiredError < Error
|
14
|
+
def initialize
|
15
|
+
super('❌ Il token è scaduto o non valido')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Errore di configurazione
|
20
|
+
class ConfigError < Error
|
21
|
+
def initialize(msg = '❌ Configurazione non valida')
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Errore restituito dalle API, con codice e corpo inclusi
|
27
|
+
class APIError < StandardError
|
28
|
+
def initialize(status, body)
|
29
|
+
super(body.dup.force_encoding('UTF-8'))
|
30
|
+
@status = status
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jwt'
|
4
|
+
require 'openssl'
|
5
|
+
require 'faraday'
|
6
|
+
require 'json'
|
7
|
+
require 'securerandom'
|
8
|
+
require_relative 'errors'
|
9
|
+
|
10
|
+
# @!group JWT Generator
|
11
|
+
# Classe responsabile della generazione di token JWT per autenticare le richieste verso l'API PDND.
|
12
|
+
# Firma il token con una chiave RSA (algoritmo RS256) e lo invia al server OAuth2 per ottenere un access token.
|
13
|
+
# @example
|
14
|
+
# generator = PDND::JWTGenerator.new(config)
|
15
|
+
# token, exp = generator.generate_token
|
16
|
+
# @attr [Hash] config Configurazione con parametri JWT
|
17
|
+
# @attr [String] env Ambiente di esecuzione ('produzione' o 'collaudo')
|
18
|
+
# @attr [Boolean] debug Flag per attivare il logging
|
19
|
+
# @attr [String] token Token di accesso ottenuto
|
20
|
+
# @attr [String] token_exp Data di scadenza del token
|
21
|
+
module PDND
|
22
|
+
# @!group JWT Generator
|
23
|
+
# Classe responsabile della generazione di token JWT per autenticare le richieste verso l'API PDND.
|
24
|
+
# Firma il token con una chiave RSA (RS256) e lo invia al server OAuth2 per ottenere un access token.
|
25
|
+
# @example
|
26
|
+
# generator = PDND::JWTGenerator.new(config)
|
27
|
+
# token, exp = generator.generate_token
|
28
|
+
class JWTGenerator
|
29
|
+
attr_accessor :env, :config, :debug, :issuer, :client_id, :priv_key_path,
|
30
|
+
:purpose_id, :kid, :endpoint, :audience, :assertion,
|
31
|
+
:token, :token_exp
|
32
|
+
|
33
|
+
# @param config [Hash] Configurazione con chiavi come :issuer, :clientId, :privKeyPath, ecc.
|
34
|
+
# @param env [String] Ambiente ('produzione' o 'collaudo')
|
35
|
+
def initialize(config, env = 'produzione')
|
36
|
+
@config = config
|
37
|
+
@env = env
|
38
|
+
@assertion = ''
|
39
|
+
@token = ''
|
40
|
+
@token_exp = ''
|
41
|
+
@debug = false
|
42
|
+
|
43
|
+
assign_config_values(config)
|
44
|
+
configure_environment
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Array<String>] Token di accesso e data di scadenza formattata
|
48
|
+
def generate_token
|
49
|
+
private_key = load_private_key
|
50
|
+
@assertion = JWT.encode(build_payload, private_key, 'RS256', build_header)
|
51
|
+
debug_log('🔐 Token JWT generato', @assertion)
|
52
|
+
|
53
|
+
response_body = post_assertion
|
54
|
+
@token = response_body['access_token']
|
55
|
+
@token_exp = format_expiration(response_body['expires_in'])
|
56
|
+
|
57
|
+
debug_log('✅ Token generato', @token)
|
58
|
+
debug_log('✅ Token scadenza', @token_exp)
|
59
|
+
|
60
|
+
[@token, @token_exp]
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def assign_config_values(config)
|
66
|
+
@issuer = config[:issuer]
|
67
|
+
@client_id = config[:clientId]
|
68
|
+
@priv_key_path = config[:privKeyPath]
|
69
|
+
@kid = config[:kid]
|
70
|
+
@purpose_id = config[:purposeId]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Imposta endpoint e audience in base all'ambiente
|
74
|
+
def configure_environment
|
75
|
+
if @env == 'collaudo'
|
76
|
+
@endpoint = 'https://auth.uat.interop.pagopa.it/token.oauth2'
|
77
|
+
@audience = 'auth.uat.interop.pagopa.it/client-assertion'
|
78
|
+
else
|
79
|
+
@endpoint = 'https://auth.interop.pagopa.it/token.oauth2'
|
80
|
+
@audience = 'auth.interop.pagopa.it/client-assertion'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [OpenSSL::PKey::RSA] Chiave privata RSA
|
85
|
+
# @raise [PDND::ConfigError] Se la chiave è invalida o il file non esiste
|
86
|
+
def load_private_key
|
87
|
+
OpenSSL::PKey::RSA.new(File.read(@priv_key_path))
|
88
|
+
rescue OpenSSL::PKey::RSAError => e
|
89
|
+
raise PDND::ConfigError, "❌ Chiave privata non valida: #{e.message}"
|
90
|
+
rescue Errno::ENOENT => e
|
91
|
+
raise PDND::ConfigError, "❌ File della chiave non trovato: #{e.message}"
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [Hash] Payload JWT con claim standard
|
95
|
+
def build_payload
|
96
|
+
issued_at = Time.now.to_i
|
97
|
+
{
|
98
|
+
iss: @issuer,
|
99
|
+
sub: @client_id,
|
100
|
+
aud: @audience,
|
101
|
+
purposeId: @purpose_id,
|
102
|
+
jti: SecureRandom.hex(16),
|
103
|
+
iat: issued_at,
|
104
|
+
exp: issued_at + 300
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
# @return [Hash] Header JWT con chiave e algoritmo
|
109
|
+
def build_header
|
110
|
+
{
|
111
|
+
kid: @kid,
|
112
|
+
alg: 'RS256',
|
113
|
+
typ: 'JWT'
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Hash] Corpo della risposta OAuth2 con access token
|
118
|
+
# @raise [PDND::APIError] Se la risposta HTTP è un errore
|
119
|
+
def post_assertion
|
120
|
+
response = send_assertion_request
|
121
|
+
raise_api_error(response) unless response.success?
|
122
|
+
JSON.parse(response.body)
|
123
|
+
end
|
124
|
+
|
125
|
+
# @return [Faraday::Response] Risposta HTTP dal server OAuth2
|
126
|
+
def send_assertion_request
|
127
|
+
Faraday.post(@endpoint) do |req|
|
128
|
+
req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
129
|
+
req.headers['Accept'] = '*'
|
130
|
+
req.body = encoded_assertion_body
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def encoded_assertion_body
|
135
|
+
URI.encode_www_form(
|
136
|
+
{
|
137
|
+
client_id: @client_id,
|
138
|
+
client_assertion: @assertion,
|
139
|
+
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
140
|
+
grant_type: 'client_credentials'
|
141
|
+
}
|
142
|
+
)
|
143
|
+
end
|
144
|
+
|
145
|
+
# @param response [Faraday::Response]
|
146
|
+
# @raise [PDND::APIError] con messaggio dettagliato
|
147
|
+
def raise_api_error(response)
|
148
|
+
parsed = JSON.parse(response.body)
|
149
|
+
message = parsed['error_description'] || parsed['error'] || response.body
|
150
|
+
raise PDND::APIError.new(response.status, message)
|
151
|
+
end
|
152
|
+
|
153
|
+
# @param expires_in [Integer] Secondi di validità
|
154
|
+
# @return [String] Timestamp formattato
|
155
|
+
def format_expiration(expires_in)
|
156
|
+
Time.at(Time.now.to_i + expires_in).strftime('%Y-%m-%d %H:%M:%S')
|
157
|
+
end
|
158
|
+
|
159
|
+
# @param title [String] Titolo del log
|
160
|
+
# @param value [String] Contenuto da stampare
|
161
|
+
def debug_log(title, value)
|
162
|
+
puts "\n#{title}:\n#{value}" if @debug
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/pdnd_ruby_client/token_manager.rb
|
4
|
+
|
5
|
+
# Questa classe è responsabile del caricamento e salvataggio del token su file esterno.
|
6
|
+
module PDND
|
7
|
+
# Gestisce caricamento e salvataggio del token su file esterno.
|
8
|
+
class TokenManager
|
9
|
+
attr_reader :token, :exp, :path
|
10
|
+
|
11
|
+
def initialize(path = 'tmp/pdnd_token.json')
|
12
|
+
@path = path
|
13
|
+
@token = nil
|
14
|
+
@exp = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def load
|
18
|
+
return unless File.exist?(@path)
|
19
|
+
|
20
|
+
data = JSON.parse(File.read(@path))
|
21
|
+
@token = data['token']
|
22
|
+
@exp = data['exp']
|
23
|
+
end
|
24
|
+
|
25
|
+
def save(token, exp)
|
26
|
+
@token = token
|
27
|
+
@exp = exp
|
28
|
+
File.write(@path, { token: token, exp: exp }.to_json)
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid?
|
32
|
+
@token && @exp && Time.now.to_i < @exp.to_i
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'pdnd-ruby-client/client'
|
4
|
+
require_relative 'pdnd-ruby-client/config_loader'
|
5
|
+
require_relative 'pdnd-ruby-client/errors'
|
6
|
+
require_relative 'pdnd-ruby-client/jwt_generator'
|
7
|
+
require_relative 'pdnd-ruby-client/token_manager'
|
8
|
+
require_relative 'pdnd-ruby-client/version'
|
data/tmp/.gitkeep
ADDED
File without changes
|
data/tmp/pdnd_token.json
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"token":"eyJhbGciOiJSUzI1NiIsInVzZSI6InNpZyIsInR5cCI6ImF0K2p3dCIsImtpZCI6Ijk0MzJjMTZiLTdhYWUtNDlkZi1iOWM0LWVhNjFiNTU2NjUyYiJ9.eyJqdGkiOiJlM2RjNDg2MS00NDkwLTRmMmItODQ3OC1mOThkMTM1YWRkNjUiLCJpc3MiOiJpbnRlcm9wLnBhZ29wYS5pdCIsImF1ZCI6IklTUFJBX3JlbmRpcyIsImNsaWVudF9pZCI6ImNjOWE1MWZlLTdhMzYtNGVjMC04MjI0LWMzZjliNWMyN2FjYSIsInN1YiI6ImNjOWE1MWZlLTdhMzYtNGVjMC04MjI0LWMzZjliNWMyN2FjYSIsImlhdCI6MTc1MzU0NTk1MywibmJmIjoxNzUzNTQ1OTUzLCJleHAiOjE3NTM1NDYxMzMsInB1cnBvc2VJZCI6IjFjYjY1NmJjLWVlY2MtNGM1YS1iZTU5LWJmZGE1YjdkMWNmNCIsInByb2R1Y2VySWQiOiIxNGRiOGI1Yy1jZWJhLTQzMzMtODYyYy1iODJiNjRlYmFhZGQiLCJjb25zdW1lcklkIjoiMTRkYjhiNWMtY2ViYS00MzMzLTg2MmMtYjgyYjY0ZWJhYWRkIiwiZXNlcnZpY2VJZCI6IjMyNjYyOGUxLWRkNzItNGI2MS04ZGRlLTRmOGY5NzEwODIxOSIsImRlc2NyaXB0b3JJZCI6IjhjNGE5NmQwLTBiNTMtNDI2MC04YzYyLWFlZThkNmMzODVlNyJ9.O_bjiaLSvHimuNubY-8gYQmzfnDPS381Lg9MOgFdhyN1HCPLhrLRqDDXu9nf-QMkuW5hkdwdeE04AXyHKVonexUK3waGW99eBZdXKpB07iKHpHPPyLxJs07R7VbABtJp668YiZW53CDqLU6kOoYIeBx1tLS-R7_5ZL68pCmu3KZ4yfD8vv0JzFrgxI6QSg3lbvRTT8ycAZruQ9VvNtQEBfJrXiXOuxkcDc-DfWVX7V8PSomgrnHpZbkp0ClXuGKN-Typ8aBB2gOFLb6gL1aL6trnAkZM9RoGjgB3YBGj3sduWgJ1wl49ZlK3SIjiNNqiR7sP2-8qtYbmeu0M_LQK-A","exp":"2025-07-26 18:08:52"}
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pdnd-ruby-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Francesco Loreti
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: dotenv
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '2.8'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '2.8'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: faraday
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.13'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.13'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: json
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '2.0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: jwt
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.1'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.1'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: net-http
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0.3'
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.3.2
|
78
|
+
type: :runtime
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - "~>"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0.3'
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.3.2
|
88
|
+
description: Client Ruby per interazione con le API della Piattaforma Digitale Nazionale
|
89
|
+
Dati (PDND).
|
90
|
+
email:
|
91
|
+
- francesco.loreti@isprambiente.it
|
92
|
+
executables: []
|
93
|
+
extensions: []
|
94
|
+
extra_rdoc_files: []
|
95
|
+
files:
|
96
|
+
- ".env.sample"
|
97
|
+
- ".rspec"
|
98
|
+
- ".rubocop.yml"
|
99
|
+
- CHANGELOG.md
|
100
|
+
- LICENSE
|
101
|
+
- README.md
|
102
|
+
- Rakefile
|
103
|
+
- configs/sample.json
|
104
|
+
- lib/pdnd-ruby-client.rb
|
105
|
+
- lib/pdnd-ruby-client/client.rb
|
106
|
+
- lib/pdnd-ruby-client/config_loader.rb
|
107
|
+
- lib/pdnd-ruby-client/errors.rb
|
108
|
+
- lib/pdnd-ruby-client/jwt_generator.rb
|
109
|
+
- lib/pdnd-ruby-client/token_manager.rb
|
110
|
+
- lib/pdnd-ruby-client/version.rb
|
111
|
+
- sig/pdnd-ruby-client.rbs
|
112
|
+
- tmp/.gitkeep
|
113
|
+
- tmp/pdnd_token.json
|
114
|
+
homepage: https://github.com/isprambiente/pdnd-ruby-client
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
metadata:
|
118
|
+
homepage_uri: https://github.com/isprambiente/pdnd-ruby-client
|
119
|
+
changelog_uri: https://github.com/isprambiente/pdnd-ruby-client/changelog.md
|
120
|
+
rubygems_mfa_required: 'true'
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: 3.2.0
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubygems_version: 3.7.1
|
136
|
+
specification_version: 4
|
137
|
+
summary: Client Ruby per la PDND.
|
138
|
+
test_files: []
|