mirror of
https://github.com/reconurge/flowsint.git
synced 2026-03-12 01:44:42 -05:00
feat: asnmap as tool
This commit is contained in:
10
.claude/settings.local.json
Normal file
10
.claude/settings.local.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(docker run:*)",
|
||||
"WebSearch"
|
||||
],
|
||||
"deny": [],
|
||||
"ask": []
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
# 📚 Système de Tutoriel Flowsint
|
||||
|
||||
Système de tutoriel global basé sur **React Joyride**, intégré avec **TanStack Router**.
|
||||
|
||||
## ✅ Installation complète
|
||||
|
||||
Le système est déjà installé et configuré :
|
||||
|
||||
```bash
|
||||
✓ react-joyride installé
|
||||
✓ TutorialProvider intégré dans main.tsx
|
||||
✓ Structure de fichiers créée
|
||||
```
|
||||
|
||||
## 📁 Structure
|
||||
|
||||
```
|
||||
src/components/tutorial/
|
||||
├── tutorial-provider.tsx # Provider React + logique Joyride
|
||||
├── use-tutorial.ts # Hook pour contrôler le tutoriel
|
||||
├── tutorial-steps.ts # Configuration des étapes par route
|
||||
└── index.ts # Exports
|
||||
```
|
||||
|
||||
## 🚀 Utilisation
|
||||
|
||||
### 1. Ajouter des étapes pour une route
|
||||
|
||||
Éditez `src/components/tutorial/tutorial-steps.ts` :
|
||||
|
||||
```typescript
|
||||
export const tutorialSteps: Record<string, Step[]> = {
|
||||
'/ma-route': [
|
||||
{
|
||||
target: '[data-tour-id="mon-element"]',
|
||||
content: 'Description de l\'élément',
|
||||
disableBeacon: true, // Démarre sans animation initiale
|
||||
},
|
||||
{
|
||||
target: '[data-tour-id="autre-element"]',
|
||||
content: 'Autre description',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Annoter vos composants
|
||||
|
||||
Ajoutez `data-tour-id` aux éléments cibles :
|
||||
|
||||
```tsx
|
||||
<div data-tour-id="graph-toolbar">
|
||||
<button>Zoom</button>
|
||||
</div>
|
||||
|
||||
<aside data-tour-id="sidebar">
|
||||
Panneau latéral
|
||||
</aside>
|
||||
```
|
||||
|
||||
### 3. Ajouter un bouton d'aide (optionnel)
|
||||
|
||||
```tsx
|
||||
import { useTutorial } from '@/components/tutorial';
|
||||
|
||||
function MyPage() {
|
||||
const { startTutorial } = useTutorial();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={startTutorial}>? Aide</button>
|
||||
{/* Votre contenu */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 Fonctionnalités
|
||||
|
||||
- ✅ **Détection automatique** : Le tutoriel se lance à la première visite d'une route
|
||||
- ✅ **Persistance** : Historique sauvegardé dans `localStorage`
|
||||
- ✅ **Multi-routes** : Chaque page a ses propres étapes
|
||||
- ✅ **Contrôle manuel** : Hook `useTutorial()` pour contrôler le tutoriel
|
||||
- ✅ **Traduction FR** : Boutons et textes en français
|
||||
- ✅ **Style personnalisable** : Couleurs et thème configurables
|
||||
|
||||
## 🔧 API du hook
|
||||
|
||||
```tsx
|
||||
const {
|
||||
startTutorial, // Démarre le tutoriel pour la route actuelle
|
||||
stopTutorial, // Arrête le tutoriel
|
||||
resetTutorial, // Efface l'historique (force la revisite)
|
||||
isRunning, // État du tutoriel (boolean)
|
||||
} = useTutorial();
|
||||
```
|
||||
|
||||
## 📝 Exemple complet
|
||||
|
||||
Voir `TUTORIAL_EXAMPLE.tsx` pour des exemples détaillés.
|
||||
|
||||
### Page avec tutoriel
|
||||
|
||||
```tsx
|
||||
import { useTutorial } from '@/components/tutorial';
|
||||
|
||||
export function GraphPage() {
|
||||
const { startTutorial } = useTutorial();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={startTutorial}>? Aide</button>
|
||||
|
||||
<div data-tour-id="toolbar">Barre d'outils</div>
|
||||
<div data-tour-id="sidebar">Menu latéral</div>
|
||||
<div data-tour-id="canvas">Canvas principal</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration des étapes
|
||||
|
||||
```typescript
|
||||
// src/components/tutorial/tutorial-steps.ts
|
||||
export const tutorialSteps = {
|
||||
'/graph/$id': [
|
||||
{
|
||||
target: '[data-tour-id="toolbar"]',
|
||||
content: 'Voici la barre d\'outils',
|
||||
disableBeacon: true,
|
||||
},
|
||||
{
|
||||
target: '[data-tour-id="sidebar"]',
|
||||
content: 'Le panneau latéral affiche vos sources',
|
||||
},
|
||||
{
|
||||
target: '[data-tour-id="canvas"]',
|
||||
content: 'Le canvas affiche votre graphe',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## 🎨 Personnalisation
|
||||
|
||||
### Modifier le style
|
||||
|
||||
Dans `tutorial-provider.tsx`, ligne 100+ :
|
||||
|
||||
```tsx
|
||||
<Joyride
|
||||
styles={{
|
||||
options: {
|
||||
primaryColor: '#3b82f6', // Couleur principale
|
||||
zIndex: 10000, // Z-index
|
||||
},
|
||||
}}
|
||||
locale={{
|
||||
back: 'Retour',
|
||||
next: 'Suivant',
|
||||
skip: 'Passer',
|
||||
// ...
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Délai de démarrage
|
||||
|
||||
Ligne 77 du `tutorial-provider.tsx` :
|
||||
|
||||
```tsx
|
||||
setTimeout(() => {
|
||||
setRun(true);
|
||||
}, 500); // Modifier le délai (ms)
|
||||
```
|
||||
|
||||
## 📊 Clé localStorage
|
||||
|
||||
Le système utilise `flowsint-tutorial-completed` pour stocker les routes visitées.
|
||||
|
||||
### Réinitialiser manuellement
|
||||
|
||||
```tsx
|
||||
const { resetTutorial } = useTutorial();
|
||||
resetTutorial(); // Efface tout l'historique
|
||||
```
|
||||
|
||||
Ou via console :
|
||||
|
||||
```javascript
|
||||
localStorage.removeItem('flowsint-tutorial-completed');
|
||||
```
|
||||
|
||||
## 🔍 Débogage
|
||||
|
||||
### Le tutoriel ne se lance pas ?
|
||||
|
||||
1. Vérifiez que la route est dans `tutorialSteps.ts`
|
||||
2. Vérifiez que les `data-tour-id` correspondent
|
||||
3. Vérifiez que les éléments sont montés dans le DOM (délai de 500ms configuré)
|
||||
4. Consultez la console pour les erreurs
|
||||
|
||||
### Forcer le redémarrage
|
||||
|
||||
```tsx
|
||||
const { resetTutorial, startTutorial } = useTutorial();
|
||||
|
||||
resetTutorial(); // Efface l'historique
|
||||
startTutorial(); // Relance immédiatement
|
||||
```
|
||||
|
||||
## 📚 Documentation React Joyride
|
||||
|
||||
https://docs.react-joyride.com/
|
||||
|
||||
## 🤝 Contribuer
|
||||
|
||||
Pour ajouter des étapes à une nouvelle page :
|
||||
|
||||
1. Ajouter la route dans `tutorial-steps.ts`
|
||||
2. Annoter les éléments avec `data-tour-id`
|
||||
3. Tester en visitant la page (effacer localStorage si besoin)
|
||||
@@ -1,12 +1,11 @@
|
||||
import json
|
||||
import socket
|
||||
import subprocess
|
||||
from typing import List, Union
|
||||
from flowsint_core.core.transform_base import Transform
|
||||
from flowsint_types.ip import Ip
|
||||
from flowsint_types.asn import ASN
|
||||
from flowsint_core.utils import is_valid_ip
|
||||
from flowsint_core.core.logger import Logger
|
||||
from tools.network.asnmap import AsnmapTool
|
||||
|
||||
|
||||
class IpToAsnTransform(Transform):
|
||||
@@ -18,7 +17,7 @@ class IpToAsnTransform(Transform):
|
||||
|
||||
@classmethod
|
||||
def name(cls) -> str:
|
||||
return "ip_to_asn_transform"
|
||||
return "ip_to_asn"
|
||||
|
||||
@classmethod
|
||||
def category(cls) -> str:
|
||||
@@ -46,29 +45,21 @@ class IpToAsnTransform(Transform):
|
||||
|
||||
async def scan(self, data: InputType) -> OutputType:
|
||||
results: OutputType = []
|
||||
asnmap = AsnmapTool()
|
||||
|
||||
for ip in data:
|
||||
try:
|
||||
# Use asnmap to get ASN info
|
||||
result = subprocess.run(
|
||||
["asnmap", "-a", ip.address, "-json"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
)
|
||||
# Use asnmap tool to get ASN info
|
||||
asn_data = asnmap.launch(ip.address, type="ip")
|
||||
|
||||
if result.returncode == 0:
|
||||
output = result.stdout.strip()
|
||||
if output:
|
||||
asn_data = json.loads(output)
|
||||
if asn_data and "as_number" in asn_data:
|
||||
asn = ASN(
|
||||
asn=str(asn_data["as_number"]),
|
||||
name=asn_data.get("as_name", ""),
|
||||
org=asn_data.get("as_org", ""),
|
||||
country=asn_data.get("as_country", ""),
|
||||
)
|
||||
results.append(asn)
|
||||
if asn_data and "as_number" in asn_data:
|
||||
asn = ASN(
|
||||
asn=str(asn_data["as_number"]),
|
||||
name=asn_data.get("as_name", ""),
|
||||
org=asn_data.get("as_org", ""),
|
||||
country=asn_data.get("as_country", ""),
|
||||
)
|
||||
results.append(asn)
|
||||
|
||||
except Exception as e:
|
||||
Logger.error(
|
||||
|
||||
Reference in New Issue
Block a user