mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-07-02 03:32:13 +02:00
Add JSON integrity hash checks
This commit is contained in:
@@ -21,7 +21,7 @@ from ccma.domain.contributions import (
|
||||
)
|
||||
from ccma.domain.dates import DateValidationError, normalize_date_input, validate_member_dates
|
||||
from ccma.domain.models import ASSET_STATUS_LABELS, MEMBERSHIP_STATUS_LABELS, Asset, ContributionData, Event, Member
|
||||
from ccma.storage.atomic import read_json, write_json_atomic
|
||||
from ccma.storage.atomic import json_content_hash_matches, read_json, write_json_atomic
|
||||
|
||||
|
||||
class RepositoryError(RuntimeError):
|
||||
@@ -142,6 +142,8 @@ class MemberRepository:
|
||||
errors: list[str] = []
|
||||
try:
|
||||
config = read_json(self.root / "repository.json")
|
||||
if not json_content_hash_matches(config):
|
||||
errors.append("repository.json: Hash fehlt oder stimmt nicht; Datei wurde vermutlich extern geändert.")
|
||||
if int(config.get("schema_version", 0)) != 1:
|
||||
errors.append("repository.json: nicht unterstützte schema_version")
|
||||
policy = config.get("member_number_policy") or {}
|
||||
@@ -155,6 +157,7 @@ class MemberRepository:
|
||||
for member_dir in self._member_directories():
|
||||
try:
|
||||
member, _contributions = self.preflight_member_record(member_dir.name)
|
||||
errors.extend(f"{member_dir.name}/{warning}" for warning in self.member_hash_warnings(member_dir.name))
|
||||
validate_member_dates(
|
||||
birth_date=member.birth_date,
|
||||
accepted_at=member.accepted_at,
|
||||
@@ -183,6 +186,7 @@ class MemberRepository:
|
||||
for asset_dir in self._asset_directories():
|
||||
try:
|
||||
asset = self.get_asset(asset_dir.name)
|
||||
errors.extend(f"{asset_dir.name}/{warning}" for warning in self.asset_hash_warnings(asset_dir.name))
|
||||
if asset.asset_id != asset_dir.name:
|
||||
errors.append(f"{asset_dir.name}/asset.json: asset_id stimmt nicht mit Ordner überein")
|
||||
if asset.schema_version != 1:
|
||||
@@ -1211,6 +1215,44 @@ class MemberRepository:
|
||||
raise RepositoryError("repository.json enthält keine gültige Konfiguration.")
|
||||
return configuration
|
||||
|
||||
def member_hash_warnings(self, member_id: str) -> list[str]:
|
||||
warnings: list[str] = []
|
||||
try:
|
||||
member_raw = read_json(self._member_path(member_id) / "member.json")
|
||||
if not json_content_hash_matches(member_raw):
|
||||
warnings.append("member.json: Hash fehlt oder stimmt nicht; Datei wurde vermutlich extern geändert.")
|
||||
except (OSError, ValueError, TypeError, json.JSONDecodeError):
|
||||
pass
|
||||
try:
|
||||
contributions_raw = read_json(self._member_path(member_id) / "contributions.json")
|
||||
if not json_content_hash_matches(contributions_raw):
|
||||
warnings.append(
|
||||
"contributions.json: Hash fehlt oder stimmt nicht; Datei wurde vermutlich extern geändert."
|
||||
)
|
||||
except (OSError, ValueError, TypeError, json.JSONDecodeError):
|
||||
pass
|
||||
return warnings
|
||||
|
||||
def asset_hash_warnings(self, asset_id: str) -> list[str]:
|
||||
warnings: list[str] = []
|
||||
try:
|
||||
asset_raw = read_json(self._asset_path(asset_id) / "asset.json")
|
||||
if not json_content_hash_matches(asset_raw):
|
||||
warnings.append("asset.json: Hash fehlt oder stimmt nicht; Datei wurde vermutlich extern geändert.")
|
||||
except (OSError, ValueError, TypeError, json.JSONDecodeError):
|
||||
pass
|
||||
return warnings
|
||||
|
||||
def refresh_member_record_hashes(self, member_id: str) -> None:
|
||||
member = self.get_member(member_id)
|
||||
contributions = self.get_contributions(member_id)
|
||||
write_json_atomic(self._member_path(member_id) / "member.json", member.to_dict())
|
||||
write_json_atomic(self._member_path(member_id) / "contributions.json", contributions.to_dict())
|
||||
|
||||
def refresh_asset_record_hashes(self, asset_id: str) -> None:
|
||||
asset = self.get_asset(asset_id)
|
||||
write_json_atomic(self._asset_path(asset_id) / "asset.json", asset.to_dict())
|
||||
|
||||
def get_member_number_policy(self) -> dict[str, str]:
|
||||
try:
|
||||
config = read_json(self.root / "repository.json")
|
||||
|
||||
Reference in New Issue
Block a user