Clean up debug scripts and update RPi docs
- Delete debug/diagnostic scripts (minimal_flask_crash.py, check_scipy.py) - Delete old version summary markdown files - Update RPi docs with default creds (admin/stegasoo) - Add --soft flag documentation for sanitize script - Switch compression from xz to zstd - Add RPi image artifacts to .gitignore - Improve sanitize-for-image.sh with validation and soft reset mode 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,500 +0,0 @@
|
||||
# API Update Summary for v3.2.0
|
||||
|
||||
## Overview
|
||||
|
||||
The FastAPI REST API has been updated to align with Stegasoo v3.2.0's breaking changes:
|
||||
1. **Removed date dependency** - No `date_str` field in requests
|
||||
2. **Renamed day_phrase → passphrase** - Updated all request/response models
|
||||
3. **Updated generation** - Now generates single passphrase instead of daily phrases
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
### Request Model Changes
|
||||
|
||||
#### 1. EncodeRequest & EncodeFileRequest
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```python
|
||||
class EncodeRequest(BaseModel):
|
||||
message: str
|
||||
reference_photo_base64: str
|
||||
carrier_image_base64: str
|
||||
day_phrase: str # ← Changed to passphrase
|
||||
pin: str = ""
|
||||
rsa_key_base64: Optional[str] = None
|
||||
rsa_password: Optional[str] = None
|
||||
date_str: Optional[str] = None # ← REMOVED
|
||||
embed_mode: EmbedModeType = "lsb"
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```python
|
||||
class EncodeRequest(BaseModel):
|
||||
message: str
|
||||
reference_photo_base64: str
|
||||
carrier_image_base64: str
|
||||
passphrase: str = Field(description="Passphrase (v3.2.0: renamed from day_phrase)")
|
||||
pin: str = ""
|
||||
rsa_key_base64: Optional[str] = None
|
||||
rsa_password: Optional[str] = None
|
||||
# date_str removed in v3.2.0
|
||||
embed_mode: EmbedModeType = "lsb"
|
||||
dct_output_format: DctOutputFormatType = "png"
|
||||
dct_color_mode: DctColorModeType = "grayscale"
|
||||
```
|
||||
|
||||
#### 2. DecodeRequest
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```python
|
||||
class DecodeRequest(BaseModel):
|
||||
stego_image_base64: str
|
||||
reference_photo_base64: str
|
||||
day_phrase: str # ← Changed to passphrase
|
||||
pin: str = ""
|
||||
rsa_key_base64: Optional[str] = None
|
||||
rsa_password: Optional[str] = None
|
||||
embed_mode: ExtractModeType = "auto"
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```python
|
||||
class DecodeRequest(BaseModel):
|
||||
stego_image_base64: str
|
||||
reference_photo_base64: str
|
||||
passphrase: str = Field(description="Passphrase (v3.2.0: renamed from day_phrase)")
|
||||
pin: str = ""
|
||||
rsa_key_base64: Optional[str] = None
|
||||
rsa_password: Optional[str] = None
|
||||
embed_mode: ExtractModeType = "auto"
|
||||
```
|
||||
|
||||
#### 3. GenerateRequest
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```python
|
||||
class GenerateRequest(BaseModel):
|
||||
use_pin: bool = True
|
||||
use_rsa: bool = False
|
||||
pin_length: int = Field(default=6, ge=MIN_PIN_LENGTH, le=MAX_PIN_LENGTH)
|
||||
rsa_bits: int = Field(default=2048)
|
||||
words_per_phrase: int = Field(default=3, ge=MIN_PHRASE_WORDS, le=MAX_PHRASE_WORDS)
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```python
|
||||
class GenerateRequest(BaseModel):
|
||||
use_pin: bool = True
|
||||
use_rsa: bool = False
|
||||
pin_length: int = Field(default=6, ge=MIN_PIN_LENGTH, le=MAX_PIN_LENGTH)
|
||||
rsa_bits: int = Field(default=2048)
|
||||
words_per_passphrase: int = Field(
|
||||
default=DEFAULT_PASSPHRASE_WORDS, # = 4, was 3
|
||||
ge=MIN_PASSPHRASE_WORDS,
|
||||
le=MAX_PASSPHRASE_WORDS,
|
||||
description="Words per passphrase (v3.2.0: default increased to 4)"
|
||||
)
|
||||
```
|
||||
|
||||
### Response Model Changes
|
||||
|
||||
#### 1. GenerateResponse
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```python
|
||||
class GenerateResponse(BaseModel):
|
||||
phrases: dict[str, str] # Monday -> phrase, Tuesday -> phrase, etc.
|
||||
pin: Optional[str] = None
|
||||
rsa_key_pem: Optional[str] = None
|
||||
entropy: dict[str, int]
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```python
|
||||
class GenerateResponse(BaseModel):
|
||||
passphrase: str = Field(description="Single passphrase (v3.2.0: no daily rotation)")
|
||||
pin: Optional[str] = None
|
||||
rsa_key_pem: Optional[str] = None
|
||||
entropy: dict[str, int]
|
||||
# Legacy field for compatibility
|
||||
phrases: Optional[dict[str, str]] = Field(
|
||||
default=None,
|
||||
description="Deprecated: Use 'passphrase' instead"
|
||||
)
|
||||
```
|
||||
|
||||
#### 2. EncodeResponse
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```python
|
||||
class EncodeResponse(BaseModel):
|
||||
stego_image_base64: str
|
||||
filename: str
|
||||
capacity_used_percent: float
|
||||
date_used: str
|
||||
day_of_week: str
|
||||
embed_mode: str
|
||||
output_format: str = "png"
|
||||
color_mode: str = "color"
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```python
|
||||
class EncodeResponse(BaseModel):
|
||||
stego_image_base64: str
|
||||
filename: str
|
||||
capacity_used_percent: float
|
||||
embed_mode: str
|
||||
output_format: str = "png"
|
||||
color_mode: str = "color"
|
||||
# Legacy fields (no longer used in crypto)
|
||||
date_used: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Deprecated: Date no longer used in v3.2.0"
|
||||
)
|
||||
day_of_week: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Deprecated: Date no longer used in v3.2.0"
|
||||
)
|
||||
```
|
||||
|
||||
### Endpoint Changes
|
||||
|
||||
#### 1. POST /encode
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```json
|
||||
{
|
||||
"message": "Secret message",
|
||||
"reference_photo_base64": "...",
|
||||
"carrier_image_base64": "...",
|
||||
"day_phrase": "apple forest thunder",
|
||||
"date_str": "2025-01-15",
|
||||
"pin": "123456",
|
||||
"embed_mode": "lsb"
|
||||
}
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```json
|
||||
{
|
||||
"message": "Secret message",
|
||||
"reference_photo_base64": "...",
|
||||
"carrier_image_base64": "...",
|
||||
"passphrase": "apple forest thunder mountain",
|
||||
"pin": "123456",
|
||||
"embed_mode": "lsb"
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. POST /decode
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```json
|
||||
{
|
||||
"stego_image_base64": "...",
|
||||
"reference_photo_base64": "...",
|
||||
"day_phrase": "apple forest thunder",
|
||||
"pin": "123456",
|
||||
"embed_mode": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```json
|
||||
{
|
||||
"stego_image_base64": "...",
|
||||
"reference_photo_base64": "...",
|
||||
"passphrase": "apple forest thunder mountain",
|
||||
"pin": "123456",
|
||||
"embed_mode": "auto"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. POST /generate
|
||||
|
||||
**Response Before (v3.1.0):**
|
||||
```json
|
||||
{
|
||||
"phrases": {
|
||||
"Monday": "apple forest thunder",
|
||||
"Tuesday": "banana river lightning",
|
||||
...
|
||||
},
|
||||
"pin": "123456",
|
||||
"rsa_key_pem": null,
|
||||
"entropy": {
|
||||
"phrase": 33,
|
||||
"pin": 20,
|
||||
"rsa": 0,
|
||||
"total": 53
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response After (v3.2.0):**
|
||||
```json
|
||||
{
|
||||
"passphrase": "apple forest thunder mountain",
|
||||
"pin": "123456",
|
||||
"rsa_key_pem": null,
|
||||
"entropy": {
|
||||
"passphrase": 44,
|
||||
"pin": 20,
|
||||
"rsa": 0,
|
||||
"total": 64
|
||||
},
|
||||
"phrases": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. POST /encode/multipart
|
||||
|
||||
**Form Fields Before (v3.1.0):**
|
||||
- `day_phrase` (required)
|
||||
- `date_str` (optional)
|
||||
- `reference_photo` (file)
|
||||
- `carrier` (file)
|
||||
- ...
|
||||
|
||||
**Form Fields After (v3.2.0):**
|
||||
- `passphrase` (required) ← renamed from day_phrase
|
||||
- `reference_photo` (file)
|
||||
- `carrier` (file)
|
||||
- ... (date_str removed)
|
||||
|
||||
**Response Headers Before (v3.1.0):**
|
||||
```
|
||||
X-Stegasoo-Date: 2025-01-15
|
||||
X-Stegasoo-Day: Wednesday
|
||||
X-Stegasoo-Capacity-Percent: 25.5
|
||||
X-Stegasoo-Embed-Mode: lsb
|
||||
```
|
||||
|
||||
**Response Headers After (v3.2.0):**
|
||||
```
|
||||
X-Stegasoo-Capacity-Percent: 25.5
|
||||
X-Stegasoo-Embed-Mode: lsb
|
||||
X-Stegasoo-Output-Format: png
|
||||
X-Stegasoo-Color-Mode: color
|
||||
X-Stegasoo-Version: 3.2.0
|
||||
```
|
||||
|
||||
### New Status Endpoint Information
|
||||
|
||||
#### GET /
|
||||
|
||||
**Added to response:**
|
||||
```json
|
||||
{
|
||||
"version": "3.2.0",
|
||||
...
|
||||
"breaking_changes": {
|
||||
"date_removed": "No date_str parameter needed - encode/decode anytime",
|
||||
"passphrase_renamed": "day_phrase → passphrase (single passphrase, no daily rotation)",
|
||||
"format_version": 4,
|
||||
"backward_compatible": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Guide for API Clients
|
||||
|
||||
### 1. Update Request Bodies
|
||||
|
||||
**Find and replace in client code:**
|
||||
```javascript
|
||||
// Before
|
||||
{
|
||||
day_phrase: "apple forest thunder",
|
||||
date_str: "2025-01-15"
|
||||
}
|
||||
|
||||
// After
|
||||
{
|
||||
passphrase: "apple forest thunder mountain"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Update Response Handling
|
||||
|
||||
**Before:**
|
||||
```javascript
|
||||
const response = await fetch('/encode', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
message: "secret",
|
||||
day_phrase: "words",
|
||||
date_str: "2025-01-15",
|
||||
...
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
console.log(data.date_used); // "2025-01-15"
|
||||
console.log(data.day_of_week); // "Wednesday"
|
||||
```
|
||||
|
||||
**After:**
|
||||
```javascript
|
||||
const response = await fetch('/encode', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
message: "secret",
|
||||
passphrase: "longer words here now",
|
||||
// date_str removed
|
||||
...
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
// date_used and day_of_week are null in v3.2.0
|
||||
```
|
||||
|
||||
### 3. Update Generate Endpoint Usage
|
||||
|
||||
**Before:**
|
||||
```javascript
|
||||
const creds = await fetch('/generate', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ use_pin: true })
|
||||
}).then(r => r.json());
|
||||
|
||||
// Use Monday's phrase
|
||||
const mondayPhrase = creds.phrases['Monday'];
|
||||
```
|
||||
|
||||
**After:**
|
||||
```javascript
|
||||
const creds = await fetch('/generate', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ use_pin: true })
|
||||
}).then(r => r.json());
|
||||
|
||||
// Use single passphrase
|
||||
const passphrase = creds.passphrase;
|
||||
```
|
||||
|
||||
### 4. Update Multipart Requests
|
||||
|
||||
**Before (JavaScript fetch):**
|
||||
```javascript
|
||||
const formData = new FormData();
|
||||
formData.append('day_phrase', 'apple forest thunder');
|
||||
formData.append('date_str', '2025-01-15');
|
||||
formData.append('reference_photo', refPhotoFile);
|
||||
formData.append('carrier', carrierFile);
|
||||
formData.append('message', 'secret');
|
||||
formData.append('pin', '123456');
|
||||
|
||||
const response = await fetch('/encode/multipart', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
```
|
||||
|
||||
**After (JavaScript fetch):**
|
||||
```javascript
|
||||
const formData = new FormData();
|
||||
formData.append('passphrase', 'apple forest thunder mountain');
|
||||
// date_str removed
|
||||
formData.append('reference_photo', refPhotoFile);
|
||||
formData.append('carrier', carrierFile);
|
||||
formData.append('message', 'secret');
|
||||
formData.append('pin', '123456');
|
||||
|
||||
const response = await fetch('/encode/multipart', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
### Endpoints to Test
|
||||
|
||||
- [ ] GET / - Returns v3.2.0 with breaking_changes info
|
||||
- [ ] GET /modes - Returns mode information
|
||||
- [ ] POST /generate - Returns single passphrase
|
||||
- [ ] POST /encode - Works without date_str
|
||||
- [ ] POST /encode/file - Works without date_str
|
||||
- [ ] POST /decode - Works without date_str
|
||||
- [ ] POST /encode/multipart - Accepts passphrase instead of day_phrase
|
||||
- [ ] POST /decode/multipart - Accepts passphrase instead of day_phrase
|
||||
- [ ] POST /compare - Still works
|
||||
- [ ] POST /will-fit - Still works
|
||||
- [ ] POST /image/info - Still works
|
||||
- [ ] POST /extract-key-from-qr - Still works
|
||||
|
||||
### Validation Tests
|
||||
|
||||
- [ ] Reject requests with `day_phrase` field (should get validation error)
|
||||
- [ ] Reject requests with `date_str` field (should be ignored or error)
|
||||
- [ ] Accept requests with `passphrase` field
|
||||
- [ ] Generate response includes `passphrase` field
|
||||
- [ ] Generate response has `phrases` as null
|
||||
- [ ] Encode response has `date_used` and `day_of_week` as null
|
||||
- [ ] Multipart encode works with new field names
|
||||
- [ ] Response headers updated correctly
|
||||
|
||||
## OpenAPI/Swagger Documentation
|
||||
|
||||
The FastAPI auto-generated documentation (/docs and /redoc) will automatically reflect the changes:
|
||||
|
||||
1. **Models updated** - Request/response schemas show new field names
|
||||
2. **Descriptions updated** - Field descriptions mention v3.2.0 changes
|
||||
3. **Examples updated** - Interactive API explorer uses new field names
|
||||
|
||||
Users can browse to `/docs` to see the updated API specification.
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
**Breaking Change:** API v3.2.0 is NOT backward compatible with v3.1.0
|
||||
|
||||
Clients using the old API will encounter:
|
||||
1. **Validation errors** - Missing required `passphrase` field
|
||||
2. **Unexpected responses** - `phrases` field will be null
|
||||
3. **Changed behavior** - Date fields no longer populated
|
||||
|
||||
### Migration Timeline Recommendation
|
||||
|
||||
1. **Deploy v3.2.0 API** to staging
|
||||
2. **Update client applications** to use new field names
|
||||
3. **Test thoroughly** with staging API
|
||||
4. **Deploy v3.2.0 API** to production
|
||||
5. **Notify users** of breaking changes
|
||||
|
||||
Alternatively, run v3.1.0 and v3.2.0 APIs side-by-side on different paths:
|
||||
- `/api/v3.1/` - Old API
|
||||
- `/api/v3.2/` - New API
|
||||
|
||||
## Constants Updates
|
||||
|
||||
Used in validation:
|
||||
```python
|
||||
from stegasoo.constants import (
|
||||
MIN_PASSPHRASE_WORDS, # = 3
|
||||
MAX_PASSPHRASE_WORDS, # = 12
|
||||
DEFAULT_PASSPHRASE_WORDS, # = 4 (increased from 3)
|
||||
)
|
||||
```
|
||||
|
||||
## Error Messages
|
||||
|
||||
All error messages updated:
|
||||
- "day_phrase is required" → "passphrase is required"
|
||||
- References to "phrase" now mean "passphrase"
|
||||
|
||||
## Implementation Status
|
||||
|
||||
✅ All request models updated
|
||||
✅ All response models updated
|
||||
✅ All endpoints updated
|
||||
✅ Multipart endpoints updated
|
||||
✅ Status endpoint shows breaking changes
|
||||
✅ Constants imported correctly
|
||||
✅ Error handling updated
|
||||
✅ No references to day_phrase in user-facing text
|
||||
✅ No date_str parameters accepted
|
||||
|
||||
Ready for deployment!
|
||||
@@ -1,426 +0,0 @@
|
||||
# Web Frontend Update Summary for v3.2.0
|
||||
|
||||
## Overview
|
||||
|
||||
The Flask web frontend has been updated to align with Stegasoo v3.2.0's breaking changes:
|
||||
1. **Removed date dependency** - No date selection or tracking in UI
|
||||
2. **Renamed day_phrase → passphrase** - Updated all forms and templates
|
||||
3. **Increased default words** - From 3 to 4 for better security
|
||||
|
||||
## Key Changes
|
||||
|
||||
### 1. Form Parameter Changes
|
||||
|
||||
#### Generate Page
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```python
|
||||
words_per_phrase = int(request.form.get('words_per_phrase', 3))
|
||||
# Generated daily phrases for all days of the week
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```python
|
||||
words_per_passphrase = int(request.form.get('words_per_passphrase', 4))
|
||||
# Generates single passphrase
|
||||
```
|
||||
|
||||
**Template variables changed:**
|
||||
- `phrases` → `passphrase` (single string instead of dict)
|
||||
- `words_per_phrase` → `words_per_passphrase`
|
||||
- `phrase_entropy` → `passphrase_entropy`
|
||||
- Removed `days` variable (no longer needed)
|
||||
|
||||
#### Encode Page
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```python
|
||||
day_phrase = request.form.get('day_phrase', '')
|
||||
client_date = request.form.get('client_date', '').strip()
|
||||
day_of_week = get_today_day() # Used in template
|
||||
|
||||
encode_result = encode(
|
||||
...,
|
||||
day_phrase=day_phrase,
|
||||
date_str=date_str,
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```python
|
||||
passphrase = request.form.get('passphrase', '')
|
||||
# No client_date or day_of_week needed
|
||||
|
||||
encode_result = encode(
|
||||
...,
|
||||
passphrase=passphrase, # Renamed
|
||||
# date_str removed
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
#### Decode Page
|
||||
|
||||
**Before (v3.1.0):**
|
||||
```python
|
||||
day_phrase = request.form.get('day_phrase', '')
|
||||
stego_date = request.form.get('stego_date', '').strip()
|
||||
|
||||
decode_result = decode(
|
||||
...,
|
||||
day_phrase=day_phrase,
|
||||
date_str=stego_date if stego_date else None,
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
**After (v3.2.0):**
|
||||
```python
|
||||
passphrase = request.form.get('passphrase', '')
|
||||
# No stego_date needed
|
||||
|
||||
decode_result = decode(
|
||||
...,
|
||||
passphrase=passphrase, # Renamed
|
||||
# date_str removed
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### 2. Template Context Updates
|
||||
|
||||
**inject_globals() changes:**
|
||||
|
||||
**Added:**
|
||||
```python
|
||||
'min_passphrase_words': MIN_PASSPHRASE_WORDS,
|
||||
'recommended_passphrase_words': RECOMMENDED_PASSPHRASE_WORDS,
|
||||
'default_passphrase_words': DEFAULT_PASSPHRASE_WORDS,
|
||||
```
|
||||
|
||||
**Used for:**
|
||||
- Showing passphrase length requirements
|
||||
- Default values in generate form
|
||||
- Validation messages
|
||||
|
||||
### 3. Validation Updates
|
||||
|
||||
**Added passphrase validation:**
|
||||
```python
|
||||
from stegasoo import validate_passphrase
|
||||
|
||||
# In encode_page()
|
||||
result = validate_passphrase(passphrase)
|
||||
if not result.is_valid:
|
||||
flash(result.error_message, 'error')
|
||||
return ...
|
||||
|
||||
# Show warning if passphrase is short
|
||||
if result.warning:
|
||||
flash(result.warning, 'warning')
|
||||
```
|
||||
|
||||
### 4. Error Message Updates
|
||||
|
||||
**Before:**
|
||||
```python
|
||||
flash('Day phrase is required', 'error')
|
||||
flash('Decryption failed. Check your phrase, PIN...', 'error')
|
||||
```
|
||||
|
||||
**After:**
|
||||
```python
|
||||
flash('Passphrase is required', 'error')
|
||||
flash('Decryption failed. Check your passphrase, PIN...', 'error')
|
||||
```
|
||||
|
||||
## Template Changes Needed
|
||||
|
||||
These Flask routes will need corresponding template updates:
|
||||
|
||||
### generate.html
|
||||
|
||||
**Changes needed:**
|
||||
```html
|
||||
<!-- Before -->
|
||||
<label for="words_per_phrase">Words per phrase</label>
|
||||
<input type="number" name="words_per_phrase" value="3">
|
||||
|
||||
{% if generated %}
|
||||
<h3>Daily Phrases</h3>
|
||||
{% for day in days %}
|
||||
<tr>
|
||||
<td>{{ day }}</td>
|
||||
<td>{{ phrases[day] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<!-- After -->
|
||||
<label for="words_per_passphrase">Words per passphrase</label>
|
||||
<input type="number" name="words_per_passphrase" value="{{ default_passphrase_words }}">
|
||||
|
||||
{% if generated %}
|
||||
<h3>Passphrase</h3>
|
||||
<div class="passphrase-display">
|
||||
<code>{{ passphrase }}</code>
|
||||
<p class="help-text">Use this passphrase to encode and decode messages (no date needed!)</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
```
|
||||
|
||||
**Entropy display:**
|
||||
```html
|
||||
<!-- Before -->
|
||||
<li>Phrase entropy: {{ phrase_entropy }} bits</li>
|
||||
|
||||
<!-- After -->
|
||||
<li>Passphrase entropy: {{ passphrase_entropy }} bits ({{ words_per_passphrase }} words)</li>
|
||||
```
|
||||
|
||||
### encode.html
|
||||
|
||||
**Changes needed:**
|
||||
```html
|
||||
<!-- Before -->
|
||||
<label for="day_phrase">Day Phrase</label>
|
||||
<input type="text" name="day_phrase" required>
|
||||
|
||||
<label for="client_date">Encoding Date (Optional)</label>
|
||||
<input type="date" name="client_date">
|
||||
<p class="help-text">Defaults to today: {{ day_of_week }}</p>
|
||||
|
||||
<!-- After -->
|
||||
<label for="passphrase">Passphrase</label>
|
||||
<input type="text" name="passphrase" required
|
||||
placeholder="Enter at least {{ recommended_passphrase_words }} words">
|
||||
<p class="help-text">
|
||||
v3.2.0: No date needed! Use your passphrase anytime.
|
||||
</p>
|
||||
```
|
||||
|
||||
### decode.html
|
||||
|
||||
**Changes needed:**
|
||||
```html
|
||||
<!-- Before -->
|
||||
<label for="day_phrase">Day Phrase</label>
|
||||
<input type="text" name="day_phrase" required>
|
||||
|
||||
<label for="stego_date">Encoding Date</label>
|
||||
<input type="date" name="stego_date" id="stego_date">
|
||||
<p class="help-text">Will be auto-detected from filename if possible</p>
|
||||
|
||||
<script>
|
||||
// Auto-detect date from filename
|
||||
stegoInput.addEventListener('change', function() {
|
||||
const filename = this.files[0]?.name || '';
|
||||
const dateMatch = filename.match(/_(\d{4})(\d{2})(\d{2})/);
|
||||
if (dateMatch) {
|
||||
document.getElementById('stego_date').value =
|
||||
`${dateMatch[1]}-${dateMatch[2]}-${dateMatch[3]}`;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- After -->
|
||||
<label for="passphrase">Passphrase</label>
|
||||
<input type="text" name="passphrase" required
|
||||
placeholder="Enter your passphrase">
|
||||
<p class="help-text">
|
||||
v3.2.0: No date needed to decode!
|
||||
</p>
|
||||
|
||||
<!-- Remove date detection script -->
|
||||
```
|
||||
|
||||
### index.html
|
||||
|
||||
**Changes needed:**
|
||||
```html
|
||||
<!-- Before -->
|
||||
<p>Generate daily passphrases and security credentials</p>
|
||||
<p>Hide messages using day-specific phrases</p>
|
||||
|
||||
<!-- After -->
|
||||
<p>Generate passphrases and security credentials</p>
|
||||
<p>v3.2.0: Simplified - no more daily rotation!</p>
|
||||
```
|
||||
|
||||
### about.html
|
||||
|
||||
**Add v3.2.0 section:**
|
||||
```html
|
||||
<h2>Version 3.2.0 Changes</h2>
|
||||
<ul>
|
||||
<li><strong>No date dependency</strong> - Encode and decode anytime without tracking dates</li>
|
||||
<li><strong>Single passphrase</strong> - No more daily rotation, just remember one strong passphrase</li>
|
||||
<li><strong>Better security</strong> - Default passphrase length increased to 4 words</li>
|
||||
<li><strong>Asynchronous ready</strong> - Perfect for dead drops and delayed delivery</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
## JavaScript Changes Needed
|
||||
|
||||
### Remove date-related code:
|
||||
|
||||
```javascript
|
||||
// REMOVE THIS (date detection from filename)
|
||||
function detectDateFromFilename(filename) {
|
||||
const match = filename.match(/_(\d{4})(\d{2})(\d{2})/);
|
||||
if (match) {
|
||||
return `${match[1]}-${match[2]}-${match[3]}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// REMOVE THIS (day-of-week display)
|
||||
function updateDayOfWeek() {
|
||||
const dateInput = document.getElementById('client_date');
|
||||
const dayDisplay = document.getElementById('day_display');
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Update validation:
|
||||
|
||||
```javascript
|
||||
// Before
|
||||
const dayPhrase = document.getElementById('day_phrase').value;
|
||||
if (!dayPhrase || dayPhrase.trim().length === 0) {
|
||||
alert('Day phrase is required');
|
||||
return false;
|
||||
}
|
||||
|
||||
// After
|
||||
const passphrase = document.getElementById('passphrase').value;
|
||||
if (!passphrase || passphrase.trim().length === 0) {
|
||||
alert('Passphrase is required');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add word count validation
|
||||
const words = passphrase.trim().split(/\s+/);
|
||||
if (words.length < {{ min_passphrase_words }}) {
|
||||
alert(`Passphrase should have at least {{ recommended_passphrase_words }} words`);
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
## CSS Updates
|
||||
|
||||
Add styling for passphrase warnings:
|
||||
|
||||
```css
|
||||
.passphrase-display {
|
||||
background: #f5f5f5;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.passphrase-display code {
|
||||
font-size: 1.2em;
|
||||
color: #2c3e50;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.help-text.v3-2-0 {
|
||||
color: #3498db;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.flash.warning {
|
||||
background-color: #fff3cd;
|
||||
border-left: 4px solid #ffc107;
|
||||
color: #856404;
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Notes for Users
|
||||
|
||||
Add to templates:
|
||||
|
||||
```html
|
||||
<div class="alert alert-info">
|
||||
<h4>⚠️ v3.2.0 Breaking Changes</h4>
|
||||
<p>If you have messages encoded with v3.1.0:</p>
|
||||
<ul>
|
||||
<li>They cannot be decoded with v3.2.0</li>
|
||||
<li>You need the original v3.1.0 installation to decode them</li>
|
||||
<li>After decoding, you can re-encode with v3.2.0</li>
|
||||
</ul>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Form Field Summary
|
||||
|
||||
### Changed Field Names
|
||||
|
||||
| Old Name (v3.1.0) | New Name (v3.2.0) | Type |
|
||||
|-------------------|-------------------|------|
|
||||
| `day_phrase` | `passphrase` | text input |
|
||||
| `words_per_phrase` | `words_per_passphrase` | number input |
|
||||
| `client_date` | (removed) | date input |
|
||||
| `stego_date` | (removed) | date input |
|
||||
|
||||
### New Validation Attributes
|
||||
|
||||
```html
|
||||
<input type="text" name="passphrase"
|
||||
required
|
||||
minlength="{{ min_passphrase_words * 4 }}"
|
||||
placeholder="Enter at least {{ recommended_passphrase_words }} words"
|
||||
pattern="^\s*\S+(\s+\S+){3,}.*$"
|
||||
title="Please enter at least 4 words">
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Generate page creates single passphrase
|
||||
- [ ] Generate page shows correct entropy (4 words = 44 bits)
|
||||
- [ ] Generate page doesn't show day names
|
||||
- [ ] Encode page accepts passphrase (not day_phrase)
|
||||
- [ ] Encode page doesn't have date selection
|
||||
- [ ] Encode page shows v3.2.0 help text
|
||||
- [ ] Decode page accepts passphrase
|
||||
- [ ] Decode page doesn't have date input
|
||||
- [ ] Decode page doesn't auto-detect date from filename
|
||||
- [ ] Error messages say "passphrase" not "day phrase"
|
||||
- [ ] Validation shows warnings for short passphrases
|
||||
- [ ] QR code functionality still works
|
||||
- [ ] DCT mode options still work
|
||||
- [ ] All flash messages updated
|
||||
|
||||
## Implementation Status
|
||||
|
||||
✅ Flask routes updated
|
||||
✅ Form parameter names changed
|
||||
✅ Function calls updated
|
||||
✅ Validation added for passphrases
|
||||
✅ Error messages updated
|
||||
✅ Template context updated
|
||||
⏳ Templates need updating (generate.html, encode.html, decode.html, index.html, about.html)
|
||||
⏳ JavaScript needs updating
|
||||
⏳ CSS styling for v3.2.0 features
|
||||
|
||||
## Quick Reference
|
||||
|
||||
**To test the Flask app:**
|
||||
```bash
|
||||
cd frontends/web
|
||||
python app.py
|
||||
# Visit http://localhost:5000
|
||||
```
|
||||
|
||||
**Key user-facing changes:**
|
||||
1. Generate: Shows one passphrase, not 7 daily phrases
|
||||
2. Encode: No date selection, just passphrase
|
||||
3. Decode: No date needed, just passphrase
|
||||
|
||||
**Benefits to highlight:**
|
||||
- ✅ Simpler UI (fewer fields)
|
||||
- ✅ No date tracking needed
|
||||
- ✅ Encode today, decode anytime
|
||||
- ✅ Perfect for asynchronous communications
|
||||
Reference in New Issue
Block a user