fluxfiles-token 0.1.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.
@@ -0,0 +1,110 @@
1
+ # Dependencies
2
+ vendor/
3
+ node_modules/
4
+ # …but the vendored front-end lib we ship on purpose (xterm.js for the SFTP
5
+ # terminal) must be committed — it's served as a static asset, not installed.
6
+ !packages/core/assets/vendor/
7
+ !packages/core/assets/vendor/**
8
+
9
+ # Environment
10
+ .env
11
+ # Adapter-e2e .env backup (global-setup restores the real one in teardown)
12
+ packages/core/.env.adapter-e2e.bak
13
+
14
+ # Storage
15
+ storage/uploads/
16
+ storage/rate_limit.json
17
+
18
+ # Core package storage (runtime/test artifacts)
19
+ packages/core/storage/uploads/
20
+ packages/core/storage/rate_limit.json
21
+ packages/core/storage/demo_ip.json
22
+
23
+ # Build output
24
+ packages/react/dist/
25
+ packages/vue/dist/
26
+ packages/node/dist/
27
+ build/
28
+
29
+ # Python (packages/python)
30
+ packages/python/.venv/
31
+ packages/python/dist/
32
+ packages/python/*.egg-info/
33
+ **/__pycache__/
34
+ .pytest_cache/
35
+ .mypy_cache/
36
+ .ruff_cache/
37
+
38
+ # Test playground scaffolds (source committed, deps not)
39
+ packages/core/tests/apps/**/node_modules/
40
+ packages/core/tests/apps/node_modules/
41
+ # Generated Laravel proxy e2e app (regenerate: laravel-e2e/setup.sh; source in laravel-e2e/)
42
+ packages/core/tests/apps/laravel-app/
43
+
44
+ # Playwright runtime artifacts
45
+ .playwright-mcp/
46
+ test-results/
47
+ playwright-report/
48
+ # Ad-hoc QA screenshots taken at the repo root during manual browser testing
49
+ # (never part of the source — they slipped in once; keep them out for good).
50
+ /*.png
51
+
52
+ # OS files
53
+ .DS_Store
54
+ Thumbs.db
55
+
56
+ # IDE
57
+ .idea/
58
+ .vscode/
59
+ *.swp
60
+ *.swo
61
+ *~
62
+
63
+ # Testing
64
+ coverage/
65
+ .phpunit.result.cache
66
+ .phpunit.cache/
67
+
68
+ # Logs
69
+ *.log
70
+
71
+ # Project docs (private)
72
+ docs/FLUXFILES-ROADMAP.md
73
+ docs/ROADMAP.md
74
+ # Wrapper lockfiles aren't needed for published libs and break cross-platform
75
+ # npm optional-dep resolution (npm/cli#4828). CI does a fresh install.
76
+ packages/sdk/package-lock.json
77
+ packages/ckeditor4/package-lock.json
78
+ packages/tinymce/package-lock.json
79
+ docs/PHASE2-OPTIMIZATION-PLAN.md
80
+ docs/COMMERCIAL-STRATEGY.md
81
+ docs/LICENSING-PLAN.md
82
+ docs/*.SECRET.txt
83
+ docs/license-signing-key*
84
+ docs/release-signing-key*
85
+ docs/*.key
86
+
87
+ # Proprietary paid modules (private — not part of the MIT core; each lives in its
88
+ # own private repo for distribution). NEVER commit these to the public monorepo.
89
+ packages/optimize/
90
+ packages/share/
91
+ packages/intake/
92
+ packages/versioning/
93
+ packages/webhooks/
94
+ packages/ai/
95
+ packages/ocr/
96
+ packages/virus/
97
+ packages/backup/
98
+ packages/c2pa/
99
+ packages/audit-export/
100
+ packages/sso/
101
+ packages/dlp/
102
+ packages/legal-hold/
103
+
104
+ # License server runtime DB (customer records — never commit)
105
+ services/license-server/data/
106
+ *.sqlite
107
+ *.sqlite-*
108
+
109
+ # Claude subagent working artifacts (plans, review findings)
110
+ .claude/work/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 thai-pc
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.
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.5
2
+ Name: fluxfiles-token
3
+ Version: 0.1.0
4
+ Summary: Server-side Python SDK for minting FluxFiles JWTs (plain + BYOB), byte-compatible with the PHP core and @fluxfiles/node
5
+ Project-URL: Homepage, https://github.com/thai-pc/fluxfiles#python-server-side-token-sdk
6
+ Project-URL: Repository, https://github.com/thai-pc/fluxfiles
7
+ Project-URL: Issues, https://github.com/thai-pc/fluxfiles/issues
8
+ Author: thai-pc
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: byob,file-manager,fluxfiles,jwt,r2,s3,server,token
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: cryptography>=42
14
+ Requires-Dist: pyjwt<3,>=2.8
15
+ Provides-Extra: dev
16
+ Requires-Dist: mypy>=1.10; extra == 'dev'
17
+ Requires-Dist: pytest>=8; extra == 'dev'
18
+ Requires-Dist: ruff; extra == 'dev'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # FluxFiles for Python (server-side token SDK)
22
+
23
+ Mint [FluxFiles](https://github.com/thai-pc/fluxfiles) JWTs from any Python
24
+ backend (Django, FastAPI, Flask, …). Tokens are **byte-compatible with the PHP
25
+ core**, so non-PHP apps can issue access tokens — including encrypted BYOB
26
+ (Bring Your Own Bucket) credentials — without running PHP.
27
+
28
+ > **This package only issues tokens — it is not a backend.** You still run a
29
+ > FluxFiles **core service** (the file-manager backend that talks to storage;
30
+ > a PHP app, e.g. the Docker image) for the token to authenticate against.
31
+ > `fluxfiles-token` simply removes the need for *your app* to be PHP in order
32
+ > to mint those tokens.
33
+
34
+ ## Requirements
35
+
36
+ - Python 3.10+
37
+ - A running FluxFiles **core service** the issued tokens authenticate against
38
+ (the SDK/iframe `endpoint` points at it).
39
+ - The same **`FLUXFILES_SECRET`** your FluxFiles core server uses to verify
40
+ tokens (HS256, **must be ≥ 32 bytes**). Keep it server-side only.
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install fluxfiles-token
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ ### Mint a token
51
+
52
+ ```python
53
+ from fluxfiles_token import create_token
54
+
55
+ token = create_token(
56
+ user_id="user-42",
57
+ perms=["read", "write"],
58
+ disks=["local", "s3"],
59
+ prefix="users/42", # scope the user to their own directory
60
+ max_upload_mb=25,
61
+ allowed_ext=["png", "jpg", "pdf"],
62
+ ttl=3600, # seconds
63
+ # secret=..., # or omit to read FLUXFILES_SECRET from the environment
64
+ )
65
+ ```
66
+
67
+ ### Role & edition presets
68
+
69
+ Mint-time-only DX sugar — they expand into ordinary claims and are never
70
+ themselves a JWT claim. Explicit kwargs always win over a preset default.
71
+
72
+ ```python
73
+ from fluxfiles_token import create_token
74
+
75
+ # perms=["read", "write"], owner_only=True, allow_extract=True,
76
+ # allow_chmod=False (the "editor" bundle).
77
+ token = create_token(user_id="user-42", role="editor")
78
+
79
+ # Every module claim the "enterprise" edition grants — license/module
80
+ # install are still the real gate; a preset just defaults the per-tenant claim.
81
+ token = create_token(user_id="tenant-9", edition="enterprise")
82
+ ```
83
+
84
+ ### Enable Import from URL
85
+
86
+ Import-from-URL is **off by default**. Turn it on for a token by setting the
87
+ import options — no server-side per-tenant config is needed:
88
+
89
+ ```python
90
+ token = create_token(
91
+ user_id="user-42",
92
+ perms=["read", "write"],
93
+ allow_url_import=True, # required — enables the feature
94
+ max_import_mb=20, # optional — cap per import (MB)
95
+ import_url_allowlist=["*.unsplash.com"], # optional — restrict source hosts
96
+ # import_path, import_rate_limit, import_concurrency also supported
97
+ )
98
+ ```
99
+
100
+ The core then accepts `POST /api/fm/import-url` for that token (SSRF-guarded,
101
+ sharing the quota/dedup/variants pipeline). Server-wide defaults come from
102
+ `FLUXFILES_IMPORT_*` env vars on the core service.
103
+
104
+ ### SFTP disk: chmod & SSH terminal
105
+
106
+ When the token targets a FluxFiles server that has an **SFTP disk** configured
107
+ (`SFTP_*` env on that server — see the
108
+ [core README](https://github.com/thai-pc/fluxfiles#sftp-disk-vps--shared-hosting)),
109
+ you can hand a token the SFTP file-manager tools. `chmod` is on by default for
110
+ SFTP; the **SSH terminal** is opt-in (it grants shell access as the SSH user):
111
+
112
+ ```python
113
+ token = create_token(
114
+ user_id="admin-7",
115
+ perms=["read", "write"],
116
+ disks=["sftp"], # an SFTP disk configured on the FluxFiles server
117
+ allow_chmod=True, # cPanel-style permissions (default on for SFTP)
118
+ allow_terminal=True, # SSH terminal — opt-in, off by default
119
+ )
120
+ ```
121
+
122
+ These are **standalone-core** features: `fluxfiles-token` mints for a real
123
+ FluxFiles server (Docker / standalone), which serves them — they aren't
124
+ available behind the WordPress / Laravel-proxy adapters.
125
+
126
+ ### BYOB — encrypt a user's own bucket credentials
127
+
128
+ ```python
129
+ import os
130
+ from fluxfiles_token import create_byob_token
131
+
132
+ token = create_byob_token(
133
+ user_id="user-42",
134
+ byob_disks={
135
+ "my-s3": {
136
+ "driver": "s3",
137
+ "key": os.environ["USER_AWS_KEY"],
138
+ "secret": os.environ["USER_AWS_SECRET"],
139
+ "bucket": "user-personal-bucket",
140
+ "region": "us-east-1",
141
+ # "endpoint": "https://<acct>.r2.cloudflarestorage.com", # R2/MinIO/Spaces
142
+ },
143
+ },
144
+ )
145
+ ```
146
+
147
+ Credentials are AES-256-GCM encrypted into the token and decrypted only at
148
+ runtime by the FluxFiles server (which also re-validates the endpoint for
149
+ SSRF). `role`/`edition` presets are supported on BYOB tokens too.
150
+
151
+ ### Verify / decode (optional)
152
+
153
+ ```python
154
+ from fluxfiles_token import verify_token, decode_token
155
+
156
+ claims = verify_token(token) # checks HS256 signature + expiry, raises on failure
157
+ peek = decode_token(token) # decode only, NO verification — never trust for auth
158
+ ```
159
+
160
+ ### Django view
161
+
162
+ ```python
163
+ from django.http import JsonResponse
164
+ from fluxfiles_token import create_token
165
+
166
+ def fluxfiles_token_view(request):
167
+ token = create_token(
168
+ user_id=str(request.user.id),
169
+ perms=["read", "write"],
170
+ prefix=f"users/{request.user.id}",
171
+ )
172
+ return JsonResponse({"token": token})
173
+ ```
174
+
175
+ ### FastAPI route
176
+
177
+ ```python
178
+ from fastapi import APIRouter, Depends
179
+ from fluxfiles_token import create_token
180
+
181
+ router = APIRouter()
182
+
183
+ @router.get("/fluxfiles/token")
184
+ def fluxfiles_token(user=Depends(get_current_user)):
185
+ return {"token": create_token(user_id=user.id, perms=["read", "write"])}
186
+ ```
187
+
188
+ ## API
189
+
190
+ | Function | Description |
191
+ |----------|-------------|
192
+ | `create_token(**opts)` | Standard token. Mirrors PHP `fluxfiles_token()`. |
193
+ | `create_byob_token(**opts)` | Token with encrypted BYOB disk credentials. Mirrors `fluxfiles_byob_token()`. |
194
+ | `verify_token(token, secret=None)` | Verify HS256 signature + expiry; returns decoded claims or raises. |
195
+ | `decode_token(token)` | Decode without verifying (inspection/logging only). |
196
+
197
+ `create_token` keyword arguments: `secret=None`, `user_id`, `perms=None`,
198
+ `disks=None`, `prefix=None`, `max_upload_mb=None`, `allowed_ext=None`,
199
+ `ttl=None`, `owner_only=None`, `max_storage_mb=None`, `max_files=None`,
200
+ `edition=None`, `role=None`. Per-tenant overrides (omit to inherit the server
201
+ default): `ai_auto_tag=None` (bool), `rate_read=None` / `rate_write=None`
202
+ (req/min), `variants=None` (`{"thumb": .., "medium": .., "large": ..}` px),
203
+ and every other `allow_*`/module claim documented in
204
+ [`docs/CONFIG.md`](https://github.com/thai-pc/fluxfiles/blob/master/docs/CONFIG.md) —
205
+ plus a `claims: dict` escape hatch for any claim by its raw snake_case name.
206
+ `create_byob_token` replaces `disks` with `byob_disks` (a map of name →
207
+ S3-compatible/SFTP config) and does not take `max_storage_mb`/`max_files`
208
+ (matching the core), but accepts the same `role`/`edition`/per-tenant kwargs.
209
+
210
+ ## Compatibility
211
+
212
+ Tokens and BYOB blobs are validated against the PHP core in CI: a
213
+ Python-minted token decodes in `JwtCompat::decode`, and BYOB credentials
214
+ round-trip both ways through `CredentialEncryptor` (HS256 + HKDF-SHA256 +
215
+ AES-256-GCM). Always mint tokens **on the server** — never ship
216
+ `FLUXFILES_SECRET` to the browser.
217
+
218
+ ## License
219
+
220
+ MIT — see [LICENSE](LICENSE) for details.
221
+
222
+ ## Links
223
+
224
+ - Main repository: `https://github.com/thai-pc/fluxfiles`
225
+ - Documentation: `https://github.com/thai-pc/fluxfiles#python-server-side-token-sdk`
226
+ - Issues: `https://github.com/thai-pc/fluxfiles/issues`
@@ -0,0 +1,206 @@
1
+ # FluxFiles for Python (server-side token SDK)
2
+
3
+ Mint [FluxFiles](https://github.com/thai-pc/fluxfiles) JWTs from any Python
4
+ backend (Django, FastAPI, Flask, …). Tokens are **byte-compatible with the PHP
5
+ core**, so non-PHP apps can issue access tokens — including encrypted BYOB
6
+ (Bring Your Own Bucket) credentials — without running PHP.
7
+
8
+ > **This package only issues tokens — it is not a backend.** You still run a
9
+ > FluxFiles **core service** (the file-manager backend that talks to storage;
10
+ > a PHP app, e.g. the Docker image) for the token to authenticate against.
11
+ > `fluxfiles-token` simply removes the need for *your app* to be PHP in order
12
+ > to mint those tokens.
13
+
14
+ ## Requirements
15
+
16
+ - Python 3.10+
17
+ - A running FluxFiles **core service** the issued tokens authenticate against
18
+ (the SDK/iframe `endpoint` points at it).
19
+ - The same **`FLUXFILES_SECRET`** your FluxFiles core server uses to verify
20
+ tokens (HS256, **must be ≥ 32 bytes**). Keep it server-side only.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install fluxfiles-token
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ### Mint a token
31
+
32
+ ```python
33
+ from fluxfiles_token import create_token
34
+
35
+ token = create_token(
36
+ user_id="user-42",
37
+ perms=["read", "write"],
38
+ disks=["local", "s3"],
39
+ prefix="users/42", # scope the user to their own directory
40
+ max_upload_mb=25,
41
+ allowed_ext=["png", "jpg", "pdf"],
42
+ ttl=3600, # seconds
43
+ # secret=..., # or omit to read FLUXFILES_SECRET from the environment
44
+ )
45
+ ```
46
+
47
+ ### Role & edition presets
48
+
49
+ Mint-time-only DX sugar — they expand into ordinary claims and are never
50
+ themselves a JWT claim. Explicit kwargs always win over a preset default.
51
+
52
+ ```python
53
+ from fluxfiles_token import create_token
54
+
55
+ # perms=["read", "write"], owner_only=True, allow_extract=True,
56
+ # allow_chmod=False (the "editor" bundle).
57
+ token = create_token(user_id="user-42", role="editor")
58
+
59
+ # Every module claim the "enterprise" edition grants — license/module
60
+ # install are still the real gate; a preset just defaults the per-tenant claim.
61
+ token = create_token(user_id="tenant-9", edition="enterprise")
62
+ ```
63
+
64
+ ### Enable Import from URL
65
+
66
+ Import-from-URL is **off by default**. Turn it on for a token by setting the
67
+ import options — no server-side per-tenant config is needed:
68
+
69
+ ```python
70
+ token = create_token(
71
+ user_id="user-42",
72
+ perms=["read", "write"],
73
+ allow_url_import=True, # required — enables the feature
74
+ max_import_mb=20, # optional — cap per import (MB)
75
+ import_url_allowlist=["*.unsplash.com"], # optional — restrict source hosts
76
+ # import_path, import_rate_limit, import_concurrency also supported
77
+ )
78
+ ```
79
+
80
+ The core then accepts `POST /api/fm/import-url` for that token (SSRF-guarded,
81
+ sharing the quota/dedup/variants pipeline). Server-wide defaults come from
82
+ `FLUXFILES_IMPORT_*` env vars on the core service.
83
+
84
+ ### SFTP disk: chmod & SSH terminal
85
+
86
+ When the token targets a FluxFiles server that has an **SFTP disk** configured
87
+ (`SFTP_*` env on that server — see the
88
+ [core README](https://github.com/thai-pc/fluxfiles#sftp-disk-vps--shared-hosting)),
89
+ you can hand a token the SFTP file-manager tools. `chmod` is on by default for
90
+ SFTP; the **SSH terminal** is opt-in (it grants shell access as the SSH user):
91
+
92
+ ```python
93
+ token = create_token(
94
+ user_id="admin-7",
95
+ perms=["read", "write"],
96
+ disks=["sftp"], # an SFTP disk configured on the FluxFiles server
97
+ allow_chmod=True, # cPanel-style permissions (default on for SFTP)
98
+ allow_terminal=True, # SSH terminal — opt-in, off by default
99
+ )
100
+ ```
101
+
102
+ These are **standalone-core** features: `fluxfiles-token` mints for a real
103
+ FluxFiles server (Docker / standalone), which serves them — they aren't
104
+ available behind the WordPress / Laravel-proxy adapters.
105
+
106
+ ### BYOB — encrypt a user's own bucket credentials
107
+
108
+ ```python
109
+ import os
110
+ from fluxfiles_token import create_byob_token
111
+
112
+ token = create_byob_token(
113
+ user_id="user-42",
114
+ byob_disks={
115
+ "my-s3": {
116
+ "driver": "s3",
117
+ "key": os.environ["USER_AWS_KEY"],
118
+ "secret": os.environ["USER_AWS_SECRET"],
119
+ "bucket": "user-personal-bucket",
120
+ "region": "us-east-1",
121
+ # "endpoint": "https://<acct>.r2.cloudflarestorage.com", # R2/MinIO/Spaces
122
+ },
123
+ },
124
+ )
125
+ ```
126
+
127
+ Credentials are AES-256-GCM encrypted into the token and decrypted only at
128
+ runtime by the FluxFiles server (which also re-validates the endpoint for
129
+ SSRF). `role`/`edition` presets are supported on BYOB tokens too.
130
+
131
+ ### Verify / decode (optional)
132
+
133
+ ```python
134
+ from fluxfiles_token import verify_token, decode_token
135
+
136
+ claims = verify_token(token) # checks HS256 signature + expiry, raises on failure
137
+ peek = decode_token(token) # decode only, NO verification — never trust for auth
138
+ ```
139
+
140
+ ### Django view
141
+
142
+ ```python
143
+ from django.http import JsonResponse
144
+ from fluxfiles_token import create_token
145
+
146
+ def fluxfiles_token_view(request):
147
+ token = create_token(
148
+ user_id=str(request.user.id),
149
+ perms=["read", "write"],
150
+ prefix=f"users/{request.user.id}",
151
+ )
152
+ return JsonResponse({"token": token})
153
+ ```
154
+
155
+ ### FastAPI route
156
+
157
+ ```python
158
+ from fastapi import APIRouter, Depends
159
+ from fluxfiles_token import create_token
160
+
161
+ router = APIRouter()
162
+
163
+ @router.get("/fluxfiles/token")
164
+ def fluxfiles_token(user=Depends(get_current_user)):
165
+ return {"token": create_token(user_id=user.id, perms=["read", "write"])}
166
+ ```
167
+
168
+ ## API
169
+
170
+ | Function | Description |
171
+ |----------|-------------|
172
+ | `create_token(**opts)` | Standard token. Mirrors PHP `fluxfiles_token()`. |
173
+ | `create_byob_token(**opts)` | Token with encrypted BYOB disk credentials. Mirrors `fluxfiles_byob_token()`. |
174
+ | `verify_token(token, secret=None)` | Verify HS256 signature + expiry; returns decoded claims or raises. |
175
+ | `decode_token(token)` | Decode without verifying (inspection/logging only). |
176
+
177
+ `create_token` keyword arguments: `secret=None`, `user_id`, `perms=None`,
178
+ `disks=None`, `prefix=None`, `max_upload_mb=None`, `allowed_ext=None`,
179
+ `ttl=None`, `owner_only=None`, `max_storage_mb=None`, `max_files=None`,
180
+ `edition=None`, `role=None`. Per-tenant overrides (omit to inherit the server
181
+ default): `ai_auto_tag=None` (bool), `rate_read=None` / `rate_write=None`
182
+ (req/min), `variants=None` (`{"thumb": .., "medium": .., "large": ..}` px),
183
+ and every other `allow_*`/module claim documented in
184
+ [`docs/CONFIG.md`](https://github.com/thai-pc/fluxfiles/blob/master/docs/CONFIG.md) —
185
+ plus a `claims: dict` escape hatch for any claim by its raw snake_case name.
186
+ `create_byob_token` replaces `disks` with `byob_disks` (a map of name →
187
+ S3-compatible/SFTP config) and does not take `max_storage_mb`/`max_files`
188
+ (matching the core), but accepts the same `role`/`edition`/per-tenant kwargs.
189
+
190
+ ## Compatibility
191
+
192
+ Tokens and BYOB blobs are validated against the PHP core in CI: a
193
+ Python-minted token decodes in `JwtCompat::decode`, and BYOB credentials
194
+ round-trip both ways through `CredentialEncryptor` (HS256 + HKDF-SHA256 +
195
+ AES-256-GCM). Always mint tokens **on the server** — never ship
196
+ `FLUXFILES_SECRET` to the browser.
197
+
198
+ ## License
199
+
200
+ MIT — see [LICENSE](LICENSE) for details.
201
+
202
+ ## Links
203
+
204
+ - Main repository: `https://github.com/thai-pc/fluxfiles`
205
+ - Documentation: `https://github.com/thai-pc/fluxfiles#python-server-side-token-sdk`
206
+ - Issues: `https://github.com/thai-pc/fluxfiles/issues`
@@ -0,0 +1,41 @@
1
+ [project]
2
+ name = "fluxfiles-token"
3
+ version = "0.1.0"
4
+ description = "Server-side Python SDK for minting FluxFiles JWTs (plain + BYOB), byte-compatible with the PHP core and @fluxfiles/node"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ requires-python = ">=3.10"
8
+ authors = [{ name = "thai-pc" }]
9
+ keywords = ["fluxfiles", "jwt", "token", "file-manager", "s3", "r2", "byob", "server"]
10
+ dependencies = ["PyJWT>=2.8,<3", "cryptography>=42"]
11
+
12
+ [project.optional-dependencies]
13
+ dev = ["pytest>=8", "mypy>=1.10", "ruff"]
14
+
15
+ [project.urls]
16
+ Homepage = "https://github.com/thai-pc/fluxfiles#python-server-side-token-sdk"
17
+ Repository = "https://github.com/thai-pc/fluxfiles"
18
+ Issues = "https://github.com/thai-pc/fluxfiles/issues"
19
+
20
+ [build-system]
21
+ requires = ["hatchling"]
22
+ build-backend = "hatchling.build"
23
+
24
+ [tool.hatch.build.targets.wheel]
25
+ packages = ["src/fluxfiles_token"]
26
+
27
+ [tool.mypy]
28
+ python_version = "3.10"
29
+ strict = true
30
+ files = ["src"]
31
+
32
+ [tool.ruff]
33
+ target-version = "py310"
34
+ line-length = 110
35
+ src = ["src", "tests"]
36
+
37
+ [tool.ruff.lint]
38
+ select = ["E", "F", "I", "UP", "B"]
39
+
40
+ [tool.pytest.ini_options]
41
+ testpaths = ["tests"]
@@ -0,0 +1,38 @@
1
+ """fluxfiles-token: mint and verify FluxFiles JWTs from Python.
2
+
3
+ Byte-compatible with the PHP core (`packages/core/embed.php`,
4
+ `CredentialEncryptor.php`) and a 1:1 port of `@fluxfiles/node`
5
+ (camelCase -> snake_case). See docs/PYTHON-TOKEN-SDK-DESIGN.md.
6
+ """
7
+
8
+ from .crypto import decrypt_byob, encrypt_byob
9
+ from .exceptions import FluxFilesByobError, FluxFilesTokenError
10
+ from .token import EDITION_PRESETS, ROLE_PRESETS, create_byob_token, create_token
11
+ from .types import (
12
+ ByobDiskConfig,
13
+ ByobS3DiskConfig,
14
+ ByobSftpDiskConfig,
15
+ FluxClaims,
16
+ FluxPermission,
17
+ )
18
+ from .verify import decode_token, verify_token
19
+
20
+ __all__ = [
21
+ "create_token",
22
+ "create_byob_token",
23
+ "verify_token",
24
+ "decode_token",
25
+ "encrypt_byob",
26
+ "decrypt_byob",
27
+ "ROLE_PRESETS",
28
+ "EDITION_PRESETS",
29
+ "FluxFilesTokenError",
30
+ "FluxFilesByobError",
31
+ "ByobDiskConfig",
32
+ "ByobS3DiskConfig",
33
+ "ByobSftpDiskConfig",
34
+ "FluxClaims",
35
+ "FluxPermission",
36
+ ]
37
+
38
+ __version__ = "0.1.0"