@le-space/rootfs 0.12.4 → 0.12.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -49,6 +49,18 @@ COMPACT_MULTIADDR_LIMIT = int(os.environ.get("ALEPH_BOOTSTRAP_COMPACT_MULTIADDR_
|
|
|
49
49
|
STALE_RECORD_MAX_AGE_SECONDS = int(
|
|
50
50
|
os.environ.get("ALEPH_BOOTSTRAP_STALE_RECORD_MAX_AGE_SECONDS", str(6 * 60 * 60))
|
|
51
51
|
)
|
|
52
|
+
# What was last published, so an unchanged registration is not posted again.
|
|
53
|
+
# The AutoTLS refresh starts this unit after each of its runs, every 2 min until
|
|
54
|
+
# AutoTLS has a certificate; on a relay where it never gets one that meant a new
|
|
55
|
+
# Aleph post every 2 min, forever. An unchanged registration is republished only
|
|
56
|
+
# once it is this old, which keeps the 6 h timer's refresh (and stays below
|
|
57
|
+
# STALE_RECORD_MAX_AGE_SECONDS, after which consumers drop it).
|
|
58
|
+
PUBLISHED_STATE_FILE = os.environ.get(
|
|
59
|
+
"BOOTSTRAP_PUBLISHED_STATE_FILE", "/var/lib/orbitdb-relay/bootstrap-published.json"
|
|
60
|
+
)
|
|
61
|
+
REPUBLISH_UNCHANGED_AFTER_SECONDS = int(
|
|
62
|
+
os.environ.get("BOOTSTRAP_REPUBLISH_UNCHANGED_AFTER_SECONDS", str(5 * 60 * 60))
|
|
63
|
+
)
|
|
52
64
|
|
|
53
65
|
|
|
54
66
|
def parse_env_file(path: str) -> dict[str, str]:
|
|
@@ -327,6 +339,61 @@ def resolve_owner_address(
|
|
|
327
339
|
return None
|
|
328
340
|
|
|
329
341
|
|
|
342
|
+
def registration_fingerprint(
|
|
343
|
+
publisher_address: str,
|
|
344
|
+
peer_id: str,
|
|
345
|
+
multiaddrs: list[str],
|
|
346
|
+
registration_id: str | None,
|
|
347
|
+
profile: str,
|
|
348
|
+
version: str | None,
|
|
349
|
+
owner_address: str | None,
|
|
350
|
+
channel: str,
|
|
351
|
+
ref: str,
|
|
352
|
+
) -> str:
|
|
353
|
+
"""What a registration says, without its timestamps and signatures."""
|
|
354
|
+
return hashlib.sha256(
|
|
355
|
+
json_dumps(
|
|
356
|
+
{
|
|
357
|
+
"publisher": publisher_address.lower(),
|
|
358
|
+
"peerId": peer_id,
|
|
359
|
+
"multiaddrs": sorted(multiaddrs),
|
|
360
|
+
"registrationId": registration_id,
|
|
361
|
+
"profile": profile,
|
|
362
|
+
"version": version,
|
|
363
|
+
"owner": (owner_address or "").lower() or None,
|
|
364
|
+
"channel": channel,
|
|
365
|
+
"ref": ref,
|
|
366
|
+
}
|
|
367
|
+
).encode("utf-8")
|
|
368
|
+
).hexdigest()
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def recently_published(fingerprint: str, now_seconds: float) -> bool:
|
|
372
|
+
try:
|
|
373
|
+
with open(PUBLISHED_STATE_FILE, encoding="utf-8") as handle:
|
|
374
|
+
state = json.load(handle)
|
|
375
|
+
except (OSError, ValueError):
|
|
376
|
+
return False
|
|
377
|
+
if not isinstance(state, dict) or state.get("fingerprint") != fingerprint:
|
|
378
|
+
return False
|
|
379
|
+
published_at = state.get("publishedAt")
|
|
380
|
+
if not isinstance(published_at, (int, float)):
|
|
381
|
+
return False
|
|
382
|
+
return 0 <= now_seconds - published_at < REPUBLISH_UNCHANGED_AFTER_SECONDS
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def remember_published(fingerprint: str, item_hash: str, now_seconds: float) -> None:
|
|
386
|
+
try:
|
|
387
|
+
os.makedirs(os.path.dirname(PUBLISHED_STATE_FILE) or ".", exist_ok=True)
|
|
388
|
+
tmp = f"{PUBLISHED_STATE_FILE}.tmp"
|
|
389
|
+
with open(tmp, "w", encoding="utf-8") as handle:
|
|
390
|
+
json.dump({"fingerprint": fingerprint, "itemHash": item_hash, "publishedAt": now_seconds}, handle)
|
|
391
|
+
os.replace(tmp, PUBLISHED_STATE_FILE)
|
|
392
|
+
except OSError:
|
|
393
|
+
# Without the state the next run publishes again, as before.
|
|
394
|
+
pass
|
|
395
|
+
|
|
396
|
+
|
|
330
397
|
def post_json(url: str, body: dict[str, object]) -> tuple[int, dict]:
|
|
331
398
|
data = json_dumps(body).encode("utf-8")
|
|
332
399
|
request = urllib.request.Request(
|
|
@@ -726,6 +793,26 @@ def attempt_publish(
|
|
|
726
793
|
)
|
|
727
794
|
owner_address = resolve_owner_address(env_values, owner_authorization)
|
|
728
795
|
|
|
796
|
+
fingerprint = registration_fingerprint(
|
|
797
|
+
publisher_address,
|
|
798
|
+
peer_id,
|
|
799
|
+
published_multiaddrs,
|
|
800
|
+
registration_id,
|
|
801
|
+
profile,
|
|
802
|
+
version,
|
|
803
|
+
owner_address,
|
|
804
|
+
channel,
|
|
805
|
+
ref,
|
|
806
|
+
)
|
|
807
|
+
if recently_published(fingerprint, now_seconds):
|
|
808
|
+
return {
|
|
809
|
+
"status": "unchanged",
|
|
810
|
+
"sender": publisher_address,
|
|
811
|
+
"peerId": peer_id,
|
|
812
|
+
"publishedMultiaddrs": published_multiaddrs,
|
|
813
|
+
"republishAfterSeconds": REPUBLISH_UNCHANGED_AFTER_SECONDS,
|
|
814
|
+
}
|
|
815
|
+
|
|
729
816
|
proof_payload = relay_proof_payload(
|
|
730
817
|
peer_id,
|
|
731
818
|
published_multiaddrs,
|
|
@@ -762,6 +849,8 @@ def attempt_publish(
|
|
|
762
849
|
)
|
|
763
850
|
signed_message = sign_aleph_message(unsigned_message, publisher_private_key)
|
|
764
851
|
http_status, response = broadcast_aleph_message(api_host, signed_message)
|
|
852
|
+
if 200 <= http_status < 300:
|
|
853
|
+
remember_published(fingerprint, str(unsigned_message["item_hash"]), now_seconds)
|
|
765
854
|
|
|
766
855
|
previous_hashes = fetch_previous_hashes(
|
|
767
856
|
api_host,
|
|
Binary file
|