Repository navigation
20.3 Geocaching Integration Examples and Conformance
This page provides a runnable local example of the actual directory codec and transaction interface. It does not publish anything on the public network. Follow Directory Operations when adding authenticated LXMF transport.
From a checkout of the codex/geocaching branch:
python -m venv .venv-geocaching
# Activate this environment using your shell's normal activation command.
python -m pip install -r tools/geocaching/interop-requirements.txtThe requirement file pins the versions used by the reference implementation. Run the example from the repository root. It uses a temporary SQLite database and the independently checked-in signed fixture; it does not need a network interface, private author key or existing directory database.
import os
import sys
import tempfile
from pathlib import Path
root = Path.cwd()
sys.path.insert(0, str(root / "tools" / "geocaching"))
from directory_store import DirectoryStore, packed, unpacked, verify_cache
fixture = root / "modules/core_geocaching/tests/fixtures/signed-cache-v1.bin"
signed = unpacked(fixture.read_bytes())
verified = verify_cache(signed)
reader = os.urandom(16)
with tempfile.TemporaryDirectory() as temporary:
store = DirectoryStore(Path(temporary) / "directory.sqlite", os.urandom(16))
try:
def request(operation, body):
request_id = os.urandom(16)
raw = packed([1, 0, operation, request_id, 8192, body])
# Production adapters must authenticate LXMF before calling handle.
response_raw = store.handle(reader, raw)
assert response_raw is not None, "No durable response"
response = unpacked(response_raw)
assert response[:4] == [1, 1, operation, request_id]
assert response[4] == 200, response[5]
# An identical retry must return the same persisted result.
assert store.handle(reader, raw) == response_raw
return response[5]
caps = request(0, [])
assert caps[2] == [0, 1, 2, 3, 4]
published = request(1, [signed])
assert published[0] == verified.cache_id
page = request(2, [[-900000000, -1800000000,
900000000, 1800000000], 7, None, 20, None])
assert len(page[1]) == 1 and page[2] is None
summary = page[1][0]
detail = request(3, [summary[0], summary[2], None])
retrieved = verify_cache(detail[0])
assert retrieved.summary == summary
assert retrieved.cache_id == verified.cache_id
assert detail[1:] == [1, 0]
print("Verified:", retrieved.record[8], retrieved.cache_id.hex())
finally:
store.close()DirectoryStore.handle() deliberately assumes an already authenticated source. Calling it directly is useful for conformance testing, but exposing it to unauthenticated input as a production API would bypass the transport trust boundary.
Use a persistent author identity and a fresh 16-byte creation nonce for each new cache. Encode the exact 16-field record described in Wire Format. Sign the domain prefix plus raw record with the author's Ed25519 key, then wrap the raw bytes and 64-byte signature as SignedCache.
For an update, retain the identity, nonce and creation timestamp, increment the revision and set the previous hash to the preceding revision's exact hash. Revisions are immutable. Persist the signed outgoing request before sending it so a restart can retry the same bytes and request ID. Coordinate writers sharing an identity to avoid signing competing revisions. Neither a directory nor a transport bridge can recreate a lost author private key.
The reference uses RNS.Identity.get_public_key() for the 64-byte public identity and RNS.Identity.sign() for signing. The corresponding verification path is verify_cache() in directory_store.py. Do not publish fixture identities or example records as user content.
Use directory_service.py as the reference for LXMF reception: validate destination, source identity and message signature before dispatching the binary application payload. Set both application fields described in the wire guide. Match responses by source, operation and request ID. A Reticulum packet acknowledgement or LXMF delivery proof does not replace the application response.
For browser integrations, reuse or study DirectoryClient in site/geocaching/src/protocol-client.js. It handles signed discovery, capabilities, request serialization, bounded retries, exact detail retrieval and author verification. Its query() emits result events; get() retrieves and verifies full details. makeGpx() exports verified signed records. The worker boundary keeps this network processing out of the UI thread.
- Parse the checked-in fixtures and reproduce their cache IDs and revision hashes.
- Reject an altered signature, invalid text, noncanonical encoding and trailing bytes.
- Verify directory summaries against the returned full signed record.
- Retry the same request after losing its reply; verify the original durable response is returned.
- Reject a reused request ID carrying different bytes.
- Continue query cursors without changing reader identity, bounds, mask, author, limit or budget.
- Start a new query after cursor expiration; do not silently splice different query snapshots.
- Fetch exact revisions during replication and commit objects before advancing the checkpoint.
- Preserve competing valid revisions as conflict evidence.
- Verify that a new live query sees newly published data without rebuilding the website.
- Disconnect and reconnect transport; verify fresh directory validation and query execution.
- Confirm local saved browsing still works with all network access unavailable.
The final two checks require runtime integration tests. Passing a codec fixture test alone does not establish network recovery or device storage behavior.
English
- Home
- 0. Why This Exists
- 1. Quick Start
- 2. Supported Hardware
- 3. Installation & Flashing
- 3.5 Configuration Guide
- 3.6 Settings Backup and Restore
- 3.7 SD-Editable Working Configuration (TMS)
- 4. Protocols & Data
- 4.1 Reticulum, LXMF and RNode Bridge
- 4.1.1 Reticulum Settings
- 5. Offline Maps
- 6. Trail Mate Center
- 6.1 Creating a Map Pack with Center
- 6.2 TMAP Maps and Terrain
- 6.3 Outdoor Navigation and Elevation Profiles
- 6.4 TMAP SDK and Resource Budgets
- 6.5 Persistent Routes and Viewport Reads
- 7. Team Features
- 8. UI Overview
- 9. Build from Source
- 10. Codebase Overview
- 11. Architecture
- 12. Design Decisions
- 13. FAQ
- 14. Troubleshooting
- 15. Logging and Debugging
- 16. Roadmap
- 17. Contributing
- 18. License and Third-Party
- 19.-GPS-Setting-Guide
- 20. Geocaching Developer Guide
- 20.1 Geocaching Wire Format and Signed Records
- 20.2 Geocaching Discovery and Directory Operations
- 20.3 Geocaching Integration Examples and Conformance
- 20.4 Geocaching GPX and Offline Storage
- 20.5 Geocaching Directory Deployment and Verification
- 21. Trails and Decentralized Sharing
- 22. Web Device Management
- 23. Device Identity and Sharing Privacy
- 24. Offline Navigation and Map Controls
- 25. Music, Widgets and Daily Controls