pwfauth 1.0.0__tar.gz
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.
- pwfauth-1.0.0/LICENSE +21 -0
- pwfauth-1.0.0/PKG-INFO +167 -0
- pwfauth-1.0.0/README.md +119 -0
- pwfauth-1.0.0/pyproject.toml +44 -0
- pwfauth-1.0.0/src/pwfauth/__init__.py +49 -0
- pwfauth-1.0.0/src/pwfauth/client.py +292 -0
- pwfauth-1.0.0/src/pwfauth/envelope.py +111 -0
- pwfauth-1.0.0/src/pwfauth/errors.py +75 -0
- pwfauth-1.0.0/src/pwfauth/hardware_id.py +94 -0
- pwfauth-1.0.0/src/pwfauth/response.py +123 -0
- pwfauth-1.0.0/tests/test_client.py +217 -0
- pwfauth-1.0.0/tests/test_envelope.py +82 -0
pwfauth-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PWF Auth
|
|
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.
|
pwfauth-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pwfauth
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python client for PWF Auth (pwfauth.com): license-key activation, hardware-ID binding, encrypted sessions with a server-driven kill switch, free trials, remote texts/slides, and OTA update checks.
|
|
5
|
+
Project-URL: Homepage, https://pwfauth.com
|
|
6
|
+
Project-URL: Documentation, https://pwfauth.com/api.php
|
|
7
|
+
Project-URL: Repository, https://github.com/pwfauth/pwfauth-python
|
|
8
|
+
Project-URL: Issues, https://github.com/pwfauth/pwfauth-python/issues
|
|
9
|
+
Author: PWF Auth
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 PWF Auth
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: activation,auth,authentication,drm,hwid,license-key,licensing,pwfauth,sdk
|
|
33
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Operating System :: OS Independent
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
43
|
+
Classifier: Topic :: Security :: Cryptography
|
|
44
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
45
|
+
Requires-Python: >=3.9
|
|
46
|
+
Requires-Dist: cryptography>=3.4
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# pwfauth
|
|
50
|
+
|
|
51
|
+
Official Python client for [PWF Auth](https://pwfauth.com) — license keys, hardware-ID
|
|
52
|
+
binding, encrypted sessions with a server-driven kill switch, free trials, remote
|
|
53
|
+
texts/slides, and OTA update checks.
|
|
54
|
+
|
|
55
|
+
PWF Auth is **100% free** — every feature, unlimited, forever.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install pwfauth
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Python 3.9+. One dependency (`cryptography`), because Python has no AES in its
|
|
62
|
+
standard library; HTTP uses `urllib` from the stdlib rather than pulling in `requests`.
|
|
63
|
+
|
|
64
|
+
## Quick start
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import os
|
|
68
|
+
import sys
|
|
69
|
+
from pwfauth import PwfClient
|
|
70
|
+
|
|
71
|
+
client = PwfClient(os.environ["PWFAUTH_SECRET"])
|
|
72
|
+
|
|
73
|
+
def on_session_ended(error_code, message):
|
|
74
|
+
"""Ban, pause, expiry, HWID reset, revoke, maintenance, or an unreachable
|
|
75
|
+
server. Actually stop here — logging alone leaves the licence unenforceable."""
|
|
76
|
+
print(f"Session ended ({error_code}): {message}", file=sys.stderr)
|
|
77
|
+
sys.exit(1)
|
|
78
|
+
|
|
79
|
+
client.on_session_ended = on_session_ended
|
|
80
|
+
|
|
81
|
+
login = client.login("XXXXX-XXXXX-XXXXX-XXXXX")
|
|
82
|
+
if not login.success:
|
|
83
|
+
print(login.message, file=sys.stderr) # safe to show the user
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
|
|
86
|
+
client.start_heartbeat() # keeps the session alive AND enforces the kill switch
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`start_heartbeat()` is what turns a one-time check into a live session. Revoke the key
|
|
90
|
+
in your dashboard and `on_session_ended` fires on the user's machine within seconds —
|
|
91
|
+
it does not wait for the next launch.
|
|
92
|
+
|
|
93
|
+
## Reading the licence
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
lic = login.license
|
|
97
|
+
if lic.is_lifetime:
|
|
98
|
+
print("Lifetime licence")
|
|
99
|
+
else:
|
|
100
|
+
print(f"Expires {lic.expires_at:%Y-%m-%d} — {lic.days_remaining} day(s) left")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`expires_at` is `None` for lifetime keys — the server sends `expires_at: null`, and
|
|
104
|
+
treating that as a date is the most common integration bug against this API. The
|
|
105
|
+
`is_lifetime` flag exists so you never have to.
|
|
106
|
+
|
|
107
|
+
## Feature flags
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
if login.get_boolean("pro_export"):
|
|
111
|
+
enable_export()
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Handles the `1` / `0` / `"true"` forms the dashboard can store.
|
|
115
|
+
|
|
116
|
+
## Checking a key without using a device seat
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
status = client.check_key(key) # no session opened, no seat consumed
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Hardware ID
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from pwfauth import get_hardware_id
|
|
126
|
+
print(get_hardware_id())
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Derived identically to the [.NET](https://www.nuget.org/packages/PWFAuth) and
|
|
130
|
+
[Node](https://www.npmjs.com/package/pwfauth) clients, so **the same machine counts as
|
|
131
|
+
one device under any SDK** — switching languages does not burn a second seat against
|
|
132
|
+
the licence's device limit.
|
|
133
|
+
|
|
134
|
+
## Everything else
|
|
135
|
+
|
|
136
|
+
| Method | What it does |
|
|
137
|
+
| --- | --- |
|
|
138
|
+
| `login(key)` / `logout()` | Open and close a session |
|
|
139
|
+
| `check_key(key)` | Read a key's state without a session |
|
|
140
|
+
| `heartbeat()` | One manual beat |
|
|
141
|
+
| `start_heartbeat()` / `stop_heartbeat()` | The background loop |
|
|
142
|
+
| `create_trial()` | Issue a free trial for this machine |
|
|
143
|
+
| `request_hardware_reset(key, reason)` | Ask an admin to unbind a device |
|
|
144
|
+
| `get_app_info()` / `get_texts()` / `get_slides()` | Remote app content |
|
|
145
|
+
| `check_update(version)` | OTA update check |
|
|
146
|
+
| `register_account()` / `account_login()` / `change_account_password()` | User accounts |
|
|
147
|
+
| `post_envelope()` / `get_envelope()` / `post_plain()` | Raw transports |
|
|
148
|
+
|
|
149
|
+
## Error codes
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from pwfauth import PwfErrorCodes, ends_session
|
|
153
|
+
|
|
154
|
+
if ends_session(res.error_code):
|
|
155
|
+
sign_out()
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`ends_session()` returns `False` for a code it does not recognise, on purpose: an
|
|
159
|
+
unknown code is far more likely to be a new transient condition than a new way of
|
|
160
|
+
being banned, and locking a paying user out on a guess is the worse failure.
|
|
161
|
+
|
|
162
|
+
## Links
|
|
163
|
+
|
|
164
|
+
- [Dashboard](https://pwfauth.com) · [API reference](https://pwfauth.com/api.php)
|
|
165
|
+
- [.NET client](https://www.nuget.org/packages/PWFAuth) · [Node client](https://www.npmjs.com/package/pwfauth) · [VS Code extension](https://marketplace.visualstudio.com/items?itemName=PWFAuth.pwfauth)
|
|
166
|
+
|
|
167
|
+
MIT
|
pwfauth-1.0.0/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# pwfauth
|
|
2
|
+
|
|
3
|
+
Official Python client for [PWF Auth](https://pwfauth.com) — license keys, hardware-ID
|
|
4
|
+
binding, encrypted sessions with a server-driven kill switch, free trials, remote
|
|
5
|
+
texts/slides, and OTA update checks.
|
|
6
|
+
|
|
7
|
+
PWF Auth is **100% free** — every feature, unlimited, forever.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install pwfauth
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Python 3.9+. One dependency (`cryptography`), because Python has no AES in its
|
|
14
|
+
standard library; HTTP uses `urllib` from the stdlib rather than pulling in `requests`.
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
from pwfauth import PwfClient
|
|
22
|
+
|
|
23
|
+
client = PwfClient(os.environ["PWFAUTH_SECRET"])
|
|
24
|
+
|
|
25
|
+
def on_session_ended(error_code, message):
|
|
26
|
+
"""Ban, pause, expiry, HWID reset, revoke, maintenance, or an unreachable
|
|
27
|
+
server. Actually stop here — logging alone leaves the licence unenforceable."""
|
|
28
|
+
print(f"Session ended ({error_code}): {message}", file=sys.stderr)
|
|
29
|
+
sys.exit(1)
|
|
30
|
+
|
|
31
|
+
client.on_session_ended = on_session_ended
|
|
32
|
+
|
|
33
|
+
login = client.login("XXXXX-XXXXX-XXXXX-XXXXX")
|
|
34
|
+
if not login.success:
|
|
35
|
+
print(login.message, file=sys.stderr) # safe to show the user
|
|
36
|
+
sys.exit(1)
|
|
37
|
+
|
|
38
|
+
client.start_heartbeat() # keeps the session alive AND enforces the kill switch
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`start_heartbeat()` is what turns a one-time check into a live session. Revoke the key
|
|
42
|
+
in your dashboard and `on_session_ended` fires on the user's machine within seconds —
|
|
43
|
+
it does not wait for the next launch.
|
|
44
|
+
|
|
45
|
+
## Reading the licence
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
lic = login.license
|
|
49
|
+
if lic.is_lifetime:
|
|
50
|
+
print("Lifetime licence")
|
|
51
|
+
else:
|
|
52
|
+
print(f"Expires {lic.expires_at:%Y-%m-%d} — {lic.days_remaining} day(s) left")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`expires_at` is `None` for lifetime keys — the server sends `expires_at: null`, and
|
|
56
|
+
treating that as a date is the most common integration bug against this API. The
|
|
57
|
+
`is_lifetime` flag exists so you never have to.
|
|
58
|
+
|
|
59
|
+
## Feature flags
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
if login.get_boolean("pro_export"):
|
|
63
|
+
enable_export()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Handles the `1` / `0` / `"true"` forms the dashboard can store.
|
|
67
|
+
|
|
68
|
+
## Checking a key without using a device seat
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
status = client.check_key(key) # no session opened, no seat consumed
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Hardware ID
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from pwfauth import get_hardware_id
|
|
78
|
+
print(get_hardware_id())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Derived identically to the [.NET](https://www.nuget.org/packages/PWFAuth) and
|
|
82
|
+
[Node](https://www.npmjs.com/package/pwfauth) clients, so **the same machine counts as
|
|
83
|
+
one device under any SDK** — switching languages does not burn a second seat against
|
|
84
|
+
the licence's device limit.
|
|
85
|
+
|
|
86
|
+
## Everything else
|
|
87
|
+
|
|
88
|
+
| Method | What it does |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `login(key)` / `logout()` | Open and close a session |
|
|
91
|
+
| `check_key(key)` | Read a key's state without a session |
|
|
92
|
+
| `heartbeat()` | One manual beat |
|
|
93
|
+
| `start_heartbeat()` / `stop_heartbeat()` | The background loop |
|
|
94
|
+
| `create_trial()` | Issue a free trial for this machine |
|
|
95
|
+
| `request_hardware_reset(key, reason)` | Ask an admin to unbind a device |
|
|
96
|
+
| `get_app_info()` / `get_texts()` / `get_slides()` | Remote app content |
|
|
97
|
+
| `check_update(version)` | OTA update check |
|
|
98
|
+
| `register_account()` / `account_login()` / `change_account_password()` | User accounts |
|
|
99
|
+
| `post_envelope()` / `get_envelope()` / `post_plain()` | Raw transports |
|
|
100
|
+
|
|
101
|
+
## Error codes
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from pwfauth import PwfErrorCodes, ends_session
|
|
105
|
+
|
|
106
|
+
if ends_session(res.error_code):
|
|
107
|
+
sign_out()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`ends_session()` returns `False` for a code it does not recognise, on purpose: an
|
|
111
|
+
unknown code is far more likely to be a new transient condition than a new way of
|
|
112
|
+
being banned, and locking a paying user out on a guess is the worse failure.
|
|
113
|
+
|
|
114
|
+
## Links
|
|
115
|
+
|
|
116
|
+
- [Dashboard](https://pwfauth.com) · [API reference](https://pwfauth.com/api.php)
|
|
117
|
+
- [.NET client](https://www.nuget.org/packages/PWFAuth) · [Node client](https://www.npmjs.com/package/pwfauth) · [VS Code extension](https://marketplace.visualstudio.com/items?itemName=PWFAuth.pwfauth)
|
|
118
|
+
|
|
119
|
+
MIT
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pwfauth"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Official Python client for PWF Auth (pwfauth.com): license-key activation, hardware-ID binding, encrypted sessions with a server-driven kill switch, free trials, remote texts/slides, and OTA update checks."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [{ name = "PWF Auth" }]
|
|
13
|
+
keywords = ["licensing", "license-key", "authentication", "auth", "drm", "activation", "hwid", "sdk", "pwfauth"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 5 - Production/Stable",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.9",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
26
|
+
"Topic :: Security :: Cryptography",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
# `cryptography` is the ONLY dependency, and it is unavoidable: Python has no AES in
|
|
30
|
+
# its standard library. HTTP goes through urllib rather than `requests`, so this does
|
|
31
|
+
# not drag urllib3/certifi/idna/charset-normalizer into every app that installs it.
|
|
32
|
+
dependencies = ["cryptography>=3.4"]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://pwfauth.com"
|
|
36
|
+
Documentation = "https://pwfauth.com/api.php"
|
|
37
|
+
Repository = "https://github.com/pwfauth/pwfauth-python"
|
|
38
|
+
Issues = "https://github.com/pwfauth/pwfauth-python/issues"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["src/pwfauth"]
|
|
42
|
+
|
|
43
|
+
[tool.hatch.build.targets.sdist]
|
|
44
|
+
include = ["src/pwfauth", "tests", "README.md", "LICENSE", "pyproject.toml"]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Official Python client for PWF Auth (https://pwfauth.com).
|
|
2
|
+
|
|
3
|
+
License-key activation, hardware-ID binding, encrypted sessions with a
|
|
4
|
+
server-driven kill switch, free trials, remote texts/slides, and OTA update checks.
|
|
5
|
+
|
|
6
|
+
from pwfauth import PwfClient
|
|
7
|
+
import os, sys
|
|
8
|
+
|
|
9
|
+
client = PwfClient(os.environ["PWFAUTH_SECRET"])
|
|
10
|
+
|
|
11
|
+
def on_session_ended(error_code, message):
|
|
12
|
+
print(f"Session ended ({error_code}): {message}", file=sys.stderr)
|
|
13
|
+
sys.exit(1)
|
|
14
|
+
|
|
15
|
+
client.on_session_ended = on_session_ended
|
|
16
|
+
|
|
17
|
+
login = client.login("XXXXX-XXXXX-XXXXX-XXXXX")
|
|
18
|
+
if not login.success:
|
|
19
|
+
print(login.message, file=sys.stderr)
|
|
20
|
+
sys.exit(1)
|
|
21
|
+
|
|
22
|
+
client.start_heartbeat() # keeps the session alive AND enforces the kill switch
|
|
23
|
+
|
|
24
|
+
The hardware ID is derived identically to the .NET and Node clients, so the same
|
|
25
|
+
machine counts as one device no matter which SDK an app uses.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from .client import PwfClient
|
|
29
|
+
from .envelope import CryptoEnvelope
|
|
30
|
+
from .errors import PwfCryptoError, PwfError, PwfErrorCodes, PwfHttpError, ends_session
|
|
31
|
+
from .hardware_id import get_hardware_id, reset_hardware_id_cache
|
|
32
|
+
from .response import License, PwfResponse
|
|
33
|
+
|
|
34
|
+
__version__ = "1.0.0"
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
"PwfClient",
|
|
38
|
+
"PwfResponse",
|
|
39
|
+
"License",
|
|
40
|
+
"CryptoEnvelope",
|
|
41
|
+
"PwfError",
|
|
42
|
+
"PwfHttpError",
|
|
43
|
+
"PwfCryptoError",
|
|
44
|
+
"PwfErrorCodes",
|
|
45
|
+
"ends_session",
|
|
46
|
+
"get_hardware_id",
|
|
47
|
+
"reset_hardware_id_cache",
|
|
48
|
+
"__version__",
|
|
49
|
+
]
|