File size: 2,218 Bytes
74ab07f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# sovereign_audit_chain.py
from __future__ import annotations

import json
import hashlib
import os
from typing import Dict, Any, List


AUDIT_CHAIN_FILE = "sovereign_audit_chain.jsonl"


def _hash(data: str) -> str:
    return hashlib.sha256(data.encode("utf-8")).hexdigest()


def _serialize(obj: Dict[str, Any]) -> str:
    return json.dumps(obj, sort_keys=True, ensure_ascii=False)


def _load_chain() -> List[Dict[str, Any]]:
    if not os.path.exists(AUDIT_CHAIN_FILE):
        return []
    with open(AUDIT_CHAIN_FILE, "r", encoding="utf-8") as f:
        return [json.loads(line) for line in f if line.strip()]


def _get_last_hash(chain: List[Dict[str, Any]]) -> str:
    if not chain:
        return "GENESIS"
    return chain[-1]["hash"]


def append_audit_event(event: Dict[str, Any]) -> Dict[str, Any]:
    chain = _load_chain()

    prev_hash = _get_last_hash(chain)

    record = {
        "event": event,
        "prev_hash": prev_hash,
    }

    record_str = _serialize(record)
    current_hash = _hash(record_str)

    record["hash"] = current_hash

    with open(AUDIT_CHAIN_FILE, "a", encoding="utf-8") as f:
        f.write(json.dumps(record, ensure_ascii=False) + "\n")

    return {
        "ok": True,
        "hash": current_hash,
        "prev_hash": prev_hash,
    }


def verify_chain() -> Dict[str, Any]:
    chain = _load_chain()

    if not chain:
        return {"ok": True, "message": "empty_chain"}

    prev_hash = "GENESIS"

    for idx, record in enumerate(chain):
        expected_prev = record.get("prev_hash")
        if expected_prev != prev_hash:
            return {
                "ok": False,
                "error": "broken_chain",
                "index": idx,
            }

        record_copy = {
            "event": record["event"],
            "prev_hash": record["prev_hash"],
        }

        recalculated = _hash(_serialize(record_copy))

        if recalculated != record.get("hash"):
            return {
                "ok": False,
                "error": "tampered_record",
                "index": idx,
            }

        prev_hash = record["hash"]

    return {
        "ok": True,
        "length": len(chain),
        "status": "valid",
    }