smart-dynamic-path 1.0.1__py3-none-any.whl
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.
- smart_dynamic_path/__init__.py +9 -0
- smart_dynamic_path/cli.py +50 -0
- smart_dynamic_path/core.py +75 -0
- smart_dynamic_path-1.0.1.dist-info/METADATA +168 -0
- smart_dynamic_path-1.0.1.dist-info/RECORD +9 -0
- smart_dynamic_path-1.0.1.dist-info/WHEEL +5 -0
- smart_dynamic_path-1.0.1.dist-info/entry_points.txt +2 -0
- smart_dynamic_path-1.0.1.dist-info/licenses/LICENSE +28 -0
- smart_dynamic_path-1.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Copyright (©) 2026, Alexander Suvorov. All rights reserved.
|
|
2
|
+
"""
|
|
3
|
+
Smart Dynamic Path CLI — Local key and path generation from a secret phrase
|
|
4
|
+
|
|
5
|
+
Installation: pip install smart-dynamic-path
|
|
6
|
+
Usage:
|
|
7
|
+
smart-dynamic-path --secret "my secret phrase"
|
|
8
|
+
smart-dynamic-path --secret "my secret phrase" --period month --full
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
from smart_dynamic_path.core import secret_to_path, get_full_path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main():
|
|
16
|
+
parser = argparse.ArgumentParser(
|
|
17
|
+
prog='smart-dynamic-path',
|
|
18
|
+
description='Generate deterministic time-based paths from a secret phrase'
|
|
19
|
+
)
|
|
20
|
+
parser.add_argument('--secret', '-s', required=True, help='Secret phrase')
|
|
21
|
+
parser.add_argument('--period', '-P', default='day',
|
|
22
|
+
choices=['day', 'month', 'hour', 'static'],
|
|
23
|
+
help='Path change period (default: day)')
|
|
24
|
+
parser.add_argument('--prefix', '-p', default='',
|
|
25
|
+
help='Optional path prefix')
|
|
26
|
+
parser.add_argument('--full', '-f', action='store_true',
|
|
27
|
+
help='Show full URL path')
|
|
28
|
+
parser.add_argument('--key-only', '-k', action='store_true',
|
|
29
|
+
help='Show only SECRET_KEY')
|
|
30
|
+
parser.add_argument('--path-only', '-a', action='store_true',
|
|
31
|
+
help='Show only path')
|
|
32
|
+
|
|
33
|
+
args = parser.parse_args()
|
|
34
|
+
|
|
35
|
+
secret_key, path = secret_to_path(args.secret, args.period, args.prefix)
|
|
36
|
+
|
|
37
|
+
if args.key_only:
|
|
38
|
+
print(secret_key)
|
|
39
|
+
elif args.path_only:
|
|
40
|
+
print(path)
|
|
41
|
+
elif args.full:
|
|
42
|
+
print(get_full_path(secret_key, args.period, args.prefix))
|
|
43
|
+
else:
|
|
44
|
+
print(f"SECRET_KEY: {secret_key}")
|
|
45
|
+
print(f"Path: {path}")
|
|
46
|
+
print(f"Full URL: {get_full_path(secret_key, args.period, args.prefix)}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == '__main__':
|
|
50
|
+
main()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Copyright (©) 2026, Alexander Suvorov. All rights reserved.
|
|
2
|
+
import hashlib
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def generate_secret_key(secret: str) -> str:
|
|
7
|
+
"""
|
|
8
|
+
Generate SECRET_KEY from secret phrase.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
secret: Secret phrase
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
64 hex chars (256 bits)
|
|
15
|
+
"""
|
|
16
|
+
return hashlib.sha256(secret.encode()).hexdigest()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def generate_path(secret_key: str, period: str = 'day', prefix: str = '') -> str:
|
|
20
|
+
"""
|
|
21
|
+
Generate deterministic time-based path.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
secret_key: 64 hex chars (256 bits) from generate_secret_key()
|
|
25
|
+
period: 'day', 'month', 'hour', 'static'
|
|
26
|
+
prefix: Optional path prefix (e.g., 'admin')
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
32 hex chars path or "prefix/path"
|
|
30
|
+
"""
|
|
31
|
+
now = datetime.now()
|
|
32
|
+
|
|
33
|
+
if period == 'day':
|
|
34
|
+
key = now.strftime("%Y-%m-%d")
|
|
35
|
+
elif period == 'month':
|
|
36
|
+
key = now.strftime("%Y-%m")
|
|
37
|
+
elif period == 'hour':
|
|
38
|
+
key = now.strftime("%Y-%m-%d-%H")
|
|
39
|
+
else:
|
|
40
|
+
key = 'static'
|
|
41
|
+
|
|
42
|
+
h = hashlib.sha256(f"{secret_key}_{key}".encode()).digest()
|
|
43
|
+
path_hash = h[:16].hex()
|
|
44
|
+
|
|
45
|
+
if prefix:
|
|
46
|
+
return f"{prefix}/{path_hash}"
|
|
47
|
+
return path_hash
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def secret_to_path(secret: str, period: str = 'day', prefix: str = '') -> tuple:
|
|
51
|
+
"""
|
|
52
|
+
Convert secret phrase to (secret_key, path).
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
secret: Secret phrase
|
|
56
|
+
period: 'day', 'month', 'hour', 'static'
|
|
57
|
+
prefix: Optional path prefix
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
(secret_key, path) tuple
|
|
61
|
+
"""
|
|
62
|
+
key = generate_secret_key(secret)
|
|
63
|
+
path = generate_path(key, period, prefix)
|
|
64
|
+
return key, path
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_full_path(secret_key: str, period: str = 'day', prefix: str = '') -> str:
|
|
68
|
+
"""
|
|
69
|
+
Get full path with leading slash.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Full path like "/admin/a1b2c3d4e5f6g7h8/"
|
|
73
|
+
"""
|
|
74
|
+
path = generate_path(secret_key, period, prefix)
|
|
75
|
+
return f"/{path}/"
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: smart-dynamic-path
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Dynamic, deterministic, time-dependent path generation. No storage. No database. No dependencies. One secret phrase → one deterministic path per time period. Same phrase + same day = same path. No storage. No database. Just pure math.
|
|
5
|
+
Author-email: Alexander Suvorov <smartlegionlab@gmail.com>
|
|
6
|
+
License: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/smartlegionlab/smart-dynamic-path
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Topic :: Security
|
|
17
|
+
Requires-Python: >=3.7
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Smart Dynamic Path <sup>v1.0.1</sup>
|
|
23
|
+
|
|
24
|
+
**Dynamic, deterministic, time-dependent path generation. No storage. No database. No dependencies.**
|
|
25
|
+
|
|
26
|
+
Generate cryptographically secure paths that change automatically based on time (day, month, hour) from a secret phrase.
|
|
27
|
+
Perfect for hiding admin panels, creating temporary access links, or building time-based API keys.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
[](https://github.com/smartlegionlab/smart-dynamic-path/)
|
|
32
|
+

|
|
33
|
+
[](https://github.com/smartlegionlab/smart-dynamic-path/blob/master/LICENSE)
|
|
34
|
+
[](https://github.com/smartlegionlab/smart-dynamic-path/stargazers)
|
|
35
|
+
[](https://github.com/smartlegionlab/smart-dynamic-path/network/members)
|
|
36
|
+
|
|
37
|
+
[](https://pypi.org/project/smart-dynamic-path/)
|
|
38
|
+
[](https://pypi.org/project/smart-dynamic-path)
|
|
39
|
+
[](https://pypi.org/project/smart-dynamic-path)
|
|
40
|
+
[](https://pepy.tech/projects/smart-dynamic-path)
|
|
41
|
+
[](https://pepy.tech/projects/smart-dynamic-path)
|
|
42
|
+
[](https://pepy.tech/projects/smart-dynamic-path)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Core idea
|
|
47
|
+
|
|
48
|
+
One secret phrase → one deterministic path per time period. Same phrase + same day = same path. No storage. No database. Just pure math.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Disclaimer
|
|
53
|
+
|
|
54
|
+
**By using this software, you agree to the full disclaimer terms.**
|
|
55
|
+
|
|
56
|
+
**Summary:** Software provided "AS IS" without warranty. You assume all risks.
|
|
57
|
+
|
|
58
|
+
**Full legal disclaimer:** See [DISCLAIMER.md](https://github.com/smartlegionlab/smart-dynamic-path/blob/master/DISCLAIMER.md)
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Use cases
|
|
63
|
+
|
|
64
|
+
- Hide Django admin: `/admin/a1b2c3d4e5f6g7h8/`
|
|
65
|
+
- Temporary download links that expire after a day
|
|
66
|
+
- Time-rotating API endpoints
|
|
67
|
+
- "Secret room" pattern for any web framework
|
|
68
|
+
|
|
69
|
+
and others...
|
|
70
|
+
|
|
71
|
+
## Local usage without installation
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git clone https://github.com/smartlegionlab/smart-dynamic-path
|
|
75
|
+
cd smart-dynamic-path
|
|
76
|
+
|
|
77
|
+
python -m smart_dynamic_path.cli --secret "my secret phrase"
|
|
78
|
+
python -m smart_dynamic_path.cli --secret "my secret phrase" --period month --full
|
|
79
|
+
python -m smart_dynamic_path.cli --secret "my secret phrase" --key-only
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Installation
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install smart-dynamic-path
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Quick start
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from smart_dynamic_path import generate_path, secret_to_path
|
|
92
|
+
|
|
93
|
+
# Generate path from secret key
|
|
94
|
+
path = generate_path(secret_key='your_64_hex_secret_key', period='day')
|
|
95
|
+
# Output: "4e30939634dfc6617f10a2f8fe259f44"
|
|
96
|
+
|
|
97
|
+
# With prefix
|
|
98
|
+
path = generate_path(secret_key='...', period='day', prefix='admin')
|
|
99
|
+
# Output: "admin/4ab3b83e39bbb1d7e31e0978ea8cea05"
|
|
100
|
+
|
|
101
|
+
# From secret phrase (local use only)
|
|
102
|
+
key, path = secret_to_path('my secret phrase', period='day')
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## CLI commands
|
|
106
|
+
|
|
107
|
+
| Command | Output |
|
|
108
|
+
|--------------------------------------------------------------|------------------------------|
|
|
109
|
+
| `smart-dynamic-path --secret "secret"` | Full info (key + path + URL) |
|
|
110
|
+
| `smart-dynamic-path --secret "secret" --key-only` | Only SECRET_KEY (64 hex) |
|
|
111
|
+
| `smart-dynamic-path --secret "secret" --path-only` | Only path (32 hex) |
|
|
112
|
+
| `smart-dynamic-path --secret "secret" --full` | Only full URL `/xxxx/` |
|
|
113
|
+
| `smart-dynamic-path --secret "secret" --period month --full` | Monthly rotation |
|
|
114
|
+
| `smart-dynamic-path --secret "secret" --prefix admin --full` | With prefix |
|
|
115
|
+
|
|
116
|
+
## Python API
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from smart_dynamic_path import generate_secret_key, generate_path, secret_to_path
|
|
120
|
+
|
|
121
|
+
# From secret phrase
|
|
122
|
+
key = generate_secret_key("my secret phrase")
|
|
123
|
+
path = generate_path(key, period='day')
|
|
124
|
+
key, path = secret_to_path("my secret phrase", period='day')
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## How it works
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
SECRET_KEY = SHA256(secret_phrase) # 64 hex chars (256 bits)
|
|
131
|
+
PATH = SHA256(SECRET_KEY + date)[:16].hex() # 32 hex chars (128 bits)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- Secret phrase → SECRET_KEY (256 bits)
|
|
135
|
+
- SECRET_KEY + current date/time → path (128 bits)
|
|
136
|
+
- Path changes automatically based on period (day/month/hour/static)
|
|
137
|
+
|
|
138
|
+
## Implemented paradigms
|
|
139
|
+
|
|
140
|
+
### 1. Pointer‑Based Security
|
|
141
|
+
The path is not stored anywhere. It is regenerated on demand from a secret phrase and current time. There is no stored "pointer" — only the ability to compute it.
|
|
142
|
+
|
|
143
|
+
**DOI:** [10.5281/zenodo.17204738](https://doi.org/10.5281/zenodo.17204738)
|
|
144
|
+
|
|
145
|
+
### 2. Local Data Regeneration
|
|
146
|
+
The exact path is computed locally on the developer's machine using only the secret phrase and date, without accessing any server.
|
|
147
|
+
|
|
148
|
+
**DOI:** [10.5281/zenodo.17264327](https://doi.org/10.5281/zenodo.17264327)
|
|
149
|
+
|
|
150
|
+
### 3. Position‑Candidate‑Hypothesis (PCH)
|
|
151
|
+
Among all possible paths (2¹²⁸ candidates), only one specific path generated by the secret phrase is valid at any given time.
|
|
152
|
+
|
|
153
|
+
**DOI:** [10.5281/zenodo.17614888](https://doi.org/10.5281/zenodo.17614888)
|
|
154
|
+
|
|
155
|
+
## Security
|
|
156
|
+
|
|
157
|
+
- No storage — paths are regenerated, not stored
|
|
158
|
+
- Deterministic — same input always produces same output
|
|
159
|
+
- 32 hex chars = 2¹²⁸ possible paths (no brute force)
|
|
160
|
+
- Time-based rotation limits exposure window
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
BSD-3-Clause
|
|
165
|
+
|
|
166
|
+
## Author
|
|
167
|
+
|
|
168
|
+
Alexander Suvorov [@smartlegionlab](https://github.com/smartlegionlab)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
smart_dynamic_path/__init__.py,sha256=VBc_CcUV8IVzcirOPLprLHui8O99mC8Oc-LnBylYsf0,256
|
|
2
|
+
smart_dynamic_path/cli.py,sha256=hJAm5CGDk6RbcvyicoIAasIpYt-3l4SygHGnnibJ-ZI,1793
|
|
3
|
+
smart_dynamic_path/core.py,sha256=VYNTSlNQbEnPcCT4G6udztybUaZvyFxk-o6vYiG_Mcg,1872
|
|
4
|
+
smart_dynamic_path-1.0.1.dist-info/licenses/LICENSE,sha256=bXnWlOMydXEp3EEgmsJuPpErliZndYEC9RReI1H-Jek,1504
|
|
5
|
+
smart_dynamic_path-1.0.1.dist-info/METADATA,sha256=a0G6HTf_TUAQycFX_bZxmSOPlsgnj7TWlHupo6fLsmk,6970
|
|
6
|
+
smart_dynamic_path-1.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
+
smart_dynamic_path-1.0.1.dist-info/entry_points.txt,sha256=HUOHeHXnqE_XeNskicxRZ1LIbLt48XWlvIgEHHiZ4SA,67
|
|
8
|
+
smart_dynamic_path-1.0.1.dist-info/top_level.txt,sha256=1SOWFhZ_ysV6m33PJwXBl5FW70gVeawRSCUYCweMfiU,19
|
|
9
|
+
smart_dynamic_path-1.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Alexander Suvorov
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
smart_dynamic_path
|