Update public source
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
class AttemptsRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
@staticmethod
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
||||
"+00:00",
|
||||
"Z",
|
||||
)
|
||||
|
||||
def create_attempt(
|
||||
self,
|
||||
handshake_id: int,
|
||||
method_id: str,
|
||||
method_version: int,
|
||||
job_id: str,
|
||||
completed_at: str | None = None,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_attempts (
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
status,
|
||||
completed_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
"COMPLETED",
|
||||
completed_at or self._now(),
|
||||
),
|
||||
)
|
||||
|
||||
def get_attempt(
|
||||
self,
|
||||
handshake_id: int,
|
||||
method_id: str,
|
||||
method_version: int,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
status,
|
||||
completed_at
|
||||
FROM crack_attempts
|
||||
WHERE handshake_id = ?
|
||||
AND method_id = ?
|
||||
AND method_version = ?
|
||||
""",
|
||||
(
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
),
|
||||
).fetchone()
|
||||
|
||||
def has_completed(
|
||||
self,
|
||||
handshake_id: int,
|
||||
method_id: str,
|
||||
method_version: int,
|
||||
) -> bool:
|
||||
row = self._conn.execute(
|
||||
"""
|
||||
SELECT 1
|
||||
FROM crack_attempts
|
||||
WHERE handshake_id = ?
|
||||
AND method_id = ?
|
||||
AND method_version = ?
|
||||
AND status = 'COMPLETED'
|
||||
""",
|
||||
(
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
),
|
||||
).fetchone()
|
||||
|
||||
return row is not None
|
||||
|
||||
def list_handshake_attempts(
|
||||
self,
|
||||
handshake_id: int,
|
||||
) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
status,
|
||||
completed_at
|
||||
FROM crack_attempts
|
||||
WHERE handshake_id = ?
|
||||
ORDER BY method_id, method_version
|
||||
""",
|
||||
(handshake_id,),
|
||||
).fetchall()
|
||||
|
||||
def list_job_attempts(
|
||||
self,
|
||||
job_id: str,
|
||||
) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
status,
|
||||
completed_at
|
||||
FROM crack_attempts
|
||||
WHERE job_id = ?
|
||||
ORDER BY handshake_id, method_id, method_version
|
||||
""",
|
||||
(job_id,),
|
||||
).fetchall()
|
||||
|
||||
def list_method_attempts(
|
||||
self,
|
||||
method_id: str,
|
||||
method_version: int,
|
||||
) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
status,
|
||||
completed_at
|
||||
FROM crack_attempts
|
||||
WHERE method_id = ?
|
||||
AND method_version = ?
|
||||
ORDER BY handshake_id
|
||||
""",
|
||||
(
|
||||
method_id,
|
||||
method_version,
|
||||
),
|
||||
).fetchall()
|
||||
@@ -0,0 +1,148 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
|
||||
class AuditRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
@staticmethod
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
||||
"+00:00",
|
||||
"Z",
|
||||
)
|
||||
|
||||
def create_event(
|
||||
self,
|
||||
event_type: str,
|
||||
job_id: str | None = None,
|
||||
client_id: str | None = None,
|
||||
handshake_id: int | None = None,
|
||||
method_id: str | None = None,
|
||||
method_version: int | None = None,
|
||||
details: dict[str, Any] | None = None,
|
||||
created_at: str | None = None,
|
||||
) -> int:
|
||||
cursor = self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_audit_log (
|
||||
created_at,
|
||||
event_type,
|
||||
job_id,
|
||||
client_id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
details_json
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
created_at or self._now(),
|
||||
event_type,
|
||||
job_id,
|
||||
client_id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
(
|
||||
json.dumps(
|
||||
details,
|
||||
ensure_ascii=False,
|
||||
separators=(",", ":"),
|
||||
sort_keys=True,
|
||||
)
|
||||
if details is not None
|
||||
else None
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
return int(cursor.lastrowid)
|
||||
|
||||
def get_event(
|
||||
self,
|
||||
event_id: int,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
created_at,
|
||||
event_type,
|
||||
job_id,
|
||||
client_id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
details_json
|
||||
FROM crack_audit_log
|
||||
WHERE id = ?
|
||||
""",
|
||||
(event_id,),
|
||||
).fetchone()
|
||||
|
||||
def list_events(
|
||||
self,
|
||||
event_type: str | None = None,
|
||||
job_id: str | None = None,
|
||||
client_id: str | None = None,
|
||||
handshake_id: int | None = None,
|
||||
method_id: str | None = None,
|
||||
method_version: int | None = None,
|
||||
) -> list[sqlite3.Row]:
|
||||
query = """
|
||||
SELECT
|
||||
id,
|
||||
created_at,
|
||||
event_type,
|
||||
job_id,
|
||||
client_id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
details_json
|
||||
FROM crack_audit_log
|
||||
WHERE 1 = 1
|
||||
"""
|
||||
params: list[Any] = []
|
||||
|
||||
if event_type is not None:
|
||||
query += "\n AND event_type = ?"
|
||||
params.append(event_type)
|
||||
|
||||
if job_id is not None:
|
||||
query += "\n AND job_id = ?"
|
||||
params.append(job_id)
|
||||
|
||||
if client_id is not None:
|
||||
query += "\n AND client_id = ?"
|
||||
params.append(client_id)
|
||||
|
||||
if handshake_id is not None:
|
||||
query += "\n AND handshake_id = ?"
|
||||
params.append(handshake_id)
|
||||
|
||||
if method_id is not None:
|
||||
query += "\n AND method_id = ?"
|
||||
params.append(method_id)
|
||||
|
||||
if method_version is not None:
|
||||
query += "\n AND method_version = ?"
|
||||
params.append(method_version)
|
||||
|
||||
query += "\n ORDER BY created_at DESC, id DESC"
|
||||
|
||||
return self._conn.execute(query, params).fetchall()
|
||||
|
||||
@staticmethod
|
||||
def decode_details(row: sqlite3.Row) -> dict[str, Any] | None:
|
||||
if row["details_json"] is None:
|
||||
return None
|
||||
|
||||
return json.loads(row["details_json"])
|
||||
@@ -0,0 +1,120 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ClientsRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
@staticmethod
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
||||
"+00:00",
|
||||
"Z",
|
||||
)
|
||||
|
||||
def create_client(
|
||||
self,
|
||||
client_id: str,
|
||||
name: str,
|
||||
token_hash: str | None = None,
|
||||
status: str = "ACTIVE",
|
||||
metadata: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
metadata_json = (
|
||||
json.dumps(
|
||||
metadata,
|
||||
ensure_ascii=False,
|
||||
separators=(",", ":"),
|
||||
sort_keys=True,
|
||||
)
|
||||
if metadata is not None
|
||||
else None
|
||||
)
|
||||
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_clients (
|
||||
id,
|
||||
name,
|
||||
token_hash,
|
||||
status,
|
||||
created_at,
|
||||
last_seen_at,
|
||||
metadata_json
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
client_id,
|
||||
name,
|
||||
token_hash,
|
||||
status,
|
||||
self._now(),
|
||||
None,
|
||||
metadata_json,
|
||||
),
|
||||
)
|
||||
|
||||
def get_client(self, client_id: str) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
token_hash,
|
||||
status,
|
||||
created_at,
|
||||
last_seen_at,
|
||||
metadata_json
|
||||
FROM crack_clients
|
||||
WHERE id = ?
|
||||
""",
|
||||
(client_id,),
|
||||
).fetchone()
|
||||
|
||||
def list_clients(self) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
token_hash,
|
||||
status,
|
||||
created_at,
|
||||
last_seen_at,
|
||||
metadata_json
|
||||
FROM crack_clients
|
||||
ORDER BY id
|
||||
"""
|
||||
).fetchall()
|
||||
|
||||
def update_last_seen(self, client_id: str) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE crack_clients
|
||||
SET last_seen_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
self._now(),
|
||||
client_id,
|
||||
),
|
||||
)
|
||||
|
||||
def update_status(self, client_id: str, status: str) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE crack_clients
|
||||
SET status = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
status,
|
||||
client_id,
|
||||
),
|
||||
)
|
||||
@@ -0,0 +1,95 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
class CredentialsRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
@staticmethod
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
||||
"+00:00",
|
||||
"Z",
|
||||
)
|
||||
|
||||
def get_credential(
|
||||
self,
|
||||
access_point_id: int,
|
||||
handshake_id: int,
|
||||
password: str,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
access_point_id,
|
||||
handshake_id,
|
||||
password,
|
||||
source,
|
||||
created_at,
|
||||
verified
|
||||
FROM credentials
|
||||
WHERE access_point_id = ?
|
||||
AND handshake_id = ?
|
||||
AND password = ?
|
||||
LIMIT 1
|
||||
""",
|
||||
(
|
||||
access_point_id,
|
||||
handshake_id,
|
||||
password,
|
||||
),
|
||||
).fetchone()
|
||||
|
||||
def create_hashcat_credential(
|
||||
self,
|
||||
access_point_id: int,
|
||||
handshake_id: int,
|
||||
password: str,
|
||||
) -> int:
|
||||
cursor = self._conn.execute(
|
||||
"""
|
||||
INSERT INTO credentials (
|
||||
access_point_id,
|
||||
handshake_id,
|
||||
password,
|
||||
source,
|
||||
created_at,
|
||||
verified
|
||||
)
|
||||
VALUES (?, ?, ?, 'hashcat', ?, 0)
|
||||
""",
|
||||
(
|
||||
access_point_id,
|
||||
handshake_id,
|
||||
password,
|
||||
self._now(),
|
||||
),
|
||||
)
|
||||
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE access_points
|
||||
SET is_cracked = 1
|
||||
WHERE id = ?
|
||||
""",
|
||||
(access_point_id,),
|
||||
)
|
||||
|
||||
return int(cursor.lastrowid)
|
||||
|
||||
def mark_access_point_cracked(
|
||||
self,
|
||||
access_point_id: int,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE access_points
|
||||
SET is_cracked = 1
|
||||
WHERE id = ?
|
||||
""",
|
||||
(access_point_id,),
|
||||
)
|
||||
@@ -0,0 +1,58 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
from typing import Any
|
||||
|
||||
|
||||
class HandshakesRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
def list_eligible(
|
||||
self,
|
||||
method_id: str,
|
||||
method_version: int,
|
||||
limit: int,
|
||||
) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
h.id AS handshake_id,
|
||||
h.hash22000,
|
||||
h.access_point_id,
|
||||
h.captured_at
|
||||
FROM handshakes AS h
|
||||
WHERE h.hash22000 IS NOT NULL
|
||||
AND TRIM(h.hash22000) <> ''
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM credentials AS c
|
||||
WHERE c.handshake_id = h.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM crack_attempts AS a
|
||||
WHERE a.handshake_id = h.id
|
||||
AND a.method_id = ?
|
||||
AND a.method_version = ?
|
||||
AND a.status = 'COMPLETED'
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM crack_reservations AS r
|
||||
WHERE r.handshake_id = h.id
|
||||
AND r.method_id = ?
|
||||
AND r.method_version = ?
|
||||
AND r.status = 'ACTIVE'
|
||||
)
|
||||
ORDER BY h.id
|
||||
LIMIT ?
|
||||
""",
|
||||
(
|
||||
method_id,
|
||||
method_version,
|
||||
method_id,
|
||||
method_version,
|
||||
limit,
|
||||
),
|
||||
).fetchall()
|
||||
@@ -0,0 +1,452 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
|
||||
class JobsRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
@staticmethod
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
||||
"+00:00",
|
||||
"Z",
|
||||
)
|
||||
|
||||
def create_job(
|
||||
self,
|
||||
job_id: str,
|
||||
method_id: str,
|
||||
method_version: int,
|
||||
status: str,
|
||||
hash_file_name: str,
|
||||
hash_file_sha256: str,
|
||||
hash_count: int,
|
||||
step_count: int,
|
||||
client_id: str | None = None,
|
||||
) -> str:
|
||||
created_at = self._now()
|
||||
queued_at = created_at if status == "QUEUED" else None
|
||||
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_jobs (
|
||||
id,
|
||||
method_id,
|
||||
method_version,
|
||||
status,
|
||||
created_at,
|
||||
queued_at,
|
||||
started_at,
|
||||
completed_at,
|
||||
cancelled_at,
|
||||
imported_at,
|
||||
client_id,
|
||||
hash_file_name,
|
||||
hash_file_sha256,
|
||||
hash_count,
|
||||
step_count,
|
||||
result_sha256,
|
||||
error
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
job_id,
|
||||
method_id,
|
||||
method_version,
|
||||
status,
|
||||
created_at,
|
||||
queued_at,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
client_id,
|
||||
hash_file_name,
|
||||
hash_file_sha256,
|
||||
hash_count,
|
||||
step_count,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
)
|
||||
|
||||
return created_at
|
||||
|
||||
def get_job(self, job_id: str) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
method_id,
|
||||
method_version,
|
||||
status,
|
||||
created_at,
|
||||
queued_at,
|
||||
started_at,
|
||||
completed_at,
|
||||
cancelled_at,
|
||||
imported_at,
|
||||
client_id,
|
||||
hash_file_name,
|
||||
hash_file_sha256,
|
||||
hash_count,
|
||||
step_count,
|
||||
result_sha256,
|
||||
error
|
||||
FROM crack_jobs
|
||||
WHERE id = ?
|
||||
""",
|
||||
(job_id,),
|
||||
).fetchone()
|
||||
|
||||
def list_jobs(
|
||||
self,
|
||||
status: str | None = None,
|
||||
method_id: str | None = None,
|
||||
client_id: str | None = None,
|
||||
) -> list[sqlite3.Row]:
|
||||
query = """
|
||||
SELECT
|
||||
id,
|
||||
method_id,
|
||||
method_version,
|
||||
status,
|
||||
created_at,
|
||||
queued_at,
|
||||
started_at,
|
||||
completed_at,
|
||||
cancelled_at,
|
||||
imported_at,
|
||||
client_id,
|
||||
hash_file_name,
|
||||
hash_file_sha256,
|
||||
hash_count,
|
||||
step_count,
|
||||
result_sha256,
|
||||
error
|
||||
FROM crack_jobs
|
||||
WHERE 1 = 1
|
||||
"""
|
||||
params: list[Any] = []
|
||||
|
||||
if status is not None:
|
||||
query += "\n AND status = ?"
|
||||
params.append(status)
|
||||
|
||||
if method_id is not None:
|
||||
query += "\n AND method_id = ?"
|
||||
params.append(method_id)
|
||||
|
||||
if client_id is not None:
|
||||
query += "\n AND client_id = ?"
|
||||
params.append(client_id)
|
||||
|
||||
query += "\n ORDER BY created_at DESC, id DESC"
|
||||
|
||||
return self._conn.execute(query, params).fetchall()
|
||||
|
||||
def update_job_status(
|
||||
self,
|
||||
job_id: str,
|
||||
status: str,
|
||||
) -> None:
|
||||
now = self._now()
|
||||
|
||||
timestamp_column = {
|
||||
"QUEUED": "queued_at",
|
||||
"RUNNING": "started_at",
|
||||
"COMPLETED": "completed_at",
|
||||
"CANCELLED": "cancelled_at",
|
||||
}.get(status)
|
||||
|
||||
if timestamp_column is None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE crack_jobs
|
||||
SET status = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
status,
|
||||
job_id,
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
self._conn.execute(
|
||||
f"""
|
||||
UPDATE crack_jobs
|
||||
SET status = ?,
|
||||
{timestamp_column} = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
status,
|
||||
now,
|
||||
job_id,
|
||||
),
|
||||
)
|
||||
|
||||
def assign_client(
|
||||
self,
|
||||
job_id: str,
|
||||
client_id: str | None,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE crack_jobs
|
||||
SET client_id = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
client_id,
|
||||
job_id,
|
||||
),
|
||||
)
|
||||
|
||||
def update_job_result(
|
||||
self,
|
||||
job_id: str,
|
||||
result_sha256: str | None = None,
|
||||
error: str | None = None,
|
||||
imported_at: str | None = None,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE crack_jobs
|
||||
SET result_sha256 = ?,
|
||||
error = ?,
|
||||
imported_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
result_sha256,
|
||||
error,
|
||||
imported_at,
|
||||
job_id,
|
||||
),
|
||||
)
|
||||
|
||||
def add_job_handshake(
|
||||
self,
|
||||
job_id: str,
|
||||
handshake_id: int,
|
||||
hash22000: str,
|
||||
access_point_id: int | None = None,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_job_handshakes (
|
||||
job_id,
|
||||
handshake_id,
|
||||
hash22000,
|
||||
access_point_id
|
||||
)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
job_id,
|
||||
handshake_id,
|
||||
hash22000,
|
||||
access_point_id,
|
||||
),
|
||||
)
|
||||
|
||||
def get_job_handshake(
|
||||
self,
|
||||
job_id: str,
|
||||
handshake_id: int,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
job_id,
|
||||
handshake_id,
|
||||
hash22000,
|
||||
access_point_id
|
||||
FROM crack_job_handshakes
|
||||
WHERE job_id = ?
|
||||
AND handshake_id = ?
|
||||
""",
|
||||
(
|
||||
job_id,
|
||||
handshake_id,
|
||||
),
|
||||
).fetchone()
|
||||
|
||||
def list_job_handshakes(
|
||||
self,
|
||||
job_id: str,
|
||||
) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
job_id,
|
||||
handshake_id,
|
||||
hash22000,
|
||||
access_point_id
|
||||
FROM crack_job_handshakes
|
||||
WHERE job_id = ?
|
||||
ORDER BY handshake_id
|
||||
""",
|
||||
(job_id,),
|
||||
).fetchall()
|
||||
|
||||
def create_job_step(
|
||||
self,
|
||||
job_id: str,
|
||||
step_no: int,
|
||||
step_id: str,
|
||||
status: str,
|
||||
session_name: str,
|
||||
definition: dict[str, Any],
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_job_steps (
|
||||
job_id,
|
||||
step_no,
|
||||
step_id,
|
||||
status,
|
||||
session_name,
|
||||
definition_json,
|
||||
started_at,
|
||||
completed_at,
|
||||
exit_code,
|
||||
restore_seen,
|
||||
error
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
job_id,
|
||||
step_no,
|
||||
step_id,
|
||||
status,
|
||||
session_name,
|
||||
json.dumps(
|
||||
definition,
|
||||
ensure_ascii=False,
|
||||
separators=(",", ":"),
|
||||
sort_keys=True,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
0,
|
||||
None,
|
||||
),
|
||||
)
|
||||
|
||||
def get_job_step(
|
||||
self,
|
||||
job_id: str,
|
||||
step_no: int,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
job_id,
|
||||
step_no,
|
||||
step_id,
|
||||
status,
|
||||
session_name,
|
||||
definition_json,
|
||||
started_at,
|
||||
completed_at,
|
||||
exit_code,
|
||||
restore_seen,
|
||||
error
|
||||
FROM crack_job_steps
|
||||
WHERE job_id = ?
|
||||
AND step_no = ?
|
||||
""",
|
||||
(
|
||||
job_id,
|
||||
step_no,
|
||||
),
|
||||
).fetchone()
|
||||
|
||||
def list_job_steps(
|
||||
self,
|
||||
job_id: str,
|
||||
) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
job_id,
|
||||
step_no,
|
||||
step_id,
|
||||
status,
|
||||
session_name,
|
||||
definition_json,
|
||||
started_at,
|
||||
completed_at,
|
||||
exit_code,
|
||||
restore_seen,
|
||||
error
|
||||
FROM crack_job_steps
|
||||
WHERE job_id = ?
|
||||
ORDER BY step_no
|
||||
""",
|
||||
(job_id,),
|
||||
).fetchall()
|
||||
|
||||
def update_job_step(
|
||||
self,
|
||||
job_id: str,
|
||||
step_no: int,
|
||||
status: str | None = None,
|
||||
started_at: str | None = None,
|
||||
completed_at: str | None = None,
|
||||
exit_code: int | None = None,
|
||||
restore_seen: bool | None = None,
|
||||
error: str | None = None,
|
||||
) -> None:
|
||||
fields: list[str] = []
|
||||
params: list[Any] = []
|
||||
|
||||
if status is not None:
|
||||
fields.append("status = ?")
|
||||
params.append(status)
|
||||
|
||||
if started_at is not None:
|
||||
fields.append("started_at = ?")
|
||||
params.append(started_at)
|
||||
|
||||
if completed_at is not None:
|
||||
fields.append("completed_at = ?")
|
||||
params.append(completed_at)
|
||||
|
||||
if exit_code is not None:
|
||||
fields.append("exit_code = ?")
|
||||
params.append(exit_code)
|
||||
|
||||
if restore_seen is not None:
|
||||
fields.append("restore_seen = ?")
|
||||
params.append(int(restore_seen))
|
||||
|
||||
if error is not None:
|
||||
fields.append("error = ?")
|
||||
params.append(error)
|
||||
|
||||
if not fields:
|
||||
return
|
||||
|
||||
params.extend((job_id, step_no))
|
||||
|
||||
self._conn.execute(
|
||||
f"""
|
||||
UPDATE crack_job_steps
|
||||
SET {", ".join(fields)}
|
||||
WHERE job_id = ?
|
||||
AND step_no = ?
|
||||
""",
|
||||
params,
|
||||
)
|
||||
@@ -0,0 +1,149 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
|
||||
class MethodsRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
@staticmethod
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
||||
"+00:00",
|
||||
"Z",
|
||||
)
|
||||
|
||||
def create_method(
|
||||
self,
|
||||
method_id: str,
|
||||
name: str,
|
||||
description: str | None = None,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_methods (
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
created_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
method_id,
|
||||
name,
|
||||
description,
|
||||
self._now(),
|
||||
),
|
||||
)
|
||||
|
||||
def get_method(self, method_id: str) -> sqlite3.Row | None:
|
||||
row = self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
created_at
|
||||
FROM crack_methods
|
||||
WHERE id = ?
|
||||
""",
|
||||
(method_id,),
|
||||
).fetchone()
|
||||
|
||||
return row
|
||||
|
||||
def list_methods(self) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
created_at
|
||||
FROM crack_methods
|
||||
ORDER BY id
|
||||
"""
|
||||
).fetchall()
|
||||
|
||||
def create_method_version(
|
||||
self,
|
||||
method_id: str,
|
||||
version: int,
|
||||
definition: dict[str, Any],
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_method_versions (
|
||||
method_id,
|
||||
version,
|
||||
definition_json,
|
||||
created_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
method_id,
|
||||
version,
|
||||
json.dumps(
|
||||
definition,
|
||||
ensure_ascii=False,
|
||||
separators=(",", ":"),
|
||||
sort_keys=True,
|
||||
),
|
||||
self._now(),
|
||||
),
|
||||
)
|
||||
|
||||
def get_method_version(
|
||||
self,
|
||||
method_id: str,
|
||||
version: int,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
method_id,
|
||||
version,
|
||||
definition_json,
|
||||
created_at
|
||||
FROM crack_method_versions
|
||||
WHERE method_id = ?
|
||||
AND version = ?
|
||||
""",
|
||||
(method_id, version),
|
||||
).fetchone()
|
||||
|
||||
def list_method_versions(
|
||||
self,
|
||||
method_id: str,
|
||||
) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
method_id,
|
||||
version,
|
||||
definition_json,
|
||||
created_at
|
||||
FROM crack_method_versions
|
||||
WHERE method_id = ?
|
||||
ORDER BY version
|
||||
""",
|
||||
(method_id,),
|
||||
).fetchall()
|
||||
|
||||
def get_next_method_version(self, method_id: str) -> int:
|
||||
row = self._conn.execute(
|
||||
"""
|
||||
SELECT COALESCE(MAX(version), 0) + 1
|
||||
FROM crack_method_versions
|
||||
WHERE method_id = ?
|
||||
""",
|
||||
(method_id,),
|
||||
).fetchone()
|
||||
|
||||
return int(row[0])
|
||||
@@ -0,0 +1,209 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
class ReservationsRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
@staticmethod
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
||||
"+00:00",
|
||||
"Z",
|
||||
)
|
||||
|
||||
def create_reservation(
|
||||
self,
|
||||
reservation_id: str,
|
||||
handshake_id: int,
|
||||
method_id: str,
|
||||
method_version: int,
|
||||
job_id: str,
|
||||
client_id: str | None = None,
|
||||
expires_at: str | None = None,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_reservations (
|
||||
id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
client_id,
|
||||
status,
|
||||
created_at,
|
||||
expires_at,
|
||||
released_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
reservation_id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
client_id,
|
||||
"ACTIVE",
|
||||
self._now(),
|
||||
expires_at,
|
||||
None,
|
||||
),
|
||||
)
|
||||
|
||||
def get_reservation(
|
||||
self,
|
||||
reservation_id: str,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
client_id,
|
||||
status,
|
||||
created_at,
|
||||
expires_at,
|
||||
released_at
|
||||
FROM crack_reservations
|
||||
WHERE id = ?
|
||||
""",
|
||||
(reservation_id,),
|
||||
).fetchone()
|
||||
|
||||
def get_active_reservation(
|
||||
self,
|
||||
handshake_id: int,
|
||||
method_id: str,
|
||||
method_version: int,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
client_id,
|
||||
status,
|
||||
created_at,
|
||||
expires_at,
|
||||
released_at
|
||||
FROM crack_reservations
|
||||
WHERE handshake_id = ?
|
||||
AND method_id = ?
|
||||
AND method_version = ?
|
||||
AND status = 'ACTIVE'
|
||||
""",
|
||||
(
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
),
|
||||
).fetchone()
|
||||
|
||||
def list_job_reservations(
|
||||
self,
|
||||
job_id: str,
|
||||
) -> list[sqlite3.Row]:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
client_id,
|
||||
status,
|
||||
created_at,
|
||||
expires_at,
|
||||
released_at
|
||||
FROM crack_reservations
|
||||
WHERE job_id = ?
|
||||
ORDER BY created_at, id
|
||||
""",
|
||||
(job_id,),
|
||||
).fetchall()
|
||||
|
||||
def list_client_reservations(
|
||||
self,
|
||||
client_id: str,
|
||||
status: str | None = None,
|
||||
) -> list[sqlite3.Row]:
|
||||
query = """
|
||||
SELECT
|
||||
id,
|
||||
handshake_id,
|
||||
method_id,
|
||||
method_version,
|
||||
job_id,
|
||||
client_id,
|
||||
status,
|
||||
created_at,
|
||||
expires_at,
|
||||
released_at
|
||||
FROM crack_reservations
|
||||
WHERE client_id = ?
|
||||
"""
|
||||
params: list[object] = [client_id]
|
||||
|
||||
if status is not None:
|
||||
query += "\n AND status = ?"
|
||||
params.append(status)
|
||||
|
||||
query += "\n ORDER BY created_at, id"
|
||||
|
||||
return self._conn.execute(query, params).fetchall()
|
||||
|
||||
def update_status(
|
||||
self,
|
||||
reservation_id: str,
|
||||
status: str,
|
||||
released_at: str | None = None,
|
||||
) -> None:
|
||||
if released_at is None and status in {
|
||||
"RELEASED",
|
||||
"EXPIRED",
|
||||
"CANCELLED",
|
||||
}:
|
||||
released_at = self._now()
|
||||
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE crack_reservations
|
||||
SET status = ?,
|
||||
released_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
status,
|
||||
released_at,
|
||||
reservation_id,
|
||||
),
|
||||
)
|
||||
|
||||
def update_expires_at(
|
||||
self,
|
||||
reservation_id: str,
|
||||
expires_at: str | None,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
UPDATE crack_reservations
|
||||
SET expires_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(
|
||||
expires_at,
|
||||
reservation_id,
|
||||
),
|
||||
)
|
||||
@@ -0,0 +1,92 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ResultsRepository:
|
||||
def __init__(self, conn: sqlite3.Connection) -> None:
|
||||
self._conn = conn
|
||||
|
||||
@staticmethod
|
||||
def _now() -> str:
|
||||
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
||||
"+00:00",
|
||||
"Z",
|
||||
)
|
||||
|
||||
def create_result(
|
||||
self,
|
||||
job_id: str,
|
||||
status: str,
|
||||
result: dict[str, Any],
|
||||
imported_at: str | None = None,
|
||||
) -> None:
|
||||
self._conn.execute(
|
||||
"""
|
||||
INSERT INTO crack_results (
|
||||
job_id,
|
||||
status,
|
||||
result_json,
|
||||
imported_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
job_id,
|
||||
status,
|
||||
json.dumps(
|
||||
result,
|
||||
ensure_ascii=False,
|
||||
separators=(",", ":"),
|
||||
sort_keys=True,
|
||||
),
|
||||
imported_at or self._now(),
|
||||
),
|
||||
)
|
||||
|
||||
def get_result(
|
||||
self,
|
||||
job_id: str,
|
||||
) -> sqlite3.Row | None:
|
||||
return self._conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
job_id,
|
||||
status,
|
||||
result_json,
|
||||
imported_at
|
||||
FROM crack_results
|
||||
WHERE job_id = ?
|
||||
""",
|
||||
(job_id,),
|
||||
).fetchone()
|
||||
|
||||
def list_results(
|
||||
self,
|
||||
status: str | None = None,
|
||||
) -> list[sqlite3.Row]:
|
||||
query = """
|
||||
SELECT
|
||||
job_id,
|
||||
status,
|
||||
result_json,
|
||||
imported_at
|
||||
FROM crack_results
|
||||
WHERE 1 = 1
|
||||
"""
|
||||
params: list[Any] = []
|
||||
|
||||
if status is not None:
|
||||
query += "\n AND status = ?"
|
||||
params.append(status)
|
||||
|
||||
query += "\n ORDER BY imported_at DESC, job_id DESC"
|
||||
|
||||
return self._conn.execute(query, params).fetchall()
|
||||
|
||||
@staticmethod
|
||||
def decode_result(row: sqlite3.Row) -> dict[str, Any]:
|
||||
return json.loads(row["result_json"])
|
||||
Reference in New Issue
Block a user