Lizenzkey Format
Dieser Commit ist enthalten in:
47
JOURNAL.md
47
JOURNAL.md
@@ -2158,4 +2158,49 @@ Ein Pool-System für Domains, IPv4-Adressen und Telefonnummern, wobei bei jeder
|
||||
- `v2_adminpanel/templates/setup_2fa.html` - Neues Step-by-Step Design
|
||||
- `v2_adminpanel/templates/backup_codes.html` - Modernisiertes Layout
|
||||
|
||||
**Status:** ✅ Abgeschlossen - Login funktioniert, UI im konsistenten Design
|
||||
**Status:** ✅ Abgeschlossen - Login funktioniert, UI im konsistenten Design
|
||||
|
||||
### 2025-06-09: Lizenzschlüssel-Format geändert
|
||||
|
||||
**Änderung:**
|
||||
- Altes Format: `AF-YYYYMMFT-XXXX-YYYY-ZZZZ` (z.B. AF-202506F-V55Y-9DWE-GL5G)
|
||||
- Neues Format: `AF-F-YYYYMM-XXXX-YYYY-ZZZZ` (z.B. AF-F-202506-V55Y-9DWE-GL5G)
|
||||
|
||||
**Vorteile:**
|
||||
- Klarere Struktur mit separatem Typ-Indikator
|
||||
- Einfacher zu lesen und zu verstehen
|
||||
- Typ (F/T) sofort im zweiten Block erkennbar
|
||||
|
||||
**Geänderte Dateien:**
|
||||
- `v2_adminpanel/app.py`:
|
||||
- `generate_license_key()` - Generiert Keys im neuen Format
|
||||
- `validate_license_key()` - Validiert Keys mit neuem Regex-Pattern
|
||||
- `v2_adminpanel/templates/index.html`:
|
||||
- Placeholder und Pattern für Input-Feld angepasst
|
||||
- JavaScript charAt() Position für Typ-Prüfung korrigiert
|
||||
- `v2_adminpanel/templates/batch_form.html`:
|
||||
- Vorschau-Format für Batch-Generierung angepasst
|
||||
|
||||
**Hinweis:** Alte Keys im bisherigen Format bleiben ungültig. Bei Bedarf könnte eine Migration oder Dual-Support implementiert werden.
|
||||
|
||||
**Status:** ✅ Implementiert
|
||||
|
||||
### 2025-06-09: Datenbank-Migration der Lizenzschlüssel
|
||||
|
||||
**Durchgeführt:**
|
||||
- Alle bestehenden Lizenzschlüssel in der Datenbank auf das neue Format migriert
|
||||
- 18 Lizenzschlüssel erfolgreich konvertiert (16 Full, 2 Test)
|
||||
|
||||
**Migration:**
|
||||
- Von: `AF-YYYYMMFT-XXXX-YYYY-ZZZZ`
|
||||
- Nach: `AF-F-YYYYMM-XXXX-YYYY-ZZZZ`
|
||||
|
||||
**Beispiele:**
|
||||
- Alt: `AF-202506F-V55Y-9DWE-GL5G`
|
||||
- Neu: `AF-F-202506-V55Y-9DWE-GL5G`
|
||||
|
||||
**Geänderte Dateien:**
|
||||
- `v2_adminpanel/migrate_license_keys.sql` - Migrations-Script (temporär)
|
||||
- `v2_adminpanel/fix_license_keys.sql` - Korrektur-Script (temporär)
|
||||
|
||||
**Status:** ✅ Alle Lizenzschlüssel erfolgreich migriert
|
||||
@@ -641,12 +641,12 @@ def verify_recaptcha(response):
|
||||
|
||||
def generate_license_key(license_type='full'):
|
||||
"""
|
||||
Generiert einen Lizenzschlüssel im Format: AF-YYYYMMFT-XXXX-YYYY-ZZZZ
|
||||
Generiert einen Lizenzschlüssel im Format: AF-F-YYYYMM-XXXX-YYYY-ZZZZ
|
||||
|
||||
AF = Account Factory (Produktkennung)
|
||||
F/T = F für Fullversion, T für Testversion
|
||||
YYYY = Jahr
|
||||
MM = Monat
|
||||
FT = F für Fullversion, T für Testversion
|
||||
XXXX-YYYY-ZZZZ = Zufällige alphanumerische Zeichen
|
||||
"""
|
||||
# Erlaubte Zeichen (ohne verwirrende wie 0/O, 1/I/l)
|
||||
@@ -664,21 +664,21 @@ def generate_license_key(license_type='full'):
|
||||
parts.append(part)
|
||||
|
||||
# Key zusammensetzen
|
||||
key = f"AF-{date_part}{type_char}-{parts[0]}-{parts[1]}-{parts[2]}"
|
||||
key = f"AF-{type_char}-{date_part}-{parts[0]}-{parts[1]}-{parts[2]}"
|
||||
|
||||
return key
|
||||
|
||||
def validate_license_key(key):
|
||||
"""
|
||||
Validiert das License Key Format
|
||||
Erwartet: AF-YYYYMMFT-XXXX-YYYY-ZZZZ
|
||||
Erwartet: AF-F-YYYYMM-XXXX-YYYY-ZZZZ oder AF-T-YYYYMM-XXXX-YYYY-ZZZZ
|
||||
"""
|
||||
if not key:
|
||||
return False
|
||||
|
||||
# Pattern für das spezifische Format
|
||||
# AF- (fest) + 6 Ziffern (YYYYMM) + F oder T + - + 4 Zeichen + - + 4 Zeichen + - + 4 Zeichen
|
||||
pattern = r'^AF-\d{6}[FT]-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$'
|
||||
# Pattern für das neue Format
|
||||
# AF- (fest) + F oder T + - + 6 Ziffern (YYYYMM) + - + 4 Zeichen + - + 4 Zeichen + - + 4 Zeichen
|
||||
pattern = r'^AF-[FT]-\d{6}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$'
|
||||
|
||||
# Großbuchstaben für Vergleich
|
||||
return bool(re.match(pattern, key.upper()))
|
||||
|
||||
13
v2_adminpanel/fix_license_keys.sql
Normale Datei
13
v2_adminpanel/fix_license_keys.sql
Normale Datei
@@ -0,0 +1,13 @@
|
||||
-- Fix für die fehlerhafte Migration - entfernt doppelte Bindestriche
|
||||
UPDATE licenses
|
||||
SET license_key = REPLACE(license_key, 'AF--', 'AF-')
|
||||
WHERE license_key LIKE 'AF--%';
|
||||
|
||||
UPDATE licenses
|
||||
SET license_key = REPLACE(license_key, '6--', '6-')
|
||||
WHERE license_key LIKE '%6--%';
|
||||
|
||||
-- Zeige die korrigierten Keys
|
||||
SELECT id, license_key, license_type
|
||||
FROM licenses
|
||||
ORDER BY id;
|
||||
54
v2_adminpanel/migrate_license_keys.sql
Normale Datei
54
v2_adminpanel/migrate_license_keys.sql
Normale Datei
@@ -0,0 +1,54 @@
|
||||
-- Migration der Lizenzschlüssel vom alten Format zum neuen Format
|
||||
-- Alt: AF-YYYYMMFT-XXXX-YYYY-ZZZZ
|
||||
-- Neu: AF-F-YYYYMM-XXXX-YYYY-ZZZZ
|
||||
|
||||
-- Backup der aktuellen Schlüssel erstellen (für Sicherheit)
|
||||
CREATE TEMP TABLE license_backup AS
|
||||
SELECT id, license_key FROM licenses;
|
||||
|
||||
-- Update für Fullversion Keys (F)
|
||||
UPDATE licenses
|
||||
SET license_key =
|
||||
CONCAT(
|
||||
SUBSTRING(license_key, 1, 3), -- 'AF-'
|
||||
'-F-',
|
||||
SUBSTRING(license_key, 4, 6), -- 'YYYYMM'
|
||||
'-',
|
||||
SUBSTRING(license_key, 11) -- Rest des Keys
|
||||
)
|
||||
WHERE license_key LIKE 'AF-%F-%'
|
||||
AND license_type = 'full'
|
||||
AND license_key NOT LIKE 'AF-F-%'; -- Nicht bereits migriert
|
||||
|
||||
-- Update für Testversion Keys (T)
|
||||
UPDATE licenses
|
||||
SET license_key =
|
||||
CONCAT(
|
||||
SUBSTRING(license_key, 1, 3), -- 'AF-'
|
||||
'-T-',
|
||||
SUBSTRING(license_key, 4, 6), -- 'YYYYMM'
|
||||
'-',
|
||||
SUBSTRING(license_key, 11) -- Rest des Keys
|
||||
)
|
||||
WHERE license_key LIKE 'AF-%T-%'
|
||||
AND license_type = 'test'
|
||||
AND license_key NOT LIKE 'AF-T-%'; -- Nicht bereits migriert
|
||||
|
||||
-- Zeige die Änderungen
|
||||
SELECT
|
||||
b.license_key as old_key,
|
||||
l.license_key as new_key,
|
||||
l.license_type
|
||||
FROM licenses l
|
||||
JOIN license_backup b ON l.id = b.id
|
||||
WHERE b.license_key != l.license_key
|
||||
ORDER BY l.id;
|
||||
|
||||
-- Anzahl der migrierten Keys
|
||||
SELECT
|
||||
COUNT(*) as total_migrated,
|
||||
SUM(CASE WHEN license_type = 'full' THEN 1 ELSE 0 END) as full_licenses,
|
||||
SUM(CASE WHEN license_type = 'test' THEN 1 ELSE 0 END) as test_licenses
|
||||
FROM licenses l
|
||||
JOIN license_backup b ON l.id = b.id
|
||||
WHERE b.license_key != l.license_key;
|
||||
@@ -173,7 +173,7 @@
|
||||
<div class="modal-body">
|
||||
<p>Es werden <strong id="previewQuantity">10</strong> Lizenzen im folgenden Format generiert:</p>
|
||||
<div class="bg-light p-3 rounded font-monospace" id="previewFormat">
|
||||
AF-YYYYMMFT-XXXX-YYYY-ZZZZ
|
||||
AF-F-YYYYMM-XXXX-YYYY-ZZZZ
|
||||
</div>
|
||||
<p class="mt-3 mb-0">Die Keys werden automatisch eindeutig generiert und in der Datenbank gespeichert.</p>
|
||||
</div>
|
||||
@@ -324,7 +324,7 @@ function previewKeys() {
|
||||
const dateStr = date.getFullYear() + ('0' + (date.getMonth() + 1)).slice(-2);
|
||||
|
||||
document.getElementById('previewQuantity').textContent = quantity;
|
||||
document.getElementById('previewFormat').textContent = `AF-${dateStr}${typeChar}-XXXX-YYYY-ZZZZ`;
|
||||
document.getElementById('previewFormat').textContent = `AF-${typeChar}-${dateStr}-XXXX-YYYY-ZZZZ`;
|
||||
|
||||
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
|
||||
modal.show();
|
||||
|
||||
@@ -37,14 +37,14 @@
|
||||
<label for="licenseKey" class="form-label">Lizenzschlüssel</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="licenseKey" name="license_key"
|
||||
placeholder="AF-YYYYMMFT-XXXX-YYYY-ZZZZ" required
|
||||
pattern="AF-\d{6}[FT]-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}"
|
||||
title="Format: AF-YYYYMMFT-XXXX-YYYY-ZZZZ">
|
||||
placeholder="AF-F-YYYYMM-XXXX-YYYY-ZZZZ" required
|
||||
pattern="AF-[FT]-\d{6}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}"
|
||||
title="Format: AF-F-YYYYMM-XXXX-YYYY-ZZZZ">
|
||||
<button type="button" class="btn btn-outline-primary" onclick="generateLicenseKey()">
|
||||
🔑 Generieren
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-text">Format: AF-YYYYMMFT-XXXX-YYYY-ZZZZ (F=Full, T=Test)</div>
|
||||
<div class="form-text">Format: AF-F-YYYYMM-XXXX-YYYY-ZZZZ (F=Full, T=Test)</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="licenseType" class="form-label">Lizenztyp</label>
|
||||
@@ -206,7 +206,7 @@ document.getElementById('licenseType').addEventListener('change', function() {
|
||||
if (keyField.value && keyField.value.startsWith('AF-')) {
|
||||
// Prüfe ob der Key zum neuen Typ passt
|
||||
const currentType = this.value;
|
||||
const keyType = keyField.value.charAt(9); // Position des F/T im Key
|
||||
const keyType = keyField.value.charAt(3); // Position des F/T im Key (AF-F-...)
|
||||
|
||||
if ((currentType === 'full' && keyType === 'T') ||
|
||||
(currentType === 'test' && keyType === 'F')) {
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren