Metadata-Version: 2.4
Name: django-smart-dynamic-path
Version: 1.0.2
Summary: Dynamic secret admin URL for Django. Time-based, deterministic, no storage. Hide your Django admin behind a URL that changes daily/monthly/hourly. Only you know the secret phrase to generate the current path.
Author-email: Alexander Suvorov <smartlegionlab@gmail.com>
License: BSD-3-Clause
Project-URL: Homepage, https://github.com/smartlegionlab/django-smart-dynamic-path
Classifier: Framework :: Django
Classifier: Framework :: Django :: 3.2
Classifier: Framework :: Django :: 4.0
Classifier: Framework :: Django :: 5.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Topic :: Security
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: smart-dynamic-path>=1.0.1
Requires-Dist: Django>=3.2
Dynamic: license-file

# Django Smart Dynamic Path <sup>v1.0.2</sup>

**Dynamic secret admin URL for Django. Time-based, deterministic, no storage.**

Hide your Django admin behind a URL that changes daily/monthly. Only you know the secret phrase to generate the current path.

---

[![GitHub release (latest by date)](https://img.shields.io/github/v/release/smartlegionlab/django-smart-dynamic-path)](https://github.com/smartlegionlab/django-smart-dynamic-path/)
![GitHub top language](https://img.shields.io/github/languages/top/smartlegionlab/django-smart-dynamic-path)
[![GitHub](https://img.shields.io/github/license/smartlegionlab/django-smart-dynamic-path)](https://github.com/smartlegionlab/django-smart-dynamic-path/blob/master/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/smartlegionlab/django-smart-dynamic-path?style=social)](https://github.com/smartlegionlab/django-smart-dynamic-path/stargazers)
[![GitHub forks](https://img.shields.io/github/forks/smartlegionlab/django-smart-dynamic-path?style=social)](https://github.com/smartlegionlab/django-smart-dynamic-path/network/members)

[![PyPI - Downloads](https://img.shields.io/pypi/dm/django-smart-dynamic-path?label=pypi%20downloads)](https://pypi.org/project/django-smart-dynamic-path/)
[![PyPI](https://img.shields.io/pypi/v/django-smart-dynamic-path)](https://pypi.org/project/django-smart-dynamic-path)
[![PyPI - Format](https://img.shields.io/pypi/format/django-smart-dynamic-path)](https://pypi.org/project/django-smart-dynamic-path)
[![PyPI Downloads](https://static.pepy.tech/badge/django-smart-dynamic-path)](https://pepy.tech/projects/django-smart-dynamic-path)
[![PyPI Downloads](https://static.pepy.tech/badge/django-smart-dynamic-path/month)](https://pepy.tech/projects/django-smart-dynamic-path)
[![PyPI Downloads](https://static.pepy.tech/badge/django-smart-dynamic-path/week)](https://pepy.tech/projects/django-smart-dynamic-path)

---

## What it does

Standard Django admin: `/admin/` (always the same)

This package: `/admin/a1b2c3d4e5f6g7h8/` (changes automatically)

---

## Disclaimer

**By using this software, you agree to the full disclaimer terms.**

**Summary:** Software provided "AS IS" without warranty. You assume all risks.

**Full legal disclaimer:** See [DISCLAIMER.md](https://github.com/smartlegionlab/django-smart-dynamic-path/blob/master/DISCLAIMER.md)

---

## Installation

```bash
pip install django-smart-dynamic-path
```

## Quick start

### 1. Add to `INSTALLED_APPS`

```python
INSTALLED_APPS = [
    'django_smart_dynamic_path',
    'django.contrib.admin',
    # ...
]
```

### 2. Replace admin URLs in `urls.py`

```python
from django.urls import path, include

urlpatterns = [
    path('admin/', include('django_smart_dynamic_path.urls')),
]
```

### 3. Generate SECRET_KEY from secret phrase (local)

```bash
smart-dynamic-path --secret "your secret phrase" --key-only
```

Copy the output and set as `SECRET_KEY` in your `.env` or `settings.py`.

### 4. Configure period (optional, in `settings.py`)

```python
SECRET_ADMIN_PERIOD = 'day'  # day, month, static
```

### 5. Get current admin path (server)

```bash
python manage.py get_admin_path --full
```

## ⚠️ Important Django limitation

Due to Django's URL compilation mechanism, the admin path is calculated **once when the server starts**. 
To apply a new path when the period changes (e.g., next day), you need to restart the server.

### Automatic restart with cron

```bash
# Add to crontab (restart at midnight)
0 0 * * * systemctl restart gunicorn
```

This is not a bug, but a Django architectural feature.

## Django management commands

| Command                                                  | Output                |
|----------------------------------------------------------|-----------------------|
| `python manage.py generate_secret_key --secret "phrase"` | SECRET_KEY and period |
| `python manage.py get_admin_path`                        | `a1b2c3d4e5f6g7h8`    |
| `python manage.py get_admin_path --full`                 | `/a1b2c3d4e5f6g7h8/`  |

## Template tag

```django
{% load admin_link %}
<a href="{% secret_admin_link %}">Secret Admin</a>
```

## Python API

```python
from django_smart_dynamic_path import get_admin_path, get_admin_url

path = get_admin_path()      # 'a1b2c3d4e5f6g7h8'
url = get_admin_url()        # 'admin/a1b2c3d4e5f6g7h8/'
```

## How it works

```
SECRET_KEY = SHA256(secret_phrase)                 # 64 hex chars (256 bits)
ADMIN_PATH = SHA256(SECRET_KEY + date)[:16].hex()  # 32 hex chars (128 bits)
```

- Secret phrase → SECRET_KEY (256 bits)
- SECRET_KEY + current date → admin path (128 bits)
- Path changes automatically based on period (day/month/hour/static)
- Same secret phrase always produces same SECRET_KEY
- Same SECRET_KEY + same date always produces same path

## Getting the path locally

```bash
git clone https://github.com/smartlegionlab/smart-dynamic-path
cd smart-dynamic-path

python3 -m smart_dynamic_path.cli --secret "my secret phrase"
python3 -m smart_dynamic_path.cli --secret "my secret phrase" --period month --prefix admin --full
python3 -m smart_dynamic_path.cli --secret "my secret phrase" --key-only
```

## Implemented paradigms

### 1. Pointer‑Based Security
The admin URL 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.

**DOI:** [10.5281/zenodo.17204738](https://doi.org/10.5281/zenodo.17204738)

### 2. Local Data Regeneration
The exact admin path is computed locally on the developer's machine using only the secret phrase and date, without accessing the server. The server never knows the secret phrase.

**DOI:** [10.5281/zenodo.17264327](https://doi.org/10.5281/zenodo.17264327)

### 3. Position‑Candidate‑Hypothesis (PCH)
Among all possible URL paths (2¹²⁸ candidates), only one specific path generated by the secret phrase is valid at any given time. The hypothesis (which path is valid) is verified through the hash function.

**DOI:** [10.5281/zenodo.17614888](https://doi.org/10.5281/zenodo.17614888)

## Security

- No additional secrets — uses only Django's existing SECRET_KEY
- Secret phrase exists only in memory, never stored
- 32 hex chars = 2¹²⁸ possible paths (no brute force)
- Time‑based rotation limits exposure window

## License

BSD-3-Clause

## Author

Alexander Suvorov [@smartlegionlab](https://github.com/smartlegionlab)
