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/setup_2fa.html` - Neues Step-by-Step Design
|
||||||
- `v2_adminpanel/templates/backup_codes.html` - Modernisiertes Layout
|
- `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'):
|
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)
|
AF = Account Factory (Produktkennung)
|
||||||
|
F/T = F für Fullversion, T für Testversion
|
||||||
YYYY = Jahr
|
YYYY = Jahr
|
||||||
MM = Monat
|
MM = Monat
|
||||||
FT = F für Fullversion, T für Testversion
|
|
||||||
XXXX-YYYY-ZZZZ = Zufällige alphanumerische Zeichen
|
XXXX-YYYY-ZZZZ = Zufällige alphanumerische Zeichen
|
||||||
"""
|
"""
|
||||||
# Erlaubte Zeichen (ohne verwirrende wie 0/O, 1/I/l)
|
# Erlaubte Zeichen (ohne verwirrende wie 0/O, 1/I/l)
|
||||||
@@ -664,21 +664,21 @@ def generate_license_key(license_type='full'):
|
|||||||
parts.append(part)
|
parts.append(part)
|
||||||
|
|
||||||
# Key zusammensetzen
|
# 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
|
return key
|
||||||
|
|
||||||
def validate_license_key(key):
|
def validate_license_key(key):
|
||||||
"""
|
"""
|
||||||
Validiert das License Key Format
|
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:
|
if not key:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Pattern für das spezifische Format
|
# Pattern für das neue Format
|
||||||
# AF- (fest) + 6 Ziffern (YYYYMM) + F oder T + - + 4 Zeichen + - + 4 Zeichen + - + 4 Zeichen
|
# AF- (fest) + F oder T + - + 6 Ziffern (YYYYMM) + - + 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 = r'^AF-[FT]-\d{6}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$'
|
||||||
|
|
||||||
# Großbuchstaben für Vergleich
|
# Großbuchstaben für Vergleich
|
||||||
return bool(re.match(pattern, key.upper()))
|
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">
|
<div class="modal-body">
|
||||||
<p>Es werden <strong id="previewQuantity">10</strong> Lizenzen im folgenden Format generiert:</p>
|
<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">
|
<div class="bg-light p-3 rounded font-monospace" id="previewFormat">
|
||||||
AF-YYYYMMFT-XXXX-YYYY-ZZZZ
|
AF-F-YYYYMM-XXXX-YYYY-ZZZZ
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-3 mb-0">Die Keys werden automatisch eindeutig generiert und in der Datenbank gespeichert.</p>
|
<p class="mt-3 mb-0">Die Keys werden automatisch eindeutig generiert und in der Datenbank gespeichert.</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -324,7 +324,7 @@ function previewKeys() {
|
|||||||
const dateStr = date.getFullYear() + ('0' + (date.getMonth() + 1)).slice(-2);
|
const dateStr = date.getFullYear() + ('0' + (date.getMonth() + 1)).slice(-2);
|
||||||
|
|
||||||
document.getElementById('previewQuantity').textContent = quantity;
|
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'));
|
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
|
||||||
modal.show();
|
modal.show();
|
||||||
|
|||||||
@@ -37,14 +37,14 @@
|
|||||||
<label for="licenseKey" class="form-label">Lizenzschlüssel</label>
|
<label for="licenseKey" class="form-label">Lizenzschlüssel</label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control" id="licenseKey" name="license_key"
|
<input type="text" class="form-control" id="licenseKey" name="license_key"
|
||||||
placeholder="AF-YYYYMMFT-XXXX-YYYY-ZZZZ" required
|
placeholder="AF-F-YYYYMM-XXXX-YYYY-ZZZZ" required
|
||||||
pattern="AF-\d{6}[FT]-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}"
|
pattern="AF-[FT]-\d{6}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}"
|
||||||
title="Format: AF-YYYYMMFT-XXXX-YYYY-ZZZZ">
|
title="Format: AF-F-YYYYMM-XXXX-YYYY-ZZZZ">
|
||||||
<button type="button" class="btn btn-outline-primary" onclick="generateLicenseKey()">
|
<button type="button" class="btn btn-outline-primary" onclick="generateLicenseKey()">
|
||||||
🔑 Generieren
|
🔑 Generieren
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</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>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label for="licenseType" class="form-label">Lizenztyp</label>
|
<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-')) {
|
if (keyField.value && keyField.value.startsWith('AF-')) {
|
||||||
// Prüfe ob der Key zum neuen Typ passt
|
// Prüfe ob der Key zum neuen Typ passt
|
||||||
const currentType = this.value;
|
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') ||
|
if ((currentType === 'full' && keyType === 'T') ||
|
||||||
(currentType === 'test' && keyType === 'F')) {
|
(currentType === 'test' && keyType === 'F')) {
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren