
Un kit d'outils de graphes pour la recherche sur les menaces - et autres choses
Ce projet a été largement « vibecodé » (développé de manière informelle), alors prenez les précautions nécessaires. Le code a été relu par de vrais programmeurs, mais il n'est pas renforcé contre les vulnérabilités. Ne l'exposez pas à l'extérieur sans une revue de sécurité approfondie.
Quantickle est une boîte à outils interactive, orientée navigateur, pour construire et explorer des graphes réseau. Le front-end (Cytoscape.js + UI personnalisée) gère le rendu, l'édition et l'exécution des dispositions, tandis que le serveur Express léger sert l'interface, relaie les appels d'intégration et stocke optionnellement les graphes dans Neo4j. En d'autres termes, le navigateur détient l'état du graphe et la visualisation, tandis que le serveur existe pour fournir les ressources et les intégrations lorsque nécessaire.
bezier), droite, regroupée (unbundled-bezier), taxi et taxi arrondi.haystack et segments via un style personnalisé.Voici quelques exemples de ce que Quantickle peut faire :

Quantickle repose sur un petit ensemble de concepts partagés qui relient l'ensemble de la documentation :
Système de coordonnées et dispositions spatiales — Les dispositions absolues et conscientes de la profondeur de Quantickle utilisent un cube de 0 à 1000 pour les coordonnées x, y et z. Voir COORDINATE_SYSTEM.md pour les règles spatiales complètes et le comportement d'éclairage.
Gestion des fichiers de graphe et fichiers de projet — Les fichiers .qut sont l'état sauvegardé canonique ; ils stockent les nœuds, les arêtes, les métadonnées et la hiérarchie des conteneurs.
Intégration Neo4j — le serveur peut persister et récupérer des graphes depuis Neo4j, y compris des instantanés de métadonnées. Voir NEO4J_INTEGRATION_README.md pour les détails de configuration et de flux de travail.
Un graphe Quantickle est un ensemble de nœuds et d'arêtes avec des métadonnées qui pilotent la disposition, le style et le regroupement.
metadata, le tableau de nœuds, le tableau d'arêtes, et éventuellement l'état de disposition ou de vue.id obligatoire plus des attributs optionnels comme label, type, size, color, et des coordonnées. Les nœuds peuvent également inclure un champ info Markdown ou des propriétés personnalisées utilisées par les intégrations.source et target, et optionnellement label, type, weight, et des métadonnées de style.Quantickle’s internal graph JSON is a flattened structure with nodes and edges arrays. Container relationships and classes are preserved as node metadata.
Quantickle accepte plusieurs formats d'import depuis Fichier → Importer des données et depuis les intégrations automatisées. Chaque importateur alimente le même pipeline de graphe utilisé lors de la sauvegarde des fichiers de projet .qut, donc les structures ci-dessous représentent également les formes d'export.
L'importateur CSV reconnaît deux dispositions :
Sections nœuds + arêtes – format d'export utilisé par Quantickle et l'option la plus sûre lors de la préparation manuelle des données. Le fichier contient un tableau de nœuds suivi d'une ligne vide et d'un tableau d'arêtes : ```csv node_id,node_label,node_type,node_size,node_color,node_x,node_y srv-1,Gateway,server,40,#2dd4bf,100,250 cli-1,Analyst,client,28,#38bdf8,320,210
source,target,label,weight,type srv-1,cli-1,allows,1,connection
Les colonnes supplémentaires sont tolérées—l'importateur normalise les en-têtes tels que
Node Label, nodeLabel, ou label, préserve toute valeur explicite de color/size
et conserve les coordonnées lorsqu'elles sont fournies.
source et target. Les colonnes optionnelles telles que label, type,
weight, source_type, target_type, source_label, ou color sont fusionnées
dans les nœuds et arêtes générés lorsqu'elles sont présentes : ```csv
source,target,label,source_type,target_type
srv-1,cli-1,allows,server,client
srv-1,sensor-2,monitors,server,sensor
Quantickle analyse les en-têtes sans tenir compte de la casse, accepte à la fois les noms en snake_case et les noms avec espaces, et ignore automatiquement les lignes vides.
.edges)Les paires d'arêtes simples séparées par des espaces sont prises en charge pour des graphes squelettes rapides. Les nœuds manquants sont créés automatiquement :```text srv-1 cli-1 srv-1 sensor-2
> **Note:** Les classeurs Excel (`.xlsx`) ne sont plus pris en charge. Exportez ou enregistrez les données au format CSV avant de les importer dans Quantickle.
#### JSON
`File → Import Data` accepte également les exports JSON produits par Quantickle ou les collections brutes d'éléments Cytoscape. Lorsque le fichier contient des `elements` avec des entrées `data` imbriquées, elles sont normalisées dans la structure interne de Quantickle.
#### Quantickle graph (`.qut`)
Les fichiers `.qut` sont des documents JSON avec des objets nœuds et arêtes aplatis. Un graphe minimal ressemble à :```json
{
"metadata": { "name": "My graph" },
"nodes": [
{ "id": "srv-1", "label": "Gateway", "type": "server", "size": 40 }
],
"edges": [
{ "id": "srv-1_cli-1", "source": "srv-1", "target": "cli-1", "label": "allows" }
]
}
Fichiers hérités qui stockent les nœuds/arêtes à l'intérieur d'un objet data sont toujours acceptés—le
chargeur les aplatit automatiquement et préserve les coordonnées, les classes et les
métadonnées de hiérarchie de conteneurs.
Lors de l'échange de données avec l'API HTTP ou l'intégration Neo4j, envoyez la même
forme aplatie utilisée par les fichiers .qut :```json
{
"nodes": [
{ "id": "srv-1", "label": "Gateway", "type": "server", "size": 40 }
],
"edges": [
{ "id": "srv-1_cli-1", "source": "srv-1", "target": "cli-1", "label": "allows" }
]
}
Le champ `info` optionnel prend toujours en charge Markdown et est conservé avec les propriétés personnalisées.
<a id="layouts"></a>
## Dispositions
Quantickle regroupe les dispositions en familles pratiques afin que vous puissiez choisir celle qui convient à la tâche :
- **Force-directed** (force, cose, fcose) — idéal pour la découverte exploratoire de structures et lorsque vous souhaitez un regroupement naturel.
- **Hiérarchique & flux** (breadthfirst, dagre) — meilleur pour les arbres de dépendances, les graphes d'appel ou les flux causaux.
- **Grille & cercle** — dispositions rapides et déterministes pour les tableaux de bord, les petits graphes et les exportations.
- **Temporel** (timeline, timeline-scatter, temporal-attraction) — utilisez lorsque l'ordre temporel ou la récence est l'élément clé.
- **Spatial/absolu** (absolute, depth-aware) — utilisez pour des dispositions de type carte ou diagrammes avec des coordonnées connues.
- **Cluster/radial** (radial-recency) — utilisez lorsque vous souhaitez un regroupement par type ou par anneaux de récence.
### Options de disposition```javascript
// js/layouts.js
const layoutOptions = {
'force': {
name: 'force',
animate: true,
randomize: false,
infinite: false
},
'grid': {
name: 'grid',
rows: undefined,
cols: undefined
}
// ... more layouts
}
La disposition personnalisée timeline positionne les nœuds le long d'un axe temporel. Vous pouvez personnaliser la barre centrale via l'option barStyle :```javascript
cy.layout({
name: 'timeline',
barStyle: {
color: '#3498db', // bar color
height: 15, // bar height in pixels
className: 'my-timeline-bar' // optional CSS class
}
}).run();
Lorsque `className` est fourni, la barre de chronologie reçoit cette classe et son style de couleur et de hauteur par défaut sont supprimés afin que vous puissiez la cibler via CSS.
### Disposition radiale de récence
Utilisez `radial-recency` pour placer les éléments les plus récents près du centre et les plus anciens sur les anneaux extérieurs. La disposition associe l'angle à un attribut secondaire (type/cluster/group) afin que les nœuds liés restent alignés autour du cercle. Vous pouvez ajuster les anneaux avec quelques options :```javascript
cy.layout({
name: 'radial-recency',
ringThickness: 140, // radial spacing between time rings
minSeparation: 80, // minimum distance between neighbors along a ring
angleJitter: 0.15, // optional jitter (radians) to break perfect symmetry
angleStrategy: 'grouped' // or 'alphabetical' for deterministic ordering
}).run();
Voir graphs/radial_time_rings.qut pour un petit exemple qui montre des bandes de temps concentriques groupées par métadonnées de cluster/type.
Utilisez la disposition timeline-scatter pour mapper les horodatages directement aux positions x tout en distribuant les nœuds verticalement par similarité, catégorie ou communauté. Elle accepte des échelles ajustables pour les deux axes et un décalage optionnel pour réduire le chevauchement :```javascript
cy.layout({
name: 'timeline-scatter',
xScale: 0.5, // pixels per millisecond (auto-calculated when omitted)
yScale: 60, // spread for similarity/category lanes
jitter: 4, // optional per-node jitter to minimise overlap
barStyle: { // applied when timeline bars already exist
color: '#222',
height: 12,
className: 'scatter-bar'
}
}).run();
Nodes with numeric similarity scores (`similarity`, `similarityScore`, or `similarity_score`) are centred around the mean, while categorical or community labels create evenly spaced lanes along the y-axis.
### Disposition d'attraction temporelle
Utilisez la distance temporelle pour diriger les forces des ressorts tout en gardant la répulsion légère :```javascript
cy.layout({
name: 'temporal-attraction',
timeMode: 'gaussian', // or 'bucket'
timeSigma: 60 * 60 * 1000, // Gaussian falloff window (in ms)
bucketSize: 24 * 60 * 60 * 1000, // bucket size when using bucket mode
repulsionStrength: 12 // minimal node repulsion
}).run();
Select Disposition → Temporal Attraction - Time Weighted dans l'interface ou passez name: 'temporal-attraction' via la configuration de disposition CLI/API pour l'activer.
Quantickle peut extraire des données ou se synchroniser avec des systèmes externes. Les intégrations transitent généralement par le serveur car elles nécessitent des identifiants, des règles de proxy ou une persistance.
http://localhost:3000.Pour des tutoriels plus détaillés et des captures d'écran, consultez le Guide d'utilisation.
.qut pour un instantané de projet haute fidélité (disposition, métadonnées, conteneurs).Quantickle s'initialise via le global window.QuantickleApp défini dans js/main.js. L'application appelle automatiquement window.QuantickleApp.init() lorsque le DOM est prêt.
// js/config.js const config = { performance: { nodeLimit: 1000, // Max nodes to render at once batchSize: 100, // Nodes to add per batch webgl: true, // Enable WebGL rendering hideEdgesOnViewport: false // Hide edges while dragging } }
<a id="api"></a>
## API
### API HTTP
Le serveur Express (`server.js`) sert le front-end statique et expose plusieurs
points de terminaison JSON utilisés par l'interface utilisateur. Toutes les routes sont préfixées par `/api` :
| Méthode et chemin | Description |
| --- | --- |
| `GET /api/domain-files` | Liste les définitions de domaine JSON présentes dans `assets/domains/`. |
| `GET /api/examples` | Renvoie les métadonnées des exemples de graphes `.qut` fournis. |
| `GET /api/serpapi` | Proxie les requêtes Google Search vers SerpApi ; nécessite `SERPAPI_API_KEY` dans la chaîne de requête ou l'environnement. |
| `GET /api/openai/models` | Proxie les requêtes de liste de modèles OpenAI vers `api.openai.com` ; nécessite un en-tête `Authorization: Bearer ...`. |
| `GET /api/proxy?url=…` | Transfère les requêtes HTTP/HTTPS vers des hôtes autorisés avec des en-têtes de type navigateur. |
| `POST /api/neo4j/graph` | Persiste un graphe dans Neo4j. Accepte le corps JSON du graphe Quantickle aplati décrit ci-dessus. |
| `POST /api/neo4j/node-graphs` | Trouve les graphes sauvegardés qui contiennent des nœuds correspondant au tableau `labels` fourni. |
| `GET /api/neo4j/graphs` | Liste les graphes stockés dans Neo4j avec leurs métadonnées récapitulatives. |
| `GET /api/neo4j/graph/:name` | Récupère un graphe sauvegardé, renvoyant `metadata`, `nodes` et `edges`. |
| `DELETE /api/neo4j/graph/:name` | Supprime un graphe stocké dans Neo4j. |
Tous les points de terminaison Neo4j acceptent les identifiants via les en-têtes `X-Neo4j-Url`, `X-Neo4j-Username`,
et `X-Neo4j-Password` (ou les variables d'environnement `NEO4J_URL`, `NEO4J_USER` et
`NEO4J_PASSWORD` sur le serveur). Lorsqu'il est fourni, l'objet `metadata` est sauvegardé avec le graphe et un horodatage `savedAt` est automatiquement ajouté.
<a id="api-keys"></a>
### Clés API
Certaines fonctionnalités nécessitent des clés API. Elles sont stockées dans le stockage local du navigateur via le panneau Intégrations.
- **SerpAPI** — requis pour la recherche web du pipeline RAG. Ajoutez votre clé dans la boîte de dialogue Intégrations et elle sera utilisée par le pipeline RAG côté client.
- **VirusTotal** — utilisé pour enrichir les nœuds de domaine/IP/fichier/URL et extraire les graphes de relations.
- **CIRCL-LU** — identifiants d'authentification optionnels si votre flux MISP les nécessite.
Pour une utilisation en ligne de commande, vous pouvez également définir `SERPAPI_API_KEY` dans l'environnement.
<a id="backend-proxy"></a>
### Proxy backend
Le serveur expose un proxy contournant le CORS qui transfère les requêtes HTTP(S) vers les hôtes listés dans la liste blanche du proxy. Utilisez `/api/proxy` avec un paramètre d'URL :```
curl "http://localhost:3000/api/proxy?url=https%3A%2F%2Fopentip.kaspersky.com%2F"
La liste blanche de base se trouve dans config/proxy-allowlist.json. Vous devez fournir ce fichier (ou définir une variable d'environnement PROXY_ALLOWLIST séparée par des virgules avant de démarrer le serveur) ; sinon, le proxy enregistre une erreur de configuration fatale et rejette chaque requête avec HTTP 403.
Les hôtes spécifiques à l'intégration (pour les adaptateurs d'intégration backend comme OpenAI et VirusTotal) sont régis par config/integration-allowlist.json (ou INTEGRATION_ALLOWLIST). Au moment de l'exécution, les deux listes blanches sont fusionnées. Chaque entrée doit lister un hôte ou un motif générique que le proxy peut atteindre. Les motifs génériques utilisant * sont pris en charge n'importe où dans une entrée, donc *.example.com permet n'importe quel sous-domaine de example.com, et les masques comme news-* se comportent comme prévu. Les sous-domaines héritent également de l'entrée de leur domaine parent, donc ajouter example.com permet automatiquement www.example.com.
Un fichier de liste blanche minimal ressemble à :
``````json
{
"allowlist": ["otx.alienvault.com", "feeds.example.org"]
}
Si vous préférez les variables d'environnement, définissez PROXY_ALLOWLIST="otx.alienvault.com,feeds.example.org" avant de lancer le serveur.
Lorsque le proxy transmet une requête, il envoie désormais un ensemble d'en-têtes similaires à ceux d'un navigateur (incluant les valeurs modernes User-Agent, Accept, Accept-Language et Sec-Fetch-* de Chrome) afin que les sites qui filtrent le contenu derrière des protections anti-bot répondent de la même manière qu'ils le feraient lors d'un chargement de page normal. N'importe lequel de ces en-têtes peut être remplacé en fournissant des surcharges x-proxy-<header> depuis la requête client si nécessaire.
Quantickle conserve l'état du graphe dans le navigateur pendant que vous travaillez, puis le persiste lorsque vous exportez ou synchronisez.
.qut) — sauvegardés dans votre dossier de travail pour des instantanés de graphe haute fidélité. Voir GRAPH_FILE_MANAGEMENT_README.md pour les règles du dossier de travail et le cycle de vie des fichiers.quantickle/
├── assets/ # Static assets
│ ├── backgrounds/ # Background graphics
│ ├── icons/ # Mostly empty now; icons are colocated with node types
│ ├── domains/ # Node type definitions
│ ├── help/ # Help pages
│ ├── examples/ # Example graphs
│ └── css/ # Stylesheets referenced by index.html
├── config/ # Proxy allowlist
├── data_retrieval/ # SerpAPI/web search helpers used by the RAG pipeline
├── graphs/ # Workspace folder for bundled and test .qut graphs
├── js/ # Front-end source modules
│ ├── main.js # Application bootstrap
│ ├── ai-input-manager.js # Currently unused
│ ├── api.js # HTTP client for server endpoints
│ ├── graph.js # Graph rendering and management
│ ├── graph-manager.js # High-level graph state orchestration
│ ├── graph-reference-resolver.js # Normalization of graph references
│ ├── layouts.js # Layout registration and options
│ ├── 3d-globe-layout.js # 3D Layout
│ ├── absolute-layout.js # Absolute coordinate layout
│ ├── custom-layouts.js # Other custom layouts
│ ├── aggressive-performance-fix.js # Aggressive Performance Fix for Large Graph Panning
│ ├── non-invasive-performance-fix.js # Non-Invasive Performance Fix for Large Graphs
│ ├── lod-system.js # Level of Detail (LOD) System
│ ├── auto-refresh.js # Auto-refresh functionality when new data arrives
│ ├── config.js # Default settings
│ ├── domain-loader.js # Loading and managing domain-specific node type configurations
│ ├── edge-editor.js # Editing edge styles
│ ├── extensions.js # Loading and registration of Cytoscape extensions
│ ├── integrations.js # Configuration and connection to external services
│ ├── rag-pipeline.js # Handles AI-assisted data ingestion
│ ├── secure-storage.js # Encrypts sensitive values in sessionStorage
│ ├── source-editor.js # Editor for the JSON graph source
│ ├── tables.js # Data table updates, filtering, and display
│ ├── ui.js # User interface interactions and notifications
│ ├── validation.js # Validation of all data inputs
│ ├── workspace-manager.js # Workspace file functionality
│ ├── utils.js # Shared browser utilities
│ ├── integrations/ # Integration-specific helpers (MISP/CIRCL-LU, etc.)
│ └── features/ # Feature modules (node editor, callouts, timeline, ...)
├── tests/ # Automated regression tests covering UI flows, imports, and APIs
├── utils/ # Node helpers (Neo4j client, readability shim, CLI scripts)
├── public/
│ ├── index.html # Static front-end
│ └── favicon.ico # Main app icon
├── package.json # Node dependencies and scripts
└── server.js # Express server exposing the HTTP API
<a id="troubleshooting"></a>
## 🐛 Dépannage
### Problèmes courants
1. **Le graphe ne s'affiche pas**
- Vérifier la console du navigateur pour les erreurs
- Vérifier le format des données
- Vérifier le support WebGL
2. **Mauvaise performance**
- Réduire la limite de nœuds dans la configuration
- Activer le rendu WebGL
- Utiliser des mises en page plus simples pour les grands graphes
3. **Problèmes de mise en page**
- Essayer différents algorithmes de mise en page
- Ajuster les paramètres de mise en page
- Vérifier les nœuds déconnectés
## 🤝 Contribuer
Ce projet n'est pas activement maintenu en tant que dépôt canonique. Les PR seront probablement ignorées. Cependant, les retours, les rapports de bogues et les commentaires sont les bienvenus.
## 📄 Licence
Ce projet est sous licence Apache 2.0 - voir le fichier LICENSE pour plus de détails.
## 🙏 Remerciements
- Construit avec [Cytoscape.js](https://js.cytoscape.org/)
- Algorithmes de mise en page de divers contributeurs de Cytoscape
- Optimisations de performance inspirées par la recherche en visualisation de graphes à grande échelle
<a id="additional-documentation"></a>
## 📚 Documentation supplémentaire
- [Guide d'utilisation](https://github.com/rsac-labs/quantickle/blob/main/USAGE_GUIDE.md)
- [Gestion des fichiers de graphes](https://github.com/rsac-labs/quantickle/blob/main/GRAPH_FILE_MANAGEMENT_README.md)
- [Intégration Neo4j](https://github.com/rsac-labs/quantickle/blob/main/NEO4J_INTEGRATION_README.md)
- [Système de coordonnées](https://github.com/rsac-labs/quantickle/blob/main/COORDINATE_SYSTEM.md)
- [Guide des performances](https://github.com/rsac-labs/quantickle/blob/main/PERFORMANCE.md)