Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2989a6e2f |
@@ -1 +1 @@
|
||||
1.2.0
|
||||
1.2.1
|
||||
|
||||
+25
-4
@@ -580,7 +580,14 @@ class User(UserMixin):
|
||||
|
||||
|
||||
def get_db_connection():
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
# timeout=15 statt Python-Default 5s: reine Verteidigungslinie gegen
|
||||
# kurze, legitime Ueberschneidungen zweier Schreibzugriffe (SQLite
|
||||
# erlaubt nur EINEN Schreiber gleichzeitig) -- ersetzt NICHT die
|
||||
# eigentliche Regel, niemals eine zweite Verbindung waehrend einer noch
|
||||
# offenen Schreibtransaktion auf derselben zu committen (siehe
|
||||
# _process_activate für ein Beispiel, wo genau das den Fehler
|
||||
# "database is locked" ausgeloest hat).
|
||||
conn = sqlite3.connect(DB_PATH, timeout=15)
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
@@ -2202,19 +2209,33 @@ def _process_activate(data):
|
||||
"SELECT license_id, customer_id FROM licenses WHERE fingerprint=? AND status='active' AND license_id!=?",
|
||||
(fingerprint, license_id),
|
||||
).fetchall()
|
||||
# log_action_system() oeffnet INTERN eine EIGENE, zweite Verbindung und
|
||||
# committet sofort -- solange `conn` hier noch eine offene Schreib-
|
||||
# transaktion haelt (erstes UPDATE oben, noch nicht committet), wuerde
|
||||
# dieser zweite Commit-Versuch auf sich selbst warten (SQLite erlaubt
|
||||
# nur EINEN Schreiber gleichzeitig) und nach Ablauf des Busy-Timeouts
|
||||
# mit "database is locked" fehlschlagen -- live reproduziert beim
|
||||
# Aktivieren einer Lizenz, die eine andere fuer denselben Fingerprint
|
||||
# ersetzt. Deshalb werden die Log-Eintraege hier nur VORGEMERKT (reine
|
||||
# Lesezugriffe auf `conn` sind unproblematisch, nur der schreibende
|
||||
# log_action_system()-Aufruf selbst muss warten) und dann als allerletzter
|
||||
# Schritt nach `conn.commit()`/`conn.close()` unten nachgeholt.
|
||||
superseded_logs = []
|
||||
for old in superseded:
|
||||
conn.execute(
|
||||
"UPDATE licenses SET status='deactivated', deactivated_at=? WHERE license_id=?",
|
||||
(now, old["license_id"]),
|
||||
)
|
||||
old_customer = _customer_row(conn, old["customer_id"])
|
||||
log_action_system(
|
||||
"license.superseded", old_customer["name"] if old_customer else old["license_id"],
|
||||
superseded_logs.append((
|
||||
old_customer["name"] if old_customer else old["license_id"],
|
||||
f"Automatisch deaktiviert -- Fingerprint {fingerprint} hat jetzt Lizenz {license_id} aktiviert.",
|
||||
)
|
||||
))
|
||||
conn.commit()
|
||||
customer = _customer_row(conn, row["customer_id"])
|
||||
conn.close()
|
||||
for target, details in superseded_logs:
|
||||
log_action_system("license.superseded", target, details)
|
||||
log_action_system("license.activated_remote", customer["name"] if customer else license_id, f"Fingerprint {fingerprint}")
|
||||
return licensing.build_master_response("activated", license_id, fingerprint, MASTER_PRIVATE_KEY, status="ok"), 200
|
||||
|
||||
|
||||
Reference in New Issue
Block a user