You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+160-8Lines changed: 160 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,22 +21,30 @@ This open-source project was sponsored by:
21
21
22
22
## Table of Contents
23
23
24
+
-[Key Features](#key-features)
24
25
-[Installing the library](#installing-the-library)
25
-
-[Getting Started - Generating Tokens](#getting-started---generating-tokens)
26
-
-[Getting Started - Decoding a Token](#getting-started---decoding-a-token)
26
+
-[Getting Started - OpenPAYGO Token](#getting-started---openpaygo-token)
27
+
-[Generating Tokens](#generating-tokens)
28
+
-[Decoding Tokens](#decoding-tokens)
29
+
-[Getting Started - OpenPAYGO Metrics](#getting-started---openpaygo-metrics)
30
+
-[Changelog](#changelog)
31
+
-[2023-10-03 - v0.2.0](#2023-10-03---v020)
27
32
33
+
## Key Features
34
+
- Implements token generation and decoding with full support for the v2.3 of the [OpenPAYGO Token](https://github.com/EnAccess/OpenPAYGO-Token) specifications.
35
+
- Implements payload authentication (verification + signing) and conversion from simple to condensed payload (and back) with full support of the v1.0-rc1 of the [OpenPAYGO Metrics](https://github.com/openpaygo/metrics) specifications.
28
36
29
37
## Installing the library
30
38
31
39
You can install the library by running `pip install openpaygo` or adding `openpaygo` in your requirements.txt file and running `pip install -r requirements.txt`.
32
40
33
41
## Getting Started - OpenPAYGO Token
34
42
35
-
### Generating Tokens
43
+
### Generating Tokens (Server Side)
36
44
37
45
You can use the `generate_token()` function to generate an OpenPAYGOToken Token. The function takes the following parameters, and they should match the configuration in the hardware of the device:
38
46
39
-
-`secret_key` (required): The secret key of the device. Must be passed as an hexadecimal string (with 32 characters).
47
+
-`secret_key` (required): The secret key of the device. Must be passed as an hexadecimal string with 32 characters (e.g. `dac86b1a29ab82edc5fbbc41ec9530f6`).
40
48
-`count` (required): The token count used to make the last token.
41
49
-`value` (optional): The value to be passed in the token (typically the number of days of activation). Optional if the `token_type` is Disable PAYG or Counter Sync. The value must be between 0 and 995.
42
50
-`token_type` (optional): Used to set the type of token (default is Add Time). Token types can be found in the `TokenType` class: ADD_TIME, SET_TIME, DISABLE_PAYG, COUNTER_SYNC.
@@ -87,12 +95,12 @@ device.save() # We save the new count that we set for the device
87
95
```
88
96
89
97
90
-
### Decoding Tokens
98
+
### Decoding Tokens (Device Side)
91
99
92
100
You can use the `decode_token()` function to generate an OpenPAYGOToken Token. The function takes the following parameters, and they should match the configuration in the hardware of the device:
93
101
94
-
-`token` (required): The token that was given by the user
95
-
-`secret_key` (required): The secret key of the device
102
+
-`token` (required): The token that was given by the user, as a string
103
+
-`secret_key` (required): The secret key of the device as a string with 32 hexadecimal characters (e.g. `dac86b1a29ab82edc5fbbc41ec9530f6`)
96
104
-`count` (required): The token count of the last valid token. When a device is new, this is 1.
97
105
-`used_counts` (optional): An array of recently used token counts, as returned by the function itself after the last valid token was decoded. This allows for handling unordered token entry.
98
106
-`starting_code` (optional): If not provided, it is generated according to the method defined in the standard (SipHash-2-4 of the key, transformed to digit by the same method as the token generation).
You can use the `MetricsRequestHandler` object to create a new OpenPAYGO Metrics request from start to finish. It accepts the following initial inputs:
165
+
-`serial_number` (required): The serial number of the device
166
+
-`data_format` (optional): The data format, provided as dictionnary matching the data format object specifications.
167
+
-`secret_key` (optional): The secret key provided as a string containing 32 hexadecimal characters (e.g. `dac86b1a29ab82edc5fbbc41ec9530f6`). Required if `auth_method` is defined.
168
+
-`auth_method` (optional): One of the auth method contained in the `AuthMethod` class.
169
+
170
+
It provides the following methods:
171
+
-`set_timestamp(timestamp)`: Used to set the `timestamp` of the request.
172
+
-`set_request_count(request_count)`: Used to set the `request_count` of the request.
173
+
-`set_data(data)`: Used to set the `data` of the request, should be set in simple format as a dictionnay.
174
+
-`set_historical_data(data)`: Used to set the `historical_data` of the request, should be set in simple format as a dictionnary. The data is assumed to be separated by the `historical_data_interval` unless an explicit timestamp is provided.
175
+
-`get_simple_request_payload()`: Returns the payload in simple format as a string containing JSON and including the authentication signature.
176
+
-`get_condensed_request_payload()`: Returns the payload in condensed format as a string containing JSON and including the authentication signature. It requires `data_format` to be set. The data is automatically condensed from the set data and the data format and the signature is automatically generated.
177
+
178
+
179
+
**Example - Full Request flow from device side:**
180
+
181
+
```python
182
+
from openpaygo import MetricsRequestHandler, AuthMethod
183
+
import requests
184
+
185
+
# We assume the users enters a token and that the device state is saved in my_device_state
186
+
...
187
+
188
+
metrics_request = MetricsRequestHandler(
189
+
serial_number=my_device_state.serial_number,
190
+
secret_key=my_device_state.secret_key,
191
+
data_format=my_device_state.data_format,
192
+
auth_method=AuthMethod.RECURSIVE_DATA_AUTH
193
+
)
194
+
195
+
metrics_request.set_timestamp(1611583070)
196
+
metrics_request.set_data({
197
+
"token_count": 3,
198
+
"tampered": False,
199
+
"firmware_version": "1.2.3"
200
+
})
201
+
# Here we assume that the data we send is separated by 60 seconds as per the data format
# We can now proceed to send the payload to the URL
219
+
# It looks something like `{"sn":"aaa111222","df":1234,"ts":1611583070,"d":[3,false,"1.2.3"],"hd":[[12.31,12.32,1.23,-1.23],[12.3,12.31,1.22,-1.21]],"a":"raa5cb1fda302cf94e"}`
# Here we decode the tokens received from the server and apply them (see example above)
225
+
...
226
+
```
227
+
228
+
229
+
### Handling a Request and Generating a Response (Server Side)
230
+
231
+
You can use the `MetricsResponseHandler` object to process your OpenPAYGO Metrics request from start to finish. It accepts the following initial inputs:
232
+
-`metrics_payload` (required): The OpenPAYGO Metrics payload, as a string containing the JSON payload.
233
+
-`secret_key` (optional): The secret key provided as a string containing 32 hexadecimal characters (e.g. `dac86b1a29ab82edc5fbbc41ec9530f6`)
234
+
-`data_format` (optional): The data format, provided as dictionnary matching the data format object specifications.
235
+
-`last_request_count` (optional): The request count of the last valid request (used for avoiding request replay)
236
+
-`last_request_timestamp` (optional): The timestamp of the last valid request (used for avoiding request replay)
237
+
238
+
It provides the following methods:
239
+
-`get_device_serial()`: Returns the serial number of the device as a string.
240
+
-`set_device_parameters(secret_key, data_format, last_request_count, last_request_timestamp)`: Used to set the device data required for proper processing of the request in the handler if it was not set initially, which is often the case as the serial number is usually required to fetch that data. It will return `ValueError` if either of the parameters is invalid.
241
+
-`is_auth_valid()`: Returns `true` if the authentication provided is valid or `false` if not. Note that it checks both that the signature is valid and that the `request_count` or `timestamp` are more recent than the one provided in the device parameters.
242
+
-`get_simple_metrics()`: Returns the metrics provided in the simple expanded format. It will also convert relative timestamps into explicit timestamps for easier processing.
243
+
-`expects_token_answer()`: Return `true` if the payload requested tokens in the answer. You can set the tokens to be returned by calling `add_tokens_to_answer(token_list)` with `token_list` being a list of token strings.
244
+
-`expects_time_answer()`: Return `true` if the payload requested either relative time or absolute time in the answer. You can set the time to be returned by calling `add_time_to_answer(target_datetime)` with `target_datetime` being a datetime object. The function will automatically provide it in the correct format based on the request.
245
+
-`add_settings_to_answer(settings_dict)`: Will add the provided settings dictionnary to the answer.
246
+
-`add_extra_data_to_answer(extra_data_dict)`: Will add the provided extra data dictionnary to the answer.
247
+
-`add_new_base_url_to_answer(new_base_url)`: Will tell the device to change the base URL to send the data to.
248
+
-`get_answer_payload()`: Will return the answer as a string based on the request and the data added to answer, it will automatically handle the authentication and fomatting.
249
+
250
+
251
+
**Example - Full Request flow from server side:**
252
+
253
+
```python
254
+
from openpaygo import MetricsResponseHandler
255
+
from my_db_service import get_device, get_data_format, store_metric
256
+
257
+
258
+
@app.route('/dd')
259
+
defdevice_data():
260
+
# We load the metrics
261
+
try:
262
+
metrics = MetricsResponseHandler(request.data)
263
+
exceptValueErroras e:
264
+
return {'error': 'Invalid data format'}, 400
265
+
# We get the serial number and load the device data from our storage
0 commit comments