Update userwallet components, services and documentation
**Motivations:** - Add new features and fixes for userwallet application - Update documentation for pairing, login state machine, and sync - Add new utilities for bloom filters, nonce store, and contract versioning - Fix mempool websocket offline issues **Root causes:** - N/A (feature additions and improvements) **Correctifs:** - Fix mempool websocket offline handling - Update ESLint configuration **Evolutions:** - Add login state machine service and hook - Add sync loop service - Add bloom filter utilities for anti-replay and state visibility - Add nonce store and contract version utilities - Update pairing confirmation and graph resolver services - Add new documentation for features and fixes - Update userwallet components (LoginScreen, SyncScreen) - Update types for contract, identity, and messages **Pages affectées:** - userwallet/src/components/LoginScreen.tsx - userwallet/src/components/SyncScreen.tsx - userwallet/src/hooks/useChannel.ts - userwallet/src/hooks/useLoginStateMachine.ts (new) - userwallet/src/services/graphResolver.ts - userwallet/src/services/pairingConfirm.ts - userwallet/src/services/syncService.ts - userwallet/src/services/syncLoop.ts (new) - userwallet/src/services/loginStateMachine.ts (new) - userwallet/src/types/contract.ts - userwallet/src/types/identity.ts - userwallet/src/types/message.ts - userwallet/src/utils/canonical.ts - userwallet/src/utils/identity.ts - userwallet/src/utils/indexedDbStorage.ts - userwallet/src/utils/relay.ts - userwallet/src/utils/verification.ts - userwallet/src/utils/bloom.ts (new) - userwallet/src/utils/contractVersion.ts (new) - userwallet/src/utils/nonceStore.ts (new) - userwallet/eslint.config.mjs - userwallet/package.json - userwallet/package-lock.json - userwallet/docs/synthese.md - userwallet/docs/specs-champs-obligatoires-cnil.md (new) - api-relay/README.md - features/userwallet-pairing-words-only-finalise.md - features/userwallet-anti-rejeu-etats-visibles-bloom.md (new) - features/userwallet-bloom-usage-sync.md (new) - features/userwallet-contrat-login-reste-a-faire.md (new) - features/userwallet-ecrans-login-a-valider.md (new) - features/userwallet-eslint-fix.md (new) - features/userwallet-login-state-machine.md (new) - features/userwallet-validation-conformite.md (new) - fixKnowledge/mempool-websocket-offline-fix.md (new) - mempool (submodule) - hash_list.txt - hash_list_cache.txt
This commit is contained in:
parent
6e8f554371
commit
c3c11f0ef0
@ -107,3 +107,8 @@ La déduplication par hash évite de relayer deux fois le même message.
|
||||
## Stockage
|
||||
|
||||
Stockage en mémoire avec persistance sur disque (`{STORAGE_PATH}/messages.json`). Sont persistés : messages, seenHashes, signatures, clés. Sauvegarde à l’arrêt (SIGINT/SIGTERM) et périodiquement si `SAVE_INTERVAL_SECONDS` > 0. En production, une base de données (SQLite, PostgreSQL, etc.) est recommandée.
|
||||
|
||||
## Documentation
|
||||
|
||||
- **`docs/synthese.md`** : synthèse (rôle, stack, structure, endpoints, config, stockage, déploiement, liens UserWallet).
|
||||
- **`features/api-relay-evolutions.md`** : évolutions (build ESM, rate limit, CORS, métriques, bloom, etc.).
|
||||
|
||||
91
api-relay/docs/synthese.md
Normal file
91
api-relay/docs/synthese.md
Normal file
@ -0,0 +1,91 @@
|
||||
# Synthèse – API Relay (UserWallet)
|
||||
|
||||
**Author:** Équipe 4NK
|
||||
**Date:** 2026-01-26
|
||||
|
||||
## 1. Rôle
|
||||
|
||||
Relais de stockage et de diffusion pour le login décentralisé UserWallet : messages chiffrés, signatures et clés publiés séparément, adressés par hash, récupération par GET (pull). Pas de destinataire explicite ; déduplication par hash.
|
||||
|
||||
## 2. Stack
|
||||
|
||||
- **Runtime** : Node.js, ESM (`"type": "module"`).
|
||||
- **Serveur** : Express, `http.createServer`, timeout configurable.
|
||||
- **Build** : TypeScript, `module`/`moduleResolution` Node16, imports `.js`. `npm start` → `node dist/index.js`.
|
||||
- **Middleware** : CORS (origines via `CORS_ORIGINS`), Pino (logging HTTP), compression gzip, `express-rate-limit`, `express.json` (body limit).
|
||||
- **Validation** : `lib/validate` (MsgChiffre, MsgSignature, MsgCle) ; 400 si corps invalide.
|
||||
- **Métriques** : Prometheus (`prom-client`), `GET /metrics`.
|
||||
|
||||
## 3. Structure
|
||||
|
||||
```
|
||||
src/
|
||||
index.ts # Bootstrap, storage, relay, routes, server timeout
|
||||
lib/
|
||||
logger.ts # Pino
|
||||
validate.ts # validateMsgChiffre, validateMsgSignature, validateMsgCle
|
||||
middleware/
|
||||
index.ts # CORS, logging, compression, rate limit ; getBodyLimit, getRequestTimeoutMs
|
||||
routes/
|
||||
health.ts # GET /health
|
||||
messages.ts # GET/POST /messages, GET /messages/:hash
|
||||
signatures.ts # GET /signatures/:hash, POST /signatures
|
||||
keys.ts # GET /keys/:hash, POST /keys
|
||||
metrics.ts # GET /metrics
|
||||
bloom.ts # GET /bloom
|
||||
services/
|
||||
storage.ts # StorageService (messages, signatures, keys, seenHashes, byService)
|
||||
relay.ts # RelayService (relayMessage, relaySignature, relayKey)
|
||||
types/
|
||||
message.ts # MsgChiffre, MsgSignature, MsgCle, Stored*
|
||||
```
|
||||
|
||||
## 4. Endpoints
|
||||
|
||||
| Méthode | Chemin | Description |
|
||||
|--------|--------|-------------|
|
||||
| GET | /health | `{ status: 'ok', timestamp }` |
|
||||
| GET | /messages?start=&end=&service= | Messages dans la fenêtre ; `service` optionnel (index `byService`). |
|
||||
| POST | /messages | Enregistrement + relais si hash non vu. |
|
||||
| GET | /messages/:hash | Message par hash. |
|
||||
| GET | /signatures/:hash | Signatures pour un message. |
|
||||
| POST | /signatures | Enregistrement + relais. |
|
||||
| GET | /keys/:hash | Clés de déchiffrement pour un message. |
|
||||
| POST | /keys | Enregistrement + relais. |
|
||||
| GET | /metrics | Métriques Prometheus (`relay_storage_entries{kind}`). |
|
||||
| GET | /bloom | Bloom filter (JSON) des hash vus. |
|
||||
|
||||
## 5. Configuration (env)
|
||||
|
||||
- **PORT**, **HOST** : écoute (défaut 3019, 0.0.0.0).
|
||||
- **STORAGE_PATH** : répertoire de persistance (défaut `./data`).
|
||||
- **PEER_RELAYS** : relais pairs (virgule), ex. `http://relay1:3019,http://relay2:3019`.
|
||||
- **SAVE_INTERVAL_SECONDS** : sauvegarde périodique (défaut 300 ; 0 = désactivé).
|
||||
- **BODY_LIMIT**, **REQUEST_TIMEOUT_MS** : body JSON max, timeout HTTP.
|
||||
- **RATE_LIMIT_WINDOW_MS**, **RATE_LIMIT_MAX** : fenêtre et max requêtes par IP.
|
||||
- **CORS_ORIGINS** : origines autorisées (virgule) ; vide = toutes.
|
||||
- **LOG_LEVEL**, **NODE_ENV** : Pino et environnement.
|
||||
|
||||
## 6. Stockage
|
||||
|
||||
- **Mémoire** : `messages`, `signatures`, `keys`, `seenHashes`, index `byService`.
|
||||
- **Disque** : `{STORAGE_PATH}/messages.json` (messages, seenHashes, signatures, keys). Chargement au démarrage ; sauvegarde à l’arrêt (SIGINT/SIGTERM) et périodique si `SAVE_INTERVAL_SECONDS` > 0.
|
||||
- **Limitations** : pas de base SQLite/PostgreSQL ; en production, une base dédiée est recommandée.
|
||||
|
||||
## 7. Déploiement
|
||||
|
||||
- **Dev** : `npm run dev` (tsx watch).
|
||||
- **Build** : `npm run build` puis `npm start` ou `./start.sh`.
|
||||
- **Systemd** : `api-relay.service` ; `WorkingDirectory` = repo, `ExecStart` = `./start.sh`. Voir README.
|
||||
|
||||
## 8. Liens avec UserWallet
|
||||
|
||||
- UserWallet appelle les endpoints (messages, signatures, keys, health) via `utils/relay`.
|
||||
- Types alignés : MsgChiffre, MsgSignature, MsgCle (`datajson_public`, etc.).
|
||||
- Port par défaut 3019 ; front 3018. Proxy Nginx : voir `features/nginx-proxy-relay-certificator.md`.
|
||||
|
||||
## 9. Références
|
||||
|
||||
- **README** : `api-relay/README.md`.
|
||||
- **Évolutions** : `features/api-relay-evolutions.md`.
|
||||
- **Persistance** : `features/api-relay-persistence-signatures-keys-periodic-save.md`.
|
||||
47
features/userwallet-anti-rejeu-etats-visibles-bloom.md
Normal file
47
features/userwallet-anti-rejeu-etats-visibles-bloom.md
Normal file
@ -0,0 +1,47 @@
|
||||
# UserWallet – Anti-rejeu, états visibles, Bloom
|
||||
|
||||
**Author:** Équipe 4NK
|
||||
**Date:** 2026-01-26
|
||||
|
||||
## Objectif
|
||||
|
||||
Implémenter les éléments « reste à faire » contrat/login (3.3, 3.4, 3.6) : anti-rejeu (nonce, timestamp), états visibles (indéchiffrable, non validé, statut relais), API Bloom.
|
||||
|
||||
## Impacts
|
||||
|
||||
- **Login** : vérification timestamp et nonce avant publication ; erreurs `X_NONCE_REUSED`, `X_TIMESTAMP_OUT_OF_WINDOW` ; persistance des nonces utilisés (IndexedDB).
|
||||
- **Sync** : compteurs `indechiffrable`, `nonValide`, statut par relais (ok / indisponible) ; affichage dans SyncScreen.
|
||||
- **Relais** : `getBloom(relay)` pour consommation optionnelle du Bloom filter.
|
||||
|
||||
## Modifications
|
||||
|
||||
**Fichiers ajoutés** : `utils/nonceStore.ts`, `services/syncLoop.ts`.
|
||||
|
||||
**3.4 Anti-rejeu**
|
||||
|
||||
- `utils/nonceStore.ts` : `init()`, `hasUsed(nonce)`, `markUsed(nonce, timestamp)`. IndexedDB `userwallet_nonce_cache`, TTL 1 h.
|
||||
- `LoginScreen` : avant publish, `verifyTimestamp(proof.challenge.timestamp)` → sinon `X_TIMESTAMP_OUT_OF_WINDOW` ; `nonceStore.init()` puis `hasUsed(nonce)` → sinon `X_NONCE_REUSED` ; après publish réussi, `markUsed(nonce, timestamp)`.
|
||||
|
||||
**3.3 États visibles**
|
||||
|
||||
- `SyncService.sync()` : retourne en plus `indechiffrable` (nouveaux messages sans clé), `nonValide` (déchiffrés mais non validés), `relayStatus` (endpoint + ok par relais). Refactor : `processNewMessage`, `processMessageBatch`, `syncOneRelay`, `runSyncLoop` (dans `syncLoop.ts`) pour respecter max-lines / max-params.
|
||||
- `SyncScreen` : affiche « Indéchiffrables (clé manquante) », « Non validés (ex. signature manquante) », « Statut relais » (OK / indisponible par relais).
|
||||
|
||||
**3.6 Bloom**
|
||||
|
||||
- `utils/relay.ts` : `getBloom(relay)` → `GET /bloom`, retourne le JSON. Pas d’usage dans le sync pour l’instant (optionnel).
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
Déploiement classique du front userwallet. Aucune migration IndexedDB imposée : `userwallet_nonce_cache` est créé au premier `init()`.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- **Anti-rejeu** : construire un challenge, publier, puis tenter de republier la même preuve → `X_NONCE_REUSED`. Construire un challenge, attendre > 5 min, publier → `X_TIMESTAMP_OUT_OF_WINDOW` si fenêtre par défaut.
|
||||
- **États visibles** : lancer une sync avec relais mixte (OK / KO) et messages éventuels non déchiffrables ou non validés → vérifier les compteurs et le statut relais dans SyncScreen.
|
||||
- **Bloom** : `getBloom(endpoint)` sur un relais avec `/bloom` → objet JSON.
|
||||
|
||||
## Références
|
||||
|
||||
- `features/userwallet-contrat-login-reste-a-faire.md`
|
||||
- `userwallet/docs/specs.md` (anti-rejeu, états)
|
||||
33
features/userwallet-bloom-usage-sync.md
Normal file
33
features/userwallet-bloom-usage-sync.md
Normal file
@ -0,0 +1,33 @@
|
||||
# UserWallet – Usage Bloom dans le sync (3.6)
|
||||
|
||||
**Author:** Équipe 4NK
|
||||
**Date:** 2026-01-26
|
||||
|
||||
## Objectif
|
||||
|
||||
Utiliser optionnellement `GET /bloom` du relais dans le sync pour éviter des fetches de clés inutiles quand un relais n’a pas vu un hash (pas de faux négatifs).
|
||||
|
||||
## Impacts
|
||||
|
||||
- **Sync** : au début de chaque sync, fetch du Bloom par relais activé ; stockage dans `bloomByRelay`.
|
||||
- **fetchKeys** : avant `getKeys(relay, hash)`, si on a un Bloom pour ce relais et `!bloom.has(hash)`, on ignore ce relais pour ce hash (le relais ne l’a pas vu).
|
||||
|
||||
## Modifications
|
||||
|
||||
- **`utils/bloom.ts`** : `fetchAndLoadBloom(relay)` → fetch `getBloom(relay)`, `BloomFilter.fromJSON`, retourne le filtre ou `null` si erreur (relais sans /bloom, etc.).
|
||||
- **`services/syncService.ts`** : `fetchBlooms()` remplit `bloomByRelay` ; `sync()` appelle `fetchBlooms()` avant `runSyncLoop` ; `fetchKeys(hash)` saute `getKeys` pour un relais dont le Bloom indique l’absence du hash.
|
||||
- **Dépendance** : `bloom-filters` (userwallet).
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
Déploiement classique du front userwallet. Les relais sans `GET /bloom` sont ignorés pour le Bloom (pas de filtre, pas de skip).
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Relais avec `/bloom` : sync fetch les Bloom, puis pour chaque hash on peut skip `getKeys` sur un relais qui ne l’a pas vu.
|
||||
- Relais sans `/bloom` ou erreur : `fetchAndLoadBloom` retourne `null`, on ne skip jamais pour ce relais.
|
||||
|
||||
## Références
|
||||
|
||||
- `features/userwallet-contrat-login-reste-a-faire.md` (§ 3.6)
|
||||
- `utils/relay.ts` (`getBloom`)
|
||||
96
features/userwallet-contrat-login-reste-a-faire.md
Normal file
96
features/userwallet-contrat-login-reste-a-faire.md
Normal file
@ -0,0 +1,96 @@
|
||||
# Contrat et login – reste à faire
|
||||
|
||||
**Author:** Équipe 4NK
|
||||
**Date:** 2026-01-26
|
||||
|
||||
## 1. Principe (rappel)
|
||||
|
||||
Le login décentralisé repose sur :
|
||||
|
||||
- **Graphe contractuel** : Service → Contrat → Champ → Action(login) → Membre → Pair ; contraintes « au moins 1 parent ».
|
||||
- **Validateurs** : signatures requises pour l’action login, liées aux pairs/membres du graphe.
|
||||
- **Pairing mFA** : obligatoire ; au moins un pair attendu par l’action login doit être disponible.
|
||||
- **Publication en trois temps** : message chiffré (sans sig ni clés) → signatures → clés ; tout adressé par hash canonique, récupéré par GET (pull-only).
|
||||
- **Vérification locale** : conformité graphe + signatures + anti-rejeu (nonce, fenêtre temporelle) ; pas d’autorité centrale.
|
||||
|
||||
Référence : `userwallet/docs/specs.md` (modèle, objets, machine à états, catalogue).
|
||||
|
||||
---
|
||||
|
||||
## 2. Déjà en place
|
||||
|
||||
- **Identité** : création secp256k1, import (hex ou BIP39), protection par mot de passe, déverrouillage.
|
||||
- **Pairing** : 8 mots BIP32-style, WordInputGrid, confirmation croisée « membre finaliser », IndexedDB, statut « Connecté ».
|
||||
- **Relais** : config, health, GET/POST messages/signatures/keys, **GET /bloom** ; sync, HashCache (IndexedDB), dédup, fetch clés/signatures.
|
||||
- **Graphe** : GraphResolver, caches (services, contrats, champs, actions, membres, pairs), `resolveLoginPath`.
|
||||
- **Login** : LoginBuilder (challenge, nonce, chiffrement « for all »), construction preuve, publication message → signatures → clés. **Anti-rejeu** : NonceStore (IndexedDB), vérification timestamp (fenêtre), `X_NONCE_REUSED` / `X_TIMESTAMP_OUT_OF_WINDOW` avant publish.
|
||||
- **Iframe** : auth-request / auth-response / login-proof, useChannel, postMessage.
|
||||
- **Écrans** : Home, CreateIdentity, ImportIdentity, RelaySettings, Sync, Manage Pairs, Pairing (setup + display), Services, Login, Data Export/Import, Unlock. Navigation via GlobalActionBar.
|
||||
|
||||
---
|
||||
|
||||
## 3. Reste à faire (principes contrat & login)
|
||||
|
||||
### 3.1 Machine à états formelle
|
||||
|
||||
- **Fait** : `loginStateMachine` (états S_LOGIN_*, événements E_*), `useLoginStateMachine`, dispatch dans LoginScreen, Retour → E_BACK. Voir `features/userwallet-login-state-machine.md`.
|
||||
- **À prévoir** : timeouts (réseau, collecte signatures), reprise sur erreur, backoff ; gardes explicites (G_PAIRING_SATISFIED, etc.) côté UI.
|
||||
|
||||
### 3.2 Écrans et UX alignés specs
|
||||
|
||||
**À valider avant implémentation.** Voir `features/userwallet-ecrans-login-a-valider.md`.
|
||||
|
||||
- **Service iframe** : fourni par channel message (contrat + contrats fils). Si absent → contrat par défaut en dur dans le front jusqu’à réception.
|
||||
- **Écrans login** : déjà en place. Reste à faire : **notifications** selon événements relais (collecte signatures, clés de déchiffrement → hash à fetch → signatures, contrats, membres, pairs, actions, champs sur le relai).
|
||||
- Cette section **évoluera avec l'avancement des tests** une fois validée.
|
||||
|
||||
- **Sélection service / sélection membre** : écrans dédiés « choisir le service cible du login » et « choisir le membre (quand plusieurs) » avec liste, statuts, validation des prérequis (action login, pairs).
|
||||
- **Construction du chemin login** : écran dédié avec résumé (service → contrat → action login → membre → pairs), tableau « signatures requises » (validateurs, qui doit signer, manquante/reçue/valide/invalide), boutons Synchroniser / Démarrer login.
|
||||
- **Message de login à valider** : écran avec résumé public (service, type, timestamp, relais), nonce (mode avancé), « signer ».
|
||||
- **Collecte signatures mFA** : écran listant les signatures requises (clé, pair/membre, état), actions « signer avec ce device », « demander signature sur autre pair », « rafraîchir » (fetch), « voir détail ».
|
||||
- **Publication du login** : écran dédié (ou étape claire) avec ordre strict message → signatures → clés, statut par relais, erreurs explicites.
|
||||
- **Vérification locale + résultat** : écran/étape « vérification locale finale » (hash, signatures, graphe, anti-rejeu) puis succès / échec avec diagnostics (signatures manquantes, objets manquants, etc.).
|
||||
|
||||
### 3.3 États et diagnostics visibles
|
||||
|
||||
- **Message reçu mais indéchiffrable (clé manquante)** et **message déchiffré mais non validé (signature manquante)** : **fait**. Sync retourne `indechiffrable` et `nonValide` ; SyncScreen affiche « Indéchiffrables (clé manquante) » et « Non validés (ex. signature manquante) ».
|
||||
- **Contrat incomplet** : affichage explicite lorsque le graphe est incomplet (LoginScreen : `path.statut === 'incomplet'`, erreur « Chemin incomplet »).
|
||||
- **Statut par relais** : **fait**. Sync retourne `relayStatus` (endpoint + ok) ; SyncScreen affiche « Statut relais » (OK / indisponible par relais).
|
||||
|
||||
### 3.4 Anti-rejeu et nonce
|
||||
|
||||
- **Nonce unique** : **fait**. Chaque login utilise un nonce ; pas de republication du même nonce.
|
||||
- **Cache `nonce_vus`** : **fait**. `NonceStore` (IndexedDB, `userwallet_nonce_cache`), TTL 1 h ; `init` / `hasUsed` / `markUsed`. Vérification timestamp via `verifyTimestamp` (fenêtre 5 min).
|
||||
- **Erreurs** : **fait**. `X_NONCE_REUSED`, `X_TIMESTAMP_OUT_OF_WINDOW` avant publish ; messages explicites dans LoginScreen.
|
||||
|
||||
### 3.5 Validation et conformité
|
||||
|
||||
- **Fait** : `verifyMessageSignaturesStrict`, `filterSignaturesByAuthorizedPubkeys` ; avant publish login, si `cle_publique` dans requirements → vérif stricte, sinon X_PUBKEY_NOT_AUTHORIZED. Contrats en version non supportée exclus du graphe (sync) ; `contrat_version` dans LoginPath et affichage. Voir `features/userwallet-validation-conformite.md`.
|
||||
- **À renforcer** : cardinalité, dépendances entre signatures ; résolution `cle_publique` depuis graphe quand absente des requirements.
|
||||
|
||||
### 3.6 Scan et optimisation (optionnel)
|
||||
|
||||
- **Bloom filter** : **fait**. `getBloom(relay)` ; `utils/bloom` → `fetchAndLoadBloom` ; sync fetch les Bloom, `fetchKeys` skip `getKeys` quand `!bloom.has(hash)` (pas de faux négatifs). Voir `features/userwallet-bloom-usage-sync.md`.
|
||||
- **Merkle trees** : checkpointing / accélération de scan (optionnel, non implémenté).
|
||||
|
||||
### 3.7 Côté service (hors userwallet)
|
||||
|
||||
- **Acceptation de session** : le service (application qui consomme le login) doit vérifier la preuve en ne s’appuyant que sur contrats + signatures (sans serveur central). Rejouer la construction du graphe depuis les UUID/messages disponibles, vérifier hash, signatures, anti-rejeu.
|
||||
- **Politique anti-rejeu** : TTL nonce, fenêtre timestamp, cache nonce_vus.
|
||||
|
||||
---
|
||||
|
||||
## 4. Synthèse
|
||||
|
||||
| Domaine | Statut | Priorité |
|
||||
|--------|--------|----------|
|
||||
| Machine à états login | Fait (loginStateMachine, useLoginStateMachine, dispatch) | — |
|
||||
| Écrans sélection service / membre, chemin login, collecte sig, publication, vérification | À valider avant implémentation (voir userwallet-ecrans-login-a-valider) ; notifications relais à implémenter | Haute |
|
||||
| États « indéchiffrable » / « signature manquante » / statut relais visibles | Fait (Sync) | — |
|
||||
| Anti-rejeu (nonce, fenêtre, cache) | Fait (NonceStore, verifyTimestamp, X_*) | — |
|
||||
| Validation stricte validateurs + clé autorisée | Fait (strict verify, version contrats) | — |
|
||||
| Version contrats | Fait (supported check, affichage) | — |
|
||||
| Bloom API + usage sync | Fait (`getBloom`, `fetchAndLoadBloom`, skip key fetch) | — |
|
||||
| Merkle (scan) | Optionnel, non implémenté | Basse |
|
||||
|
||||
Les éléments de la section « Déjà en place » restent le socle ; les développements ci‑dessus les complètent pour coller au principe « contrat + login » décrit dans `specs.md`.
|
||||
40
features/userwallet-ecrans-login-a-valider.md
Normal file
40
features/userwallet-ecrans-login-a-valider.md
Normal file
@ -0,0 +1,40 @@
|
||||
# UserWallet – Écrans login (3.2) – À valider avant implémentation
|
||||
|
||||
**Author:** Équipe 4NK
|
||||
**Date:** 2026-01-26
|
||||
|
||||
## Statut
|
||||
|
||||
**À valider avant implémentation.** Les écrans listés dans « reste à faire » (sélection service, sélection membre, construction chemin login, message à valider, collecte mFA, publication, vérification locale + résultat) ne doivent pas être implémentés tant que ce document n’a pas été validé.
|
||||
|
||||
## Contexte
|
||||
|
||||
### Service fourni par l’iframe
|
||||
|
||||
- Le **service** (contrat + contrats fils complets du service) est fourni à l’appel de l’iframe via **channel message** (postMessage).
|
||||
- Si le message **n’est pas reçu** : usage du **contrat par défaut**, défini **en dur dans le code front**, jusqu’à réception du message.
|
||||
|
||||
### Écrans login actuels
|
||||
|
||||
- Les **écrans du login sont déjà en place** (sélection service/membre, chemin, challenge, preuve, publication).
|
||||
- **Reste à implémenter** : les **notifications** en fonction des **événements des relais**, notamment :
|
||||
- **Collecte des signatures** et **clés de déchiffrement** pour savoir **quel message (hash)** aller chercher sur le relai.
|
||||
- Une fois le hash connu : récupération sur le relai des **signatures**, **contrats**, **membres**, **pairs**, **actions**, **champs**, etc.
|
||||
- Les notifications doivent donc piloter : quel hash fetch, puis fetch signatures/clés et mise à jour du graphe (contrats, membres, pairs, actions, champs).
|
||||
|
||||
## Écrans à préciser (après validation)
|
||||
|
||||
- Sélection service / sélection membre.
|
||||
- Construction du chemin login.
|
||||
- Message de login à valider.
|
||||
- Collecte signatures mFA.
|
||||
- Publication.
|
||||
- Vérification locale + résultat.
|
||||
|
||||
Ces écrans **évolueront avec l’avancement des tests** (cf. reste à faire).
|
||||
|
||||
## Références
|
||||
|
||||
- `features/userwallet-contrat-login-reste-a-faire.md` (§ 3.2)
|
||||
- `userwallet/docs/specs.md` (machine à états, écrans)
|
||||
- `userwallet/src/utils/iframeChannel.ts`, `userwallet/src/hooks/useChannel.ts`
|
||||
12
features/userwallet-eslint-fix.md
Normal file
12
features/userwallet-eslint-fix.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Userwallet – Correction ESLint (config + script)
|
||||
|
||||
**Objectif :** Faire fonctionner `npm run lint` : résoudre `ERR_MODULE_NOT_FOUND` pour `typescript-eslint`, activer le type-aware linting, et adapter le script lint à la flat config.
|
||||
|
||||
**Modifications :**
|
||||
- **package.json** : ajout de la dépendance `typescript-eslint` ; script `lint` simplifié (`eslint . --report-unused-disable-directives --max-warnings 0`, suppression de `--ext ts,tsx`).
|
||||
- **eslint.config.mjs** : `import.meta.url` + `fileURLToPath` pour `__dirname` ; `parserOptions.project: ['./tsconfig.json', './tsconfig.node.json']` et `tsconfigRootDir: __dirname` pour les règles type-aware (`prefer-nullish-coalescing`, etc.).
|
||||
- **Correctifs annexes** : `canonical.ts` et `verification.ts` — variables volontairement non utilisées préfixées par `_` ; `indexedDbStorage.ts` — types de retour explicites sur les callbacks IndexedDB ; `contract.ts` — interfaces vides `Contrat` et `ActionLogin` remplacées par des type aliases.
|
||||
|
||||
**Impacts :** `npm run lint` s’exécute. Il reste environ 95 erreurs de lint (max-lines, max-lines-per-function, complexity, max-params, no-non-null-assertion, etc.) à traiter au fil de l’eau par refactoring.
|
||||
|
||||
**Modalités d’analyse :** Lancer `npm run lint` et `npm run type-check` ; vérifier qu’aucune régression n’est introduite.
|
||||
47
features/userwallet-login-state-machine.md
Normal file
47
features/userwallet-login-state-machine.md
Normal file
@ -0,0 +1,47 @@
|
||||
# UserWallet – Machine à états login (3.1)
|
||||
|
||||
**Author:** Équipe 4NK
|
||||
**Date:** 2026-01-26
|
||||
|
||||
## Objectif
|
||||
|
||||
Implémenter la machine à états formelle du login (S_LOGIN_* , E_* , transitions) décrite dans `specs.md`, et l’intégrer au flux login existant.
|
||||
|
||||
## Impacts
|
||||
|
||||
- **Module** : `services/loginStateMachine.ts` (états, événements, `transition`, `getInitialLoginState`, `isTerminal`, `isErrorState`).
|
||||
- **Hook** : `hooks/useLoginStateMachine` (`state`, `dispatch`, `reset`).
|
||||
- **LoginScreen** : utilise le hook, dispatch des événements aux points clés (build path, challenge, publish, Retour), affichage de l’état (sr-only, aria-live).
|
||||
- **Flux** : E_SELECT_SERVICE / E_SELECT_MEMBER → E_PATH_OK | E_PATH_INCOMPLETE | E_PATH_INVALID → E_PAIRS_OK → E_CHALLENGE_READY → E_SIGNATURES_COMPLETE → E_PUBLISH_LOGIN_OK | E_PUBLISH_LOGIN_PARTIAL → E_LOCAL_VERDICT_ACCEPT | (reject) → S_LOGIN_SUCCESS | S_LOGIN_FAILURE. E_BACK, E_RETRY, E_SYNC_NOW, E_ADD_PAIR pour reprises.
|
||||
|
||||
## Modifications
|
||||
|
||||
- `src/services/loginStateMachine.ts` : types `LoginState`, `LoginEvent`, `TransitionResult` ; `transition(state, event)` ; helpers.
|
||||
- `src/hooks/useLoginStateMachine.ts` : état local, `dispatch`, `reset`.
|
||||
- `src/components/LoginScreen.tsx` : hook, dispatch dans `handleBuildPath`, `handleBuildChallenge`, `handlePublish` ; `handleBack` + E_BACK ; libellé état (sr-only).
|
||||
- `src/index.css` : `.sr-only` pour le statut.
|
||||
|
||||
## États couverts
|
||||
|
||||
S_LOGIN_SELECT_SERVICE, S_LOGIN_SELECT_MEMBER, S_LOGIN_BUILD_PATH, S_LOGIN_CHECK_PAIRS, S_LOGIN_NEED_MORE_PAIRS, S_LOGIN_BUILD_CHALLENGE, S_LOGIN_COLLECT_SIGNATURES, S_LOGIN_PUBLISH_PROOF, S_LOGIN_VERIFY_LOCAL, S_LOGIN_SUCCESS, S_LOGIN_FAILURE, S_ERROR_RECOVERABLE.
|
||||
|
||||
## Reste à faire (hors scope 3.1)
|
||||
|
||||
- Timeouts (réseau, collecte signatures), backoff.
|
||||
- Gardes explicites (G_PAIRING_SATISFIED, etc.) côté UI avant dispatch.
|
||||
- S_LOGIN_NEED_MORE_PAIRS : boutons E_ADD_PAIR, E_SYNC_NOW dédiés.
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
Déploiement classique du front userwallet.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Parcourir le flux login (sélection → chemin → challenge → publication) et vérifier les transitions (DevTools, log état si besoin).
|
||||
- Vérifier que Retour envoie E_BACK et navigue vers `/`.
|
||||
- Publication partielle → S_ERROR_RECOVERABLE, pas S_LOGIN_SUCCESS.
|
||||
|
||||
## Références
|
||||
|
||||
- `userwallet/docs/specs.md` (machine à états)
|
||||
- `features/userwallet-contrat-login-reste-a-faire.md` (§ 3.1)
|
||||
@ -8,4 +8,4 @@
|
||||
|
||||
**Impacts :** Aucun sur le comportement actuel. Les écrans utilisent déjà `WordInputGrid`, `addRemotePairFromWords(parsed, [], undefined)` et la confirmation avec `remote.publicKey` optionnel.
|
||||
|
||||
**Lint :** Le projet userwallet signale `ERR_MODULE_NOT_FOUND` pour `typescript-eslint` dans la config ESLint. `npm run type-check` et les lints IDE sur les fichiers modifiés sont OK.
|
||||
**Lint :** Voir `userwallet-eslint-fix.md`. ESLint config + script corrigés ; il reste des violations (max-lines, complexity, etc.) à corriger progressivement.
|
||||
|
||||
42
features/userwallet-validation-conformite.md
Normal file
42
features/userwallet-validation-conformite.md
Normal file
@ -0,0 +1,42 @@
|
||||
# UserWallet – Validation et conformité (3.5)
|
||||
|
||||
**Author:** Équipe 4NK
|
||||
**Date:** 2026-01-26
|
||||
|
||||
## Objectif
|
||||
|
||||
Renforcer la validation : validateurs stricts, clé autorisée, version des contrats (specs).
|
||||
|
||||
## Impacts
|
||||
|
||||
- **Clé autorisée** : vérification stricte des signatures avant publication login ; rejet si `cle_publique` non autorisée par les validateurs (X_PUBKEY_NOT_AUTHORIZED).
|
||||
- **Version contrats** : contrats en version non supportée exclus du graphe (sync) ; affichage de la version dans le chemin login.
|
||||
|
||||
## Modifications
|
||||
|
||||
**Vérification stricte**
|
||||
|
||||
- `utils/verification.ts` : `filterSignaturesByAuthorizedPubkeys`, `verifyMessageSignaturesStrict`. Garde `verifyMessageSignatures` (crypto seule) pour usage générique.
|
||||
- `LoginScreen` : avant publish, si `loginPath.signatures_requises` comporte des `cle_publique`, construction de `allowedPubkeys` ; appel à `verifyMessageSignaturesStrict` sur la preuve ; si aucune signature autorisée ou présence de non autorisées → erreur X_PUBKEY_NOT_AUTHORIZED, pas de publication.
|
||||
|
||||
**Version contrats**
|
||||
|
||||
- `utils/contractVersion.ts` : `SUPPORTED_CONTRACT_VERSIONS` (ex. `['1.0']`), `isContractVersionSupported(version)`.
|
||||
- `SyncService.updateGraph` : pour chaque message de type contrat, test `isContractVersionSupported` ; si non supporté, log warning et skip (contrat isolé, non ajouté au graphe).
|
||||
- `LoginPath` : ajout de `contrat_version?: string`. `GraphResolver.resolveLoginPath` renseigne `contrat_version` dès qu’un contrat est résolu.
|
||||
- `LoginScreen` : affichage « Version contrat » dans la section chemin lorsque `contrat_version` est défini.
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
Déploiement classique du front userwallet.
|
||||
|
||||
## Modalités d’analyse
|
||||
|
||||
- Contrat en base avec `version` non supportée → sync : log « Contrat … version … not supported, skipped », absent du graphe.
|
||||
- Login path résolu avec contrat → « Version contrat » affiché.
|
||||
- Preuve avec signature dont `cle_publique` hors validateurs (si `cle_publique` dans requirements) → X_PUBKEY_NOT_AUTHORIZED avant publish.
|
||||
|
||||
## Références
|
||||
|
||||
- `features/userwallet-contrat-login-reste-a-faire.md` (§ 3.5)
|
||||
- `userwallet/docs/specs.md` (validateurs, version)
|
||||
106
fixKnowledge/mempool-websocket-offline-fix.md
Normal file
106
fixKnowledge/mempool-websocket-offline-fix.md
Normal file
@ -0,0 +1,106 @@
|
||||
# Correction: Mempool affiche "hors connexion"
|
||||
|
||||
**Date**: 2026-01-26
|
||||
**Auteur**: Équipe 4NK
|
||||
|
||||
## Motivations
|
||||
|
||||
- Le mempool affichait le site mais indiquait "hors connexion"
|
||||
- Le WebSocket ne pouvait pas se connecter au backend
|
||||
- L'utilisateur ne pouvait pas utiliser l'explorateur blockchain
|
||||
|
||||
## Root causes
|
||||
|
||||
- Le backend mempool était en état "unhealthy" mais fonctionnait partiellement
|
||||
- Le backend avait des problèmes de connexion avec Bitcoin RPC (erreurs `ECONNRESET`)
|
||||
- Le processus de mise à jour des blocs était bloqué (`$updateBlocks stalled`)
|
||||
- Le backend nécessitait un redémarrage pour se resynchroniser correctement
|
||||
|
||||
## Correctifs
|
||||
|
||||
- Redémarrage du backend mempool pour résoudre les problèmes de connexion
|
||||
- Vérification de la configuration nginx du frontend (proxy WebSocket vers `http://api:8999/`)
|
||||
- Vérification de la connectivité entre le frontend et le backend via le réseau Docker
|
||||
- Restauration de la configuration nginx après des modifications incorrectes
|
||||
|
||||
## Evolutions
|
||||
|
||||
- Création d'un script de diagnostic (`mempool/diagnose-mempool.sh`) pour vérifier l'état des services localement
|
||||
- Création d'un script de diagnostic et correction (`mempool/fix-mempool-websocket.sh`) pour diagnostiquer et corriger les problèmes sur le serveur services
|
||||
- Amélioration de la configuration nginx pour le WebSocket (ajout des headers nécessaires dans `mempool/nginx-mempool.conf`)
|
||||
|
||||
## Pages affectées
|
||||
|
||||
- `mempool/diagnose-mempool.sh` : Script de diagnostic local
|
||||
- `mempool/fix-mempool-websocket.sh` : Script de diagnostic et correction distant
|
||||
- `mempool/nginx-mempool.conf` : Configuration nginx pour le WebSocket (amélioration des headers)
|
||||
|
||||
## Modalités de déploiement
|
||||
|
||||
1. **Diagnostic local** :
|
||||
```bash
|
||||
cd mempool
|
||||
./diagnose-mempool.sh
|
||||
```
|
||||
|
||||
2. **Redémarrage du backend si nécessaire** :
|
||||
```bash
|
||||
docker-compose -f docker-compose.signet.yml restart api
|
||||
```
|
||||
|
||||
3. **Vérification de la connectivité** :
|
||||
```bash
|
||||
docker-compose -f docker-compose.signet.yml exec -T web curl -f -s http://api:8999/api/v1/backend-info
|
||||
```
|
||||
|
||||
4. **Redémarrage du frontend si la configuration nginx a été modifiée** :
|
||||
```bash
|
||||
docker-compose -f docker-compose.signet.yml restart web
|
||||
```
|
||||
|
||||
## Modalités d'analyse
|
||||
|
||||
### Vérifier l'état des services
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.signet.yml ps
|
||||
```
|
||||
|
||||
### Vérifier les logs du backend
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.signet.yml logs --tail=50 api | grep -E "(ERROR|ERR|WARN|failed|error)"
|
||||
```
|
||||
|
||||
### Tester la connectivité backend
|
||||
|
||||
```bash
|
||||
# Depuis le conteneur frontend
|
||||
docker-compose -f docker-compose.signet.yml exec -T web curl -f -s http://api:8999/api/v1/backend-info
|
||||
|
||||
# Depuis l'extérieur
|
||||
curl -s http://localhost:3015/api/v1/backend-info
|
||||
```
|
||||
|
||||
### Vérifier la configuration nginx WebSocket
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.signet.yml exec -T web cat /etc/nginx/conf.d/nginx-mempool.conf | grep -A 5 "api/v1/ws"
|
||||
```
|
||||
|
||||
La configuration doit être :
|
||||
```nginx
|
||||
location /api/v1/ws {
|
||||
proxy_pass http://api:8999/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Le backend mempool écoute sur toutes les routes pour les WebSockets (WebSocket.Server créé directement sur le serveur HTTP)
|
||||
- Le nginx du frontend proxyfie `/api/v1/ws` vers `http://api:8999/` (racine du backend)
|
||||
- Le backend peut être en état "unhealthy" mais fonctionner quand même si le healthcheck échoue pour une raison technique (par exemple, `curl` non disponible dans le conteneur)
|
||||
- Les erreurs `ECONNRESET` avec Bitcoin RPC peuvent être temporaires et se résoudre avec un redémarrage
|
||||
578
hash_list.txt
578
hash_list.txt
@ -21610,3 +21610,581 @@ e6f2da61319aaf36ca8abf67c9497a216382958bbb2cc68066925a6480f2ac1a;067043e0a0707a6
|
||||
7d119fc4009692544fb467fa138518103b56dd595c6338c0ca664b3f693df4f0;4112d13968378ae7fbf294bc77b66201288074afe3e7600852caba9c31d413d8;9995;1;2026-01-26T11:35:02.151Z
|
||||
e8fb8a5257fb75b1bd0c592a321451f327c4c72721c63c136dfc5aa9904a923d;d669f465177e7ab53a18ad10216d7281b3da0e3ab46fcfe76231ad2bd937cfeb;9995;1;2026-01-26T11:35:02.152Z
|
||||
9cafe4e5c2dacc0b09e44bb8c297e561a73ea6c7825da0bba9ac178c9fa0e628;a2085dbccf7da0b0764dc86c3c54d4197610936e68ab8987e04e1b3dfb965cf0;9995;1;2026-01-26T11:35:02.154Z
|
||||
766a5608701aaad0753c7f4300d5dedb81d8bbff2aa93e12cb9f3cf45aefb0c7;0befadd427939a89ec9ea9c8c885c53e755b6e4f004026226b407f784994f500;9996;11;2026-01-26T12:18:29.788Z
|
||||
d04117ebcac2855ae293c384bda4f77533d14d59423507667c518c978a3d81ec;8f9a02d058c555bd925dbd9f4b34df7e82e4e28da5ce1a858f0a7d4604a19e08;9996;11;2026-01-26T12:18:29.791Z
|
||||
84e1f3d2910451cae8adad7764bff1a2ff89b106fb8a92897d9b52883902f34e;fdef8a9a5f4064f919daca7a963318ed87bfe77caf4ed0ea343ea9f345aa0094;9996;11;2026-01-26T12:18:29.794Z
|
||||
91f6b7b173e1d9c40adef1dd2e650845cc7005aae6fd1454269914d15dc6e86c;1047eda8fcd574fd74aa0b465ab7a3ac15f0b029360f0c2cf17ba17727166607;9996;11;2026-01-26T12:18:29.796Z
|
||||
fd13dcc95cd732efade3f5a9b38ab997889cc3801584be2efd89facd7aa9879a;e6a6acded09d64381a59cf8791105f70ee0d0866032908bb14bff9d09e77ab0c;9996;11;2026-01-26T12:18:29.799Z
|
||||
e8a8fdda3d1034f50badd1f4d8385891f803f5cc6a90655fc51861351e0b3f1f;185c7a3ebd1c0fdfe2bb02968390ebf7c529a0629563b9204898ad3e5117ac0f;9996;11;2026-01-26T12:18:29.802Z
|
||||
8ba63f54029f983363cfeb6b8f9cae66aec0a7b41f10dea3b9379335b1c903e3;101fd89b3eae3947d8ffd7dacc34ed3fe2a0911f7f7470ee2d87042cfd553210;9996;11;2026-01-26T12:18:29.805Z
|
||||
807a9be744537752c5fdff26e9d6c8a0f1a767c4cf3ff60adf8e23c6c4c4fc94;7bc416611cc88bb27aca1c4f263bdabf5afe5f6fb9f37a2ea7531d4449c24512;9996;11;2026-01-26T12:18:29.807Z
|
||||
2a70fa8f1162fc88f97a40002464d310da7f4de93c4c21f50364e965277307d3;937a8751a535cdb01a4512eabafcc01ab4f7e2b8e5b3756220262d0e0e2b8b13;9996;11;2026-01-26T12:18:29.810Z
|
||||
d7a7768a16c91b67d5d8c69b43d731e7af5c812ffcc341b9f87bb40e54c25ce2;e74c5712906ce0cd0da0c3875c8751586cb55bf1fb21972f652a35b310e4bc33;9996;11;2026-01-26T12:18:29.812Z
|
||||
c04e2edbe2d9dbe80805effacde57bdb89f6cd6fdcc307a00d12026af4e8f959;43f85ea5f5de5ecbc05e4772edca178c942aaec5fc13a45f50f28f65ca6e3819;9996;11;2026-01-26T12:18:29.814Z
|
||||
8ccd01fbd73d1a6058f8dd1902b1aeaf8c0f82ac864cc16c8da79d5b188d1fe6;5434e374ca6aa6d308c00b6b48cfd601538b9b6aef9ca54d9765e20c2daaab1d;9996;11;2026-01-26T12:18:29.817Z
|
||||
18cbf298edb94e63c0feaaabcd593f66fc3990d9d78128c9b663ee9ffc56a25b;deecaf7b3371ab3e74d368ef7d7ece701031d4958977c77c870a67593df8b123;9996;11;2026-01-26T12:18:29.819Z
|
||||
09509d9fd331d08fda5e08f5eadc4642154419f594cc3fa678e665c8d2e4922a;03b70297b0c8f7d0ac7e1f9478e09eb1f4776b3853ede2a46eb4628584b4dc25;9996;11;2026-01-26T12:18:29.822Z
|
||||
3229f3a9ccad53d0fe9b304d362e7340a8a6b25ec5423f9cc1a323267c19357c;c78dc50fb8e4a97a94a57d36f0fcbb6039c31c4ac75e8eb89325cd6a7088362c;9996;11;2026-01-26T12:18:29.824Z
|
||||
075ba1ec18957719ce456a8f011900b7a13a2b2eb1db830e32f1a1c87001b109;b0edb073aaeb757b2c0276493445f6a0cb22c63b239ecf5bd8110516b696b12c;9996;11;2026-01-26T12:18:29.826Z
|
||||
9c15bf3fd9bc2158eaba04baf99b9708273d54d61bf614e597b1a595c7f407d0;14660149faf539d0202406f15b4c055b5ac57f866f9296e88df0bafcc33a892d;9996;11;2026-01-26T12:18:29.828Z
|
||||
a07e5d9fe7033ba50e0659cff5311a89c87b98e9dda0785b81cfdaf3daa09954;ea24c11db2e85961805c956a0a74aee24754e48b9415d3a981fe7c7b324df442;9996;11;2026-01-26T12:18:29.831Z
|
||||
c91b9ff567069c10a711c2fb13970f779b3b15286580d201d2ad5e3906d125da;7c2d66d722030298e6a76050630843016eb3f447a797c7107f29907c24931146;9996;11;2026-01-26T12:18:29.833Z
|
||||
1f7708a6df2271290f4c16798c7e0f2542778253e4f00bce5eea6e9ee00c9b89;06222f747e14ea4c7255e0514cb3288c8c00b0edb8b72387d258a7b69e5f4c46;9996;11;2026-01-26T12:18:29.835Z
|
||||
cb32b1a79e03d1670d09ecd7ec5c5bef202f92484bec2c7cb8ba8a855055e2f2;427f5c8659e819000e2ddfcbf295058de5fb30b70d8993ce88666acc55911948;9996;11;2026-01-26T12:18:29.837Z
|
||||
3a6ac0efa202bdd0d487cba91db1d7e8976b2bc389b1a445f73bfdb9c5dc769a;0089921aec8da2a19891a6d1906b959ff0ef2a9fbbdd4bb0365bdad4ed42d94a;9996;11;2026-01-26T12:18:29.840Z
|
||||
7eb82be6f27c440e9b6991888b073155d58f66e76cde18f7bc30213d890cbe52;84a69d5f509b582f0db60f8a55ad1d2a9e74d07d17792192567b7d977c8d904b;9996;11;2026-01-26T12:18:29.842Z
|
||||
e99ff4a99f438136e77cad7ea656bbff861d6c572d5c05121b184503bc23f2d3;22580b1e8578cd1525036339f868109eaf7c604480b9ed7ebdeda31754c2e54e;9996;11;2026-01-26T12:18:29.844Z
|
||||
29d4eba2a8b8616dafff739ce95f16d8bb989ab92e690922f66ab0937a9b08f4;5caa39cc27d916159856af7537655cd636d84b319d62577c5a0738201453f450;9996;11;2026-01-26T12:18:29.846Z
|
||||
920abe684172e7a82464fc18d2a2ee1f7ad03493644c96c769f60226f23657f0;a2cffb06637c22234f82ac2db679759acb0ee975e6d9aff4c272b0e9820c25fb;9996;11;2026-01-26T12:18:29.848Z
|
||||
7bbbf960bd1a3f5e28292edee0e11ab5991034c8c34291e3dd114ac7659f44fe;bb7a40bde0ce1c487d7725efc4166a968e32f824d5ff887003809d320aebc75a;9996;11;2026-01-26T12:18:29.851Z
|
||||
1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef;95e3f97b72ce881ba549b84b609a2e283796b617cd5a961fa99b2d85b78d205b;9996;11;2026-01-26T12:18:29.853Z
|
||||
9082263bd8a438123e379d72f162cbf5a8e2d8f0d07714529e45447ad4918716;123c6c6a7f2edba9bc3786875fbb3d42d2a3f4289a3c94c529fd074b2ad2955e;9996;11;2026-01-26T12:18:29.855Z
|
||||
e39255f4904103b715006608dd5497fc13ac80e23bc926be21ce6231881ffe9e;7e1211bef77bda9f257a0b5f48e27dba6e169f2f4449cc743428fb2a1849ef60;9996;11;2026-01-26T12:18:29.859Z
|
||||
920abe684172e7a82464fc18d2a2ee1f7ad03493644c96c769f60226f23657f0;2092965ad8824a8d8fdd2b1f53f92ec49e1c1542e286c4bdeedf956723b2a594;9996;11;2026-01-26T12:18:29.862Z
|
||||
d1fe8b13879b14707b66e2ea416e08c58e0d7b239024aa44f8fcec21c11beeba;68c97bc578ef9a6b218ac55bd5989e2b1e9e3ca7f6661cdcba4f8a795e0f7761;9996;11;2026-01-26T12:18:29.864Z
|
||||
d05df98ab7b3e8dc26be55931635135d503a2a72b411836b833f62e7be712a19;5dee546b13b1f98826bddfc34147380444068b311b14f087db2757aabb014164;9996;11;2026-01-26T12:18:29.866Z
|
||||
2ec6cfa47750025816d1b2487dc39f9f30f1fb83b55c9263b7511acd0374b1f1;b0c50a4d196f4a08e5ece613ac3f9b29f8af5439841b1a974d692466f347f164;9996;11;2026-01-26T12:18:29.868Z
|
||||
78e06e22e4dd8cd2ff70ca24dff35a91aaeef79b83c8016eaec8d182f76d90ba;e7f2ba690917684c0dd6a888052e6d8af0e461a8fc3b0e146cf865a6ea7f416a;9996;11;2026-01-26T12:18:29.870Z
|
||||
1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef;05e8022d9046337bcbea6b2b9413b738da1c6e015ccfaba389544c669de18374;9996;11;2026-01-26T12:18:29.872Z
|
||||
898aa57c6ac4f9d50e74e1b04f9d69d4004fd71692cf94d483be1a42264003cc;b6cbdde721fca3079daa51f3fda18f7623285184888d369558ba7db004443876;9996;11;2026-01-26T12:18:29.874Z
|
||||
666294c563da1a891a6694da5fdfac8c01c6ba997fc25cc911e2fe06159e1c7b;49579ca1995a8bde86330f86713aa4c7aefdfd95a579ba64d7a44e8e8e5092cb;9996;11;2026-01-26T12:18:29.876Z
|
||||
37ffca42d9cd804908022b590b30c57352f21657d36b39b2b47a59234d0692eb;721d992da9453c62154896873c62ccb658d152df70aec04d2ed58a0e88caf378;9996;11;2026-01-26T12:18:29.878Z
|
||||
153f57b8e6c14aec622f208b4e8cc06bc4aa52ccb77a3272f89a44ef460d64d4;576d9afef2309e111e0f628b4a5d50df1871fab9d2ae8a8452a8326bff50e279;9996;11;2026-01-26T12:18:29.880Z
|
||||
e1e110c18cf5f6f9a38e892a83d95e2840ed60251f2c7e63b595a5fa97acf776;39d423f911af383bf027512acd1022aab0628772544e756ed658065e07bd6e83;9996;11;2026-01-26T12:18:29.883Z
|
||||
8f1cbebc6ef3f0011beb5eb9d46a38bf4294463664573cbac0ff79edcfd600de;447db496f3cc0c663e16dfc9f676ac44a4d535e23cc42d2640854b35c58c3a96;9996;11;2026-01-26T12:18:29.885Z
|
||||
577573eb99f3da04fbe1f6504c9a7bc034d9a79409af80be2797a1333ba14dd4;65da5b34c617c5afb5a33525f27c2f187c1d2740f5edc216751f9ca2510e6b97;9996;11;2026-01-26T12:18:29.887Z
|
||||
a7191a5b5cb7350a628ca72bc35a4fb316547c320dcf58102394ad30e82c0817;b93b7150da867ab642e8bf56acc104815d7772c0ae953874fee1356d2456519a;9996;11;2026-01-26T12:18:29.890Z
|
||||
3224ea60760a19c6083801dd6aaa732f332514c0fe43c3e545e2fe85acc3d67f;034549480ce7109e2d0b6c116c16dda1e3ad9af9c493864aebe004cd715e10a3;9996;11;2026-01-26T12:18:29.892Z
|
||||
b30edaeaf6cabe7a8e67639529edc343c375fdc03487e8569245b6124d3fd5df;0d41cc7008f27a889b8c8b7761a6a73c0efccfd8cee0a5d9727299b49eee0bad;9996;11;2026-01-26T12:18:29.894Z
|
||||
62257bb39478f58819df954efcd4cbc9c7725e93382d44fd6e156d0f676b7c31;b87036842e5251aaf47047254930976bfce94102f79720a23c01db0e082bdfae;9996;11;2026-01-26T12:18:29.896Z
|
||||
b1ef4208d8311415f0986c695a9ffc776c23e30f4192c7406c419f79c6ab4ff4;57ae5e11c7ce766c5cf77ae4f8382bd76ee0c944d00b9b039ef0fe25d6b257b1;9996;11;2026-01-26T12:18:29.898Z
|
||||
67857fc77bc24fbf13f01b88b0f6aa1ca426df8d3689d821d76744cab0f9cec3;523f3e19ddc6d64c91ae99d6f103e4b228b5a4dc69e06ddcfec7dba2d146a7b3;9996;11;2026-01-26T12:18:29.900Z
|
||||
2b48b1c465e99c1e59eb5782351c244059c90ee13f89ac3f7f9f9e52da1bc110;9c848d352bc4a0204c35f615d5742be38772a11b4f1a3d665f868c69be1a87b9;9996;11;2026-01-26T12:18:29.902Z
|
||||
664eae7dc24ff2689eca9451ff8d71acb73836a1d3f178b1a23d26f63f33cd1b;e4432b1ba92e2b278d283325fbb206002a19a0272cadd2cc0124b50e9f2eeccb;9996;11;2026-01-26T12:18:29.904Z
|
||||
9bf661f0630ff87e1e6e45ba53881871cc64e9be6547ebc3bf403d2ebad1e803;6b90c14b934af66e6c3e094f148fe78f1022873aac61cbeede0e60ed0853e5ce;9996;11;2026-01-26T12:18:29.910Z
|
||||
6f0796d686b9b5bf2ef02a1476c778ddbd4c44a88f3943cad222901d257ca453;734303967dd55d2f491280228534a5415cd1dd22fb3ec3190c8a8da0fe36bbe3;9996;11;2026-01-26T12:18:29.912Z
|
||||
49518327d4e6ccbf2ee41ba2b578a7754b0ae736a00a6b18a28a6d32c81fab82;659b365409fa233b74a68f31d4a3b0360921a54f4388761eaacefee111c84ae4;9996;11;2026-01-26T12:18:29.916Z
|
||||
a0cbdeb192da2d55153d0b5248101cf3c01e10b4d2bc0e339cb6f1681a6a94ba;45ae969f20223ae52ccbd9705732ada868ce40f7ef02ab7a9824093a0a4ae7e8;9996;11;2026-01-26T12:18:29.919Z
|
||||
817d2de663906a9bb347fdfd7aee971ef13e0126be15f70490dcb85eb6943ecd;91cd25d99fa3d0d34b5476ca22b4446b282fe1514eb288db0de2cc12b71ee5ea;9996;11;2026-01-26T12:18:29.921Z
|
||||
eaa8b1e35fe335e243b2ba0e614d8493621b1441fe8b9761add931aa25624afd;d27a9a25086a243cba24b8fd496080de5cfd2dde0916cc7f636f470bbd2d66ed;9996;11;2026-01-26T12:18:29.923Z
|
||||
67857fc77bc24fbf13f01b88b0f6aa1ca426df8d3689d821d76744cab0f9cec3;44a77f538c457272180c5c86bf3b1bda0359ee1fa3cfa0891e82b56c216403f3;9996;11;2026-01-26T12:18:29.940Z
|
||||
4fec69b99425ad83d55a769169b56bfc56c2041652b22ba0213f6b37e2c7eb10;90bef1a0fccdd6ef1a35431df681da31c2e08140283e2f92838690873eb041f6;9996;11;2026-01-26T12:18:29.942Z
|
||||
7e631d7a3a280a16ddc9f17cf302b5cbaf35f2b7429fd8ade45c89f6d30f4426;a57ca7cbc4072a1796caae4cfdd3b577389e127d6d1f1955a0c54d852a3ef9f8;9996;11;2026-01-26T12:18:29.945Z
|
||||
8dc5cb965e968644ec8564bf7f180fb7ca1a5b116cd3421a5a4a3f50d61b35c6;2389fda7f68275930ab70ada3ec93f3f4edbc513f6ac50ca11ee7c85e67cfdf9;9996;11;2026-01-26T12:18:29.947Z
|
||||
4a04dba275d68e6bd0619eb6b1ae5fdff0b482680482623d1d93ceff8f239e3e;2ae538c9d558747d7d68db694e94cd548925f49e0a6292fe0ea8096bb6517ffd;9996;11;2026-01-26T12:18:29.949Z
|
||||
1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef;789ab4f960023da92367127c8544bfb5f01b7c9abe22f84dfdebac2c5474bdb3;9999;8;2026-01-26T12:18:29.968Z
|
||||
cfd51286374af9bcbc90967621b66b02d436abb162aa90c9f82c13852ea43bef;da2031c121003008203236e19f290bb544f35d1d7aed29ad050e0d59928d5d49;10000;7;2026-01-26T12:18:29.980Z
|
||||
a8ef7629cae402729ca0a6c27733cf5561c22c2b0122b7b7779eb3a1b1398709;8444ef2fae986bfe74b6b4ba29cf5bd14870f3ca491011cefcc9f664a90ec15f;10000;7;2026-01-26T12:18:29.982Z
|
||||
375b90ea68f110e6f418134a36050654ceecc16ad39051cf1abc89bbad9871d8;3cdd4a670073006080aeb0c295a00517dc70fd6350b1447cf07ff86f0b4f6763;10000;7;2026-01-26T12:18:29.985Z
|
||||
0cd03760d5713e9c63f99a5e51e0dd1498b6ba53eb43f7a873bf8e194c8bd183;7bf1f6cb6e6d931ab227c426e0655786ce67abd43f5e634dcb55fb3a15be39b3;10000;7;2026-01-26T12:18:29.987Z
|
||||
2dbbffea231441827005d529657c062cf6a2a005edde12df6b572884d38a6149;122329709af1415b27f87c3d368a39148863616809e83fa3bc6a649715edae00;10001;6;2026-01-26T12:18:30.068Z
|
||||
3ae86209fd9f91dd7e3be974c667c765619d86b319083d6c16d3a49d7cc3386d;26a04e9755c2b049221e95102d5f79eb55b8f8cac78e08f5bb34563ee3c3107c;10001;6;2026-01-26T12:18:30.079Z
|
||||
569ee389de9412011b4f2c96907a3865cce6d9ee8e9197a33f1ff988cd5e20ac;a35bd5e6c1989862c6ab4cc7437d5a7bf1e51266d2bbee6f69293be09e6a168d;10001;6;2026-01-26T12:18:30.081Z
|
||||
0b62b71388b7308fa434706f9c692ccfa7d8260989fcb1f6a67517183ccd7c1f;47d4217a79351bf969444ee7506761463ace94ecb56405e8ca0c8e5a726555ac;10001;6;2026-01-26T12:18:30.083Z
|
||||
6a4bf869ba881b324a662fd09d3d9ee6ad7d9e5d0ed6f3b91e870e7e7fa88490;71bb3cbcab41810092713443463c93d68019ae55d03dbf50093cb617acb1cfcf;10001;6;2026-01-26T12:18:30.086Z
|
||||
f5b7debbc5ce4ca99523645dbf7ddac48aa3d7b80272fa85271867382f099331;ebd7c7d4772467b6e66f09777241a230dd7d6e9ebcdc0374a8a84ee8904d20e8;10001;6;2026-01-26T12:18:30.088Z
|
||||
1ac24548e901b33cb35ff62cbdad19624bb5d6129b54a17ec2c8b9ce4fac38d3;dad41c5eec557fec031e581088eb0eab968a25dd6e251fe8f4777da76300f4e9;10001;6;2026-01-26T12:18:30.090Z
|
||||
e36a63f523f304f24cfece0e7bd2aeec18e7c0f441c5052b4b5a7ea51c4b110b;b8f9412f932ae25b51bf47d378893da46d97fe268f3f54c6d13ab2772a0f10ea;10001;6;2026-01-26T12:18:30.092Z
|
||||
88cf23e8bf70d730e4b402282371d6578c7be9d4951e26ccfc865756e2c360a0;238d75f94300faf90eced7749182d87ff55d830095b8bf9af0286b04f51dc425;10002;5;2026-01-26T12:18:30.102Z
|
||||
dafd28384d9a6fdaa6631c2ba77a547e8e092ea8461cdc6cc7c95c7a46982d84;1766d8dd7c19bae4a054d9b5d4c915f3c34d06065a7c9e8b7ca89607141c163a;10002;5;2026-01-26T12:18:30.105Z
|
||||
03f2383f825eaef3580213207731ae26015ff5854681dd6c1aebf718dd97554e;874e83bc4266b3017b7d63f302c54b7935eb0610849e9c9c3c50b13f1ae4f743;10002;5;2026-01-26T12:18:30.107Z
|
||||
01960340f123682ec53b57ce621adb159159ae4613e70f62577192bca65a9fca;30706ffd506ebc4c2610c9c0b4c58922bfa4b9035f03d932e307a3473edfce9c;10002;5;2026-01-26T12:18:30.109Z
|
||||
c13053ba8dc92099ad06dd05ac9f53f345d062c3be0a51b5c7bd96265958eb5c;25ce7bbb83feeac0acc47e13eed9b501bf64dfa67998b46d05285bb97cdde2d2;10002;5;2026-01-26T12:18:30.111Z
|
||||
cd20f99386b3a31455aa33dc524736d19c5ae2aed4317ef0643ffc1ce23e8170;932ff00f800572ec8e44ee37de1c0425176847ba7629e3c8b3d505e6e5230493;10003;4;2026-01-26T12:18:30.119Z
|
||||
2d6a1d28b0039c5f2c3791a01dae30b07419bb9fc6f214fcdd632862574e9536;835827289a732bab9724b9e2fbd41709723a71b3c11ab429d201b7cbf1ab8932;10004;3;2026-01-26T12:18:30.128Z
|
||||
f2cc149b624de3c4c186429fe6395c43ed8cf284fb996e009a40eb40e626e0c9;f170b95b0a750954e31b768ab5d33b6611dcce4d12035f92e55599170cc5d47a;10004;3;2026-01-26T12:18:30.131Z
|
||||
9ab0c7d08bae0eae571c105a5389da86a0d751e56b056b1d47ec83963e8faed3;6d32f5165beec752dfe828a34d5ee6b2b45598a334e1e815d7fc74ca2072a7b8;10004;3;2026-01-26T12:18:30.133Z
|
||||
69e602021c96f2fd4553b163020e7dd162ba8bd94b5095f20559f138d1ef085a;09689e9fa198b8ac89e8af11e08648047e6cfda0392404b64ba771a0e564cf76;10005;2;2026-01-26T12:18:30.141Z
|
||||
8b3fc5e1d62e93cae891c9546c4d50512617b8cae9b65d6fb16f71de71cd5b82;d403e61430d2c1f680e56a440d29236632e65900fb1598a2988012c4e9442219;10006;1;2026-01-26T12:18:30.156Z
|
||||
4c156f6aafa8137377c7eb5471138dbf35f12ca5f13e08545f185ffa8d19e0e1;1308e4e0cce05a30e60fa7e7d73803db2c1b8fff8a7121b82c1a4ed656fb5a0e;10006;1;2026-01-26T12:18:30.158Z
|
||||
ecc7b3fe05ef89bdec3699fe00c518bbd4656a416f96d92536a74612f06d0b31;5bd53397c8b31873322dd7020e4c351c9b21edb9e758d1a0c0717eeaf373d312;10006;1;2026-01-26T12:18:30.160Z
|
||||
4e13b8f9b683bcc42d937f37f2bf3fe5140dcbd981db7bfaf17b512bf2029c52;b4634fee151f2a3d094596ca4678fdf8121faa86eb10a57d0e0b74d4f0d42a20;10006;1;2026-01-26T12:18:30.162Z
|
||||
d5759c67ecdbc72b56faacd54de44d57cde5a7050d76d1fa87456701a7c1dbb3;505d943a5b0379d514baad72e0a8c04ec954009b292e822d4e47648239a66145;10006;1;2026-01-26T12:18:30.164Z
|
||||
3cc004f7e6188d6c360515dfa783e5a48d9e1bfbc99ed12892aac36736d1110b;21c1e802c76d1d5ab366a527bb4a3b03d1b4d7902096935488328a8967ea6e54;10006;1;2026-01-26T12:18:30.167Z
|
||||
ec952a95fa418f22cd6dca50b092e1e40fd327080bd715f501bc8a185541b99e;0d3047f925c2f4fe666186b868c5c1c30bf73344c616ffd54b2e0a7c0d995964;10006;1;2026-01-26T12:18:30.169Z
|
||||
9fbd3b1a7c48c633e66031972a53781acbb426c6951c85ac4551db1cee63db88;af52a90a26a6050a94625c59a9e35ab0ea00da3eb7bc2774b6dfebb041a9727c;10006;1;2026-01-26T12:18:30.172Z
|
||||
73a210c556a327037c72cda57e48e9633fcfb47167b2522c033bd4659976679d;8610218ce4866ee08f9a65b5db99efe31baa6aa47b4db3aa8808ad96ee969a7c;10006;1;2026-01-26T12:18:30.174Z
|
||||
6279810e61dad91891cb16b504a4d582d1c9405cf514f7a07fc7779e8156d74e;faab172e790873baada0021777229edc6dfd8a0b62e5ccdc1e86211af9357b88;10006;1;2026-01-26T12:18:30.176Z
|
||||
acc2dc94e70806d491cd10951af55b25d518ffcdaa18e8e8c39dbf4fec1ebb16;9074c3a7f338c915768ae5673e64041939cff1901a719732a0f18066c6526ea6;10006;1;2026-01-26T12:18:30.179Z
|
||||
8de5cf8b03b03a489c81859584a4ce5083059186e34ceb4286b0c8a8a38d2681;38425e8690d8dfa3fde70c71c98016886f95e25c33a7f6c55fee1147a77187ab;10006;1;2026-01-26T12:18:30.181Z
|
||||
35c9ade59fc66f75a308f082cab7b033b847fe1fd5295ff888a61681080fdb67;0c862dd5327b3c68e29a148cd488e3bb823cd09f3c358006bd52243ad3d907b5;10006;1;2026-01-26T12:18:30.183Z
|
||||
9fbb71987c5660a16b642ba286c06a1c9339f1c96b54e8e5d23c4ffcf085335b;532bccce0482f309bf692855c26f219ab8147d4a0bfdadbc3771f0900ece68bb;10006;1;2026-01-26T12:18:30.185Z
|
||||
a0873bd4abefc2a0899884509f9a02a87a03bb503b7eb0c5f65d6e61261aa529;0cf1f5b017ecc21999ff68e5eaac6fbfea40e3481318021e39626bd4e695bfc2;10006;1;2026-01-26T12:18:30.212Z
|
||||
eb503f92d7e12b27eaf687897026ae643862893c84c522f54d07a96abeb76b0e;d1251fcabcd70a58e95e8d2b772522b34feb2af3e7a4d47863a06ae03f1c6ceb;10006;1;2026-01-26T12:18:30.223Z
|
||||
782a945d0e8fdbddf6534db0ff981307567a302b108be55b6d1c5b713413c5b0;438ccb722169dee000a41d893424ae0570a72835dbae27029c646e71fbf258fe;10006;1;2026-01-26T12:18:30.230Z
|
||||
5eb9427d56613d6b1102a186acf43380b3061c43fba469eeef0f7f3d3133ae21;48481908313f8a4bae1d4d67ea2d7bd9dd4996734ab8d418b9fd017376771028;10007;2;2026-01-26T12:20:00.590Z
|
||||
2a6a1b41f85c887ac7c479d4a306cfae248d42653a50c8469ff337f69615aa35;9f74c08f4f1a73190d4d4c9a9585dfadf0e89b52918358ffce3087f4eb4e8774;10007;2;2026-01-26T12:20:00.593Z
|
||||
400fc99af1860e13d5b1b1189d817c0d6643b4c20835116c03e530deb8ac51a3;2f8917228fc9e8589c3755a246ab9b6e28fb91304e36819e038efbd19aed587a;10007;2;2026-01-26T12:20:00.595Z
|
||||
c83490de1b9914f62b8897aba71b5a14246fc1704cdee345343a834679919053;3e4a9c967b8068a533410be0ed9946c282190bfeae15275daa987914c2157b96;10007;2;2026-01-26T12:20:00.597Z
|
||||
fc24141b064e68fb0169d288f344927aaa8338a75dba3001908bad239ea5fe26;801d92124710a157b907d6fa543e38044fa7433f9699982cded1cdc6e6069bae;10007;2;2026-01-26T12:20:00.599Z
|
||||
d26f0cf898d99102bf46d584b403c5a930b2fea5f5d42f9633e143d2722fd22b;14a43b13eaf9f01facb0e64b0309b3b74ebc88f56c6b503d0b15789ecae4b3e3;10008;1;2026-01-26T12:20:00.618Z
|
||||
7870c26bdf81edd5a6c7928e1c466b5b0c5185573532984ddf7b05d3e8cefc00;fe49637f944bfd493c692343c336370b26edc49c164bc63b9e7b0bb2f4577707;10008;1;2026-01-26T12:20:00.620Z
|
||||
e0c6f755682c5fc82161f1a61604f79ce056fa69b35ee9951606d9cd39cd7d32;0b602e6a697022f87af7abdae0f0d80321c27163a73da80366b693c9d7c41b13;10008;1;2026-01-26T12:20:00.622Z
|
||||
ebde6757554a8726e7d7b7a9ed0320d2cb269ef8b7e809305da211ef7585dadb;7ae625266f09ef6eff66054e35a669c3c674deaa01e12817f7c7bf9899dae017;10008;1;2026-01-26T12:20:00.623Z
|
||||
83a41abfde748c6b40d66519ddf5771b7c27d49093068bc7037c715cba0cc762;9966605c9cb6d52c4d0077aa94984e5bc7e02a96d279357c7bc47ea9cb477919;10008;1;2026-01-26T12:20:00.625Z
|
||||
2c33d268ae685878bec42b97a8ab291e2ec96a65e1b1fa4d44acf5a3c0d9ce82;6c030f2f22442a69d90675baf90aa6f87e3d720b7b3975453b75008c45e6381f;10008;1;2026-01-26T12:20:00.627Z
|
||||
a7231aba490c10ccb402a00b89f19571013d282ddf677eb9f9f328175b261b68;79fb6a6d00de0b906037381f8918552f8f33fa689522c6811cadd7ec308b362c;10008;1;2026-01-26T12:20:00.629Z
|
||||
a5d0d1fd14dc464fc763d935cb7415b3f9c5a6eb66a5bc54ff5fbb6a3d9a91a8;1ccae64fc227e09cc2379cf9e058a194270cff1303d64c1644de66431cb93436;10008;1;2026-01-26T12:20:00.632Z
|
||||
1092a72ecc3b59ad82fb3c3bee559337db14bbb2f0c2187c0c58a5ab168b7cd8;ec6100c18f3b84463b7c2f37a6ba5d84b990867d22980c6f24cebd7ba3670037;10008;1;2026-01-26T12:20:00.634Z
|
||||
0f283673f674da4a8de5889fe3d23737659594b13d6abb767a164d11fdbdedfc;0130d9c4cd6c4e42c417510a4ecb4591693f5fe97b9e205f2a2ac6cfa42a8b37;10008;1;2026-01-26T12:20:00.636Z
|
||||
25c9a169a442b9cf66dbcb4ade8019a9e21b4d09e5d7c24fa1c476bb378d53ec;0a08ee325874ee31aa9ed3e3ae86698e63d1a593f105f3a64f6dab251f7d6239;10008;1;2026-01-26T12:20:00.638Z
|
||||
0f819b554af99d3c1404feb6ee3e6e51172cd245f4ab77807dad6634d3733a06;8e44f1bfc2c3e781d90c61476e636794e3eec2bae228b6348ed3236d8546733e;10008;1;2026-01-26T12:20:00.640Z
|
||||
35659e4d22ae6bde085abfb97e8b13a621ea8a02d4fbda9b012c7e15b20301d0;a9ee1b796d834c0566e4faa165395258bfbe478b7b8550269f93d799c8919055;10008;1;2026-01-26T12:20:00.642Z
|
||||
5a0423bdc3a6564f10b31d0ccd8735fa0886fe679b579224a7ec8cb9d7a77328;7d956df4afa43c40ff2d36b1caa98c4690834b526af3116892b4d3e485673062;10008;1;2026-01-26T12:20:00.644Z
|
||||
ef25e77fd7ec4e5765642e352a02faf51404829834a30bc942787c05df45e804;bb9e7fa29871d3fd01d44979e02a120d0469725022d6cb5c0466b4aa471f3c75;10008;1;2026-01-26T12:20:00.646Z
|
||||
c77ddc5ab3e2f43dbf3dd6069fee2295d1be0c7b4e4f7015f8d8c6abd7da2d2b;fcefa439df01ca85bbbf446df7db87429a363a4551aa21dedede318eedc0fe81;10008;1;2026-01-26T12:20:00.648Z
|
||||
aa87a1e5d7bf965fde87f514963b9c79995b75a7c964961b16ce05e656803ae9;3980ed3a2e2f1ea17af8a1ae39e3acf5c8aca105b323d7ef570d1c7c685f8c84;10008;1;2026-01-26T12:20:00.650Z
|
||||
88e1fae660c1b7eaa3395c744d25e452935b83cd8aa05166d76fbae48ceea12b;17083c8481f946172e791a716b393d1380fc8f9150e2add65ef952d85af4aa8f;10008;1;2026-01-26T12:20:00.652Z
|
||||
606dbbbbbcffde9ea9bc4c94f475043bd86983461bff47a45cf9816ed78985ea;4163aa46b0add699f32ff3598e97df497ffd6766286fe2971282a9397564e69a;10008;1;2026-01-26T12:20:00.654Z
|
||||
b7f2801781ea4a9dc10b7eb315c223b253b4246b07781f8de1bdf4d955857990;17a1979171a8325f9f32a585d61021dbfcca0e8bfa2510f7c27fb19e43a57f9e;10008;1;2026-01-26T12:20:00.656Z
|
||||
f1968825f51f65c121b3c1463abce381894b51be6b1ee5aab7770b11d5b8ef45;ce1699f52819b61d8ef7d05fd265410af760967f7733001d8f6cd27bf4a7139f;10008;1;2026-01-26T12:20:00.658Z
|
||||
5e2c1f0e31a4b380ace191fe2dc1e935d4b69ec85ef7a75e342c1e1cd7efb2f2;156c2480ee818edb5a5e2643df1c8b0bda28d7e27c0e9b5c8b7e7af3ad750dad;10008;1;2026-01-26T12:20:00.660Z
|
||||
75a3bd60df18834257042132d288a233078ca1b0c6482d2a6b45f7072fdcb420;12809588c83c1868e140bfc3d87f57d848e32ace9e3ae02e441ce434565159b6;10008;1;2026-01-26T12:20:00.663Z
|
||||
98685599a646a0e1e5d8e0b358949a2544ed79d4078a29f283809bf8c4e1d890;bcc88af20aaedf0d1d4de229a89758ac74f6749e5265f6da869bb14d3c8ed3b7;10008;1;2026-01-26T12:20:00.665Z
|
||||
dd7294ee8a94a1ceb7c5bc8405672c92221ccee1819b5ce738a6203010bb3e84;45ed12717d5b44bc55670ce94fcd3096aefbaa3a47c3ff7b3dac2ab51f0fa3bc;10008;1;2026-01-26T12:20:00.666Z
|
||||
dde6f332097e21f3b401576716f46a56e4489ab1780771d1ce88765c747bd6fa;078082853b15a86f1f0e191fc8058d02f485c1e13ce56cf2b1a441a6bf75f2ca;10008;1;2026-01-26T12:20:00.669Z
|
||||
1a0459ddaece692555913efb3f439b7b362f4d381bdc130fc094a147b4306fe4;81bcc837f22b51abe267a6a3368c96e10ab6ad7e09c9dd5a512fbfa6af3a83e5;10008;1;2026-01-26T12:20:00.671Z
|
||||
fc6ffa32fae4da89ced2806e9a300d1b15be3a6a20c8481bff36a17ef87c0899;6026e0c2a0bd8a0b918d68c70a8883d16e8b406f0f16cc90a11c85836ba865ef;10008;1;2026-01-26T12:20:00.674Z
|
||||
2a537a9e975c67af3744a022b84e60415fac62c3c25cf3821093db0c621e8234;36f30364d10be3940675a12fe67b7e88306ce75fb2b4e215a562f3c7983bbbfe;10008;1;2026-01-26T12:20:00.676Z
|
||||
35cd8ded9f69a93a41278d4a77ca050543f83de1e5187bdbb6af6021e4b20cfb;441fa16491f1c091f86fb56447a03688275fa5f4577802e0423222e2c44fdf0a;10009;1;2026-01-26T12:20:30.596Z
|
||||
21a2e018e1e3ad25a765590b66c4ae0aa3a5c1601bb9fcec695efc32e7187f6c;9d0d406f4222f97d8a174092cd242aa9b3cf803ec74da54c08b529d9dc365214;10009;1;2026-01-26T12:20:30.598Z
|
||||
7d863e4f39a711efbffaf362cbfcf020cb91055e2fa460e1fba809a1ed1e82d5;5ce6548d85d4ae79834e4ed16d217079d4f09d16a3e13c6159f5a6844599d375;10009;1;2026-01-26T12:20:30.600Z
|
||||
ecd1b3feaf18c71a076bd4a5f75c63ff78d10d40779512f9700f59aefcdf169f;9c93749ccb0bf01a7ddede8ddaf8625de6030572d596dfb55fa8165588fe27bc;10009;1;2026-01-26T12:20:30.602Z
|
||||
d0fba1ecff33cdcabfa39f5d59146f8638b0fc794c8bbcd13d19bb1427289f55;8662a9cbf4fa34e5fc42fb68014ade81266de917df4a2b235eacac22add80a85;10010;1;2026-01-26T12:21:00.610Z
|
||||
2cb437cb573c6c17f6cd5b7bb86254cf4cc7aac45298943aa2bbbdbe1afbd251;e1527a2c95e6faaf9e809204c63f9dfbedce60d22603fcc4e0cb2c394e94db8b;10010;1;2026-01-26T12:21:00.614Z
|
||||
d4c2d4deb883104477d4ec341c725f131ecc504dac6e21de060fd1ee2d3d999b;c1844e1c8cf3e1a8f3375cb4aadc905420b8fcb5aa1562b2e71763991d39f89c;10010;1;2026-01-26T12:21:00.619Z
|
||||
b87c1ef087058ad4e1f1c916f8f1165f467e498b0fef42a5a5ee9f7fe4a06425;00089ff6aaec18d56cc4a2b4cbac2a411bb709e6e888c356fe0349887ea9eeab;10010;1;2026-01-26T12:21:00.624Z
|
||||
f7aa953fc0fff9bf61b8e7700f21795fc8227203856741299147faf06de9f45f;ff981bee7e43c4b057673222fd2bc1864b12eab5624669f34d8b8db5888b40b3;10010;1;2026-01-26T12:21:00.628Z
|
||||
317d3ed76dc2ebd02f356cf2002b9ff2490d5a6a01755405926e3874e3adbf92;aa8972cc6d0f46b8a389edba790fe2231bbf9a11506655c2d1fa3e51afb63dd4;10010;1;2026-01-26T12:21:00.632Z
|
||||
bb86f32bdbcf974e440cbbee731d38c928498bb048b0c161cf0af39eda7ccd0b;3a1c6d01097e089d55097c463ba128b440de164a0098c9228ce66f9d0b4b9a1f;10011;2;2026-01-26T12:22:22.644Z
|
||||
65c4184d7807c99a74d08ba754a8f7cf3511131b68259145afef956dc772d8a2;2801ca753fc7453eb95aecfab9da1fe88be3082e57da9ee6c80f865e3d67693f;10011;2;2026-01-26T12:22:22.647Z
|
||||
d7a2ae1b53e76502b548265af97e8d1ea6bb2306ab8da380cb37ae5e984f675f;7dfd9d05a311a4d128d5c8dfd05dcd3d5bf9a070dce295c580f63613c3c06c54;10011;2;2026-01-26T12:22:22.649Z
|
||||
bdb45885d7c314e855d6e9c21303ce1a091943844d22e036dfb762f496766d86;4ce990af9a8289481f7aa8192a0ad5c305759c447975f75f5463ee3b2b1b588a;10011;2;2026-01-26T12:22:22.651Z
|
||||
4f62f0902cf8434c600ee41e9ff296865a522bffcdc0d9c69fe7003fc0276567;5a39f91b76bbd3f5ad3b6884cda3928cdace30bdef82d52c8e72ed69ed739793;10011;2;2026-01-26T12:22:22.653Z
|
||||
869f813d8fedc49ee3619fc5f57c3739fbe9a2410ac681fe8c6467186e4d9ac6;e6aee17550b63e2e31e843c9ad21982f83bba426e0b868af385b85cd19a4b9a4;10011;2;2026-01-26T12:22:22.656Z
|
||||
65c4184d7807c99a74d08ba754a8f7cf3511131b68259145afef956dc772d8a2;7e00dfe353da504e1825b4f2a68f2c81ca3c5215a128a01e5723ca81611c6ba8;10011;2;2026-01-26T12:22:22.658Z
|
||||
70ee6edd726f88b893ef4c6b080e5b95b21d0f0b6769b6baef0c211910bc3dbe;d6983842f8170e9589bcb4b98123cd55a2245f2a4a31199539f79740ca1856ca;10011;2;2026-01-26T12:22:22.660Z
|
||||
03f08cee16578af016e13e7ced1f4b9cd440a5ef30fdbb2e7be970d1e5d32c1a;cbc3278b8df11ec67dcbad4c77b02a660d7c7c61e36a6169733497e832d71405;10012;1;2026-01-26T12:22:22.670Z
|
||||
d8c847d64be4841045368704383a92fac35110ef37118d8f23399f4926db4d65;b246ee33959a5f9381bbbdad215b923ff046a07d22786abf5ac1ec9d1c792d47;10012;1;2026-01-26T12:22:22.672Z
|
||||
596d0781efa9add9963d26cc96a5c5bb4fa5f246d0ac19ad61ad15e521edb4cf;b66bace78e97916dd272baeb6f53f0d96944dd944c3cd6b92fd3877eeee1d757;10012;1;2026-01-26T12:22:22.675Z
|
||||
e6f9c85910a6d403504a03babe46c6ee9733f52f114b852a796f7bc5f39f71d4;db1c8947135e3422cab79ace018b76b0b7c8051c1aa559d3fead570b21eabc70;10012;1;2026-01-26T12:22:22.677Z
|
||||
37928063da3caca8176258eb1d4cb76a414c8df1eb724d336e5486819ee36aff;df755f34bb62ef6037c38e7939bad6a4770585b3b08b177b0bb1d7740b522b93;10012;1;2026-01-26T12:22:22.679Z
|
||||
476c88d260c88a7e38cb7f10b28819b928a6e93deb264c6513b2021a565db304;a4ac29798056e43d19afdbc12bcf4bb88408392f50c5feaba4fb80d6a66542a3;10012;1;2026-01-26T12:22:22.681Z
|
||||
630252ac874b081e8b8880e38b3dbf643358a68058cd2034ffadde6804ec1691;d5ce43319875067cec96e397973e7907f8b9bf071b35807cfcc2c8d1a0023bb3;10012;1;2026-01-26T12:22:22.683Z
|
||||
f781fbd7ea36a8228c0dc4527eac99ffdf9c76049d42ddebb83f5b02637ba4c4;9afa9a13a6b0bff4829786da465193a90809d953a2b89aeab13d833cf3ebe52d;10013;2;2026-01-26T12:23:22.677Z
|
||||
448eb1dcd61b608f4e994f18775c1df26b9e602be08d6e28f4e380ad86128a71;5880813042e11d7bf5b6a69447204382c8f6e644589f171e93343e249856cb58;10013;2;2026-01-26T12:23:22.679Z
|
||||
8722cb1e47ed7e50587406264e657ccb8bc381d911742e885432878f3bfad0c7;108e8a88eac9d0ab3c1a472ae5b818863bfd4e703a69ff96722b75217a32915b;10013;2;2026-01-26T12:23:22.681Z
|
||||
a3dde2776fc4e271d97770baf6b3bef3deacb139da3b71cfb1faddd2d366b369;d5c4da561642d6dd2d47be725603a87c2b5e85bc162d813eedad95f06c4f0765;10013;2;2026-01-26T12:23:22.684Z
|
||||
c5442cbee55327d9d9b963b230060ae55da6d9d66be5d7491e4044fd0ec60842;53076ab5f24e81cf847d2a0f840ecffe4cd04733f31d893e4bb46861636f1a72;10013;2;2026-01-26T12:23:22.686Z
|
||||
a7f82ef944fb6690f2c117f110c49a811a79b08a3af0d35db78561c5fb5c978d;00518f8d80d856e889a058e5c739cc34bec8e45a4bf53fa4bee4ed971defbdd0;10013;2;2026-01-26T12:23:22.688Z
|
||||
cbfc82274adfe8a441dd4559f322fb7cb8895f9192acd25ff9fd026053faee55;eca47cca8e12483d872102e844b5d25f5131cba60102d7b833e3d3d5bd6903d1;10013;2;2026-01-26T12:23:22.691Z
|
||||
ab93450de22a0b516fe172d0463cbeac2f56c22f37ea21221bf0ee5005537958;549ba8742f2246ecfeb7ce8bf399c385cc2d19a30af2543f3d24047ae35bedf6;10013;2;2026-01-26T12:23:22.699Z
|
||||
63917ef88e15b3f481d16b7d096ee1e1d7a4235a74f3aa9a54d6b621e43a6185;98bad4756d6c4a4afb9cf3db0975e5c3f029c18a8dd8dd42ec9c3f595ab6bd3c;10014;1;2026-01-26T12:23:22.717Z
|
||||
d20c33256e31a101ad1a50bb7c216262e255f7bde690a61328681f36117a69ea;3e7eeade1f9e5ba8568af83d31176f83fd5cef2362c5340efec5e920d46e675b;10014;1;2026-01-26T12:23:22.719Z
|
||||
1add9c4a5c2480efe5118f70c8ca8b282fa1d56e55592c586b9db7508222faf8;84135d3e73afe39051f70b1d62df05649e22da933c8b435622ced437b63c326a;10014;1;2026-01-26T12:23:22.722Z
|
||||
d9eb8ee85d2798e0a9e94a1d022563a9321b43630756ef27d6fe217813be2f19;e2502e9d74e5fa82fc87411fb004c10280cd39907fabae4987d0a7b7b86c406c;10014;1;2026-01-26T12:23:22.725Z
|
||||
bcdd665ee3b83471da59c2c93ea0405dc67c190b6c487bc4e702c252545b2881;f58295c555b7ec3fa426ce7e189eae585d8d3f5de2b832e9cd6d1cb9ba47c576;10014;1;2026-01-26T12:23:22.730Z
|
||||
2dab37ff3886a6e5127f93dff651da8cd4474579d4e24fcf9c441710cf32ef78;ac6efa97e52aa7c42ca3323c8ba39e13ffe61c39983cf2bf5f674ea3b1ccd6a0;10014;1;2026-01-26T12:23:22.733Z
|
||||
b39f53022e6238e17011d176810339f1c67d0404975535a012bd4e09a8fc8111;153bc05c5afd22e14dd33d1af836240b1c35f71a4235d9ea607678c0ba8f637a;10015;1;2026-01-26T12:24:22.656Z
|
||||
cc9a8c6e4573422dd0f81081d1fe98f0640709494d9ef342a98d33ba3218dc11;3868bb3bc070837025018471e0ef0c3b425bd02db27fffb608ebee943bb13eb2;10015;1;2026-01-26T12:24:22.659Z
|
||||
b2b3139cfd5803cd662306ce15438edc0665ecb3523331cfce2e0b260d4bd714;1c96f8c09294291c3793a5ef775cd5cb548e8926a93c6eb4ae9023ea49f661b2;10015;1;2026-01-26T12:24:22.670Z
|
||||
cba5ed6e7ac462dcb37d702babcdadf675b7fd708f7491f7867ca363ce0fa19b;c70dd32da3fe997a44f5c8a38c129e0c7d63755e696241b0a87598372ef6a9e4;10015;1;2026-01-26T12:24:22.680Z
|
||||
054ec15684f4cacd1314146bd2c3e9a1fa9a5122dee23712f308b4867bb412d4;4681dc369f03d17fc27efd2eb3bdfc9ad17c268a0923c3fec676c68282817af4;10015;1;2026-01-26T12:24:22.683Z
|
||||
36d6747e36b682d506b8ccc7bfd49c4f890c0ac3bf74ec69f9c66d6eb2d274f7;aa6379338b1e0d70f05ce23a2114bc288c0c0d6548be6ec1ae54a90fa34ad629;10016;2;2026-01-26T12:26:22.707Z
|
||||
a4f790181a8887cef32ff83f6974b0a15b4e006f908bfe044ad38db28d34ae13;ce833dee49b70c33cc9f6355fb60d1e7d35213a334031a277f386fc420e0f18b;10016;2;2026-01-26T12:26:22.711Z
|
||||
e1919c69e4abd39c08a035433d0ba65fcae7ba1a5bb3e312a4531e9497f7c370;06fb4753da73892e88c04377d5218f124b9bbaf15919f1ed7787c1ce2b5d3c8c;10016;2;2026-01-26T12:26:22.713Z
|
||||
55ce370999ffa5744bcee9c0480322bf38d8ebfc0b38335a58de76b8b590be7b;6e43c3c87dc1dd8d1de857d88e4feba5735e914d9a0fc2461d0d80109379259a;10016;2;2026-01-26T12:26:22.719Z
|
||||
3b9813da86a11eb4d47795aa1d2945eb291794d057be67490a64c3bb389101b3;e03e8ffc3c20bb3d5964addb0331cd35fbb2095e635618b618b369cb2c0315cc;10016;2;2026-01-26T12:26:22.721Z
|
||||
678f7f19be0e88c7be0a9adad185cfe30483a5b80b0a0ec4fc72548a9b7f4795;40edf308d7eadfa999492e9eb4706a68389d7acb9db2d76b1005da361d111204;10017;1;2026-01-26T12:26:22.745Z
|
||||
069639f4f50689f1b74b029b25d93e3c7d7b8233720b25cbdb6cd4f9bb76596d;73f994e2e2c2c7f23520c50f9c6387e59edd7226d40a13986b0809823ce43e09;10017;1;2026-01-26T12:26:22.747Z
|
||||
bfa1cbeb9bfb7dfdf0bdd76953e0e6579a1b91005061eea979acc452897ae2e7;ce85155a343d73455a2de588cebf694d5bef161429ff279e50eb891d6247b22f;10017;1;2026-01-26T12:26:22.749Z
|
||||
99721f741b53030dab5b8b719481f9e05729228a3db2d110ae36fdce39a9953e;074bd1a4b5fb3c596244e7e9efa0d6b41f00c95a114410bbebb4e31dec38165c;10017;1;2026-01-26T12:26:22.752Z
|
||||
a47c93c5b70ee8cd2e820e49d430004073451d6420299b2227482e54aa6d1e1a;9e529e942059347b7bf0cb98f0c14311d6efb242346c25e895a54647df774264;10017;1;2026-01-26T12:26:22.754Z
|
||||
0311b5649141d4e1d617143e506c3332acb46c8b9be3062a3c27b5220d6f68a9;2620cf83a3dfa1cb5d2020a5f73e6e8ec67c49216b43debe3cb948c2427c3671;10017;1;2026-01-26T12:26:22.756Z
|
||||
8a90fcf66b18e2769a8c938b6988fe0ae8329b2684af4ee632966dce6f15111f;1a2576814535a88869f474df089d08e4a28c33f6a5cdcaa8b265e4200a84bd8c;10017;1;2026-01-26T12:26:22.758Z
|
||||
5594676edc28653ba5ea2b93aed18708562082c7ec6091f86e63f4f5e71f95ac;03f5f8e99458d7619a669fd009743800daf07028a352776e2280fd8a74a6f28e;10017;1;2026-01-26T12:26:22.761Z
|
||||
014b6dd24e241df5653d53af58f4ccc066e0273ec355e5753e55b6643872307e;3ca9fd0416c1b5e6ff873e5b58878c503d773081a8b5d3578bd3492d3c0b3493;10017;1;2026-01-26T12:26:22.763Z
|
||||
79e00d70ceca10667c6d3c59dbe501a4b7651744e6dc2940e988eadc0ec8d726;2b4f2f26a27768629ea41880f0536f68b977d9a4b7036babb592f1e8bf4c47a0;10017;1;2026-01-26T12:26:22.765Z
|
||||
2aaa9d597aa9a2d08f26ecd354426095d46a0a0b6b624f07f4d709c7ffc38d8d;012df0130e84c83d222a8ff4ea876523eb7041ecbb301ccfb53511da2ee597a1;10017;1;2026-01-26T12:26:22.768Z
|
||||
b12f667dc418f1a0be845f599379763774c7cae944987f15ce3c224eaa2b74d3;1b4f8e2cd6295e73ce9f98499f168a6e539d599719c6fc83b3fc7f5b1a09a1a7;10017;1;2026-01-26T12:26:22.770Z
|
||||
5acac0008e2656ef4bd4cf1b733d832c399a61452e10c2984a91fc6da4b6fd35;a8cb6e54ad83c090f95de2f4d574b1706616dede6a965d6787600c047a0e2aa8;10017;1;2026-01-26T12:26:22.773Z
|
||||
fa4cd096ec24f94729d3aebe8df01b85d85220bcd2a353228280c550a0064527;bf0c65db866533494322de908f58bee25b22d4117c44e480eacc238338b9f9af;10017;1;2026-01-26T12:26:22.775Z
|
||||
58415966bd40a7e0d186edb893c725eeff2f15843485bf69c603433c62a3fcb4;0b0d2646a4c1e2b9e155f3490eff0b64b8d9938de10242ea8050939e521685b5;10017;1;2026-01-26T12:26:22.777Z
|
||||
b8146416115649fd5916639993ab6bdcbd1c9d94aee61cfb85d41ee048d7a6f0;b2259726f11e6a569f94b8e70353f604e15cc00f2104608bde87cbd6ae0914cb;10017;1;2026-01-26T12:26:22.779Z
|
||||
9e3c3e98168a5f8dbb59d8943687832b3feb48c6b8f22e2cc4589cd246a12117;fae648d57d61b2b991ac8e8a1075c4fa57fb51832fdff801175cebf61b8f3cd1;10017;1;2026-01-26T12:26:22.782Z
|
||||
afe607f8192e7bc5fe789747ec9b47e44b2f473a39a1b15bdb1cafd37d1b96d2;2deb82c61acc9051194154e0b56de15d7a01626602cba08be4b4097ee87ea5db;10017;1;2026-01-26T12:26:22.784Z
|
||||
791b7713f68f6644fe3b6b7d31481d1f93e2c29f07e2e16746a2cf141dbce378;a7f6ac90bdf697b9cc96afd66f6cc4ebc969bd1ec622467c66d17118456313dc;10017;1;2026-01-26T12:26:22.786Z
|
||||
f3cb7580d158d5db8f5d454881e55a41b6db5031b1dd3d471f7a404eaeb3ebbc;4302da408ca63b080039a23e4364e399524b55a48b3d880850a371aa8dec43dd;10017;1;2026-01-26T12:26:22.789Z
|
||||
30295e3273ba5c67df62812c0731b6160e34137c1aebedd2e51dd4ea370656e6;1682c7abf328b482306868fe218871cf109d1a26340b7b98c6e008cc4d9151eb;10017;1;2026-01-26T12:26:22.791Z
|
||||
f9cca9715832e1f64abcbcbfd5299cd8e0b9ade64be5b39aa3ebe50922acdd7d;c53387ab1f5e75a7145b7552edd0bfa081858ea6925faf3da91415de76871f31;10018;2;2026-01-26T12:27:22.699Z
|
||||
2667c6c6911501639face2afd4d49d822896eb5ac808c35fd21d0e09dfa30720;a9336602bf7d09ba913267af114d3d0fe7c92d75cfa22fad9d88245be09c873f;10018;2;2026-01-26T12:27:22.703Z
|
||||
8b7ff05873bb1f8fec485bb4ef2602520076f76a7a6d23f2d2e82ec714dded2c;6b9b19678fd835902f6bec0d3bd05949221c7c8fa7fb13f37bc4e88f9676125d;10018;2;2026-01-26T12:27:22.707Z
|
||||
f2e297d867df7521925eebb81296b0267f114b51104f3a363da7aaa59c229ddf;b52ba9617033aa7e6a172f5dc40e576c6a56d48eef9524669d0ee45e0b307e66;10018;2;2026-01-26T12:27:22.711Z
|
||||
5a7459641218dac42bb47c5da04d7ea8fef0da1436c5a63e5887eb77ac15647a;2d53608d7c91ad90eb6365311fb4193aca5e37001f4c4b278a3e5fc88dd1ffb8;10018;2;2026-01-26T12:27:22.726Z
|
||||
017132cb94ec656c4780c007fda4e597e4e7c255c09499c19537f0d5634294ee;7f3449229c7dc13b7bc59d9968c674f7510f011c9e21961f6b9d52b096a81606;10019;1;2026-01-26T12:27:22.754Z
|
||||
c5c4e77f2212c45b6836881ab871f3f890d036fb3982dc5a803b26717fa61cc3;e2f15cbfb0924699ef81339b057dba12563bedeecdbcf745a6e74bc1c79bfc21;10019;1;2026-01-26T12:27:22.757Z
|
||||
300b18c2b26fb0d04d22f0e8af77b610558210be84e2a139d244423b607fda65;8c2d19ef2908d858d6f75d08e69efb5dec35cd2263f7a93d6171b7f747524d59;10019;1;2026-01-26T12:27:22.759Z
|
||||
4723d839da64e3bb6d1354327b91b2e595ee4553a0481d292126a03d1fa1355e;5edf31e4d0652d528eb90b460c2ab0f6a75dd5a3046f2b2e09b2106e52a04d6a;10019;1;2026-01-26T12:27:22.761Z
|
||||
415a903a232bbaea133f0417a42e97bf778dd93c8e8f22f18bfae8ef97e9283d;139ac84da69d5029bb2d1c05a5d01755ea4b7e5aed74b7389d7da708c5d11f7d;10019;1;2026-01-26T12:27:22.763Z
|
||||
89c695426593296f8288814d3b1c53d63e4bc181e586692b38eb30b1f4fab951;8b5567be6db13b5014085ed781b21e312d75b5ad51b0d03a52f69c89cf413d88;10019;1;2026-01-26T12:27:22.765Z
|
||||
031025a106506350ea5ccc58e364a15c6a7e27151d09382bbf8f3510c1248f40;5072b9595a3801dec39ec791248c068e3a204025be6280dd52083a2f4f484bc0;10019;1;2026-01-26T12:27:22.767Z
|
||||
dbef624c8c69ad2c300fbfca3224e0568fe02338dc5a30b7c302692763464fac;5cf84edbe2ad6f9b3b4cb8e75d9a146708ec2753e9069eeb3a45cba7ba89bad4;10019;1;2026-01-26T12:27:22.771Z
|
||||
b803f0496f86dfb7800535f7270523246d3c291904401908fc5f864b56b03516;2981e8d31662b94d453f573b01ffcb69c70a0cc7d336f54270a2f0cd1c7872de;10019;1;2026-01-26T12:27:22.774Z
|
||||
e3ec63123956e0b576ef58a472bc10a996f6c072d5cdaf72274c37a0d0ed8ee9;962cc4ef2c09785ba1259a0be2d8818c977955dcf912b15c978fc27b607f9920;10020;1;2026-01-26T12:28:22.737Z
|
||||
584a69c6988225a759dd14ce276f164fec7fff973074115a37bd9ebc25a5ba83;42bac16b779e54e15869356b2b54d9ff78b3047994611cc4e2f4282191ce6027;10020;1;2026-01-26T12:28:22.740Z
|
||||
49fa592e595f64eca366ce224a3f8590d12c8fbe407b3d36bfbd4a2e7ba8c6c0;d4ef0f8f96de7a53f35a44f2b437e0bbf58e11be7d6b3dbd2a18c4460b30984e;10020;1;2026-01-26T12:28:22.746Z
|
||||
3b99161b55b8aee1f5ce1dde73233ebcee528b76120cee181cf65b7f7fc11759;d17d51461636f7f8883f11563e2ab2d855f97a27da197f93a3000529353e6178;10020;1;2026-01-26T12:28:22.750Z
|
||||
bb035d6bce8566eb4161aa518321189fc8868084d50925fe579eadb5b5fcdba1;8dddfbbbbc540b483334cef9e7816126f9e969b67ba38775dedb4ebe15ca438d;10021;3;2026-01-26T12:29:22.579Z
|
||||
f8296d5946d8d1413fa3aafdda64628fcc03fb292fb68cb41915b9a81aa419f2;4ef722d2b451c94035c02abd41bb8ce2b6071256f8d8ebc40db41c5474933f05;10021;3;2026-01-26T12:29:22.581Z
|
||||
e059264b8305d634a6b1b1cbe543fdde3fada7b17d88e863c43e1cab244590b0;0ab2ee7c97535ed85fb7e6a569b6915599ca6609d5c6c1fa209fc30600c62519;10021;3;2026-01-26T12:29:22.584Z
|
||||
d6731d0a9fe6f46a04b83a30c1e13eda93cb9e073d3cd1c0cc89acdb7252d0c8;e395a8d1998052c8d6b9089799c786c470437de6dfa40c81263f917f822eda28;10021;3;2026-01-26T12:29:22.586Z
|
||||
5c8c9d742c1a0187e03750f253e2f5349d37284b5ac615cd770ed7579b8e386a;19d9b62523043840f3def78a6f7802c249ddd1c0f1315fd8f8166f7853db0633;10021;3;2026-01-26T12:29:22.587Z
|
||||
6e9992c1372193ab8374ac8ffdf657e250a8231b52515b535ee14feac6d27c31;ac91d3873225ea3b46f55d1cf10b2964abe229d11f843bc625e5359eccd35a3f;10021;3;2026-01-26T12:29:22.590Z
|
||||
32248c980a8775b555b6204f6519b2875bfddfc4007c52a05588bf72c8926252;5c32f9ee93db661f7258260abe2516f76aee484ea14e6e844f7936ef8cb95852;10021;3;2026-01-26T12:29:22.592Z
|
||||
461af11e5b527a880bac3059c90a97d75472f87b842550843fd606cc99051d07;4f2086e1cda0c507a770435864d4f65c49695c863856b623571cdf2be73aab55;10021;3;2026-01-26T12:29:22.594Z
|
||||
f9b1a8ab9a458bff605345a0f4dd5338f21afaefd18478ecc97873f51ab2b8ef;3b4d793222cf3598693073260be5286e5d3bb369309e1aad694a4955dc2d7c5f;10021;3;2026-01-26T12:29:22.595Z
|
||||
bc2f23086a88373971369f74bcfa2ccff3461fedf175407a2e8c024822ecaeda;8e966d4352a1f5e206f8b7dd6d21ff9f8bfe070b1ef693383ea182bb4c082f82;10021;3;2026-01-26T12:29:22.597Z
|
||||
7d6e21ffaac1f6cac7124593c6f9444ca0b79ba3223cf462262623ede5fdae42;ebc2817ea9ae5a9cf9eaa99869163551e31166f0974a6403894198aac641e983;10021;3;2026-01-26T12:29:22.599Z
|
||||
0fd90fadc19a0885d7bec6e2bac1dd06b4c40782e13fdb46b935095ee804112c;5d665d78705cc873d323bd370a9c2c5f57dd81e57026bddd72fd9221c41b3dcf;10021;3;2026-01-26T12:29:22.601Z
|
||||
8900979309224599644e03a4c4dca1576c8dec52ece0e5368645902a68c3355e;52df5f1a36522a059ffd868a1c26027bd914231890f7732b6ed879e686a780f1;10021;3;2026-01-26T12:29:22.603Z
|
||||
a1c58adfc59922991622b5c6b8959ca0ea4871f31678dca059429d5e083ba372;6de504fd0e6fa8ed0952693ded7a75b3df5141f2eca41f49a145013dff8bbdfe;10021;3;2026-01-26T12:29:22.605Z
|
||||
9e6fc531c4ef1a81e557b03ec0cbe11c7cf0a680c13933374a319c9d65370f08;888b15d85be38364fa9d0dbcfc24d5ff3b4037e07a350d2cc9ca815a73c8c418;10022;2;2026-01-26T12:29:22.613Z
|
||||
4e2d87f5f08756527072b03e06791cadc75d36bae935dacfd834e7763278133b;03d97e95d8aec9af4482f6814b90fba9edae882fae56030e28bc977803e1b224;10022;2;2026-01-26T12:29:22.615Z
|
||||
0012093f3f355aff1d2aae976caedc987bc3fbc0338f711d2825adf476bf678f;b1923e00d40ca964f1b48af857423395bcce21af337c18020b85060d2ac31c48;10022;2;2026-01-26T12:29:22.617Z
|
||||
7116419e892c1eca4f9e679ff17493d498cfe1279d151c23ec362d3f0af2c879;0f632f02f87abef26776dcef9a26d337a4d1d7c131858892f7008b18efaa40c2;10022;2;2026-01-26T12:29:22.619Z
|
||||
bc003a2c598a8b76a027e2a8508e7bb2a8a7a49434df6786d6652d1d3c309242;9c22b5c006b36699f9f5650391b54a84ee780cf16a7a0c278a06314f205bd7f9;10022;2;2026-01-26T12:29:22.621Z
|
||||
aa27cbdde8b3329862b5c61d84efeb6d54bab115bf8abb0d4dfe60c972df5ff8;d9e116673dd363b824ab20e80c15ebd97965fa5df321822a1af56fda44f35f01;10023;1;2026-01-26T12:29:22.631Z
|
||||
e2dfff8e9c4635e9769eae86c670b994816bb4c327681256510acd5937e36ab3;6827e390053ce8249588f29c18fd98d8669ef634a5bf8325012dd9152bb2a019;10023;1;2026-01-26T12:29:22.633Z
|
||||
a049bc8cb48e4bcd2c3dcf6fb735a4171845ce3e94feb052be694b7034abd0f2;98a985f466fb9255841222aef0307ec1e69961b1e473aa2714f35a95b8088722;10023;1;2026-01-26T12:29:22.635Z
|
||||
63e276268cfd85c50c61a4b4a9d19160a2d285a5d85af32173775f811c685fb6;a3a49f440e2eae4cd1d120c13a8c75da76894bee92a6c2a70fffe0ecd931283a;10023;1;2026-01-26T12:29:22.637Z
|
||||
a2fe39cbd08d079afd5e4b3ca7413646a178813b069012c130ea59ca30ca86c1;6684f2d14409e2099c9f708635c6139bf6cca04ca5d04db1e9165f62e1c22b55;10023;1;2026-01-26T12:29:22.639Z
|
||||
8b157676ddf31d04895f9a9b3664a3996c111a969d7e2ca815aa61341f01359e;c0138ba3453efb9f1786717a97b54ecf3d3392ea4e4e1a7f127a433303be0e83;10023;1;2026-01-26T12:29:22.641Z
|
||||
be7ecf78a74721f02b5df760b24627e817f9ce1909b553f34e5d67496d8c9be6;27ae059415cf0950d205c24aaac35ab665222acfe059e9f9e8a02041f081dd55;10024;1;2026-01-26T12:30:22.624Z
|
||||
95c592463fa73b086a9461b437ab2e6f3f05da79355bfc5068600565259e8a10;7ebcbe974475db9906368865f7a721ab6c1c1260ba485553a142d45e72acd665;10024;1;2026-01-26T12:30:22.626Z
|
||||
f9fa9021b42435e13a67e1873fac94b55edb63b004dc942d7ad41040a7b3231f;4abdc22866b45a71c2096c983aaaa948db06b6ef8fd52ffaa03e0a5c119e9169;10024;1;2026-01-26T12:30:22.628Z
|
||||
357d3f8f9dadae8e8e5fc4a8247a3d071f79854764b7d409f3cebea6097abdc5;015110387cffd2a1a8c84eec180f20cf6b30f5fdfcadb41f546c99d737646cfc;10024;1;2026-01-26T12:30:22.630Z
|
||||
fad156085d8728c27d246151266d8d5d264f5aaf65b91a45a4275a29b851a4d9;198253f3a4d47d0ba6abc3759cd7d18a0833bc531b3bf20492ede87311907001;10025;2;2026-01-26T12:31:22.643Z
|
||||
9c0c902fb1a42ecaafd3f8cf1e97af58ed4b220dedc8ba014c7a811bd472404a;41b0d984b0e078a389b640a0a8db67b44338bda08d83b1a5769b94a7d3515e09;10025;2;2026-01-26T12:31:22.646Z
|
||||
a313f581787200151f87890674763b0092217cf279896c4168c0f911f204a8d9;ed46068e0c04cc15b23af90c74c2e2c0594bc48cfc082b5b864a71ac8b774b3a;10025;2;2026-01-26T12:31:22.649Z
|
||||
b52c2e54a5e5859c2219e75a272fa708354f273720530e6f55b3a6468d608aa0;e10fd8bac960e6f79a6a6656fd77f677a0c0a75cdf424f939571e84589c7144a;10025;2;2026-01-26T12:31:22.652Z
|
||||
eaaab88f5763aded28f3fed0748aa3f630c25c3bc48c7750d679fbd1cb17049b;018f03f82253422730c4889776aed5738b5c8a8d7a4feb8ff961953672959962;10025;2;2026-01-26T12:31:22.656Z
|
||||
c10883fa05636a50c3ba452bf68aca0468ae6761ed1f8e8069e2e68441996fde;11abb77b20c03388fcbf0496a86fa6a1eb71c0a4c2315f8cd990174ec28cbb6e;10025;2;2026-01-26T12:31:22.659Z
|
||||
c5268eb60fa2b222b5001ce7a2bd573643ed513aa46e412ac9bf3f24a7a431ca;a6774a189a89c453dd0fbeb69844be78881116c8ecfd9248aae3ae777bccf1c0;10025;2;2026-01-26T12:31:22.662Z
|
||||
5932f8805f60b37e484ffd8f9c937fa54a02930cc7a2c138b16c17db8f30c73a;00f7380b937674a3e70bd898d4ae58b261a83a1e4c846c3fac33f7f5b0fa6af6;10025;2;2026-01-26T12:31:22.665Z
|
||||
f765c2f9d74bf4a680d627a7e5897df36eec61105ef0af63eaa865489e83ff83;a3ac6e1f671a18d98eff3ac33368486bd7b3b87d76da0e9f26fd68deca7c01fd;10025;2;2026-01-26T12:31:22.668Z
|
||||
8a744d57660384cbbe610943e0a8693d27a9105fa85e0b8839c47473e9417468;05427ae591d636f39d971e6c0a134958cddf4fe99f36e6b6a2025c1b692ef401;10026;1;2026-01-26T12:31:22.684Z
|
||||
07270bebb8faec8f126e055cef2b157bb7e60f2e8bdfb87ade8499dd15d6a0e5;3e586cedab72579bd77a24864ac87af919282ab6511a62e1d348f3bc01ce4b3e;10026;1;2026-01-26T12:31:22.688Z
|
||||
1c8282aefcdae8888d069bcef06e0134596a056cc40fe99489dd1af5339665c9;0280d672cfd3bcb946eec9ef7a2005d70cb55cd45701df246ed3be7f10d9b957;10026;1;2026-01-26T12:31:22.691Z
|
||||
a7da7ff53fc9aca9ec55a7b9927958509b489a3609a574aa4c10eeacfcf0903b;82322460b997f340b8678e5c072c5ab71a5f2837edbe0792ffbd53ed6905fc6e;10026;1;2026-01-26T12:31:22.694Z
|
||||
d67ed3658dadd79c702d14353d17af3c9159fafbe670c1c42db8f7c248821c26;071c372d800139fe35f3dcef3a9d7a5dd07f4b6daf04646a4e0b8e92012d6074;10026;1;2026-01-26T12:31:22.699Z
|
||||
dfb8cc7f615629ef9458c348d59289605973c072dcc4c978dc5ba2ecf4211890;5c90aaf9e1d279e4b35a61a0b3f396d6d2db67b09fd6f4809cfcf7dd66afa197;10026;1;2026-01-26T12:31:22.702Z
|
||||
0efb2b16ed3aa5d90bd82564ba04e3a70ca7d3991b0dc1e0076ea81073e5c6d6;ab1e860a9f2a8318eb1c2928ac376a6046fdbf7d98bf81a3efc0b676accfcb9c;10026;1;2026-01-26T12:31:22.705Z
|
||||
bea94eb73195d7f5b87424ce25b360506804c5b9dc535e035ff6766e5f0f11ac;b572bb12003a434bfe25535cd2cc14ce860c36fb3d3376a2f2b7af84b4d2e1c8;10026;1;2026-01-26T12:31:22.709Z
|
||||
9f22f372907bd79600f5b4cc94654d355082244857fa551a03626de341e692f5;74a3107a43f0489173d8f5b9a54b69e19fc0113fd22816e31bf30f35404939cd;10026;1;2026-01-26T12:31:22.712Z
|
||||
587a2b80caa0f9edce70dcf69431c67173174df7ce7d7f3a80be64308e810737;cbb1d67843a786c792bff0e268616531cdb8a15a121c77e077f9c065bec9ffcd;10026;1;2026-01-26T12:31:22.715Z
|
||||
0f984d5641396d5008997be3eef2120349fc30bfd54bba152e136429af753fe7;506e1d5d016ff6a5885e6d98bf2d3755116133d09edf8348a2946b6d49651013;10027;1;2026-01-26T12:32:07.295Z
|
||||
88739fa0131ee2e285e19b55317186ead856421b5d7934fa887bdc8887e88b4c;e5512919a8fe47901ac9a47e68d0363944e088ef516fa558a9d5c91863d02788;10027;1;2026-01-26T12:32:07.301Z
|
||||
da726dafdb447b1bb63040eb73b5fe08057e05fac72befb9032f631614e0be36;02ccf3549e98962af8fb51c2829ee045a7716e20dbe853eadf97573ecb00e2c1;10027;1;2026-01-26T12:32:07.309Z
|
||||
4e44735b9cefdf56e7758db74e3a4b97413628a6662ba7e0235acd3610d99d34;4c910ef2cac32877a48707cd9a3c8f6a2fed8cb30b4bd1e0374c9f9af48bdeeb;10027;1;2026-01-26T12:32:07.315Z
|
||||
fffc790579acb6d6a60eadc834a6cd9c138578c486d510678392c32854a0f922;41d321d9e558f271d8fc393d59473b9695d8dbec03fea67da221f942690a6df6;10027;1;2026-01-26T12:32:07.317Z
|
||||
5ff70766f1452c35cf5acb876f91c1e02f1d498305603233199820713336cf7e;3c2e0b383b1f69fe537081bcc80b20079a945f5d9cc7783ba1bbdf15f8ce8230;10028;3;2026-01-26T12:34:22.651Z
|
||||
83b90e15b72b1c318356f0e0a1aee9fab90532072c45aaea030ecaca28de8708;940800fffdaebf12a7dca4eb3f866dda627e878187c986a24ebc236b3873494d;10028;3;2026-01-26T12:34:22.653Z
|
||||
954c4a146bfff503379b44a022fde18f0d79b21f695ba8f93e7ba97240c36a31;bacd9dfc8efe154de45f5768bfae80f44d13641be49b835061be6c39423cf796;10028;3;2026-01-26T12:34:22.656Z
|
||||
3e44dfd07b35c052dd0f5f5b3f9158b54e8e2079d7d7b6fb824a570e0835a3ac;e3b7a304137ce832476ccd6aae35dbf3b131b763c8a0ffdc00e1a486e7486ac3;10028;3;2026-01-26T12:34:22.658Z
|
||||
c97554b541d00d158d15e77a8e9f282568865953c2d924eef99cd69530bd124a;7ac058b13af44d8ba014fcbf4e2c0cd42edf5e9db4b9a0eec1387c67f05e7ace;10028;3;2026-01-26T12:34:22.663Z
|
||||
79e83b5d7ed7aef3c40efa3881ea5b3403bec04d1c09ef3df1998e573cb3342d;d26b6fc7b48fd7814828086895c8c24c95e170e7d4b6df144c68dd47c2e25c17;10029;2;2026-01-26T12:34:22.687Z
|
||||
bc5c94fad0593aa37f61f60d73aa60408bed61454ec206d59a04f3159ec294b6;24c7088efd3ba334b4af47e499ea4072d476ecd3d1e1ddd4890901d733d87a3d;10029;2;2026-01-26T12:34:22.689Z
|
||||
776824a648028f90bb2f270ddcfe9503ab082999cc3da6bf8b037f61b28429bb;95f7f085dbf3420f4016c4ed69104ca439dcfd626cb75a49026310eced37445c;10029;2;2026-01-26T12:34:22.692Z
|
||||
9763539c1039d6bee728cafc96778cbb9428983961135d1d64dd823f36639803;c7c5f3707839a167304fcec3cef834e371fb93af950e65535dd2696a460cd581;10029;2;2026-01-26T12:34:22.694Z
|
||||
149a8d8503eeca97959d1fd4c77cb259991c8b26e17148d13140b63e88f94906;68ceee788ca8bf3c6da826d33d7b61fafe0c9eae6defbbe097f16c1f00ee098a;10029;2;2026-01-26T12:34:22.697Z
|
||||
347c7c375e27363388e64e6cabe4a313a4c9b252202e609d513dc1ab25ebca81;2a761db1fbcd06debcda59fa242c3919788ee9dbb782205b2d6891976372318a;10029;2;2026-01-26T12:34:22.700Z
|
||||
5b35405ddf463031a148bf398948b6b1f4810d9421f15232443a7188371e5e4f;2b5aa5bd08b0397186314476259ef2d273f37c9b629abd84def338fd4ec1479c;10029;2;2026-01-26T12:34:22.704Z
|
||||
68564c251621b51a2b8b0f2dea20b6bc56d9a91d438b23cf16589abc4655c169;c122638d6aecb4365075a90da0620b6b937772e8cabdfa8e0d301a5a80bde4ab;10029;2;2026-01-26T12:34:22.706Z
|
||||
56c2df21181bd86f93d6df0b7296dd229a19231434a4b6fc14d3b8a9c5bcb3fb;c6d5bb4a799f87d6e0d75f7852a236f814958d15f957d97ea8958fd56c888ab1;10029;2;2026-01-26T12:34:22.709Z
|
||||
3747d9c5aaa3ba72ed2538de2eccf9ecce8e24e8d4202a3c560a88781640579b;92464c99cc8fcdf8301ee24cc6d8ddd0084c12d9a652f13a040b90f8d3d670b5;10029;2;2026-01-26T12:34:22.712Z
|
||||
5e66be99ba58199f15134260ec0c4f4afd68c611024763a923a385caf2be2a8a;9dac86d7ec8bf030d0b225f550065015dad996049925b8ddc5361816a15ce6b7;10029;2;2026-01-26T12:34:22.715Z
|
||||
15f4eaf0f5b5884e21c71739b7bfd74cbeda13022378cc118870d619d48e6a44;421d79a4037b5d3b723991b8abb5e2808f42a81bd9f7057136fce78a8e6d56ce;10029;2;2026-01-26T12:34:22.718Z
|
||||
383ba6b066ab0ccc532e00db240a82e2db560685501ecfd6897918e7594970b1;bc005040c5e85f4456b5c8b5a1972295ee9da94a7ddd37556ee46655b75edcd9;10029;2;2026-01-26T12:34:22.720Z
|
||||
77659374d39726efb270e1ef28437b8421305957ee22db97d60e9f5a59d32369;77792d7509240b30efde17209022944f476310513f9120289f0b2953b98f64e2;10029;2;2026-01-26T12:34:22.723Z
|
||||
c8e549a9a2f4328587446b025ac93bd42189711e9f3939eee5d472e065a6b435;eaea7a218f811782f15e3f3b617a96adea094def07f8912adb747a2c80dc13ef;10029;2;2026-01-26T12:34:22.725Z
|
||||
a86c2a06103c60899ff1f1614791659b2d6f9639f069ed1df3382b85e8336afb;a148e082f4469ce381a59cd27bb9fec38b8d82e5876f295fa02ee0f7daa6b0ef;10029;2;2026-01-26T12:34:22.728Z
|
||||
bf06c4c35972c7dad3b3413dfa44f28dcf77e5162203b5d73a2d87d05d946967;2bbe5d1d1c27c3975fca57f41a0ebcda21917f5a3b5fb23a2f96dbf1dad853f7;10029;2;2026-01-26T12:34:22.731Z
|
||||
12465fc99d3c551433dd15ed2a71d6cddd4978046786244ec8341c718c8202fc;4a5002253913a2d03ec5c00133d92d571b9c734a5fd922c27824d8b49c767c19;10030;1;2026-01-26T12:34:22.748Z
|
||||
2fa16b1485ed13609d44d48af5540f251270e173743ff5c195e528dddb92f61a;950125413a399ad4e80cabaacf8a521f7dbbd1e64cfdf03b77bba6dc55455123;10030;1;2026-01-26T12:34:22.751Z
|
||||
ff8bb4c555c3beb03aa5a8a189f70bac1c6a89053bd6f71ba845aa79ddf8f8aa;9827bfa13d5a7d789762dcb0d9e4c12dd309dacbcd9ef62ddbc7544f1eb32858;10030;1;2026-01-26T12:34:22.753Z
|
||||
89004d3d8b64cc6755d70d247ee08034f753962acfa5b7b8bedcdc86f0b89f80;cf995ae815bcdbac79fe17c47b122fe83e80911b8fef717dcbe62d4bf97c73a2;10030;1;2026-01-26T12:34:22.756Z
|
||||
3b2ae5211f3e5604bd8f3461e5e7e5cc62b89d21a6c84419466664352c37f87d;b695106ca3359f7169462f5ebeedc241c5c12e7d5780f360ba1341e84aab2ea5;10030;1;2026-01-26T12:34:22.758Z
|
||||
1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef;84e2bbefea51cb6d9e3483884b86e9c00efb4daa9c317e341b1a855d7a1fa2d8;10030;1;2026-01-26T12:34:22.760Z
|
||||
8b89f41c65029bd3640b9726b94f8d3520de6b87ad391c88c9f6b8a279d8a07d;9741c7daa1536bef9618a6e5492fe4880697534a032560449f3083fec2f61206;10031;1;2026-01-26T12:36:22.604Z
|
||||
0ec9f89bd1100c8a79e02f05c98b2a6816734fd8f7d9bc37d20e0120eb02c6e5;0e23ad001879e2d2614a98a9dd5fed2eb9c7d844555dae7978ec8ead35606a59;10031;1;2026-01-26T12:36:22.607Z
|
||||
25281f5b61bd776672eb228c2031ba7dc0d371c842084c1de04a1cf6d32c0188;ad269f17bf4808b3d6cfc6b97f71d228461bd7ef4111dca59506f383b7b301a5;10031;1;2026-01-26T12:36:22.609Z
|
||||
31a812da3df2d0893f1134dbddde0d234c7f8222b999e607e7454ad5e2364adb;a9b1fa05af2151e5707aa0383d89e31d40594e61c1c0272921387c3c081fc4ed;10031;1;2026-01-26T12:36:22.611Z
|
||||
b7598d31d899b93849be596bfb8079184f2131a7e263bb06deb6ceeca52ed824;7f565e9b7098d828acd66b31628e8bf71441825deb77c36b0b58c07f655bc901;10032;1;2026-01-26T12:37:22.611Z
|
||||
fe4fb8c3a194eeceb3fdd45bba7854cc821487cc3e2c88f56eb014dbe8358ab9;c7bd9b8da1b943e98a261bc1b7f823963ba4d1013de63f5053f33c1241553539;10032;1;2026-01-26T12:37:22.614Z
|
||||
428a425d0f97d482e2bde6a10eb0926d2fe4a5e0740e84d2f70920db1ccd4d2b;f44c3cd96071b3ecca5ceea0d48817bc1d96abed8dd33e66f8a1de8a9a573256;10032;1;2026-01-26T12:37:22.616Z
|
||||
8a5c4acb8fe2c9e097de8c21aeb6c40605491032b58dc59dfc54f813cd69422f;ed7a462bd586a0a7fc92a635e6ddd92335d81a3c4a30bc5a7bdba439bc0d1b5e;10032;1;2026-01-26T12:37:22.618Z
|
||||
9d8b51a6fd6472167438b5228648c7ede148a765b7b0bd70a7b194a224034073;19dbd57cda1aee5ac7f37f452af6ffc56a97f26248786b0fbe5b7963ff0f815e;10032;1;2026-01-26T12:37:22.621Z
|
||||
9bd8682fb1e8d3974a8eb32e99794b3dd1eb68809ee1cc0f1091ec25b0e4acbc;3d523fb899fdef5780e534ae800f9da48b4313897d72fc1660ed34fded035b63;10032;1;2026-01-26T12:37:22.623Z
|
||||
dcf8945cd7adc0461f7cc7658d20043a70e89db587c58b07e32525463b695ff9;b0bec6e339ca671a54b21e2ac261891f552299c6dd27e784f4ba64090b65c763;10032;1;2026-01-26T12:37:22.625Z
|
||||
c0e5e84a0a598ed4212522f2083b2f936265029cb8cf73d782f2f67fbe4c5a74;f0dda83b5949c473d166f254de22fc2be3ab561d4a02da89ab8bb16d08e36d70;10032;1;2026-01-26T12:37:22.627Z
|
||||
eff5e73ece563f3d3aa52cf65814704faa82322a2e74efedf206d2a657c5e034;a29eef5761f79cae71d14129118ec5971b0c45e60034a4d2834651906ece5787;10032;1;2026-01-26T12:37:22.629Z
|
||||
6bb629df629d819a18b894177953d1ba35198bf34be1500844fdc3f17c29daf0;6edc8154fc171cf67baf5ba03629a09218873e25eb31e94c39e7a06ca9c8db87;10032;1;2026-01-26T12:37:22.631Z
|
||||
f9daa77af1ba5ffd094ff5b203e2306cc004ac7770d01d493adca5eff1d2ae22;5ffa632d429ea1860501569b9ca75aea164b37be1640a033ae23e1448700dc89;10032;1;2026-01-26T12:37:22.633Z
|
||||
ca91b8cbb4adf9563861b8ac46cb5a7d8a7a1b34629839ce4c05c24dbb9260b3;34c96d739331403f43f7132944e951cbb89cb7fec2431369a3004a0109a5a391;10032;1;2026-01-26T12:37:22.635Z
|
||||
79eeeb9e885424e6377228d58709d8e7498c419f3c70450441e2383a94a03af4;ed9e2e7d2518bfa7d968904de10e7ac5820820ded845df3bde3def76a37fae93;10032;1;2026-01-26T12:37:22.637Z
|
||||
ed44a34c1dab4fc336dad61eb830dd9e80999346b0ee906c8f0884e8d3897d8e;623973f74350741c0903b32a0ed2f67bacf0800815674e8f6e72383f5ab9af96;10032;1;2026-01-26T12:37:22.639Z
|
||||
ed10e86fa94bd44001ee300e93f0b3157b1f2c250d411c539955e9c87ad8fbfb;6db6e2a129a07bd7e838e54919f80101feb5455e23471e6505fd5a482c42929d;10032;1;2026-01-26T12:37:22.641Z
|
||||
0bab5e62fccc5086b480876f41b20f7392b428f56ef2fc1b5a75fb575e854bbd;8111c17420ef7986e73959059976a67ff67b901cdb593edece8a63449b64dda9;10032;1;2026-01-26T12:37:22.650Z
|
||||
7a3058301396b1ce61329d30d5f6fb98246f76d69894898fe6dded7261c949d1;712b30cffa9ba15c819f81565b14f781edf377b4e0a9b787c8921d55d94200ad;10032;1;2026-01-26T12:37:22.652Z
|
||||
2019e264298520a916f755b35c47e779cb1881c2a1b9aad1f2a92d1bd73dfcb4;12fabb038951502043f6975e93ab71c52930b8a471703aa5c40465d5c45d15b6;10032;1;2026-01-26T12:37:22.654Z
|
||||
bada5a5db97f0724fa6ed11fb65b542e96760f211cefd917e405b3dfbafe1289;5df6426bdf7ea1caa686f2445503cba0d8e946cc5239e5629e52d429e8d954b7;10032;1;2026-01-26T12:37:22.657Z
|
||||
4cec25415d3d268d6fe509a369cdae0a9461230b83e9d483a10b983a0c93885d;afad13dcf6c3f71bba51001df9ad8b3ab1c308b65aa539b5cc1b21be80b12fb9;10032;1;2026-01-26T12:37:22.659Z
|
||||
ae376708351650b5c2ce05f4c9eb7b88999cdf338d98cc0f2d1ab81ebc468b5b;4115788a69fa69e9d0e2a5d0a0bb9640a346d2acefdfb3eee8bf32a74ae3b4bd;10032;1;2026-01-26T12:37:22.661Z
|
||||
93a14509852ce6888a9ea9172fd9201c17922e564fd70d695b7c4a3be94e259b;df53399368b2786967369a3fcca83bd3c92759cf47c91d0148de031ebb4665dc;10032;1;2026-01-26T12:37:22.662Z
|
||||
b383080fdaa3f46bd1f308ffdf35c1a43f6d334c17505dad895fd991ba3b4b33;29a281ef775205df3f0fe7902b7a8de9bdb89823496c9bd4baa6735fbf141fe2;10032;1;2026-01-26T12:37:22.664Z
|
||||
8745d7fe6b31aca80e0d03121cfb60ca83191ec81da686dc9983699c188884a5;d11cdc3b3366195164910319f1e24a14706d7756edb02733a1312c5dddd638e8;10032;1;2026-01-26T12:37:22.667Z
|
||||
0430ebb4c26aab48750e7b38fea7be878f0e3703f2da926f08ca1da6cf4a01c8;43af98ce01ad47f70cdfa086f017adbef31878726b030f513dbad864aa57ceec;10032;1;2026-01-26T12:37:22.669Z
|
||||
570bd1bb42337f16e273194faa3079abc7788d885ca8022041b73b2c792bed14;6b4d4cbb3d782d2bb3fc7e6353cc0113c9530e61532afd5989b2cea1e5f9f3f2;10032;1;2026-01-26T12:37:22.671Z
|
||||
8cd8bfb7bbc1c83bedc6a78c1d35da985a39875646c7f056a926aa2dfa939f2b;8cd951f340969f7fb88a1d6ab085c4462779f0edf86774021c2538a5fe4b70f9;10032;1;2026-01-26T12:37:22.673Z
|
||||
ec8208b4a4185f77a08d48c479823eedf8fa823ec3c9c8783f26d3b6c5af4707;c38be03513cad632374754f4907fc0e795282a4b411ffc85c0fb11c2c4628dfc;10032;1;2026-01-26T12:37:22.676Z
|
||||
16e2ced0ab8c2dc5db85d46b4dc09c0133f8349f9f452afcc5bbf1849f1be09d;f765ab0dca0685fc9808ab3adf44d65443a1cdb631bce55fd301b85cedb92923;10033;2;2026-01-26T12:38:22.620Z
|
||||
cf7e26f627c900574c4dcbd2adf53359a68dffa750ed6691561aaac75267a18b;3c66f4028207809450587a71e81f4570ab0190707fd5f15d576698ed607ddc55;10033;2;2026-01-26T12:38:22.623Z
|
||||
f46c30689e53e82f09f4eef14211bc20c0ed4ee15f99c79dd43e96efc29b511e;0a283710a0f3429ff9fc6773be90e3c217b4db5b53d52059d1f2847a2200d490;10033;2;2026-01-26T12:38:22.627Z
|
||||
806c2870d678ff5755903581a823670a8b4ff8f892ec31320573ff9c2aacf77e;da2828b56ed9eac49e599f4a1dc7d46d87b47ec38934dea875e519c03af6aca9;10033;2;2026-01-26T12:38:22.630Z
|
||||
88aae457774c3860cb20bac81564e268cdee94c642a690b63b9cd1d342927a1f;78d48ee1f1d9147a7046d574d7d4cd77b3b4cc5a5b3c5ae1228f3a1f68a679e8;10033;2;2026-01-26T12:38:22.634Z
|
||||
ddade8b1654ad9a59d5938c5f35f8b3f73e023b51dc2c4f041f14eb099bf9122;b9007de8f2c0ec0ccb0be29ecb32d956babccbe8dd37faa4cbec5618b642a5fa;10033;2;2026-01-26T12:38:22.638Z
|
||||
b6ff278a4b14018838f59377d4e883cf8be7d974f1b1d63a6a27dcd59bee8e90;a1bc0a3c467dcc128a63a004ef64cf73df6116727b67f5383c41d3d413610127;10034;1;2026-01-26T12:38:22.656Z
|
||||
e8c5a3b7bc70618d08fe813f6bbb5f0fe9b80793e3526bc19adfd7e4ac3d40e9;1a21ae185221d5432e906e21b3055ef7dab152af0c41a5899bd281d3a683aa36;10034;1;2026-01-26T12:38:22.660Z
|
||||
f259259ae16e6404d0d3f6cf5309c97fa81de0062d3e8d233351f4f8e30a1a04;2ae2562fe7652781904b1d0b903e688440aa78c08d54ba75943b453526f18a42;10034;1;2026-01-26T12:38:22.663Z
|
||||
4868b20631df9312bb0c9688ff1afc1c48656c9ef700a6ea831bef33352d36c8;b921b9bbc9895e0ad7551adbddf80ecf608cc6e65a8dd5ad98e212eba6b71444;10034;1;2026-01-26T12:38:22.667Z
|
||||
dc5e6045c937f7112e98acc8cd86695941610abfc1071f6d52bfae4e3335aa58;598656ab03dc74911ebfcf9dc215ffcdc7b302628323110665b71c8cdf6f9b61;10034;1;2026-01-26T12:38:22.671Z
|
||||
145c9837191b55234be168c3832d196c76c047109bc0262021e5074018c068a0;6a2ef5b01b9a501dc969d59b1b8026685f1b9a3270c57c87800569d76d29f363;10034;1;2026-01-26T12:38:22.674Z
|
||||
a79d81bf602bfadcf3f5ad1e67de9a74baf5858d8f1a60b2b34f697d06264075;ff05e5d280d0fba4d4b6d3b776ecf32303979f644f312f79f2159b90fb345a72;10034;1;2026-01-26T12:38:22.678Z
|
||||
a2c4aa6cdc9390fc8b7e323c042b76a0eeae8cdd24c62d73d0860b4f99db5ec6;8b5a8e8fb614db8f912e14b4af13e727fab4b34f0c44414c55dea517212a35a1;10034;1;2026-01-26T12:38:22.682Z
|
||||
1fc4a7d28a510edfd8435fbae40c9b0e8f20818a3a90ae91caac5afa402fa5dd;7c4803a19b3bcbcc33a1d9787be11291fc30ffc122f8bc9ba26ccc0de79371a7;10034;1;2026-01-26T12:38:22.685Z
|
||||
813db9d1a8b5d8c40e5547ba12fb3a57ada63bee29ebba1149588ab29e1f1591;b6e698f1f128fb7c94a3ae037dd8210f5c4e6039a285487485679fd1d9e171a8;10034;1;2026-01-26T12:38:22.690Z
|
||||
b4cb22a7928b7736c995e15ed28b506c4041bc60a421458240e46861f881e6b7;723694b1521c0cd77964845e33fa771b91b48088a9f0c4d279f73306ae7518ec;10034;1;2026-01-26T12:38:22.694Z
|
||||
50d0ac8fa0255495911634c98b300b20273c22c983446847eac0876a0ad37546;5633e56b72b89654ea1b19d00ffba399a289a98910afc9bf584fa5f13bd4ad3f;10035;1;2026-01-26T12:39:22.627Z
|
||||
f07dddbb13c8483c576b260fdeaf3316a43e2cf28c6e671cfbdb874e0120b11c;2260e84d07e3160fe596161f5cffbee154c7e08a6c6a1c60afd92853e47dd084;10035;1;2026-01-26T12:39:22.631Z
|
||||
2dbf4bca429f0a680fe8fbdfa330c20b726f432bca6c463f4c56232bd49a7c65;6982143e46d20290240aad69878ba173a6b1105d509bade7571f5d3fb3891598;10035;1;2026-01-26T12:39:22.635Z
|
||||
f8742fac9cdf51f57f2ceee9d59d460b9ab077ad35f68680662efdada51ad4d4;a7745bf29af3b6a4218e39c59be60b62cdd372c07733b5efbb1e5210c29af9ba;10035;1;2026-01-26T12:39:22.639Z
|
||||
eaa286dd391f2d3934a6be52fa443b08ee3e2d9e44d67699ca46de87ba70b2ab;2f094d9f3617c53714805b4a20ded5e4eda148ea32458df50823e04b1d4fb3c2;10035;1;2026-01-26T12:39:22.643Z
|
||||
348f49394077e0ba03763b42c38882f523ae3d7af57834aa0d6e035ebf8f1397;eb9133fcbe29f7e0d93cc7ddedb43234e775db41b2c94689a0200d4eae5307c4;10035;1;2026-01-26T12:39:22.648Z
|
||||
724e1627df138e39c4315ce9c8bd59bb1fd4a0d6ee1f2d063d474e383e173953;08ac32beeec4263d6e3d36fc9b1ab04f04e71c8f54f02797b808c8df4bcd7edd;10035;1;2026-01-26T12:39:22.652Z
|
||||
9e4450493d25afc384e0b8035e0494faf3f55dc0c3311b88f92effc8cd19bf1c;7ed1fb085f60c14b18f573823eacfd672c47de85c37764575ac48b2d1dc1ff24;10036;2;2026-01-26T12:40:22.558Z
|
||||
5ad9fdb8efefaad4570a02bfcbea751f2ca34caf60641d2de92dbf609bbc2d9a;5c3e986f3a05ff45b517f44c91d2353506045984f7bcb2cb12bf08f857c79d30;10036;2;2026-01-26T12:40:22.562Z
|
||||
98ce42d1da33e0888518c1baec46a9d61d6d11ff4bfe6ff2e50929996a25b76b;ccdc8964aa105661cb85e6a9ededee216c3d7aaf5367764f58f2f78660720b35;10036;2;2026-01-26T12:40:22.564Z
|
||||
9dec4a667ef564619b9c50f368d224a58aefb48407042d2e16b0a3933c801915;1c655c8a4565ff67bdbe42681b4d6c5f44a0e350a79563f7f111146b2bd92b44;10036;2;2026-01-26T12:40:22.570Z
|
||||
0052623599677719112b878a53f2c2c3eb50f89fc0bfe748f6346dd0c9e587ef;83db5b549ea36960ee133d1ff1bec38502366169b0e3c1dea4fc0d56a2f52474;10036;2;2026-01-26T12:40:22.574Z
|
||||
98d925e22fb738a085feeafe6e2fa8799d69519a0693356fbf7ac8c28666e1a7;b8027f413d3e5f533698b110b7fcee5479147cbbc34f1cd001a822fc68f44b76;10036;2;2026-01-26T12:40:22.578Z
|
||||
74aebabb24a885eddd4cb4425825c63d7844aa7d73c3dff21662acab2c026f22;d334e066b65a4e6ba03738f3ad71ac39b97993d07cf10156f937aaeb3b6ca77c;10036;2;2026-01-26T12:40:22.582Z
|
||||
e1191a89de99dcc5f3678932470b5af5cd728aef8ffa76ffbf3163e7d9a7001a;7148c459952bffcd28509416ab47263c1ef1ee066c33a9161eb4e34ab1e62a8b;10036;2;2026-01-26T12:40:22.586Z
|
||||
7d2f4c32963cb3437abc98b48f196c32400dbc7583677cb6435e2059dcbee14b;51625e4073e7996d43cb05af188a5b6c40d32746b4f33abcd47d7edbb703169f;10036;2;2026-01-26T12:40:22.590Z
|
||||
edc05557d97c2109517e5b8d6283fc26218042c5ad8b38d883cd3ee709b4338c;fd148294ee79ecc60237ceae3188be3fa84f1d2da1a288e1522fe92b2024d2aa;10036;2;2026-01-26T12:40:22.595Z
|
||||
d9b21768b7295ca3ae348469404433c000bc7fadca8b5530e72f2384c78e4454;2ec6c3561fa2824a4129f802808a3431f2f136a03463715155629800f291c0b5;10036;2;2026-01-26T12:40:22.597Z
|
||||
1f25244f53a6fd4dfa0c5b218049df95db52e8076ad1f589f653e140ed0a1179;42f6b17f10ab990fbdc8ee4bd35af202f8d965f8408765f92babc63a196e21f6;10036;2;2026-01-26T12:40:22.599Z
|
||||
5fac54bb48befc3c47e5ad03fe0c70a6ac912dc6de9c95b58009b5f6c58d9c6a;ed0ef6e0060887e6dd74305dea736e60d33b5db38793fb164883676ddd70d224;10037;1;2026-01-26T12:40:22.609Z
|
||||
721bd870f7558e7efa1b72e789af81567b7b2db8066825f459b2ecc083cbdd2a;1ea672a1483c43c6a4d7fbe03e2a6e580c176d29df3feff682e80ef43f7a0d31;10037;1;2026-01-26T12:40:22.611Z
|
||||
b69761f02349275cd51b6b018edcb1bf1dfa965a86a4e4ad604e193cfc5400e9;dfa33c068e3b0a7c25f36b76ce1966458450058cf6d2af8c0aeb1c7cc83da932;10037;1;2026-01-26T12:40:22.614Z
|
||||
c1962dde5a83d9c46d69723dae2d8559dca0352fa584b11626200f4e408507d0;a2e4e9582e957d09f97e98065cdf1cbc9f3f24ebe6f496ad3a92a5805a1b45e8;10037;1;2026-01-26T12:40:22.616Z
|
||||
57c2a2e745d543aab3f20936717087666509046440fc5f592b69c1ea974052fd;93f4101468762b1875b9bd9e7271f9d04619a03f555a546424a8a79017b471f4;10037;1;2026-01-26T12:40:22.618Z
|
||||
3e8c32ff18cb8e646ce177cbdbd210cd57d155831070a45db3beaab0e1048c57;581f7448aa0d4f5ad842f81d75311fd7b8f8e90d22bfc322791237ac3e41df17;10038;1;2026-01-26T12:42:22.563Z
|
||||
8166c82175d738009a01f7e1ab2f79a299f9302a9d39f3e1367cb73c6a4800e6;13256aae5bbd7cdf8d7dfba36c32065e046ec4ed6dddc3a5a145d09d81357066;10038;1;2026-01-26T12:42:22.565Z
|
||||
5904935d17207ccd84673e334c61bf0f4718ea0e70513a617754be84f89e0fef;51fec391033097e1e61dc7ecd62500e8bf0d3c7e42e9fe165c28bced5b71346d;10038;1;2026-01-26T12:42:22.567Z
|
||||
c19f1aa36df989fa26ee67e50962bb3828b1424cd9f5fe9d2dc810d305b52ad2;2331449e836b86f15d42d66a65831b5207e1492e6e06a17df744118aa23b8081;10038;1;2026-01-26T12:42:22.569Z
|
||||
fe44e86f626046b18f25b51170b135e993108c48914b9fea1d575b2413be2fae;44baf690a21e739e05681b5e46bb3c6154ba1df61ae677e2ee3fe8b142e9f986;10038;1;2026-01-26T12:42:22.571Z
|
||||
42a68bb8c9d468510313c1053102922338b95196d1c18cc00bd7ff553e7c4400;e20dff47715587ccf96977158aab1189cbec272c18ed6430d6d31579ddc102a0;10038;1;2026-01-26T12:42:22.574Z
|
||||
0c872fb788c6e8d4a4e2675af79943770b143456601da0c7fcb89cced5cf1f05;886e6afeb8f6b7154511910655df5ba46547b54cec3eb1cf972a78085fe31a11;10039;1;2026-01-26T12:44:22.561Z
|
||||
f1d1181a025fbc8acd638c4dc3c6bff3b2ea3864898aa82d83a4713df28d2a95;2a6d3425189af6228ac858fc81206da33ab9d1eeec6a5ea281f25753b47f9d1b;10039;1;2026-01-26T12:44:22.564Z
|
||||
cd5ce0b81b3f92f4244a1a01d5cd508c2551b825d754ccb0a3371b41b36a9861;e972c799bc987fe85b17f1ccbe6f5fae7792ed437370d8226dbf7b00285abd1c;10039;1;2026-01-26T12:44:22.574Z
|
||||
4a2e1317aeb28ac70a219074d8c35fa304b6212d748ba8ea172875041e8ae643;127ca9ded018394faa6e56a37194c754d79f429aa4da871dc340b29b2a0cdc35;10039;1;2026-01-26T12:44:22.579Z
|
||||
c0770e3dfb1cb7acb0180989bebd9da02a06f2bff0325b809de07322fc672336;87a4f69aea2fe6cbaf68b5a1111a95d87f2dbffe38544b6ce1dd99c26188483c;10039;1;2026-01-26T12:44:22.581Z
|
||||
4148649a18a57efa4318d8af663105533df74bb90563e1aed599dff8f43b9449;20eeaabfc9bcf78a877b05a6a3b78d55496f9e6212729c3f221df514992f4747;10039;1;2026-01-26T12:44:22.584Z
|
||||
b7ecb5b74ef83d21d646d605f0b89f4980daa2897ca1aad4461fd3dc082710a7;d8b215e75095ec6533fe209e0b8be6f1b89b49874a24295b2b9b79b543e28556;10039;1;2026-01-26T12:44:22.586Z
|
||||
0d088ba2f7c4a9a8e25536da81e3fc8d9316ae5bf9b07215081b4f77490cead1;a6f1fcc3f9fe3ef9a6397e7b52a27a297ea83e695c856522fff7ef0f06a25875;10039;1;2026-01-26T12:44:22.591Z
|
||||
8bba2d789232a58a39b5d22432ec243b8c83ef7054697bde31c0f3fcf1dc1e06;703b2d6492e632697e2c1802d4f3757213075787437c1a71709b03bf6656f1a0;10039;1;2026-01-26T12:44:22.593Z
|
||||
5c94c9083269bf152bbb426d3fde8198b39e6c507de0b2af0475a22f5da09358;70178bd3cde16dd8b1c0b91fe75757de53fa40e9f18bb97a53eb39c3516cbfa1;10039;1;2026-01-26T12:44:22.607Z
|
||||
1d7c0a94d7164f43888d8410113de77ef0db175cea30515b73547ad6337d5af5;518c600f15919a4b1bc246d87d5fe028c26bf3bb17ee3e5f65fc6a96b499e4a1;10039;1;2026-01-26T12:44:22.609Z
|
||||
ec7ae9b1c9def96147e1064fd83911044cb440a6fe56dac6040ac2d18c8824bd;6ce346b16eeca5de6b3818f203fab9b3f86c306ce0b249f04607ad671aa91cc7;10039;1;2026-01-26T12:44:22.619Z
|
||||
070235196df826385c9639098bea44d1ba71dbf3a1fb6464ead28f6e878a4cd9;d735a1e835bfef197622a3f3e4ca340c785b11f7a1cec95fc859b80662948ac9;10039;1;2026-01-26T12:44:22.621Z
|
||||
2502800ae88f5a0f2766ece2a5609f2a3c61c868d4c14b6fcaa4ece0955ba947;c48736c2b7ffc257036b7a99df6bd131b495dd9666d8a51ccd3e3270f057dacb;10039;1;2026-01-26T12:44:22.623Z
|
||||
2c361647a978f9059aa0df36284aebe915a689d5d0f93fc43bcb8ee07789342e;922289b9219d27e1f8c410e98a7d73381d3394f7b21714f9e543d38648479ed1;10039;1;2026-01-26T12:44:22.626Z
|
||||
1d7fa4d28eabb50596e6d5519198a723694afd902f95b185f2680e8f3e8f200b;d372accf4d63c6dd8e826d02ccdc164c310a40ae50b602b0143ff84f8beec4f1;10039;1;2026-01-26T12:44:22.630Z
|
||||
d267ec8dd6091ca4cdf48dfe83edbc80dbc08a1ed90c756347045b60e7f4c1ef;54a2c55bcbffb4fedbaf791f06b748e853a02c73793aa6afd4a1b1270bc13ef6;10039;1;2026-01-26T12:44:22.633Z
|
||||
966d2dd0a79ed33bf885cacbf5e45f209f52090173b7ef0e05eaf1ff7b8e2080;d501ac4b11b23bad4ee7e59887af8a6d18f9cef78280d14e858a0ee4b67514f7;10039;1;2026-01-26T12:44:22.635Z
|
||||
c5c499bddebd25aa2f2a05513372c82ad7148ed96fb61365804a410123c66fdd;c3ccf2894f6e0a08398a7e24680efa0fff6ee4282f6a5be6a16ffcd3a31271fe;10039;1;2026-01-26T12:44:22.637Z
|
||||
aac496bc0cb24c349669b5a600970905d5c67795df9a2cbb5e2b37c4add78110;1d11d7667d663e1501fe1d7786d2a9bae8a0feba789622e8413eb9b8aff6fc00;10040;2;2026-01-26T12:45:22.554Z
|
||||
fcac1ec5c4b2f0becef9288e334f979a5b3cb3ac1adc311e0d4c81b43092992a;ffa70c7876f838827b8986b93725545fb4e2dd85b671df1f63b43d39d912e206;10040;2;2026-01-26T12:45:22.556Z
|
||||
315fb8e36d8b75e9a7884866290e3deb901d983852b16dad350977dcb489da17;95ba19b208211334d1012412f48fba4dddf32604a1057765ba785e0db911090c;10040;2;2026-01-26T12:45:22.558Z
|
||||
05ff41b5d3770e8dd43f8a34479ba65d22368ee51f0b4ced76ca38cd8ba911c3;a4643ef593dffa701bb84547941ae5bd389e0a38a1c515075f8c3db2d4eeb835;10040;2;2026-01-26T12:45:22.560Z
|
||||
2e0cc8cdd2c375603b22a10893f4c00039916e767da89daef1366144be3612e6;e4b6d9c458f57c7ff66f489f2d943149666621e1b0dedda22bd2151f282ec937;10040;2;2026-01-26T12:45:22.562Z
|
||||
b758b50f88e026f62c3c8ce64df80544d57a7e86735fdb085fce03fc455bdecd;a7d7e5952fbac9417928a2217b08e7e5f85e98021edb3ad05e1453efc4e5ad44;10040;2;2026-01-26T12:45:22.564Z
|
||||
2c1728200fbd3218323839afd4bc1e1d12f3a947a080dc01f2859c9ae1759fdb;3c7cc81ad3a229310ca3293179ace4ee0bff2de7e4f385706cb8148c12a61a48;10040;2;2026-01-26T12:45:22.566Z
|
||||
70b40f20bc44e7504afc09e981f520bf3f5dce2ecb89d7b8a76c1d824faca480;ef4d20ed8ccdcbe79f5d78fededac08387e3f8e98e990d6383293bfa6ca1b652;10040;2;2026-01-26T12:45:22.568Z
|
||||
cbb85f5eadbc8301c93aa2a53c737f6e3854bf99e4f7c436274e5a9e894a91e4;ab3ac4a2e87d14e5032f24b4f5141239be800da7776bf9ccdafe8e96bfd57157;10040;2;2026-01-26T12:45:22.570Z
|
||||
239a3a35e42223fc6e4295704d79f8e6771ce4995944e0634ec6d0c51ab50e87;14f7f37d44116590d015c471b73fe00466758b6f9164841cba71ce512fcff557;10040;2;2026-01-26T12:45:22.573Z
|
||||
fd2f234eba48a1fef93cad98e2432b83daa312778793311be05c84a0ca4e4eaa;2068535c4a0f9aa7614fdd201cd6b2a93742cb971d1a78a73e1558e421dd0a67;10040;2;2026-01-26T12:45:22.575Z
|
||||
f1e4815673ab9100eace18961e7994b21c036ec389830c48dc8d0033dde4e376;d37e42606797f2adb44d149c7cd1d484eba9ccece95c900f1059847685a5d56f;10040;2;2026-01-26T12:45:22.577Z
|
||||
2c2d365496df1fc251bb561e44b8a39e551183b3c0afb4e68834d9afe63613fc;2dfb263a9dbf715f1e3c1d5c63e1a64ff1093f7fdf5b01a64699f4db5193d872;10040;2;2026-01-26T12:45:22.579Z
|
||||
208b06d31823567a2241223a50a1ad1f6b9f1093347022a66d4b5da22d612960;23ef5b6c0e3c2e7f9a377d03fdf6a2ef13826dca6a1db4af4c3c241e715e268a;10040;2;2026-01-26T12:45:22.581Z
|
||||
d4ec55096ba0337392e8d1963969d0765a750af5c454c8418ee5698940a74ec8;0cab856ee4ff7c6ebd880256df4dcc878ebd12c9cde7bdfaac8884a137ff4190;10040;2;2026-01-26T12:45:22.584Z
|
||||
1c4c97ac97a487d713ed161a1d262a0ad797ef7c4df225e5fd780fa4915bdae2;f9ab7e072b460638d32b6982612668ecf8f630108cc244eb7bd1f78673aaf791;10040;2;2026-01-26T12:45:22.586Z
|
||||
7e6d8b708a5ee12e9e13601a1e8ada48f9b6c016be3fac165d35cd19999dfbcf;7d8a59b080de4efb11276e5c3de80a2e1a5705e6991ffe67dafbd5e107c8d1c1;10040;2;2026-01-26T12:45:22.588Z
|
||||
a8ecd428457dc87c092f49c2fb340815ddffba9777f088f950fff1e40cd4df3f;8710fd41b6907d6ed332ae61969bfee77f233d8f996a6c53ec25663ca84251c2;10040;2;2026-01-26T12:45:22.590Z
|
||||
220a4ea504699933e08bb6256458cbae9677f0eb835b40cf3e3c7ce956414759;f9f270220e3a82645e40576536fc0bf07072a764cb0bc031d201c02f31133ac3;10040;2;2026-01-26T12:45:22.592Z
|
||||
1e54fece569cde5e1658a6d3b4d9a70b91ca2ed1c7651fd98340850aca6d0a6a;46e3aabae0f1720fc658c1302af5f7a99da7905b5947f9726a541424d6e875cc;10040;2;2026-01-26T12:45:22.594Z
|
||||
c1829c4d1b19baa800f9bdbd677e9c6938cea170b1dbfface85fd87ac0bfb95f;e2994cb82bc86d06c9364d3029b14e50b7334b767d654fca1ecbae3f845725ce;10040;2;2026-01-26T12:45:22.597Z
|
||||
37553b2012c6dd715b8e1b9de029e4e9a9c1d3f09f0bbf1a416b59999331403f;d5a02ae15302983ffff99ab20b8ff1c86ac62fb8444686a6217334a8e317ace2;10040;2;2026-01-26T12:45:22.599Z
|
||||
7a0fc32113398d97304268823c080ca53057db5dd3352ce1d4833d01232d239b;59b0f9c7f92659fca4b1a9b4dc62aeeeb9dded7af7081e4029c7e9b36e4b8e29;10041;1;2026-01-26T12:45:22.612Z
|
||||
d13c39551752757cf00e61826b3b171bb8aaca6c8137261e3c16330976306dfe;519c4ef8d60890595e5f78163d4913eda9dc7475e729ddf3007ea6be2876e65d;10041;1;2026-01-26T12:45:22.614Z
|
||||
745119ab0c4012bd8839e711bd0dc3d6fd592762d5c2980fc09b321b0e13b7d4;125d1ce873f5af74d2f64105ccdde18c89a5efb924b36d8ddfa9a99212da1e6b;10041;1;2026-01-26T12:45:22.617Z
|
||||
04140ba71b94c3dad4983c57dc7789f0c43d2baf362bff7e80f40ef820955009;61325afd56b2334c54294ad155898a7b920b4b9bd229d5281b95af62c804da6e;10041;1;2026-01-26T12:45:22.619Z
|
||||
43eb9c25adc3550b4120418a048c3177fdd66e1168a95c1f52afbbcc5d9ae7f9;43dcd80c18fb0d1badd3a2c05b1948a813149d9b0e757d50ee253c4bde8bda76;10041;1;2026-01-26T12:45:22.621Z
|
||||
a2b1544f1eb6f8f1110062ee814c53af4f3b9066f723b1ff6034da33d265554a;00d564d2b875208793855a472ae65aba4e323e825b057953670a83cbd54b287a;10041;1;2026-01-26T12:45:22.623Z
|
||||
121cdc0c9d19d088b98f4b78f8892d1d08f8129bd261b2ac52a82d0964f37716;1d1ee53aba0bbfdfc355b549bc5bfdf1400c2e567cadc72c77d87a1b95319089;10041;1;2026-01-26T12:45:22.626Z
|
||||
301a7fa73e84e4b38c19c04c38f1ae3e847915b0c4fc3f8ad60a14c652d6c5f5;66dc86996cc26e89124997a6862ed0d8dc8aca910cfc937f310207f4a6b8cf89;10041;1;2026-01-26T12:45:22.628Z
|
||||
891cf6e63e0e4e86aa7f574db1d8e6f7c462856d954042d99944abd77c162e85;08d189318b9babdd004a6c4be8080ce3fc711a5713937656a4de3994f8f1ea8f;10041;1;2026-01-26T12:45:22.630Z
|
||||
866e6875e2f0e9ccd2963e75b233f0b1bfd207ac0ccf51c7ba0a0d4321621513;f5e9f3ed52fb9f209c8802d5671685ab4149ca709c654b05251a823954d8d391;10041;1;2026-01-26T12:45:22.633Z
|
||||
382023419c1a37b9dd9a522da06a4e11e7a56140f84650896a284c51e761b0c3;2d099f6f0bf0b1902017ee22bf76dae85f188e59a16dac9f0d020b0cc837009c;10041;1;2026-01-26T12:45:22.635Z
|
||||
ec162f8f52f0324046d2b77773f47294156173cf2a4053a8dbdbbbc7a06ec80a;169e10df9971850a266543fa522f62b2029a51645ad04b7db16626f7f8d9e0b7;10041;1;2026-01-26T12:45:22.637Z
|
||||
efb3d6a9159f229f695be1d2cba591e85b874621ee73780d03166f403f5d5bcf;997f71e09230a4e6ea54ab45fde1baf942f4a69873487d2e2b5e095c057edfd1;10041;1;2026-01-26T12:45:22.640Z
|
||||
8063285105110cb51e698546da66b2cfabb7d6322b4cfa7499547101b58c5db4;08c1ca2a66bd95c7df96b5d505ca46ae0a09ce46699809ea7f1a565bac8d320a;10042;1;2026-01-26T12:46:22.556Z
|
||||
96cc4c617287e0cddc402e688eb9dc60be9c6aeb325ccc3cc04c82175d0a7020;ac7c7111ab895f9b4c8b47443d6962c42781b75bea1bd6b228f4cd63815fa40c;10042;1;2026-01-26T12:46:22.562Z
|
||||
1abfd8b8d4ca7877dbb8cb5b874c640f0b749058df3f6ce15285fbffd1606d36;7609db5e6877015dcb26d615f5b573e5b026320e17188e60fef459613cdadb44;10042;1;2026-01-26T12:46:22.570Z
|
||||
82ba8a9c46fada193793c05778ac852d5d9c7cd7cbe7d21de8c8d6dc8a56d3e9;36602aa389a45eb6d87274795162d918f6d9e8cafad758f22734a4545f8b6c4a;10042;1;2026-01-26T12:46:22.574Z
|
||||
169ccfb3f8dd2f362ee8c7fc7058956bbdf74379ec4f920d84272d54dad1354a;3bd6a8a90c248a1f759a2384d274bb4874dbd5c9a332257b2fa757f4ea91f2c5;10042;1;2026-01-26T12:46:22.577Z
|
||||
9e4bf8a9aa0f8a7af622a4274962274310a097080793baca5f70479e78d26db6;33d43eb3995c0a31a9fabc3d9229481a62360219ef5e6cb2987b76e41b29312c;10043;1;2026-01-26T12:47:22.574Z
|
||||
aa62ac3783f640880802045459dad58bdd69badcce55b73e52acf961ec6d2e81;e6d19a9a12c35023850c85158953deb615bb5963f84ad487a3b1646fa183013f;10043;1;2026-01-26T12:47:22.579Z
|
||||
b07b6731b6a04fc998940008958aff0d0d594f30bc26697a5b425da5af11718d;b88bef24c6610a7dc410fcaca64dffef2aa63eea8d3a24ba4ed56e9b6c05e89a;10043;1;2026-01-26T12:47:22.582Z
|
||||
7d51d33648a5308c95c2c239d25e768d7326d84cdfb125b305243c2632cba32e;71f205ba9dd9d76adb49df82411f754218d63ff8d2f157261828a6736d718fc4;10043;1;2026-01-26T12:47:22.590Z
|
||||
894b4d8ffc0ea6a03e0aac1da66ed481ddfbd349afc4b34740cc15ffebce82bc;cd9481a38d35b97ff7341e5ef7252451c864b877bd2487f0a5ee9b2afb8034d1;10043;1;2026-01-26T12:47:22.598Z
|
||||
364e4a0aa0ef2418805f0a68c40a1a038192c632442d55988adc32567542a08c;675181ebd83163b1bd9a691fa124325fb16dc72018cd1dc806475eeab51fe3ef;10043;1;2026-01-26T12:47:22.602Z
|
||||
b6bb2300887da830611f4b7fb61d5d4173cc6fd03bf785ff86e86153462c24f0;55ff4fb904dc219acc1f2a1fe279b67ee50abd0dd3cff11706b2ac49e0488228;10044;2;2026-01-26T12:48:18.402Z
|
||||
78eaf77cd5ba180e27778232eca1c50e664ffaefbfc0e02260e6f4c227c47f9b;9a610dc418b37dd96dc38c55d82170fc49a5be21f28ad26822da495bb0597b41;10044;2;2026-01-26T12:48:18.405Z
|
||||
7cc0b2cf6da61cd5648c14a2074971261d355a2d76da444911b3b351dce21252;da4c44e429a05844b40cef8cf999843ea835047fbf878b9ee603260fc1c08845;10044;2;2026-01-26T12:48:18.409Z
|
||||
caf8014e7fc7f5e781ebfaf26bff38454bf72dccc412f012a64bf0864959448d;f5e0112ab2b0b23fbb4987bea186efe7f3e6c72d4ab22ae23529da2f94211b48;10044;2;2026-01-26T12:48:18.412Z
|
||||
8e43631a28e56d09a75b0ad7fbfdee2ab74a203608b9e8dcde62dab4208f8dc4;6b540c51574e9b52a3d9723e05f54821a657b98d4606c72ca7db86e083dd2057;10044;2;2026-01-26T12:48:18.416Z
|
||||
84804db7584c919d349935439639a474537a6f6e0c513c67b6cbd35106e90e91;a4744561de387c62430c7b43425d8a41a6dd8d58ab706639274846b511ad3757;10044;2;2026-01-26T12:48:18.419Z
|
||||
2fd2b13a18c03e4d8c7cac4688ebb6f43b8a1ef9898be045503b23beda5ed519;dc4b58e26fe808ad8da8958e9ae8cc2e829eb21b00cb983f4ad55b81edb53c5e;10044;2;2026-01-26T12:48:18.423Z
|
||||
ef4a5716b5acf5ea971eca7aa57d4ae4a94c976c50785bd2fa5a1d48d1b5487f;280959d7bd3415fdca2a18406616b6a58f5d859f3926793212454c36c5036c64;10044;2;2026-01-26T12:48:18.426Z
|
||||
b6a3105cf38e27d558038c0fa1df9fec4c93f206fa5e45b41bc67ad0b8c7e6d4;38a2fa36d85298c90d9badd68f89014b6f1ffca89ef74e88498a7c12af25ebc4;10044;2;2026-01-26T12:48:18.430Z
|
||||
9da668faccd6de55696f79c88b2fae08e14f28a794731e64e9cabfbb8eafa329;81789d5bf798920ac84cb045b13dda9c78fdbc5ae1e9d03404e45350a38c8be2;10044;2;2026-01-26T12:48:18.433Z
|
||||
e9c90beafbe474bcd29f7b692b19648d339a7bcc447e12a8771a130ae3206f88;f476c6b60949e3da396865d5abbc08fdd0f0c2c8c5b11399e09742254ee592ec;10044;2;2026-01-26T12:48:18.437Z
|
||||
8e86c8371bb2b2b974ce16d5b2d950fe135190a37358bcfa5cc0139afd1c1e64;91781b48cf226955666029d099d38b413a280e1946aac8db1d8a489edf9a46fd;10044;2;2026-01-26T12:48:18.441Z
|
||||
eeb278aae70f1ff8905633c20e115663b9510b59d3c1e2ed0471b4ad2d93ea9d;312515ae70182857b1530258f8d51fa9fed02c45e4096921c1f332076cd81504;10045;1;2026-01-26T12:48:18.466Z
|
||||
ac61220b9610e3cfbe1426ca5a5670836c253f6f3079eec4bd7ed00c10e90d36;7ba4169e9b1c3f8deb41efd4a74cbdd2ced3d7119fa65410ef24ed07278e1f19;10045;1;2026-01-26T12:48:18.470Z
|
||||
17d8ddc90e2e51c993b766d99d1b074b16c354933a7dbbd30ab3051ff9a7c8fc;ba1450a56f117b13f4381699bd685d54a27b1d5b690d1f8fb20fef28a3f62a33;10045;1;2026-01-26T12:48:18.474Z
|
||||
3214837c59748280ca134348e3a473893d4326d0ab413d72dd415103669ab75b;003204a68809600c0d90ce5336738dda08849b47872de472af1c2498baf2ba50;10045;1;2026-01-26T12:48:18.477Z
|
||||
f693601db3fc65e0403fb71645264ad41a906f66f959ba4768d8be981b2fe78c;58c2b856cdce68c17110d4ac339bb7eae3cafe46bae6f8b69884c140dcbd4f6a;10045;1;2026-01-26T12:48:18.480Z
|
||||
438caa32c47d46f805039116a47fc59580f0c037f4691a5675dcc8ffa56657f9;64d91304ab31b2549442e59ef0c4e991c07ccab27093f799e6298cb1a5263e77;10045;1;2026-01-26T12:48:18.483Z
|
||||
87a14023546071befdf37293fe3baa1c8acf311e0f3ec783f5b7959e9e6c413a;1ce4eea2a54bbdeb1dc9a43eeb34662e6960004687fa8691e8a8cebe2f5b259c;10045;1;2026-01-26T12:48:18.486Z
|
||||
39d95255a60c97b27851df9f510914e03f38e7782edd7c84f399a66c7feb64ba;eea5244f08c1820e19dfdaea7c7bf79df0e9c28cfc392f4018f31cc7d6bfe3b4;10045;1;2026-01-26T12:48:18.490Z
|
||||
14cc65cb9731b57050165643c530c6ff8fec831c484bbcacd778d0238272e93c;d34eb912fd670e492ae9c5bb489349d67c0dcf79ca5e43e75cc11dcc4f258dc1;10045;1;2026-01-26T12:48:18.493Z
|
||||
9b92ff8b13433c7c1cc0cc347dd6f503bfb99b17b311cc773ca4e9ad73619153;0bb8eacee89a307c289ba5b85ddab0b2137e946cfebebe64eb582960294497dd;10045;1;2026-01-26T12:48:18.497Z
|
||||
9f36830a117701435ddb078307524f0bbb534184258b04bb037cebdb7e9a4926;5cb7c961652f1b216dc265b48c0464b2a5bf8154b695895647c89e194d5980f8;10045;1;2026-01-26T12:48:18.500Z
|
||||
71b1827764a1bf166371be9336bd25035df2c52d7393ca8a2f4db7238a329661;7dea8fb9fda676466126cd691f252b79c980200aa2f46435e0a83f348345c952;10046;1;2026-01-26T12:49:30.557Z
|
||||
72dfaa8d4d15d3765b4d41024acceedebf0f61dca2406d2829d0fe69f016b23b;7252af269fda59f08cc023e18a709f4500bc58a03a45bf9f7ffb77380ae3186b;10046;1;2026-01-26T12:49:30.559Z
|
||||
339c73ab1f1d0eae3ff2c586d22588207502f6265ba24bd9e1324ae93177962b;7981b82e20f42652acace93f0dfa291bf88fea8237a48297f59473e10ffb35c4;10046;1;2026-01-26T12:49:30.562Z
|
||||
4b2cad1e500414596f9913c617c05b96d9f633df5254d76231c27c16312d64f0;0fc248ff2ba6e6dc3173d94ec7af81a226badb7eaacb9ab06c3982e29e72a1d4;10046;1;2026-01-26T12:49:30.566Z
|
||||
491f98755284b1233b810e2e9d87501b48cd330591b1eaf99d5feaf02610aa80;cf14d98b81676a35202d0125e4beb7fa96d2a5e43f1b9a814fc388717ca018e2;10046;1;2026-01-26T12:49:30.568Z
|
||||
3fec6201c9661179d8b3aceac3c9a0f82c708c3da210296e0d8b4b505e312986;c0bb8ec1c8ef135a21c5cec8e670618d1cecdf68ae17cb105113b2416f1f14f1;10046;1;2026-01-26T12:49:30.571Z
|
||||
f6a9065f4dc6f657cd46ab7b5c4f4296dbad9dc5d57e2d87049fc026e4aad2a7;8ef33db52b9612cad75afa75e11b6f0f71cd7711d2c470379341d244fd6fba09;10047;1;2026-01-26T12:52:22.522Z
|
||||
d4c608af345136b944ff080401fdbcce6154c469569868ac523e6844b233e338;c14d9a363ed6a0364efee10030bcc5f2e7d25dff1826c77505229ebb31cb030e;10047;1;2026-01-26T12:52:22.527Z
|
||||
0e2c7e3febad253f087d530c201064e391f91c68f4837171224611adb3ec5b19;686da52efcd3ae07460c0897817a49f28f5a9293490a74db6395c256de9d1a32;10047;1;2026-01-26T12:52:22.530Z
|
||||
db30766a54abadc1c6028667c1e85511b47bf2931ffe7115a4ed7b985f07e85f;9f0cf41c39933812469002e2a36b8aac2e1d17e68a97c70e324f781ea560cb77;10047;1;2026-01-26T12:52:22.533Z
|
||||
0dffdd7e047944e4dcf5cf26193ab2c0e2ed27dfd94810d16039825d4b09dc8f;80230c7de17595d66774c8eeaff62effe3ab2af8c5f9243c269f1a97f72e0e7a;10047;1;2026-01-26T12:52:22.539Z
|
||||
4def93ddb0c965b001689b65e70ca63a3fc3a096b04db11b79f61f5e699c3ab6;7fc838a208b082bfbb0bf05d53764f1862fae66e39a953150766e604708e5d88;10047;1;2026-01-26T12:52:22.542Z
|
||||
a78000273e728853246dc82a432fd6e8c6b0804ba3cfa8e3c7eb3535bed9b65a;7ffe3c3e21a27b4e1ac12222048e68142050da19ecaf54309cc60453b9a964a1;10047;1;2026-01-26T12:52:22.547Z
|
||||
2628959ff9262f6f0a13ab00490d19bf84792f252f21eda3537c13c23739761b;a43b44c8859442bee23f805066fa8970ec93f6207d352fdf4cb8a1eede52a9b8;10047;1;2026-01-26T12:52:22.549Z
|
||||
827a9b9c1010367a365dbe238249a36ef74b8a91a357f05acd76252c3b607d52;ab0b28b3c469e6d01cd5bdcfd204b2de15bf55f18e261351635f2161ea42bbde;10047;1;2026-01-26T12:52:22.555Z
|
||||
54b8d69fb8dd0a945e35c1cc502356655c512cdf2917c422c7c4d5ba475a695d;0a438536e9086d2a7258db8631781531107ab3c349281f52f366ebb350e92deb;10047;1;2026-01-26T12:52:22.559Z
|
||||
3f2dabedf852140c4ec89d2d2de10c287a821204fbbf31772b191fbab5c629f4;18d5f856d075dc05786160c12bc1145c52d84eeffa72a7540c6406e982bc74ee;10047;1;2026-01-26T12:52:22.563Z
|
||||
a53a4cfae694c78d31f1e2ba3f5108c80b4c1bff2b89a6a01ec5fc19ae5d5c93;1ecad8b1e50f2eff159a34219002f0a6504c5616d9022c416555d923676d3302;10048;1;2026-01-26T12:54:22.547Z
|
||||
783e7af5c8ef5bad23ab9e5b0f9833208a53a479d7470f52d39a0d64049d37bb;c16762882cded685dcb400f272f6076d3d464ae2367fbad87a11811c2d00851a;10048;1;2026-01-26T12:54:22.551Z
|
||||
180f104d89251ef9b3a5039029412f7977bc26c2d0d68c1c079ae494f4a79d68;46bc56a9f55fe96eea604b5e6be71dd1c255ac6835a198531edffbe86b93822e;10048;1;2026-01-26T12:54:22.555Z
|
||||
b031052c739a23c365a6e745aff0642a707ee674c7d5582fdb00ff5e862cffc4;2a1e4dc75a42b2dc900ff1396e043abfefb598ecbbf7de19bf3651de5275412f;10048;1;2026-01-26T12:54:22.558Z
|
||||
bfd4e90eb0a08afa0d96517e22018e5fb06236716dde597f12ed4ab45cac01a6;df551d475b2c0cbf83a8ffc37123cefaa5632273eeab7eeb1256158259d90132;10048;1;2026-01-26T12:54:22.560Z
|
||||
33808270c95c41a700ded9f1270914b3d66cc14ff9795078ee9a2df501e53902;4dc0629413435a00efb8ccf94efa0dd65e9897aa36a28c51180c1f070ebebc34;10048;1;2026-01-26T12:54:22.563Z
|
||||
9a1085b1ba8c6f482276150d52d886d9f30c839c572ef7f86b60fe682100cd82;86ff0e53e88ad6b348020083bc526570d84ab23314e2f1cdb97ec69b8f882c38;10048;1;2026-01-26T12:54:22.565Z
|
||||
d0f5f8d95a832e02e3281b88401cad9de950b97324debd351c0ce0fa03301c66;74321dd4a4869339df16198ddbdaf33bd99f3c79a2479d8222bb3f51238bba38;10048;1;2026-01-26T12:54:22.567Z
|
||||
3d12496411cdc010401adc6078bda97aae85f391d50235d75352d7bc87e0f4ff;bcb4e17118fcd7e7b873a4eff13488d52fbbf090cf4431471a156ca24acbe93a;10048;1;2026-01-26T12:54:22.570Z
|
||||
74a307495e7578928ca6da46d166365e09472956b9f66509abb6f4d1a0ff99f4;7992d36e8f060a765c6a1d748786c2261c15eb8119d6faaaea18e03adf3b4a47;10048;1;2026-01-26T12:54:22.572Z
|
||||
a7b9248f2eee72a8ecaaf8e8195cf030c1f9d5604c36d4e03e5700d4f6132ae1;7c21df6d9b4400c899ae86b6b74ea173715e6008970869f73fbb76fb6d1c8253;10048;1;2026-01-26T12:54:22.575Z
|
||||
90e3dd79be9e02d95d836c571068d2f28972f4bac163e33edc198a96b266a808;eb8ab3255d095e49bd6fe0f4849004daebfdd8017bb45e3357d9df10937c937a;10048;1;2026-01-26T12:54:22.578Z
|
||||
dd2b83dc2526344eee9d1a8cf86829ce05252f22237256782be903b2d33208d0;7b03fc56c57855c9baef0c2df521c4d88c80fec022e0877cba9f3de15c83b181;10048;1;2026-01-26T12:54:22.580Z
|
||||
110f68b7f87b24f7a16a1dd65fa82127e8069e005626883444faa4b7e2573bd8;51faa5931a819ae8a87e8fad2451af093d1e75a1d782b424c8c5cdd52304428f;10048;1;2026-01-26T12:54:22.583Z
|
||||
b22f77c8efe6bef89ee950d0a48b42ab753474b10966c6b809c81fc5d10e307b;5fb1a25f184fb2df1e3a048d70e90723cab638993bbed786e56f5bd710bf6597;10048;1;2026-01-26T12:54:22.588Z
|
||||
0b825ec4f81d665ba8b39e9c17ca5bb65addd8023f8bb69436631280847c2026;1c992698117fe0067c79227e39a792b9fa9042b6a137f2e8d60f85a7b31b7da0;10048;1;2026-01-26T12:54:22.590Z
|
||||
f2ad6bacc9e27ef2c1cb42e9f1a7ebb4e6d7aa4cceb8bfa5f5cfba305cb3352c;63f8978a8f8f87dea0ea52f96088fa438621a120dd0093e5503166d47457a8a2;10048;1;2026-01-26T12:54:22.592Z
|
||||
c25df13650db58b6207855e03e69aa78aa7fb4bc4c514818257f7a1a977ecf79;b82b4af669dd5e5f4dd48a34a7789c3b93e7e19d6d2096e2b5ed7681f5d532bd;10048;1;2026-01-26T12:54:22.595Z
|
||||
d9dcc549ce32cb3b9704b594d2c1389c5ba2fc843f6bc542c866542432ced448;e9ea42b6f931420ec417d13bd588a758152807f1c1ad0c5b03aed916f67022c0;10048;1;2026-01-26T12:54:22.597Z
|
||||
381b9fe680d46aa2756ce8d335aa1b237f5217e2d4a577ddb3c180d7ddd851bb;fc917cf7e8a3369317852314fc76539bc1460bfd3ed7229fee7fa8bd489637c3;10048;1;2026-01-26T12:54:22.599Z
|
||||
7e9b7627c7d3cc4adef044b869d902ceef47a1153ab74dc8028ac0c2f0754502;42d1374e02bd099e51877e4245e1f111034a3af5f104645e9d505a905716f7d4;10048;1;2026-01-26T12:54:22.601Z
|
||||
0691fb95d799747b70fd2c57ebb551c65731031d459ad4184f1fd4d5ae1bb58d;4a4efb92dd361e4afad34f15488d20689ab64bc6b7f68e6a169e3a964589e9db;10048;1;2026-01-26T12:54:22.603Z
|
||||
0d89115462fb92f0cf8762974c02fe7e5a320b3593e045d5b36802a7da04ea9d;b771a32a6cfb0f0969856b857f7d3882a69af50f6396530a4a6da66993b328e4;10048;1;2026-01-26T12:54:22.605Z
|
||||
466bf7821cf2fe9a1e1d429e7b80ba688b891fac5f4f38da65fb649f212ffac1;b08c148584514766c1477feb2b37923a52db4e3c6212be4405a247d863772fe4;10048;1;2026-01-26T12:54:22.607Z
|
||||
35a47243a5d6e938968b42d02953bf99193b79b16575817c749b460450c437a6;2abef345916d1cb445dc85eefa08f2c4e1ceed8082fce3c332ca6b3882a4b7e8;10048;1;2026-01-26T12:54:22.609Z
|
||||
bf7fc6ffa4e9db16165a4121a99f3fb6e475d0b243ec64776fec37dc38232c81;83d29355f6fd2c05c54bc6117dbf1678f5bb9948a7bd43c82cf307bbc3a48df0;10048;1;2026-01-26T12:54:22.612Z
|
||||
4418de4bc8dd1cc22675a3ff41b43951cc46b59fe8849a15293b2318523d1822;0aa1147931494624c82a6069b8243514f75a25a19603611ec29bf154ad6196f0;10048;1;2026-01-26T12:54:22.613Z
|
||||
011d3bae763ca56f62e5c8d691857da8a551f2ae8f3f99a72546f9209d4a8843;eca3752c3c26eec1ebc0dc64cb84a7203fc0c12fd1a0abc26e4c301f952eb7fb;10048;1;2026-01-26T12:54:22.616Z
|
||||
eb80eb93e3a551990af7334320b7d1f275ed9aa7c64ad0844b3cfa5d2a75d831;07510486ff915f082d6f76205b1964122ce1736b8da749731939119b0c5093fe;10048;1;2026-01-26T12:54:22.618Z
|
||||
d64bb893c86f060e5098d8bac2ee93312e41f4a36de70d06300dbde303acc2f3;74d94018561359830ddf9084b1e29ee5a9f0d3dcd399ad7c5d210358f14ababb;10049;1;2026-01-26T12:56:22.545Z
|
||||
2962437c29004ebdb6b92efb6da40c30cf399f59504ba0a8f69b4a335470ec82;b80ba62c973033215ac785d8b09a7e8f6874b1be5f3a83a49d9113559351920e;10049;1;2026-01-26T12:56:22.548Z
|
||||
148c4a04f99d3a437cce9ecde08b01a49dfe28c33a6ba11705d118ac2d0a2b12;4fce2335628d24ddb778ab48fb743c6a94d02923607004d44f40d8b77fa9eb0e;10049;1;2026-01-26T12:56:22.550Z
|
||||
07c883dd6f4913d4033dd0b2cd5d8c925653c63dc55b77c3883dd8d326625822;827c0e419a7acba2c490fcd88310490cf2ccd4e856d4aeac59a177f44094c717;10049;1;2026-01-26T12:56:22.553Z
|
||||
2722504a377a41aa41fa092d57453f6fc4ad985521036891ee5753f3e59c899c;58083952206b1b3c2310758cb358cfeaab2110784d4d4e20aaef8621a2a69718;10049;1;2026-01-26T12:56:22.555Z
|
||||
58d0740a4cf5d251bd359ebae62d8263c7023736592b71621c5d302c96173dc4;31c65fae35e38568621fa4953671a48fe18dde23500bccfe116fe759f1641a20;10049;1;2026-01-26T12:56:22.557Z
|
||||
633cecd834680cec5a1b208ac7b38468bd6ad6c78867b012ebabff60879ff83e;c2b981d863990992b6cb48822e83105e7fae6f27b1976cb9b540bed15069f128;10049;1;2026-01-26T12:56:22.559Z
|
||||
1060f0231cf78b88255f7ed54f524f2a142ab0b592d0d9f3642b999e1346860d;8b7800bf86d87ea53057787260b4614c0bb3364e0e1de890c100340363a1dd2a;10049;1;2026-01-26T12:56:22.561Z
|
||||
6a267049f1a59bcfd09195c3a22cff0311f016992732d2dfdbb78698a94b16aa;bad95fc5db117ea2b16f39bf5226338409aa562a645b96764f4b3f044e15f32a;10049;1;2026-01-26T12:56:22.563Z
|
||||
ffa6444615c2508542c14c7758328cfdf197e685a5499b81d895ea806fff5035;1dc8e999c14b432e575a48c7c78bee74fa1dbbde677e551dbb2028fbf77ff542;10049;1;2026-01-26T12:56:22.566Z
|
||||
1c8309ee5a3cde18cd3bbad60ada4a0d236c8a6a809f9ae3661b19e87311859f;33c6a58f045ddc095ed6d28a6b216c50bf6c6b4cf222885d909db714a66ea444;10049;1;2026-01-26T12:56:22.568Z
|
||||
05e8e651458ebfd57b0ce8a174d2b08fe86db2e2b4f3d53e52feecc679878f49;6e3a091c01aa202d4657e97bca907301688810bf7301074b4b306b359eb39d4d;10049;1;2026-01-26T12:56:22.570Z
|
||||
9d799a885f338311ad958413af5162f00650a73e85e6520980d962caae3940cb;02652f28bf073fb144ab2c4835317cd30ae2e8f247a7fb1dc2f31754daca9065;10049;1;2026-01-26T12:56:22.572Z
|
||||
d4ecd5c808f3885eaf1bf668b3477a8a4fe83ff9ceb1d31159b751ada29596d8;75f6a956f8f047e0c47f5abb8773dac8810ed5850188f7df669265c0e7759d7d;10049;1;2026-01-26T12:56:22.579Z
|
||||
bbaaed26ece9c54387d8e998d64fae2fd4d23ea7b0bd9207a94b5d9501a5952e;6e147dc079ea7fa4a18dff44201db912f16e28b13bba012f38849e2248615986;10049;1;2026-01-26T12:56:22.587Z
|
||||
e2581d0c87c940c72ae3fde34749ba142158856cc08ea049c72f0790602b9ea2;f5c9e19199b4860da8daf22a50b92a17416cb8b47354029d9e76f2c3daf5f497;10049;1;2026-01-26T12:56:22.589Z
|
||||
879810711e1567e88db9a2ae7ae5f2386722840032c466ca2528fafa5925e88c;6a591321737e0bc9527079f376acfa41fe79e5a13c6c6909cf5fa92a71b4f699;10049;1;2026-01-26T12:56:22.591Z
|
||||
dfb11ef005ea897570aea283f5e2e6e70d01199d7add5348228b9795b41d0e44;79b03a77de5a34d08a8a7aaf5aedbc761d58f868c7f601a532282db286d8dc9b;10049;1;2026-01-26T12:56:22.593Z
|
||||
86f86d1d8382b175aa28983aaa957d803b231570e9b581f706f13b67ab9e16e1;8bac3824ac50908e22e0a65d73ece9ccaebf7c5e2833dac91921130bd7f651ac;10049;1;2026-01-26T12:56:22.595Z
|
||||
77ed295a2fdb588235292593565fd8f1e56a90a04361176b6c258bfc320e73f5;9d2649e4a1f494d1d48db12615233d7973966ffe7db034d9823ccc653434cbbf;10049;1;2026-01-26T12:56:22.597Z
|
||||
359719de5f27d77eccf6c923e48f29bac075ce5dc22e684fcb1a5ca426db6d35;e0b9c87ebd36dba67bd817a105c76a23589c51f28793b28c054117969e60efc0;10049;1;2026-01-26T12:56:22.598Z
|
||||
98b34e3923d4f67708b15ef93006b9b117b824bc393f32c2af2a919046861b67;8e4572947fdc4c1dcb61cda7edb9f47c14ca3867353a1c5a1c117cb3c21b06cf;10049;1;2026-01-26T12:56:22.600Z
|
||||
df118408ecdbf60d599c3b9b52130b406be734997d583227f107b090b37dc570;b3fe70271b96d3d584447c09147cd8f01aef74ec97f1058927d59ca3e19ea6cf;10049;1;2026-01-26T12:56:22.602Z
|
||||
75a6fd1b08ce45633fa5ede8b32f225ed14a610bf1bfb096002072eeb24b8dce;eb4b040abe3533cdf591e480ccb828bfb95bb077f856028e06c83dd8edff73d4;10049;1;2026-01-26T12:56:22.604Z
|
||||
5ddcb0e8271b913f8c7cd0d214ab1aea8089e13ea927f06f84588fab85982abd;f4daa456b6f53c7cf9fdfb3e47d9767b1f3456905fd9df39acf64cddd3bdf9e5;10049;1;2026-01-26T12:56:22.606Z
|
||||
4abd377a1d3891d2da823700fce041c72b93576a6a9942d16a7d064e5895e88e;6b55f08d8ee121658d5612c2a35d92ef458b8f8885e8dd3b8a93e5917fc3ace7;10049;1;2026-01-26T12:56:22.608Z
|
||||
044fcd1952dacc718725af17c86ea99a0a212dfb1adc9a90f00660b68bb20017;6843b69f02d45b8dc2097ed45eec1ac1e753c71c6e553c442bb8f90fff065eea;10049;1;2026-01-26T12:56:22.610Z
|
||||
faf22047110fd4dfc02b3c1109926edd86baa6504e4909f68a781de2178b11a6;bba36cce983608c90593e11858e397def39f84e53621ba483a4cc1df11690e00;10050;1;2026-01-26T12:57:22.554Z
|
||||
82ed4337fa58a3ae95a70149d1bde70baea9d4e30bdae62b2659a606f79b1871;a50a6830bf42894f92f78cd55438410a6b3e241b3c4bbda7e92e274bc1cc9003;10050;1;2026-01-26T12:57:22.558Z
|
||||
9dbe71c68ce876272c869d1d98a0ae6cead02c564a03d79a13fde94a0b45868b;5b424df30adfa8fba4c549e794327a5f0e81ff995b31a31a9b5de6fa4689f81e;10050;1;2026-01-26T12:57:22.562Z
|
||||
82a7dfa988ae78b442ef9c7df8e9455dc78d8cfebc2ff434291cc3e1bdb205d8;f45e5e74a9822373e567293d626ebf8de9ecf4a61654b28ffce7f6b3b7807427;10050;1;2026-01-26T12:57:22.565Z
|
||||
3634754ce605cf9e28108ceef793876cbf7d2c43c415013861cd33f918aec563;f96aa632ed8dfe47e71ff3c1ecb4a286118a00546d7fcecc50c17275aa3b6729;10050;1;2026-01-26T12:57:22.569Z
|
||||
804d3ccef3c7eac07a1e41f86da3d4fc858d0f251e69fafcbc3ac5bdcae94c2f;5f2a7843ee96ca04c1fcd5f720b52b9e91586d5543b542352e805e531923f14a;10050;1;2026-01-26T12:57:22.573Z
|
||||
8d1cdd698bbdd46d0c2a9bf0b3be1c43a401dcd3fbef82bf146ed919dd8f854f;26e35abfc1756edbb5ccf4b50eaa04c62b25b1d2ada4ba4dacf666f300d7d565;10050;1;2026-01-26T12:57:22.577Z
|
||||
939ca2d8a00878e3897e532bde3a2969a3057e6a6b2f4263ab56c51a6d973fed;d56ab1ca18b5c8d3176f7a7058289acc9e3e1c3fbde572a504c0dbf27b45916a;10050;1;2026-01-26T12:57:22.581Z
|
||||
718ef6331d6c1ec158a1f8312e393e9c78c219d818c1124e7089155930c5a435;be540e835a607386d0e39973e21c2f444f7e7e9b8c6f9033d348631080117773;10050;1;2026-01-26T12:57:22.585Z
|
||||
7e851c0da2cacca8d698a277b73436081383436b1820a22899b83c1f34150d3a;b021dd39ab9ba146b8990666bc056651172d60f82d75b72517bd55161f7f4488;10050;1;2026-01-26T12:57:22.589Z
|
||||
ea2d5bf1cfe498c6c7abdd81dd029675b3995495c6ca0f518aa72ef05a875189;ba9acc922a6ba8f41cd6168872eb0ea689aa958bc711c78049544d4942adff88;10050;1;2026-01-26T12:57:22.594Z
|
||||
7491bce435a6b8251d97dfefadb6e543d5bbf6c950ef7e227b4f3484eb1211e9;d5522f5698cc3a757caec5ec3c70e04d7fd238e0978b007202f176a4cfab3e8c;10050;1;2026-01-26T12:57:22.598Z
|
||||
0829396fecc8e5bcbbcf33dc5ca660b51848a167743fc8c65c5e903481d7dfb8;eb08e774f459a9785609a717da1ef92af3d0e5bd6ff9040c038152983f0b35a0;10050;1;2026-01-26T12:57:22.602Z
|
||||
149060fe641983f745970166583fca3d341c18420923c81e6fd954ea0c1aeb27;0eca6cf717a9277fa542c092d1fb4b69cade22554035f445f91750e4f83a23a7;10050;1;2026-01-26T12:57:22.606Z
|
||||
1470f19431db1dd255638fd723315eecb7b88861808f2023c0416aba9f00df79;4e5bae0700e37ec58bac9a0a9305ef39aceb14c4a08b067afc04bcce5ac223ab;10050;1;2026-01-26T12:57:22.609Z
|
||||
d83452a7bc0adb3d8384fa6dc5500a9039c6f2162799fe34c2d3ee6bbf85f8a5;75e5761aee35869e2937aa58632772c41fe52b4a220167654386865cf60499bc;10050;1;2026-01-26T12:57:22.613Z
|
||||
f590daf0386b2ed8e409da57ff09eaa68a86f9ad29b175918fcf1a6a62c3ecb2;3b194b7b011b1cb8b72f82f5497d5542cd4327ddb3f689d876d0339f1e9c31d6;10050;1;2026-01-26T12:57:22.617Z
|
||||
6b13e8cc16dfb2b5d95303c964a9982c11f13d795d9f7e025cd86b9870e68947;d954f51c123fc14bdc8c0bc020e17a12295b47e38ae4dfaef98e1a27618e7be6;10050;1;2026-01-26T12:57:22.620Z
|
||||
2f364b57c98e713a3fa5c34ac0c0f43acba80385ee74d2511c7dbcc51efb0062;01c1e957caf5da10e0ae03592744fee99cfa049325765ffc8fc1682ca52ed7e8;10050;1;2026-01-26T12:57:22.624Z
|
||||
e7f6d84b8c297b7a6bdeaeb1b9043b9e30ee60cb5bafad36dfdef8301696349e;6bc69787ed91659e39bdb7051840712a6ad644f0a885f43700dba82e4937f9ea;10050;1;2026-01-26T12:57:22.629Z
|
||||
99f42f3dfa0662296fb488fe21afad34f7a4f399b901601e89f5a347486b5af5;d520f0160fbc8bc51bab6e4e3b1d3fa61a37cddfbe6c36a685e33d0bed9c812d;10051;1;2026-01-26T12:59:22.485Z
|
||||
57a6d9b2bbfd76bf7493cbfc32998d248fcab9b3623fc0202dd81f8f318d24b1;853736048b92c6edb773c1585db36568717b0108f804f7e6aa5b689466b8663c;10051;1;2026-01-26T12:59:22.487Z
|
||||
d387648a8961d328ec87f1f49c216191b242e29b36fdf7737355aa807b8076e2;8830268e6685e7f890e6ac831dae4b840c6782b1979b353caba63f013b23d34c;10051;1;2026-01-26T12:59:22.490Z
|
||||
21fbc67af4d0dcb08c5e6a8bcb8adb0d79615ce62ebe5150cfb9b2d2752043db;e45d726c54c969e9af666c2717bc2c1247a63fcf07f7714d39a98c03d91ac064;10051;1;2026-01-26T12:59:22.493Z
|
||||
9e9724b0b2308967513d6b9669ff02be2b81dc375ec3615c7b13a67897499868;6efb7024b8d83bbe78ae49340bb4e3c2c94c183d77fb96cd89c14d88e20bba69;10051;1;2026-01-26T12:59:22.495Z
|
||||
39316f2f1eef63e93bcff47982c841af3e7de1bb98441a81febb4393b8459c2c;acdcd7b17b996ffc39a949dbdb15142ed711b70b660ef8a6ba22ee66528fe473;10051;1;2026-01-26T12:59:22.497Z
|
||||
c72864d2510f66d0ba8c5967f0a86961bb5129fb5b5c98aeb9d25a63fd80bb8e;adf9523e883677c4b888558658fcfe8d781fc0d9928f41b3a4e4e2f82d939480;10051;1;2026-01-26T12:59:22.499Z
|
||||
e00b3bb7b9abd55bbd3112b5bc641008e335b12ae0624548221c047291aa2e68;2b1898464a91291b04b7ad342bf4f22056ea2a194314bc667a8f69a9a9141687;10051;1;2026-01-26T12:59:22.501Z
|
||||
22a630d90a9b15b1176f529d056e8b0da100ba5d96dbf4c6b6e40e4a4b17f632;8f4c14fd82c75af78dafcb771b1358bb6aacdd8e0fccdc7a48142a795b7291d1;10051;1;2026-01-26T12:59:22.503Z
|
||||
9b57cae546364d361deda871938970af07596e0ac454bb687e8e31b4850d7cd7;a26f7ba2a7e34a1d31fb903ed41a9296f5598fb7e571ef0975caf0b9be3183d9;10051;1;2026-01-26T12:59:22.505Z
|
||||
06121bc2751e64748e536cf49484043bf5ef87fb027922063c8a5a984fc6284b;fbe7563f8099ebbde05178514a4497397a9ace6f23911c99f6a626757ce6f7db;10051;1;2026-01-26T12:59:22.507Z
|
||||
3e4726a5ed732d0abbdb1069e42c6f13d34ea16ebd8353e2d24720a866424cc2;1ce6d0179d049585c37e1e756173b619131055f4c7b41d3d08735c2ea540f6fa;10051;1;2026-01-26T12:59:22.510Z
|
||||
6100ed0ee59a17a23292979ef05d6baecaf6686b7a8045385a05b57c8035a684;e357d1504e963d89982fabeb0d63e10a3305b515fbe22f5a2b87a88abd846afe;10051;1;2026-01-26T12:59:22.512Z
|
||||
@ -1 +1 @@
|
||||
2026-01-26T11:35:02.178Z;9995;0000000d6c321679c322031d1952f0e8cab4db0896a0cf16dce36cba37ceccd7
|
||||
2026-01-26T12:59:22.551Z;10051;0000000d02cc6dd24f8c8773b4ce967dfe284705296a141d00adcaf95b9f1d5f
|
||||
88
userwallet/docs/specs-champs-obligatoires-cnil.md
Normal file
88
userwallet/docs/specs-champs-obligatoires-cnil.md
Normal file
@ -0,0 +1,88 @@
|
||||
# Complément de specs – Champs obligatoires et attributs CNIL
|
||||
|
||||
**Author:** Équipe 4NK
|
||||
**Date:** 2026-01-26
|
||||
|
||||
Référence : `specs.md` (Contrat, Champ, MessageBase, DataJson).
|
||||
|
||||
---
|
||||
|
||||
## 1. Champs obligatoires des contrats
|
||||
|
||||
Tous les contrats ont **certains** des champs (objets `Champ`) suivants. Chaque type correspond à un usage métier précis ; un contrat donné en possède un sous-ensemble selon le contexte.
|
||||
|
||||
| Type de Champ | Description |
|
||||
|---------------|-------------|
|
||||
| Partage avec les institutions | Champ dédié au partage de données avec des institutions |
|
||||
| Messages au RSSI | Messages au RSSI de la société responsable du service |
|
||||
| Messages au Correspondant CNIL | Messages au Correspondant CNIL de la société responsable du service |
|
||||
| Messages au Responsable cybersécurité | Messages au Responsable cybersécurité au bord de la société responsable du service |
|
||||
| Messages de support infogérant | Messages de support de l’infogérant du service |
|
||||
| Messages de support administrateur système | Messages de support de l’administrateur système du service |
|
||||
| Messages de support niveau 1 | Messages de support de niveau 1 du service |
|
||||
| Messages de support niveau 2 | Messages de support de niveau 2 du service |
|
||||
| Messages de support niveau 3 | Messages de support de niveau 3 du service |
|
||||
|
||||
- Les `Champ` sont des `MessageAValider` avec `contrats_parents_uuid` (au moins 1).
|
||||
- L’identification du type (partage, RSSI, CNIL, cybersécurité, support N1/N2/N3, etc.) se fait via `types.types_names_chiffres` / `types_uuid` ou via des métadonnées dans `datajson`, selon les conventions du catalogue.
|
||||
|
||||
---
|
||||
|
||||
## 2. Attributs CNIL dans `datajson`
|
||||
|
||||
Pour les objets concernés (ex. contrats, champs), la partie **`datajson`** peut contenir des attributs **CNIL** supplémentaires. Ceux-ci sont optionnels au sens du schéma de base mais requis pour la conformité CNIL lorsqu’ils s’appliquent.
|
||||
|
||||
### 2.1 Usage et partage avec les tiers
|
||||
|
||||
- **Raisons de l’usage avec les tiers et description du tiers**
|
||||
Tableau de couples `[raisons, tiers]` : pour chaque usage avec un tiers, les raisons et la description du tiers.
|
||||
- **Raisons du partage avec les tiers et description du tiers**
|
||||
Tableau de couples `[raisons, tiers]` : pour chaque partage avec un tiers, les raisons et la description du tiers.
|
||||
|
||||
Structure suggérée (à préciser dans le catalogue) :
|
||||
|
||||
```json
|
||||
{
|
||||
"raisons_usage_tiers": [
|
||||
{ "raisons": ["…"], "tiers": "…" }
|
||||
],
|
||||
"raisons_partage_tiers": [
|
||||
{ "raisons": ["…"], "tiers": "…" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Conditions de conservation
|
||||
|
||||
- **Conditions de conservation**
|
||||
Objet JSON contenant **au moins** le **délai d’expiration** (durée de conservation des données).
|
||||
|
||||
Exemple :
|
||||
|
||||
```json
|
||||
{
|
||||
"conditions_conservation": {
|
||||
"delai_expiration": "P1Y",
|
||||
"unite": "annees"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(`P1Y` : ISO 8601 duration, ou équivalent selon le catalogue.)
|
||||
|
||||
---
|
||||
|
||||
## 3. Synthèse
|
||||
|
||||
| Domaine | Contenu |
|
||||
|--------|---------|
|
||||
| Champs obligatoires | Sous-ensemble des 9 types (partage, RSSI, CNIL, cybersécurité, support infogérant / admin / N1 / N2 / N3) selon le contrat |
|
||||
| `datajson` CNIL | `raisons_usage_tiers`, `raisons_partage_tiers` (tableaux [raisons, tiers]) ; `conditions_conservation` (JSON avec au moins `delai_expiration`) |
|
||||
|
||||
---
|
||||
|
||||
## 4. Références
|
||||
|
||||
- `userwallet/docs/specs.md` (MessageBase, DataJson, Champ, Contrat)
|
||||
- `userwallet/src/types/message.ts` (DataJson)
|
||||
- `userwallet/src/types/contract.ts` (Champ)
|
||||
@ -24,8 +24,8 @@ Spécification du login décentralisé (secp256k1, contrats, pairing mFA, relais
|
||||
|
||||
### storage.md
|
||||
|
||||
- **Relais** : stockage hybride (mémoire + `./data/messages.json`). Messages + `seenHashes` persistés ; **signatures et clés non persistées** (perdues au redémarrage).
|
||||
- **Front** : LocalStorage (`userwallet_identity`, `userwallet_relays`, `userwallet_pairs`, `userwallet_hash_cache`, plus legacy `userwallet_keypair`, `userwallet_services`). Graphe en mémoire uniquement (`GraphResolver`).
|
||||
- **Relais** : stockage hybride (mémoire + `./data/messages.json`). Messages, `seenHashes`, **signatures et clés** persistés. Sauvegarde à l’arrêt et périodique (`SAVE_INTERVAL_SECONDS`).
|
||||
- **Front** : LocalStorage (`userwallet_identity`, `userwallet_relays`, `userwallet_pairs` ; legacy `userwallet_keypair`, `userwallet_services`). **IndexedDB** : `hash_cache`, `userwallet_pairing_confirm`. Protection par mot de passe (identité chiffrée). Graphe en mémoire uniquement (`GraphResolver`).
|
||||
|
||||
---
|
||||
|
||||
@ -47,53 +47,46 @@ Spécification du login décentralisé (secp256k1, contrats, pairing mFA, relais
|
||||
|
||||
### Points notables
|
||||
|
||||
- **Identité** : création (secp256k1), import (clé hex 64 car. ou phrase BIP39, dérivation m/44'/0'/0'/0/0 ; passphrase BIP39 non supportée).
|
||||
- **Identité** : création (secp256k1), import (clé hex 64 car. ou phrase BIP39, dérivation m/44'/0'/0'/0/0 ; passphrase BIP39 non supportée). Protection par mot de passe (PBKDF2 + AES-GCM), déverrouillage (UnlockScreen), verrouillage manuel.
|
||||
- **Relais** : config dans LocalStorage, test `/health`, GET/POST messages/signatures/keys via `utils/relay`.
|
||||
- **Pairing** : BIP32 UUID ↔ mots, `PairConfig` avec `membres_parents_uuid`, `is_local`, `can_sign`.
|
||||
- **Pairing** : BIP32 UUID ↔ 8 mots (BIP32-style), `PairConfig` avec `membres_parents_uuid`, `is_local`, `can_sign`, `publicKey?` (optionnel, ECDH). WordInputGrid pour saisie. Confirmation croisée « membre finaliser » (IndexedDB), statut « Connecté ».
|
||||
- **Graphe** : GraphResolver avec caches (services, contrats, champs, actions, membres, pairs), `resolveLoginPath`, validation des parents.
|
||||
- **Login** : LoginBuilder (challenge, nonce, chiffrement « for all », preuve avec signatures), publication message → signatures → clés.
|
||||
- **Sync** : SyncService appelle les relais, HashCache (LocalStorage), déduplication, fetch clés/signatures, vérification hash/signatures/timestamp, mise à jour du graphe.
|
||||
- **Sync** : SyncService, HashCache (IndexedDB), `markSeenBatch`, déduplication, fetch clés/signatures, vérification hash/signatures/timestamp, mise à jour du graphe. Détection des confirmations de pairing au sync.
|
||||
- **Iframe** : iframeChannel + useChannel ; messages `auth-request`, `auth-response`, `login-proof`, `service-status`, `error` ; postMessage vers parent avec `'*'`.
|
||||
- **Export/import** : identité, relais, pairs, hash_cache, pairing_confirm (IndexedDB). « Supprimer » global avec option export avant suppression.
|
||||
- **ESLint** : config flat, `typescript-eslint`, type-aware ; voir `features/userwallet-eslint-fix.md`.
|
||||
|
||||
---
|
||||
|
||||
## 3. api-relay (backend relais)
|
||||
|
||||
Voir **api-relay/docs/synthese.md** et **api-relay/README.md**.
|
||||
|
||||
### Stack
|
||||
|
||||
- Express, CORS, JSON. TypeScript, tsx en dev.
|
||||
- Pas de base de données : mémoire + persistance optionnelle (`./data`).
|
||||
- Express, CORS, JSON. TypeScript, build ESM (`node dist/index.js`). Pino, compression, rate limiting, validation POST.
|
||||
|
||||
### Structure
|
||||
|
||||
- **/routes** : messages, signatures, keys, health.
|
||||
- **/services** : StorageService, RelayService.
|
||||
- **/types** : message (MsgChiffre, MsgSignature, MsgCle, Stored), config.
|
||||
- **/routes** : messages, signatures, keys, health, **metrics**, **bloom**.
|
||||
- **/services** : StorageService (index `byService`), RelayService.
|
||||
- **/lib** : logger, validate. **/middleware** : CORS, logging HTTP, compression, rate limit.
|
||||
|
||||
### Endpoints
|
||||
|
||||
- **GET /health** : `{ status: 'ok', timestamp }`.
|
||||
- **GET /messages?start=&end=&service=** : messages dans la fenêtre, optionnellement par service.
|
||||
- **POST /messages** : enregistrement + relais.
|
||||
- **GET /messages/:hash** : message par hash.
|
||||
- **GET/POST /signatures/:hash** et **/signatures** : idem pour signatures.
|
||||
- **GET/POST /keys/:hash** et **/keys** : idem pour clés.
|
||||
- **GET /messages?start=&end=&service=** : messages dans la fenêtre, indexés par `service_uuid`.
|
||||
- **POST /messages**, **GET /messages/:hash** : idem.
|
||||
- **GET/POST /signatures**, **GET /signatures/:hash** : idem.
|
||||
- **GET/POST /keys**, **GET /keys/:hash** : idem.
|
||||
- **GET /metrics** : Prometheus (`relay_storage_entries` par kind).
|
||||
- **GET /bloom** : Bloom filter (JSON) des hash vus.
|
||||
|
||||
### Comportement
|
||||
|
||||
- **Storage** : messages, signatures, keys en mémoire ; `seenHashes` pour déduplication. Persistance : messages + `seenHashes` dans `messages.json` ; signatures et clés non sauvegardées.
|
||||
- **Relay** : `PEER_RELAYS` en env ; relais des messages/signatures/clés vers les pairs via POST.
|
||||
|
||||
### Correctif relais (POST /messages)
|
||||
|
||||
- Vérifier `alreadySeen = storage.hasSeenHash(msg.hash)` **avant** `storeMessage`.
|
||||
- Puis `storage.storeMessage(stored)`.
|
||||
- Relayer seulement si `!alreadySeen` : `await relay.relayMessage(msg)` et `stored.relayed = true`.
|
||||
|
||||
### Autres points
|
||||
|
||||
- **config.ts** : RelayConfig avec `relay_enabled`, `max_message_age_days`, etc. Non utilisé dans `index.ts` (config réelle : PORT, HOST, STORAGE_PATH, PEER_RELAYS).
|
||||
- **README** : port par défaut 3019.
|
||||
- **Storage** : messages, signatures, keys, `seenHashes` en mémoire ; **tout persisté** dans `messages.json`. Sauvegarde à l’arrêt et périodique (`SAVE_INTERVAL_SECONDS`). Déduplication par hash ; relais uniquement si `!alreadySeen` avant `storeMessage`.
|
||||
- **Config** : PORT, HOST, STORAGE_PATH, PEER_RELAYS, BODY_LIMIT, REQUEST_TIMEOUT_MS, RATE_LIMIT_*, CORS_ORIGINS, LOG_LEVEL. **Déploiement** : `start.sh`, `api-relay.service` (systemd).
|
||||
|
||||
---
|
||||
|
||||
@ -112,5 +105,7 @@ Spécification du login décentralisé (secp256k1, contrats, pairing mFA, relais
|
||||
|-----------|--------------------------------------------------------------------|----------------------------------------------------------|
|
||||
| **Rôle** | Front login décentralisé (secp256k1, contrats, pairing mFA) | Relais stockage + diffusion messages/signatures/clés |
|
||||
| **Port** | 3018 | 3019 |
|
||||
| **Stockage** | LocalStorage (identité, relais, pairs, hash cache) | Mémoire + JSON (messages, seenHashes) ; sig/keys non persistées |
|
||||
| **Stockage** | LocalStorage (identité, relais, pairs) ; IndexedDB (hash_cache, pairing_confirm) ; protection optionnelle | Mémoire + JSON (messages, seenHashes, signatures, keys) |
|
||||
| **Specs** | Aligné avec specs.md (graphe, ordre message→sig→clés, pull-only) | Séparation messages / signatures / clés, dédup par hash |
|
||||
|
||||
**Reste à faire (contrat & login)** : voir `features/userwallet-contrat-login-reste-a-faire.md` (machine à états, écrans, anti-rejeu, validation, etc.).
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
import js from '@eslint/js';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import react from 'eslint-plugin-react';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import unusedImports from 'eslint-plugin-unused-imports';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: ['dist', 'node_modules'],
|
||||
@ -24,6 +28,8 @@ export default tseslint.config(
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
project: ['./tsconfig.json', './tsconfig.node.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
|
||||
456
userwallet/package-lock.json
generated
456
userwallet/package-lock.json
generated
@ -12,6 +12,7 @@
|
||||
"@noble/secp256k1": "^2.0.0",
|
||||
"@scure/bip32": "^2.0.1",
|
||||
"@scure/bip39": "^2.0.1",
|
||||
"bloom-filters": "^3.0.4",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@ -30,6 +31,7 @@
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-unused-imports": "^3.0.0",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-eslint": "^8.53.1",
|
||||
"vite": "^5.0.8"
|
||||
}
|
||||
},
|
||||
@ -1547,6 +1549,12 @@
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/seedrandom": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.8.tgz",
|
||||
"integrity": "sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
|
||||
@ -1619,6 +1627,42 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.1.tgz",
|
||||
"integrity": "sha512-WYC4FB5Ra0xidsmlPb+1SsnaSKPmS3gsjIARwbEkHkoWloQmuzcfypljaJcR78uyLA1h8sHdWWPHSLDI+MtNog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.53.1",
|
||||
"@typescript-eslint/types": "^8.53.1",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz",
|
||||
"integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
|
||||
@ -1637,6 +1681,23 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.1.tgz",
|
||||
"integrity": "sha512-qfvLXS6F6b1y43pnf0pPbXJ+YoXIC7HKg0UGZ27uMIemKMKA6XH2DTxsEDdpdN29D+vHV07x/pnlPNVLhdhWiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz",
|
||||
@ -2032,6 +2093,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64-arraybuffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.9.18",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.18.tgz",
|
||||
@ -2042,6 +2112,25 @@
|
||||
"baseline-browser-mapping": "dist/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/bloom-filters": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/bloom-filters/-/bloom-filters-3.0.4.tgz",
|
||||
"integrity": "sha512-BdnPWo2OpYhlvuP2fRzJBdioMCkm7Zp0HCf8NJgF5Mbyqy7VQ/CnTiVWMMyq4EZCBHwj0Kq6098gW2/3RsZsrA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/seedrandom": "^3.0.8",
|
||||
"base64-arraybuffer": "^1.0.2",
|
||||
"is-buffer": "^2.0.5",
|
||||
"lodash": "^4.17.21",
|
||||
"long": "^5.2.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"seedrandom": "^3.0.5",
|
||||
"xxhashjs": "^0.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
@ -2271,6 +2360,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cuint": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
|
||||
"integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/data-view-buffer": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
|
||||
@ -3664,6 +3759,29 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-buffer": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
|
||||
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-callable": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||
@ -4158,6 +4276,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.23",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||
@ -4165,6 +4289,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
@ -4743,6 +4873,12 @@
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect-metadata": {
|
||||
"version": "0.1.14",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz",
|
||||
"integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/reflect.getprototypeof": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
||||
@ -4991,6 +5127,12 @@
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/seedrandom": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
|
||||
"integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||
@ -5362,6 +5504,54 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -5506,6 +5696,263 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.53.1.tgz",
|
||||
"integrity": "sha512-gB+EVQfP5RDElh9ittfXlhZJdjSU4jUSTyE2+ia8CYyNvet4ElfaLlAIqDvQV9JPknKx0jQH1racTYe/4LaLSg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.53.1",
|
||||
"@typescript-eslint/parser": "8.53.1",
|
||||
"@typescript-eslint/typescript-estree": "8.53.1",
|
||||
"@typescript-eslint/utils": "8.53.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.1.tgz",
|
||||
"integrity": "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
"@typescript-eslint/scope-manager": "8.53.1",
|
||||
"@typescript-eslint/type-utils": "8.53.1",
|
||||
"@typescript-eslint/utils": "8.53.1",
|
||||
"@typescript-eslint/visitor-keys": "8.53.1",
|
||||
"ignore": "^7.0.5",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.53.1",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.1.tgz",
|
||||
"integrity": "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.53.1",
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/typescript-estree": "8.53.1",
|
||||
"@typescript-eslint/visitor-keys": "8.53.1",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.1.tgz",
|
||||
"integrity": "sha512-Lu23yw1uJMFY8cUeq7JlrizAgeQvWugNQzJp8C3x8Eo5Jw5Q2ykMdiiTB9vBVOOUBysMzmRRmUfwFrZuI2C4SQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/visitor-keys": "8.53.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.1.tgz",
|
||||
"integrity": "sha512-MOrdtNvyhy0rHyv0ENzub1d4wQYKb2NmIqG7qEqPWFW7Mpy2jzFC3pQ2yKDvirZB7jypm5uGjF2Qqs6OIqu47w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/typescript-estree": "8.53.1",
|
||||
"@typescript-eslint/utils": "8.53.1",
|
||||
"debug": "^4.4.3",
|
||||
"ts-api-utils": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/@typescript-eslint/types": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.1.tgz",
|
||||
"integrity": "sha512-jr/swrr2aRmUAUjW5/zQHbMaui//vQlsZcJKijZf3M26bnmLj8LyZUpj8/Rd6uzaek06OWsqdofN/Thenm5O8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.1.tgz",
|
||||
"integrity": "sha512-RGlVipGhQAG4GxV1s34O91cxQ/vWiHJTDHbXRr0li2q/BGg3RR/7NM8QDWgkEgrwQYCvmJV9ichIwyoKCQ+DTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.53.1",
|
||||
"@typescript-eslint/tsconfig-utils": "8.53.1",
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/visitor-keys": "8.53.1",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^9.0.5",
|
||||
"semver": "^7.7.3",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"ts-api-utils": "^2.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.1.tgz",
|
||||
"integrity": "sha512-c4bMvGVWW4hv6JmDUEG7fSYlWOl3II2I4ylt0NM+seinYQlZMQIaKaXIIVJWt9Ofh6whrpM+EdDQXKXjNovvrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.53.1",
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"@typescript-eslint/typescript-estree": "8.53.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.53.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.1.tgz",
|
||||
"integrity": "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.1",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/eslint-visitor-keys": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
|
||||
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/ignore": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
|
||||
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint/node_modules/ts-api-utils": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
|
||||
"integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/unbox-primitive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
|
||||
@ -5775,6 +6222,15 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/xxhashjs": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",
|
||||
"integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cuint": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||
|
||||
@ -8,15 +8,16 @@
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"start": "vite preview",
|
||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"lint": "eslint . --report-unused-disable-directives --max-warnings 0",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.3.0",
|
||||
"qrcode": "^1.5.4",
|
||||
"@noble/secp256k1": "^2.0.0",
|
||||
"@scure/bip32": "^2.0.1",
|
||||
"@scure/bip39": "^2.0.1",
|
||||
"bloom-filters": "^3.0.4",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.20.0"
|
||||
@ -34,6 +35,7 @@
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-unused-imports": "^3.0.0",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript-eslint": "^8.53.1",
|
||||
"vite": "^5.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,14 +2,20 @@ import { useState, useEffect } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useIdentity } from '../hooks/useIdentity';
|
||||
import { useErrorHandler } from '../hooks/useErrorHandler';
|
||||
import { useLoginStateMachine } from '../hooks/useLoginStateMachine';
|
||||
import { ErrorDisplay } from './ErrorDisplay';
|
||||
import { getStoredRelays } from '../utils/relay';
|
||||
import { GraphResolver } from '../services/graphResolver';
|
||||
import { LoginBuilder } from '../services/loginBuilder';
|
||||
import { postMessageChiffre, postSignature } from '../utils/relay';
|
||||
import { useChannel } from '../hooks/useChannel';
|
||||
import {
|
||||
verifyTimestamp,
|
||||
verifyMessageSignaturesStrict,
|
||||
} from '../utils/verification';
|
||||
import * as nonceStore from '../utils/nonceStore';
|
||||
import type { LoginPath, LoginProof } from '../types/identity';
|
||||
import type { MsgSignature } from '../types/message';
|
||||
import type { MessageBase, MsgSignature } from '../types/message';
|
||||
|
||||
export function LoginScreen(): JSX.Element {
|
||||
const navigate = useNavigate();
|
||||
@ -17,6 +23,7 @@ export function LoginScreen(): JSX.Element {
|
||||
const { identity } = useIdentity();
|
||||
const { error, handleError, clearError } = useErrorHandler();
|
||||
const { sendLoginProof } = useChannel();
|
||||
const { state: loginState, dispatch } = useLoginStateMachine();
|
||||
const [serviceUuid, setServiceUuid] = useState(searchParams.get('service') ?? '');
|
||||
const [membreUuid, setMembreUuid] = useState('');
|
||||
const [loginPath, setLoginPath] = useState<LoginPath | null>(null);
|
||||
@ -41,18 +48,26 @@ export function LoginScreen(): JSX.Element {
|
||||
|
||||
setIsBuilding(true);
|
||||
clearError();
|
||||
dispatch({ type: 'E_SELECT_SERVICE', serviceUuid });
|
||||
dispatch({ type: 'E_SELECT_MEMBER', membreUuid });
|
||||
try {
|
||||
const path = graphResolver.resolveLoginPath(serviceUuid, membreUuid);
|
||||
if (path === null) {
|
||||
handleError('Impossible de résoudre le chemin de login', 'PATH_RESOLUTION_FAILED');
|
||||
dispatch({ type: 'E_PATH_INVALID' });
|
||||
return;
|
||||
}
|
||||
setLoginPath(path);
|
||||
if (path.statut === 'incomplet') {
|
||||
handleError('Chemin incomplet. Synchronisez d\'abord les données.', 'INCOMPLETE_PATH');
|
||||
dispatch({ type: 'E_PATH_INCOMPLETE' });
|
||||
} else {
|
||||
dispatch({ type: 'E_PATH_OK' });
|
||||
dispatch({ type: 'E_PAIRS_OK' });
|
||||
}
|
||||
} catch (err) {
|
||||
handleError(err, 'Erreur lors de la construction du chemin');
|
||||
dispatch({ type: 'E_PATH_INVALID' });
|
||||
} finally {
|
||||
setIsBuilding(false);
|
||||
}
|
||||
@ -124,6 +139,8 @@ export function LoginScreen(): JSX.Element {
|
||||
|
||||
const newProof = await loginBuilder.buildProof(challenge, signatures);
|
||||
setProof(newProof);
|
||||
dispatch({ type: 'E_CHALLENGE_READY' });
|
||||
dispatch({ type: 'E_SIGNATURES_COMPLETE' });
|
||||
} catch (err) {
|
||||
handleError(err, 'Erreur lors de la construction du challenge');
|
||||
} finally {
|
||||
@ -137,6 +154,52 @@ export function LoginScreen(): JSX.Element {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!verifyTimestamp(proof.challenge.timestamp)) {
|
||||
handleError(
|
||||
'Timestamp hors fenêtre de validité (anti-rejeu)',
|
||||
'X_TIMESTAMP_OUT_OF_WINDOW',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await nonceStore.init();
|
||||
if (nonceStore.hasUsed(proof.challenge.nonce)) {
|
||||
handleError('Nonce déjà utilisé (anti-rejeu)', 'X_NONCE_REUSED');
|
||||
return;
|
||||
}
|
||||
|
||||
if (loginPath !== null) {
|
||||
const allowedPubkeys = new Set<string>();
|
||||
for (const req of loginPath.signatures_requises) {
|
||||
if (req.cle_publique !== undefined) {
|
||||
allowedPubkeys.add(req.cle_publique);
|
||||
}
|
||||
}
|
||||
if (allowedPubkeys.size > 0) {
|
||||
const minimalMsg = {
|
||||
hash: { hash_value: proof.challenge.hash },
|
||||
} as unknown as MessageBase;
|
||||
const sigs = proof.signatures.map((s) => ({
|
||||
hash: proof.challenge.hash,
|
||||
cle_publique: s.cle_publique,
|
||||
signature: s.signature,
|
||||
nonce: s.nonce,
|
||||
}));
|
||||
const { valid, unauthorized } = verifyMessageSignaturesStrict(
|
||||
minimalMsg,
|
||||
sigs,
|
||||
allowedPubkeys,
|
||||
);
|
||||
if (unauthorized.length > 0 || valid.length === 0) {
|
||||
handleError(
|
||||
'Signature(s) avec clé non autorisée par les validateurs (X_PUBKEY_NOT_AUTHORIZED)',
|
||||
'X_PUBKEY_NOT_AUTHORIZED',
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setIsPublishing(true);
|
||||
clearError();
|
||||
try {
|
||||
@ -181,16 +244,22 @@ export function LoginScreen(): JSX.Element {
|
||||
return;
|
||||
}
|
||||
|
||||
await nonceStore.markUsed(proof.challenge.nonce, proof.challenge.timestamp);
|
||||
|
||||
const updatedProof = { ...proof, statut: 'publie' as const };
|
||||
setProof(updatedProof);
|
||||
sendLoginProof(updatedProof);
|
||||
|
||||
if (successCount < relays.length) {
|
||||
handleError(
|
||||
`Publication partielle: ${successCount}/${relays.length} relais`,
|
||||
'PARTIAL_PUBLISH',
|
||||
);
|
||||
dispatch({ type: 'E_PUBLISH_LOGIN_PARTIAL' });
|
||||
} else {
|
||||
dispatch({ type: 'E_PUBLISH_LOGIN_OK' });
|
||||
dispatch({ type: 'E_LOCAL_VERDICT_ACCEPT' });
|
||||
}
|
||||
|
||||
const updatedProof = { ...proof, statut: 'publie' as const };
|
||||
setProof(updatedProof);
|
||||
sendLoginProof(updatedProof);
|
||||
} catch (err) {
|
||||
handleError(err, 'Erreur lors de la publication');
|
||||
} finally {
|
||||
@ -207,9 +276,17 @@ export function LoginScreen(): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
const handleBack = (): void => {
|
||||
dispatch({ type: 'E_BACK' });
|
||||
navigate('/');
|
||||
};
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>Se connecter</h1>
|
||||
<p role="status" aria-live="polite" className="sr-only">
|
||||
État: {loginState}
|
||||
</p>
|
||||
{error !== null && <ErrorDisplay error={error} onDismiss={clearError} />}
|
||||
<section aria-labelledby="service-selection">
|
||||
<h2 id="service-selection">Sélection du service</h2>
|
||||
@ -252,6 +329,11 @@ export function LoginScreen(): JSX.Element {
|
||||
<p>
|
||||
<strong>Statut:</strong> {loginPath.statut}
|
||||
</p>
|
||||
{loginPath.contrat_version !== undefined && (
|
||||
<p>
|
||||
<strong>Version contrat:</strong> {loginPath.contrat_version}
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
<strong>Service:</strong> {loginPath.service_uuid}
|
||||
</p>
|
||||
@ -297,7 +379,7 @@ export function LoginScreen(): JSX.Element {
|
||||
</section>
|
||||
)}
|
||||
<div>
|
||||
<button onClick={() => navigate('/')}>Retour</button>
|
||||
<button onClick={handleBack}>Retour</button>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
|
||||
@ -19,6 +19,9 @@ export function SyncScreen(): JSX.Element {
|
||||
newMessages: number;
|
||||
decrypted: number;
|
||||
validated: number;
|
||||
indechiffrable: number;
|
||||
nonValide: number;
|
||||
relayStatus: Array<{ endpoint: string; ok: boolean }>;
|
||||
} | null>(null);
|
||||
|
||||
const handleSync = async (): Promise<void> => {
|
||||
@ -101,7 +104,25 @@ export function SyncScreen(): JSX.Element {
|
||||
<li>Nouveaux messages: {stats.newMessages}</li>
|
||||
<li>Messages déchiffrés: {stats.decrypted}</li>
|
||||
<li>Messages validés: {stats.validated}</li>
|
||||
<li>
|
||||
Indéchiffrables (clé manquante): {stats.indechiffrable}
|
||||
</li>
|
||||
<li>
|
||||
Non validés (ex. signature manquante): {stats.nonValide}
|
||||
</li>
|
||||
</ul>
|
||||
{stats.relayStatus.length > 0 && (
|
||||
<>
|
||||
<h3 id="relay-status">Statut relais</h3>
|
||||
<ul aria-labelledby="relay-status">
|
||||
{stats.relayStatus.map((r) => (
|
||||
<li key={r.endpoint}>
|
||||
{r.endpoint}: {r.ok ? 'OK' : 'indisponible'}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
<div>
|
||||
|
||||
@ -15,7 +15,7 @@ export function useChannel() {
|
||||
|
||||
const handleAuthRequest = useCallback(
|
||||
(_message: AuthRequestMessage): void => {
|
||||
if (identity === null || identity.privateKey === undefined) {
|
||||
if (identity?.privateKey === undefined) {
|
||||
sendToChannel({
|
||||
type: 'error',
|
||||
payload: {
|
||||
|
||||
30
userwallet/src/hooks/useLoginStateMachine.ts
Normal file
30
userwallet/src/hooks/useLoginStateMachine.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import {
|
||||
transition,
|
||||
getInitialLoginState,
|
||||
type LoginState,
|
||||
type LoginEvent,
|
||||
type TransitionResult,
|
||||
} from '../services/loginStateMachine';
|
||||
|
||||
export interface UseLoginStateMachineResult {
|
||||
state: LoginState;
|
||||
dispatch: (event: LoginEvent) => TransitionResult;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export function useLoginStateMachine(): UseLoginStateMachineResult {
|
||||
const [state, setState] = useState<LoginState>(getInitialLoginState);
|
||||
|
||||
const dispatch = useCallback((event: LoginEvent): TransitionResult => {
|
||||
const result = transition(state, event);
|
||||
setState(result.nextState);
|
||||
return result;
|
||||
}, [state]);
|
||||
|
||||
const reset = useCallback((): void => {
|
||||
setState(getInitialLoginState());
|
||||
}, []);
|
||||
|
||||
return { state, dispatch, reset };
|
||||
}
|
||||
@ -283,4 +283,17 @@ a:focus-visible {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* Screen-reader only (e.g. login state machine status) */
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Dark theme is now the default with Bitcoin colors */
|
||||
|
||||
@ -139,6 +139,7 @@ export class GraphResolver {
|
||||
statut: 'incomplet',
|
||||
};
|
||||
}
|
||||
const contratVersion = contrat.version;
|
||||
|
||||
const champs = Array.from(this.cache.champs.values()).filter((c) =>
|
||||
c.contrats_parents_uuid.includes(service.contrat_uuid),
|
||||
@ -149,6 +150,7 @@ export class GraphResolver {
|
||||
return {
|
||||
service_uuid: serviceUuid,
|
||||
contrat_uuid: [service.contrat_uuid],
|
||||
contrat_version: contratVersion,
|
||||
champ_uuid: champs.map((c) => c.uuid),
|
||||
action_login_uuid: '',
|
||||
membre_uuid: membreUuid,
|
||||
@ -163,6 +165,7 @@ export class GraphResolver {
|
||||
return {
|
||||
service_uuid: serviceUuid,
|
||||
contrat_uuid: [service.contrat_uuid],
|
||||
contrat_version: contratVersion,
|
||||
champ_uuid: champs.map((c) => c.uuid),
|
||||
action_login_uuid: '',
|
||||
membre_uuid: membreUuid,
|
||||
@ -189,6 +192,7 @@ export class GraphResolver {
|
||||
return {
|
||||
service_uuid: serviceUuid,
|
||||
contrat_uuid: [service.contrat_uuid],
|
||||
contrat_version: contratVersion,
|
||||
champ_uuid: champs.map((c) => c.uuid),
|
||||
action_login_uuid: actionLogin.uuid,
|
||||
membre_uuid: membreUuid,
|
||||
|
||||
187
userwallet/src/services/loginStateMachine.ts
Normal file
187
userwallet/src/services/loginStateMachine.ts
Normal file
@ -0,0 +1,187 @@
|
||||
/**
|
||||
* Login state machine (specs.md).
|
||||
* States S_LOGIN_*, events E_*, transitions. Guards are evaluated by the caller.
|
||||
*/
|
||||
|
||||
export type LoginState =
|
||||
| 'S_LOGIN_SELECT_SERVICE'
|
||||
| 'S_LOGIN_SELECT_MEMBER'
|
||||
| 'S_LOGIN_BUILD_PATH'
|
||||
| 'S_LOGIN_CHECK_PAIRS'
|
||||
| 'S_LOGIN_NEED_MORE_PAIRS'
|
||||
| 'S_LOGIN_BUILD_CHALLENGE'
|
||||
| 'S_LOGIN_COLLECT_SIGNATURES'
|
||||
| 'S_LOGIN_PUBLISH_PROOF'
|
||||
| 'S_LOGIN_VERIFY_LOCAL'
|
||||
| 'S_LOGIN_SUCCESS'
|
||||
| 'S_LOGIN_FAILURE'
|
||||
| 'S_ERROR_RECOVERABLE';
|
||||
|
||||
export type LoginEvent =
|
||||
| { type: 'E_SELECT_SERVICE'; serviceUuid: string }
|
||||
| { type: 'E_SELECT_MEMBER'; membreUuid: string }
|
||||
| { type: 'E_BACK' }
|
||||
| { type: 'E_PATH_OK' }
|
||||
| { type: 'E_PATH_INCOMPLETE' }
|
||||
| { type: 'E_PATH_INVALID' }
|
||||
| { type: 'E_PAIRS_OK' }
|
||||
| { type: 'E_PAIRS_INCOMPLETE' }
|
||||
| { type: 'E_CHALLENGE_READY' }
|
||||
| { type: 'E_SIGNATURES_COMPLETE' }
|
||||
| { type: 'E_PUBLISH_LOGIN_OK' }
|
||||
| { type: 'E_PUBLISH_LOGIN_PARTIAL' }
|
||||
| { type: 'E_LOCAL_VERDICT_ACCEPT' }
|
||||
| { type: 'E_LOCAL_VERDICT_REJECT' }
|
||||
| { type: 'E_DONE' }
|
||||
| { type: 'E_RETRY' }
|
||||
| { type: 'E_SYNC_NOW' }
|
||||
| { type: 'E_ADD_PAIR' };
|
||||
|
||||
export interface TransitionResult {
|
||||
nextState: LoginState;
|
||||
errorCode?: string;
|
||||
}
|
||||
|
||||
const INITIAL: LoginState = 'S_LOGIN_SELECT_SERVICE';
|
||||
|
||||
/**
|
||||
* Compute next state from (state, event). Guards are caller responsibility.
|
||||
*/
|
||||
export function transition(
|
||||
state: LoginState,
|
||||
event: LoginEvent,
|
||||
): TransitionResult {
|
||||
switch (state) {
|
||||
case 'S_LOGIN_SELECT_SERVICE':
|
||||
if (event.type === 'E_SELECT_SERVICE') {
|
||||
return { nextState: 'S_LOGIN_SELECT_MEMBER' };
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_SELECT_SERVICE' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_SELECT_MEMBER':
|
||||
if (event.type === 'E_SELECT_MEMBER') {
|
||||
return { nextState: 'S_LOGIN_BUILD_PATH' };
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_SELECT_SERVICE' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_BUILD_PATH':
|
||||
if (event.type === 'E_PATH_OK') {
|
||||
return { nextState: 'S_LOGIN_CHECK_PAIRS' };
|
||||
}
|
||||
if (event.type === 'E_PATH_INCOMPLETE' || event.type === 'E_PATH_INVALID') {
|
||||
return {
|
||||
nextState: 'S_ERROR_RECOVERABLE',
|
||||
errorCode: 'E_PATH_INCOMPLETE',
|
||||
};
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_SELECT_MEMBER' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_CHECK_PAIRS':
|
||||
if (event.type === 'E_PAIRS_OK') {
|
||||
return { nextState: 'S_LOGIN_BUILD_CHALLENGE' };
|
||||
}
|
||||
if (event.type === 'E_PAIRS_INCOMPLETE') {
|
||||
return { nextState: 'S_LOGIN_NEED_MORE_PAIRS' };
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_BUILD_PATH' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_NEED_MORE_PAIRS':
|
||||
if (event.type === 'E_ADD_PAIR') {
|
||||
return { nextState: 'S_LOGIN_SELECT_SERVICE' };
|
||||
}
|
||||
if (event.type === 'E_SYNC_NOW') {
|
||||
return { nextState: 'S_LOGIN_BUILD_PATH' };
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_BUILD_PATH' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_BUILD_CHALLENGE':
|
||||
if (event.type === 'E_CHALLENGE_READY') {
|
||||
return { nextState: 'S_LOGIN_COLLECT_SIGNATURES' };
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_CHECK_PAIRS' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_COLLECT_SIGNATURES':
|
||||
if (event.type === 'E_SIGNATURES_COMPLETE') {
|
||||
return { nextState: 'S_LOGIN_PUBLISH_PROOF' };
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_BUILD_CHALLENGE' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_PUBLISH_PROOF':
|
||||
if (event.type === 'E_PUBLISH_LOGIN_OK') {
|
||||
return { nextState: 'S_LOGIN_VERIFY_LOCAL' };
|
||||
}
|
||||
if (event.type === 'E_PUBLISH_LOGIN_PARTIAL') {
|
||||
return {
|
||||
nextState: 'S_ERROR_RECOVERABLE',
|
||||
errorCode: 'E_PUBLISH_LOGIN_PARTIAL',
|
||||
};
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_COLLECT_SIGNATURES' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_VERIFY_LOCAL':
|
||||
if (event.type === 'E_LOCAL_VERDICT_ACCEPT') {
|
||||
return { nextState: 'S_LOGIN_SUCCESS' };
|
||||
}
|
||||
if (event.type === 'E_LOCAL_VERDICT_REJECT') {
|
||||
return { nextState: 'S_LOGIN_FAILURE' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_LOGIN_SUCCESS':
|
||||
case 'S_LOGIN_FAILURE':
|
||||
if (event.type === 'E_DONE') {
|
||||
return { nextState: 'S_LOGIN_SELECT_SERVICE' };
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S_ERROR_RECOVERABLE':
|
||||
if (event.type === 'E_RETRY') {
|
||||
return { nextState: 'S_LOGIN_BUILD_PATH' };
|
||||
}
|
||||
if (event.type === 'E_SYNC_NOW') {
|
||||
return { nextState: 'S_LOGIN_BUILD_PATH' };
|
||||
}
|
||||
if (event.type === 'E_BACK') {
|
||||
return { nextState: 'S_LOGIN_SELECT_SERVICE' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return { nextState: state };
|
||||
}
|
||||
|
||||
export function getInitialLoginState(): LoginState {
|
||||
return INITIAL;
|
||||
}
|
||||
|
||||
export function isTerminal(state: LoginState): boolean {
|
||||
return state === 'S_LOGIN_SUCCESS' || state === 'S_LOGIN_FAILURE';
|
||||
}
|
||||
|
||||
export function isErrorState(state: LoginState): boolean {
|
||||
return state === 'S_ERROR_RECOVERABLE';
|
||||
}
|
||||
@ -277,8 +277,7 @@ export async function fetchPairingMessage(
|
||||
const useEcdh =
|
||||
senderPublicKey !== undefined &&
|
||||
senderPublicKey !== '' &&
|
||||
ourIdentity !== undefined &&
|
||||
ourIdentity.privateKey !== undefined;
|
||||
ourIdentity?.privateKey !== undefined;
|
||||
|
||||
for (const r of enabled) {
|
||||
try {
|
||||
|
||||
67
userwallet/src/services/syncLoop.ts
Normal file
67
userwallet/src/services/syncLoop.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import type { RelayConfig } from '../types/identity';
|
||||
|
||||
export interface SyncOneRelayResult {
|
||||
ok: boolean;
|
||||
newHashes: string[];
|
||||
messages: number;
|
||||
newMessages: number;
|
||||
decrypted: number;
|
||||
validated: number;
|
||||
indechiffrable: number;
|
||||
nonValide: number;
|
||||
}
|
||||
|
||||
const ACC_KEYS: Array<keyof Omit<SyncOneRelayResult, 'ok' | 'newHashes'>> = [
|
||||
'messages',
|
||||
'newMessages',
|
||||
'decrypted',
|
||||
'validated',
|
||||
'indechiffrable',
|
||||
'nonValide',
|
||||
];
|
||||
|
||||
export interface RunSyncLoopOpts {
|
||||
relays: RelayConfig[];
|
||||
fetchOne: (
|
||||
endpoint: string,
|
||||
start: number,
|
||||
end: number,
|
||||
serviceUuid?: string,
|
||||
) => Promise<SyncOneRelayResult>;
|
||||
start: number;
|
||||
end: number;
|
||||
serviceUuid?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate enabled relays, call fetchOne per relay, aggregate results.
|
||||
*/
|
||||
export async function runSyncLoop(opts: RunSyncLoopOpts): Promise<{
|
||||
acc: Omit<SyncOneRelayResult, 'ok' | 'newHashes'>;
|
||||
relayStatus: Array<{ endpoint: string; ok: boolean }>;
|
||||
allNewHashes: string[];
|
||||
}> {
|
||||
const { relays, fetchOne, start, end, serviceUuid } = opts;
|
||||
const relayStatus: Array<{ endpoint: string; ok: boolean }> = [];
|
||||
const allNewHashes: string[] = [];
|
||||
const acc = {
|
||||
messages: 0,
|
||||
newMessages: 0,
|
||||
decrypted: 0,
|
||||
validated: 0,
|
||||
indechiffrable: 0,
|
||||
nonValide: 0,
|
||||
};
|
||||
for (const relay of relays) {
|
||||
if (!relay.enabled) {
|
||||
continue;
|
||||
}
|
||||
const one = await fetchOne(relay.endpoint, start, end, serviceUuid);
|
||||
relayStatus.push({ endpoint: relay.endpoint, ok: one.ok });
|
||||
for (const k of ACC_KEYS) {
|
||||
acc[k] += one[k];
|
||||
}
|
||||
allNewHashes.push(...one.newHashes);
|
||||
}
|
||||
return { acc, relayStatus, allNewHashes };
|
||||
}
|
||||
@ -3,11 +3,14 @@ import {
|
||||
getSignatures,
|
||||
getKeys,
|
||||
} from '../utils/relay';
|
||||
import { fetchAndLoadBloom } from '../utils/bloom';
|
||||
import type { RelayConfig } from '../types/identity';
|
||||
import type { MessageBase, MsgChiffre, MsgSignature, MsgCle } from '../types/message';
|
||||
import { GraphResolver } from './graphResolver';
|
||||
import { verifyMessageHash, verifyMessageSignatures, verifyTimestamp } from '../utils/verification';
|
||||
import { HashCache } from '../utils/cache';
|
||||
import { runSyncLoop, type SyncOneRelayResult } from './syncLoop';
|
||||
import { isContractVersionSupported } from '../utils/contractVersion';
|
||||
import type {
|
||||
Service,
|
||||
Contrat,
|
||||
@ -20,10 +23,15 @@ import type {
|
||||
/**
|
||||
* Service for synchronizing messages from relays.
|
||||
*/
|
||||
interface BloomLike {
|
||||
has(element: string): boolean;
|
||||
}
|
||||
|
||||
export class SyncService {
|
||||
private relays: RelayConfig[];
|
||||
private graphResolver: GraphResolver;
|
||||
private hashCache: HashCache;
|
||||
private bloomByRelay: Map<string, BloomLike> = new Map();
|
||||
|
||||
constructor(relays: RelayConfig[], graphResolver: GraphResolver) {
|
||||
this.relays = relays;
|
||||
@ -31,6 +39,22 @@ export class SyncService {
|
||||
this.hashCache = new HashCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch Bloom filter from each enabled relay. Optional: skip key fetch when hash not in relay Bloom.
|
||||
*/
|
||||
private async fetchBlooms(): Promise<void> {
|
||||
this.bloomByRelay.clear();
|
||||
for (const r of this.relays) {
|
||||
if (!r.enabled) {
|
||||
continue;
|
||||
}
|
||||
const bloom = await fetchAndLoadBloom(r.endpoint);
|
||||
if (bloom !== null) {
|
||||
this.bloomByRelay.set(r.endpoint, bloom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize HashCache (load from IndexedDB). Call before sync().
|
||||
*/
|
||||
@ -38,6 +62,114 @@ export class SyncService {
|
||||
await this.hashCache.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a new message: decrypt, validate, update graph.
|
||||
* Returns kind for stats (indechiffrable | validated | nonValide).
|
||||
*/
|
||||
private async processNewMessage(msg: MsgChiffre): Promise<
|
||||
'indechiffrable' | 'validated' | 'nonValide'
|
||||
> {
|
||||
const decrypted = await this.tryDecrypt(msg);
|
||||
if (decrypted === null) {
|
||||
return 'indechiffrable';
|
||||
}
|
||||
const valid = await this.validateMessage(decrypted);
|
||||
if (valid) {
|
||||
this.updateGraph(decrypted);
|
||||
return 'validated';
|
||||
}
|
||||
return 'nonValide';
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a batch of messages: filter seen, decrypt/validate, return counts.
|
||||
*/
|
||||
private async processMessageBatch(
|
||||
msgs: MsgChiffre[],
|
||||
): Promise<{
|
||||
newHashes: string[];
|
||||
decrypted: number;
|
||||
validated: number;
|
||||
indechiffrable: number;
|
||||
nonValide: number;
|
||||
}> {
|
||||
const newHashes: string[] = [];
|
||||
let decrypted = 0;
|
||||
let validated = 0;
|
||||
let indechiffrable = 0;
|
||||
let nonValide = 0;
|
||||
for (const msg of msgs) {
|
||||
if (this.hashCache.hasSeen(msg.hash)) {
|
||||
continue;
|
||||
}
|
||||
newHashes.push(msg.hash);
|
||||
this.hashCache.markSeen(msg.hash);
|
||||
const kind = await this.processNewMessage(msg);
|
||||
if (kind === 'indechiffrable') {
|
||||
indechiffrable++;
|
||||
} else if (kind === 'validated') {
|
||||
decrypted++;
|
||||
validated++;
|
||||
} else {
|
||||
decrypted++;
|
||||
nonValide++;
|
||||
}
|
||||
}
|
||||
return {
|
||||
newHashes,
|
||||
decrypted,
|
||||
validated,
|
||||
indechiffrable,
|
||||
nonValide,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch messages from one relay and process new ones.
|
||||
*/
|
||||
private async syncOneRelay(
|
||||
endpoint: string,
|
||||
start: number,
|
||||
end: number,
|
||||
serviceUuid?: string,
|
||||
): Promise<SyncOneRelayResult> {
|
||||
try {
|
||||
const msgs = await getMessagesChiffres(
|
||||
endpoint,
|
||||
start,
|
||||
end,
|
||||
serviceUuid,
|
||||
);
|
||||
const batch = await this.processMessageBatch(msgs);
|
||||
return {
|
||||
ok: true,
|
||||
newHashes: batch.newHashes,
|
||||
messages: msgs.length,
|
||||
newMessages: batch.newHashes.length,
|
||||
decrypted: batch.decrypted,
|
||||
validated: batch.validated,
|
||||
indechiffrable: batch.indechiffrable,
|
||||
nonValide: batch.nonValide,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Error syncing from ${endpoint}:`, error);
|
||||
return this.emptyRelayResult();
|
||||
}
|
||||
}
|
||||
|
||||
private emptyRelayResult(): SyncOneRelayResult {
|
||||
return {
|
||||
ok: false,
|
||||
newHashes: [],
|
||||
messages: 0,
|
||||
newMessages: 0,
|
||||
decrypted: 0,
|
||||
validated: 0,
|
||||
indechiffrable: 0,
|
||||
nonValide: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize messages from all enabled relays.
|
||||
*/
|
||||
@ -50,54 +182,29 @@ export class SyncService {
|
||||
newMessages: number;
|
||||
decrypted: number;
|
||||
validated: number;
|
||||
indechiffrable: number;
|
||||
nonValide: number;
|
||||
relayStatus: Array<{ endpoint: string; ok: boolean }>;
|
||||
}> {
|
||||
let messages = 0;
|
||||
let newMessages = 0;
|
||||
let decrypted = 0;
|
||||
let validated = 0;
|
||||
const newHashes: string[] = [];
|
||||
|
||||
for (const relay of this.relays) {
|
||||
if (!relay.enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const msgs = await getMessagesChiffres(
|
||||
relay.endpoint,
|
||||
start,
|
||||
end,
|
||||
serviceUuid,
|
||||
);
|
||||
|
||||
for (const msg of msgs) {
|
||||
messages++;
|
||||
if (!this.hashCache.hasSeen(msg.hash)) {
|
||||
newMessages++;
|
||||
newHashes.push(msg.hash);
|
||||
this.hashCache.markSeen(msg.hash);
|
||||
|
||||
const decryptedMsg = await this.tryDecrypt(msg);
|
||||
if (decryptedMsg !== null) {
|
||||
decrypted++;
|
||||
const isValid = await this.validateMessage(decryptedMsg);
|
||||
if (isValid) {
|
||||
validated++;
|
||||
this.updateGraph(decryptedMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error syncing from ${relay.endpoint}:`, error);
|
||||
}
|
||||
await this.fetchBlooms();
|
||||
const fetchOne = (
|
||||
ep: string,
|
||||
s: number,
|
||||
e: number,
|
||||
u?: string,
|
||||
): Promise<SyncOneRelayResult> =>
|
||||
this.syncOneRelay(ep, s, e, u);
|
||||
const { acc, relayStatus, allNewHashes } = await runSyncLoop({
|
||||
relays: this.relays,
|
||||
fetchOne,
|
||||
start,
|
||||
end,
|
||||
serviceUuid,
|
||||
});
|
||||
if (allNewHashes.length > 0) {
|
||||
await this.hashCache.markSeenBatch(allNewHashes);
|
||||
}
|
||||
|
||||
if (newHashes.length > 0) {
|
||||
await this.hashCache.markSeenBatch(newHashes);
|
||||
}
|
||||
|
||||
return { messages, newMessages, decrypted, validated };
|
||||
return { ...acc, relayStatus };
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,6 +225,7 @@ export class SyncService {
|
||||
|
||||
/**
|
||||
* Fetch decryption keys for a message hash.
|
||||
* Skip relay when Bloom says hash not seen (no false negatives).
|
||||
*/
|
||||
private async fetchKeys(hash: string): Promise<MsgCle[]> {
|
||||
const allKeys: MsgCle[] = [];
|
||||
@ -125,6 +233,10 @@ export class SyncService {
|
||||
if (!relay.enabled) {
|
||||
continue;
|
||||
}
|
||||
const bloom = this.bloomByRelay.get(relay.endpoint);
|
||||
if (bloom !== undefined && !bloom.has(hash)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const keys = await getKeys(relay.endpoint, hash);
|
||||
allKeys.push(...keys);
|
||||
@ -198,7 +310,14 @@ export class SyncService {
|
||||
if (typeNames.includes('service')) {
|
||||
this.graphResolver.addService(msg as unknown as Service);
|
||||
} else if (typeNames.includes('contrat')) {
|
||||
this.graphResolver.addContrat(msg as unknown as Contrat);
|
||||
const c = msg as unknown as Contrat;
|
||||
if (!isContractVersionSupported(c.version)) {
|
||||
console.warn(
|
||||
`[SyncService] Contrat ${c.uuid} version ${c.version} not supported, skipped`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.graphResolver.addContrat(c);
|
||||
} else if (typeNames.includes('champ')) {
|
||||
this.graphResolver.addChamp(msg as unknown as Champ);
|
||||
} else if (typeNames.includes('action')) {
|
||||
|
||||
@ -10,9 +10,7 @@ export interface Service extends MessageBase {
|
||||
/**
|
||||
* Contract object - identity contract.
|
||||
*/
|
||||
export interface Contrat extends MessageAValider {
|
||||
// Inherits MessageAValider (MessageBase + validateurs)
|
||||
}
|
||||
export type Contrat = MessageAValider;
|
||||
|
||||
/**
|
||||
* Field object - attached to contracts.
|
||||
@ -32,9 +30,7 @@ export interface Action extends MessageAValider {
|
||||
/**
|
||||
* Login action - specialization of Action.
|
||||
*/
|
||||
export interface ActionLogin extends Action {
|
||||
// types_names_chiffres includes "login"
|
||||
}
|
||||
export type ActionLogin = Action;
|
||||
|
||||
/**
|
||||
* Member object - identity authorized to execute actions.
|
||||
|
||||
@ -50,6 +50,7 @@ export interface ServiceStatus {
|
||||
export interface LoginPath {
|
||||
service_uuid: string;
|
||||
contrat_uuid: string[];
|
||||
contrat_version?: string;
|
||||
champ_uuid?: string[];
|
||||
action_login_uuid: string;
|
||||
membre_uuid: string;
|
||||
|
||||
@ -46,8 +46,28 @@ export interface EncryptionKeys {
|
||||
cle_chiffree?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* CNIL: reasons for usage with third party and third-party description.
|
||||
*/
|
||||
export interface RaisonsTiers {
|
||||
raisons: string[];
|
||||
tiers: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* CNIL: retention conditions (at least expiration delay).
|
||||
* See specs-champs-obligatoires-cnil.md.
|
||||
*/
|
||||
export interface ConditionsConservation {
|
||||
delai_expiration: string;
|
||||
unite?: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public data JSON with required and optional fields.
|
||||
* CNIL attributes (raisons_usage_tiers, raisons_partage_tiers, conditions_conservation)
|
||||
* are optional but required for CNIL compliance when applicable.
|
||||
*/
|
||||
export interface DataJson {
|
||||
services_uuid: string[];
|
||||
@ -64,6 +84,12 @@ export interface DataJson {
|
||||
image?: string;
|
||||
}>;
|
||||
tarif?: string;
|
||||
/** CNIL: reasons for usage with third parties and description. */
|
||||
raisons_usage_tiers?: RaisonsTiers[];
|
||||
/** CNIL: reasons for sharing with third parties and description. */
|
||||
raisons_partage_tiers?: RaisonsTiers[];
|
||||
/** CNIL: retention conditions (at least delai_expiration). */
|
||||
conditions_conservation?: ConditionsConservation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
23
userwallet/src/utils/bloom.ts
Normal file
23
userwallet/src/utils/bloom.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import bloomFilters from 'bloom-filters';
|
||||
import { getBloom } from './relay';
|
||||
|
||||
type BloomFilterInstance = ReturnType<typeof bloomFilters.BloomFilter.fromJSON>;
|
||||
|
||||
/**
|
||||
* Fetch Bloom filter from relay and load from JSON.
|
||||
* Returns null on fetch or parse failure (e.g. relay without /bloom).
|
||||
*/
|
||||
export async function fetchAndLoadBloom(
|
||||
relay: string,
|
||||
): Promise<BloomFilterInstance | null> {
|
||||
try {
|
||||
const json = await getBloom(relay);
|
||||
const { BloomFilter } = bloomFilters;
|
||||
const filter = BloomFilter.fromJSON(
|
||||
json as Parameters<typeof BloomFilter.fromJSON>[0],
|
||||
);
|
||||
return filter;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,7 @@ export function calculateCanonicalHash(
|
||||
message: Record<string, unknown>,
|
||||
algo: string = 'sha256',
|
||||
): string {
|
||||
const { hash, signatures, cles_de_chiffrement, ...canonical } = message;
|
||||
const { hash: _hash, signatures: _signatures, cles_de_chiffrement: _cles_de_chiffrement, ...canonical } = message;
|
||||
const canonicalJson = canonicalizeJson(canonical);
|
||||
return hashString(canonicalJson, algo);
|
||||
}
|
||||
|
||||
8
userwallet/src/utils/contractVersion.ts
Normal file
8
userwallet/src/utils/contractVersion.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Supported contract versions. Reject or isolate unsupported ones (specs).
|
||||
*/
|
||||
export const SUPPORTED_CONTRACT_VERSIONS: readonly string[] = ['1.0'];
|
||||
|
||||
export function isContractVersionSupported(version: string): boolean {
|
||||
return SUPPORTED_CONTRACT_VERSIONS.includes(version);
|
||||
}
|
||||
@ -135,7 +135,7 @@ export function isProtectionEnabled(): boolean {
|
||||
*/
|
||||
export async function enableProtection(password: string): Promise<void> {
|
||||
const identity = getStoredIdentity();
|
||||
if (identity === null || identity.privateKey === undefined) {
|
||||
if (identity?.privateKey === undefined) {
|
||||
throw new Error('No identity or private key to protect');
|
||||
}
|
||||
const payload = await encryptPrivateKey(identity.privateKey, password);
|
||||
|
||||
@ -8,14 +8,16 @@ function openDb(): Promise<IDBDatabase> {
|
||||
if (dbInstance !== null) {
|
||||
return Promise.resolve(dbInstance);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<IDBDatabase>((resolve, reject): void => {
|
||||
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
||||
req.onerror = () => reject(req.error);
|
||||
req.onsuccess = () => {
|
||||
req.onerror = (): void => {
|
||||
reject(req.error);
|
||||
};
|
||||
req.onsuccess = (): void => {
|
||||
dbInstance = req.result;
|
||||
resolve(req.result);
|
||||
};
|
||||
req.onupgradeneeded = () => {
|
||||
req.onupgradeneeded = (): void => {
|
||||
const db = req.result;
|
||||
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
||||
db.createObjectStore(STORE_NAME, { keyPath: 'key' });
|
||||
@ -29,12 +31,14 @@ function openDb(): Promise<IDBDatabase> {
|
||||
*/
|
||||
export async function idbGet(key: string): Promise<string | null> {
|
||||
const db = await openDb();
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<string | null>((resolve, reject): void => {
|
||||
const tx = db.transaction(STORE_NAME, 'readonly');
|
||||
const store = tx.objectStore(STORE_NAME);
|
||||
const req = store.get(key);
|
||||
req.onerror = () => reject(req.error);
|
||||
req.onsuccess = () => {
|
||||
req.onerror = (): void => {
|
||||
reject(req.error);
|
||||
};
|
||||
req.onsuccess = (): void => {
|
||||
const row = req.result as { key: string; value: string } | undefined;
|
||||
resolve(row?.value ?? null);
|
||||
};
|
||||
@ -46,12 +50,16 @@ export async function idbGet(key: string): Promise<string | null> {
|
||||
*/
|
||||
export async function idbSet(key: string, value: string): Promise<void> {
|
||||
const db = await openDb();
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<void>((resolve, reject): void => {
|
||||
const tx = db.transaction(STORE_NAME, 'readwrite');
|
||||
const store = tx.objectStore(STORE_NAME);
|
||||
const req = store.put({ key, value });
|
||||
req.onerror = () => reject(req.error);
|
||||
req.onsuccess = () => resolve();
|
||||
req.onerror = (): void => {
|
||||
reject(req.error);
|
||||
};
|
||||
req.onsuccess = (): void => {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -60,11 +68,15 @@ export async function idbSet(key: string, value: string): Promise<void> {
|
||||
*/
|
||||
export async function idbRemove(key: string): Promise<void> {
|
||||
const db = await openDb();
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise<void>((resolve, reject): void => {
|
||||
const tx = db.transaction(STORE_NAME, 'readwrite');
|
||||
const store = tx.objectStore(STORE_NAME);
|
||||
const req = store.delete(key);
|
||||
req.onerror = () => reject(req.error);
|
||||
req.onsuccess = () => resolve();
|
||||
req.onerror = (): void => {
|
||||
reject(req.error);
|
||||
};
|
||||
req.onsuccess = (): void => {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
92
userwallet/src/utils/nonceStore.ts
Normal file
92
userwallet/src/utils/nonceStore.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { idbGet, idbSet } from './indexedDbStorage';
|
||||
|
||||
const STORAGE_KEY = 'userwallet_nonce_cache';
|
||||
const DEFAULT_TTL_MS = 3600000;
|
||||
|
||||
interface NonceEntry {
|
||||
n: string;
|
||||
t: number;
|
||||
}
|
||||
|
||||
interface Stored {
|
||||
entries: NonceEntry[];
|
||||
ttlMs: number;
|
||||
}
|
||||
|
||||
let cache: Map<string, number> = new Map();
|
||||
let initialized = false;
|
||||
let ttlMs = DEFAULT_TTL_MS;
|
||||
|
||||
function prune(now: number): void {
|
||||
for (const [n, t] of cache.entries()) {
|
||||
if (now - t >= ttlMs) {
|
||||
cache.delete(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function load(): Promise<void> {
|
||||
const raw = await idbGet(STORAGE_KEY);
|
||||
cache = new Map();
|
||||
if (raw !== null) {
|
||||
try {
|
||||
const parsed = JSON.parse(raw) as Stored;
|
||||
ttlMs = parsed.ttlMs ?? DEFAULT_TTL_MS;
|
||||
for (const e of parsed.entries ?? []) {
|
||||
cache.set(e.n, e.t);
|
||||
}
|
||||
} catch {
|
||||
/* invalid JSON: start empty */
|
||||
}
|
||||
}
|
||||
prune(Date.now());
|
||||
}
|
||||
|
||||
async function save(): Promise<void> {
|
||||
const entries: NonceEntry[] = [];
|
||||
for (const [n, t] of cache.entries()) {
|
||||
entries.push({ n, t });
|
||||
}
|
||||
const stored: Stored = { entries, ttlMs };
|
||||
await idbSet(STORAGE_KEY, JSON.stringify(stored));
|
||||
}
|
||||
|
||||
/**
|
||||
* Anti-replay nonce store (IndexedDB-backed).
|
||||
* Call init() before hasUsed / markUsed.
|
||||
*/
|
||||
export async function init(ttlMsOverride?: number): Promise<void> {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
if (ttlMsOverride !== undefined) {
|
||||
ttlMs = ttlMsOverride;
|
||||
}
|
||||
await load();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if this nonce was already used within the TTL window.
|
||||
*/
|
||||
export function hasUsed(nonce: string): boolean {
|
||||
const t = cache.get(nonce);
|
||||
if (t === undefined) {
|
||||
return false;
|
||||
}
|
||||
if (Date.now() - t >= ttlMs) {
|
||||
cache.delete(nonce);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark nonce as used. Persists to IndexedDB.
|
||||
*/
|
||||
export async function markUsed(nonce: string, timestamp: number): Promise<void> {
|
||||
const now = Date.now();
|
||||
cache.set(nonce, timestamp);
|
||||
prune(now);
|
||||
await save();
|
||||
}
|
||||
@ -143,3 +143,18 @@ export async function postKey(relay: string, key: MsgCle): Promise<void> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET Bloom filter (JSON) of seen message hashes from relay.
|
||||
* Optional: clients can use it to avoid requesting messages for hashes already known.
|
||||
* Throws on fetch failure or non-ok response.
|
||||
*/
|
||||
export async function getBloom(relay: string): Promise<unknown> {
|
||||
const response = await fetch(`${relay}/bloom`);
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Relay GET /bloom failed: ${response.status} ${response.statusText} (${relay})`,
|
||||
);
|
||||
}
|
||||
return (await response.json()) as unknown;
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ export async function verifyMessageHash(
|
||||
algo: string = 'sha256',
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const { hash, signatures, cles_de_chiffrement, ...canonical } = message;
|
||||
const { hash, signatures: _signatures, cles_de_chiffrement: _cles_de_chiffrement, ...canonical } = message;
|
||||
const calculatedHash = await hashStringAsync(
|
||||
JSON.stringify(canonical),
|
||||
algo,
|
||||
@ -22,7 +22,7 @@ export async function verifyMessageHash(
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify all signatures of a message.
|
||||
* Verify all signatures of a message (crypto only).
|
||||
*/
|
||||
export function verifyMessageSignatures(
|
||||
message: MessageBase,
|
||||
@ -57,6 +57,54 @@ export function verifyMessageSignatures(
|
||||
return { valid, invalid };
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter signatures to those whose cle_publique is in allowedPubkeys.
|
||||
* Use after crypto verification to enforce "clé autorisée" (validators).
|
||||
*/
|
||||
export function filterSignaturesByAuthorizedPubkeys(
|
||||
signatures: Signature[],
|
||||
allowedPubkeys: Set<string>,
|
||||
): { authorized: Signature[]; unauthorized: Signature[] } {
|
||||
const authorized: Signature[] = [];
|
||||
const unauthorized: Signature[] = [];
|
||||
for (const sig of signatures) {
|
||||
if (allowedPubkeys.has(sig.cle_publique)) {
|
||||
authorized.push(sig);
|
||||
} else {
|
||||
unauthorized.push(sig);
|
||||
}
|
||||
}
|
||||
return { authorized, unauthorized };
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify signatures: crypto then filter by allowed pubkeys.
|
||||
* Returns valid only if both crypto-valid and authorized.
|
||||
*/
|
||||
export function verifyMessageSignaturesStrict(
|
||||
message: MessageBase,
|
||||
signatures: Signature[],
|
||||
allowedPubkeys: Set<string>,
|
||||
): {
|
||||
valid: Signature[];
|
||||
invalid: Signature[];
|
||||
unauthorized: Signature[];
|
||||
} {
|
||||
const { valid: cryptoValid, invalid } = verifyMessageSignatures(
|
||||
message,
|
||||
signatures,
|
||||
);
|
||||
const { authorized, unauthorized } = filterSignaturesByAuthorizedPubkeys(
|
||||
cryptoValid,
|
||||
allowedPubkeys,
|
||||
);
|
||||
return {
|
||||
valid: authorized,
|
||||
invalid: [...invalid, ...unauthorized],
|
||||
unauthorized,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a nonce has been used before (anti-replay).
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user