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 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
@@ -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
+ ]