
Um kit de ferramentas de grafos para pesquisa de ameaças - e outras coisas
Este projeto foi em grande parte vibecoded, então tome as devidas precauções. O código foi revisado por programadores reais, mas não está endurecido contra vulnerabilidades. Não exponha externamente sem uma revisão de segurança minuciosa.
O Quantickle é um kit de ferramentas interativo, focado no navegador, para construir e explorar grafos de rede. O front-end (Cytoscape.js + UI personalizada) lida com renderização, edição e execução de layout, enquanto o servidor leve Express serve a UI, faz proxy de chamadas de integração e, opcionalmente, armazena grafos no Neo4j. Em outras palavras, o navegador detém o estado do grafo e a visualização, enquanto o servidor existe para fornecer recursos e integrações quando necessário.
bezier), retas, agrupadas (unbundled-bezier), taxi e taxi arredondado.haystack e segments através de estilização personalizada.Aqui estão alguns exemplos do que o Quantickle pode fazer:

O Quantickle se baseia em um pequeno conjunto de conceitos compartilhados que conectam o conjunto de documentação:
Sistema de coordenadas e layouts espaciais — Os layouts absolutos e cientes de profundidade do Quantickle usam um cubo de 0–1000 para coordenadas x, y e z. Consulte COORDINATE_SYSTEM.md para regras espaciais completas e comportamento de iluminação.
Gerenciamento de arquivos de grafo e arquivos de projeto — Arquivos .qut são o estado salvo canônico; eles armazenam nós, arestas, metadados e hierarquia de contêineres.
Integração Neo4j — o servidor pode persistir e recuperar grafos do Neo4j, incluindo snapshots de metadados. Consulte NEO4J_INTEGRATION_README.md para detalhes de configuração e fluxo de trabalho.
Um grafo do Quantickle é um conjunto de nós e arestas com metadados que orientam layout, estilização e agrupamento.
metadata, array de nós, array de arestas e estado opcional de layout ou visualização.idlabeltypesizecolorinfosource + target e label, type, weight opcionais e metadados de estilização.O JSON interno do grafo do Quantickle é uma estrutura achatada com arrays nodes e edges. Relacionamentos e classes de contêiner são preservados como metadados de nó.
O Quantickle aceita vários formatos de importação de Arquivo → Importar Dados e de integrações automatizadas. Cada importador alimenta o mesmo pipeline de grafo usado ao salvar arquivos de projeto .qut, portanto, as estruturas abaixo também representam formas de exportação.
O importador CSV reconhece dois layouts:
Seções de nós + arestas – formato de exportação usado pelo Quantickle e a opção mais segura ao preparar dados manualmente. O arquivo contém uma tabela de nós seguida por uma linha em branco e uma tabela de arestas: ```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
Colunas adicionais são toleradas—o importador normaliza cabeçalhos como
Node Label, nodeLabel, ou label, preserva quaisquer valores explícitos de color/size
e mantém coordenadas quando fornecidas.
source e target. Colunas opcionais como label, type,
weight, source_type, target_type, source_label, ou color são mescladas
nos nós e arestas gerados quando presentes: ```csv
source,target,label,source_type,target_type
srv-1,cli-1,allows,server,client
srv-1,sensor-2,monitors,server,sensor
Quantickle analisa cabeçalhos de forma insensível a maiúsculas/minúsculas, aceita nomes tanto em snake_case quanto com espaços, e pula linhas vazias automaticamente.
.edges)Pares de arestas separados por espaço em branco simples são suportados para gráficos de esqueleto rápidos. Nós ausentes são criados automaticamente:```text srv-1 cli-1 srv-1 sensor-2
> **Nota:** Pastas de trabalho do Excel (`.xlsx`) já não são suportadas. Exporte ou salve
> os dados como CSV antes de importá-los para o Quantickle.
#### JSON
`File → Import Data` também aceita exportações JSON produzidas pelo Quantickle ou coleções
de elementos Cytoscape brutas. Quando o ficheiro contém `elements` com entradas
`data` aninhadas, elas são normalizadas na estrutura interna do Quantickle.
#### Graph Quantickle (`.qut`)
Ficheiros `.qut` são documentos JSON com objetos de nó e aresta achatados. Um
graph mínimo parece com:```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" }
]
}
Arquivos legados que armazenam nós/arestas dentro de um objeto data ainda são aceitos—o carregador os achata automaticamente e preserva coordenadas, classes e metadados de hierarquia de contêineres.
Ao trocar dados com a API HTTP ou integração Neo4j, envie a mesma estrutura achatada usada pelos arquivos .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" }
]
}
O campo opcional `info` ainda suporta Markdown e é persistido junto com quaisquer propriedades personalizadas.
<a id="layouts"></a>
## Layouts
Quantickle agrupa layouts em famílias práticas para que você possa escolher o mais adequado para a tarefa:
- **Force-directed** (force, cose, fcose) — bom para descoberta exploratória de estruturas e quando você deseja agrupamento natural.
- **Hierarchical & flow** (breadthfirst, dagre) — melhor para árvores de dependência, grafos de chamada ou fluxos causais.
- **Grid & circle** — layouts rápidos e determinísticos para painéis, grafos pequenos e exportações.
- **Time-based** (timeline, timeline-scatter, temporal-attraction) — use quando a ordenação temporal ou atualidade é o foco.
- **Spatial/absolute** (absolute, depth-aware) — use para layouts semelhantes a mapas ou diagramáticos com coordenadas conhecidas.
- **Cluster/radial** (radial-recency) — use quando você deseja agrupamento por tipo ou anéis de atualidade.
### Opções de Layout```javascript
// js/layouts.js
const layoutOptions = {
'force': {
name: 'force',
animate: true,
randomize: false,
infinite: false
},
'grid': {
name: 'grid',
rows: undefined,
cols: undefined
}
// ... more layouts
}
O layout personalizado timeline posiciona nós ao longo de um eixo temporal. Você pode personalizar a barra central através da opção 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();
Quando `className` é fornecido, a barra de linha do tempo recebe essa classe e seu estilo padrão de cor e altura são removidos para que você possa segmentá-la via CSS.
### Layout Radial de Recência
Use `radial-recency` para plotar os itens mais novos mais próximos do centro e os mais antigos em anéis externos. O layout mapeia o ângulo para um atributo secundário (tipo/cluster/grupo) para que os nós relacionados permaneçam alinhados ao redor do círculo. Você pode ajustar os anéis com algumas opções:```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();
Veja graphs/radial_time_rings.qut para um pequeno exemplo que demonstra faixas de tempo concêntricas agrupadas por metadados de cluster/tipo.
Use o layout timeline-scatter para mapear timestamps diretamente para posições no eixo x, enquanto distribui os nós verticalmente por similaridade, categoria ou comunidade. Ele aceita escalas ajustáveis para ambos os eixos e um jitter opcional para reduzir sobreposição:```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();
Nós com pontuações de similaridade numéricas (`similarity`, `similarityScore`, ou `similarity_score`) estão centrados em torno da média, enquanto rótulos categóricos ou de comunidade criam faixas uniformemente espaçadas ao longo do eixo y.
### Layout de Atração Temporal
Use a distância do timestamp para direcionar as forças das molas, mantendo a repulsão leve:```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();
Selecione Layout → Temporal Attraction - Time Weighted na interface ou passe name: 'temporal-attraction' através da configuração de layout da CLI/API para ativá-lo.
O Quantickle pode obter dados de sistemas externos ou sincronizar com eles. As integrações geralmente fluem através do servidor porque exigem credenciais, regras de proxy ou persistência.
http://localhost:3000.Para tutoriais mais detalhados e capturas de tela, veja o Guia de Uso.
.qut para um snapshot de projeto com fidelidade total (layout, metadados, contêineres).O Quantickle inicializa através do global window.QuantickleApp definido em js/main.js. O aplicativo chama automaticamente window.QuantickleApp.init() quando o DOM está pronto.
// 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
### HTTP API
O servidor Express (`server.js`) serve o front-end estático e expõe vários
endpoints JSON usados pela interface do usuário. Todas as rotas são prefixadas com `/api`:
| Método & Caminho | Descrição |
| --- | --- |
| `GET /api/domain-files` | Lista definições de domínio JSON presentes em `assets/domains/`. |
| `GET /api/examples` | Retorna metadados sobre exemplos de grafos `.qut` incluídos. |
| `GET /api/serpapi` | Faz proxy de requisições de pesquisa do Google para o SerpApi; requer `SERPAPI_API_KEY` na string de consulta ou no ambiente. |
| `GET /api/openai/models` | Faz proxy de requisições de listagem de modelos da OpenAI para `api.openai.com`; requer um cabeçalho `Authorization: Bearer ...`. |
| `GET /api/proxy?url=…` | Encaminha requisições HTTP/HTTPS para hosts permitidos com cabeçalhos semelhantes a navegadores. |
| `POST /api/neo4j/graph` | Persiste um grafo no Neo4j. Aceita o corpo JSON do grafo Quantickle achatado descrito acima. |
| `POST /api/neo4j/node-graphs` | Encontra grafos salvos que contêm nós correspondentes ao array `labels` fornecido. |
| `GET /api/neo4j/graphs` | Lista grafos armazenados no Neo4j junto com metadados resumidos. |
| `GET /api/neo4j/graph/:name` | Busca um grafo salvo, retornando `metadata`, `nodes` e `edges`. |
| `DELETE /api/neo4j/graph/:name` | Remove um grafo armazenado do Neo4j. |
Todos os endpoints do Neo4j aceitam credenciais através dos cabeçalhos `X-Neo4j-Url`, `X-Neo4j-Username`
e `X-Neo4j-Password` (ou das variáveis de ambiente `NEO4J_URL`, `NEO4J_USER` e
`NEO4J_PASSWORD` no servidor). Quando fornecido, o objeto `metadata` é salvo junto com o grafo e um timestamp `savedAt` é automaticamente anexado.
<a id="api-keys"></a>
### Chaves de API
Alguns recursos exigem chaves de API. Elas são armazenadas no armazenamento local do navegador através do painel Integrações.
- **SerpAPI** — necessária para a pesquisa web do pipeline RAG. Adicione sua chave no diálogo de Integrações e ela será usada pelo pipeline RAG do lado do cliente.
- **VirusTotal** — usada para enriquecer nós de domínio/IP/arquivo/URL e obter grafos de relacionamento.
- **CIRCL-LU** — credenciais de autenticação opcionais se seu feed MISP exigir.
Para uso em linha de comando, você pode alternativamente definir `SERPAPI_API_KEY` no ambiente.
<a id="backend-proxy"></a>
### Proxy de Backend
O servidor expõe um proxy que contorna CORS e encaminha requisições HTTP(S) para hosts listados na lista de permissões do proxy. Use `/api/proxy` com um parâmetro de URL:```
curl "http://localhost:3000/api/proxy?url=https%3A%2F%2Fopentip.kaspersky.com%2F"
A lista de permissões base reside em config/proxy-allowlist.json. Você deve fornecer este arquivo (ou definir a variável de ambiente PROXY_ALLOWLIST separada por vírgulas antes de iniciar o servidor); caso contrário, o proxy registra um erro fatal de configuração e rejeita todas as requisições com HTTP 403.
Os hosts específicos de integração (para adaptadores de integração de backend como OpenAI e VirusTotal) são regidos por config/integration-allowlist.json (ou INTEGRATION_ALLOWLIST). Em tempo de execução, ambas as listas de permissões são mescladas. Cada entrada deve listar um host ou padrão curinga que o proxy possa alcançar. Caracteres curinga usando * são suportados em qualquer lugar em uma entrada, então *.example.com permite qualquer subdomínio de example.com, e máscaras como news-* funcionam conforme o esperado. Subdomínios também herdam a entrada de seu domínio pai, portanto, adicionar example.com automaticamente permite www.example.com.
Um arquivo de lista de permissões mínimo se parece com:```json { "allowlist": ["otx.alienvault.com", "feeds.example.org"] }
Se preferir variáveis de ambiente, defina `PROXY_ALLOWLIST="otx.alienvault.com,feeds.example.org"` antes de iniciar o servidor.
Quando o proxy encaminha uma requisição, ele agora envia um conjunto de cabeçalhos semelhante a um navegador (incluindo valores modernos do Chrome `User-Agent`, `Accept`, `Accept-Language` e `Sec-Fetch-*`) para que sites que bloqueiam conteúdo com filtros anti-bot respondam da mesma forma que responderiam a um carregamento normal de página. Qualquer um desses cabeçalhos pode ser sobrescrito fornecendo substituições `x-proxy-<header>` da requisição do cliente quando necessário.
<a id="storage"></a>
## Armazenamento
O Quantickle mantém o estado do grafo no navegador enquanto você trabalha e o persiste quando você exporta ou sincroniza.
- **Armazenamento no navegador** — configurações e chaves de API são armazenadas localmente no navegador.
- **Arquivos de projeto (`.qut`)** — salvos na sua pasta de workspace para snapshots de grafo com fidelidade total. Veja [GRAPH_FILE_MANAGEMENT_README.md](https://github.com/rsac-labs/quantickle/blob/HEAD/GRAPH_FILE_MANAGEMENT_README.md) para regras de workspace e ciclo de vida de arquivos.
- **Neo4j** — persistência opcional no servidor para colaboração e pesquisa, configurada através da integração com Neo4j.
<a id="project-structure"></a>
## Estrutura do Projeto```
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
Grafo Não Renderizando
Desempenho Ruim
Problemas de Layout
Este projeto não é mantido ativamente como um repositório canônico. PRs provavelmente serão ignorados. No entanto, feedback, relatos de bugs e comentários são bem-vindos.
Este projeto está licenciado sob a Licença Apache 2.0 - consulte o arquivo LICENSE para detalhes.