Collecteur d'informations de bug bounty
Ceci est unMarket Research, Multimodal AIworkflow d'automatisation du domainecontenant 8 nœuds.Utilise principalement des nœuds comme Code, HttpRequest, GoogleSheets, ScheduleTrigger. Collecte automatique des indications de prime de vulnérabilité Twitter vers Google Sheets
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
- •Informations d'identification Google Sheets API
Nœuds utilisés (8)
Catégorie
{
"id": "Hl5YR8MHd1AyDYXk",
"meta": {
"instanceId": "c5257b5cf4d48704d636909c07c4408a69d6799d0a855eab46287eeb702c84b0",
"templateCredsSetupCompleted": true
},
"name": "BB Tip Harvestor",
"tags": [],
"nodes": [
{
"id": "95247308-430c-4f13-bc7d-98beecb5b945",
"name": "Déclencheur Planifié",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
320,
80
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 4
}
]
}
},
"typeVersion": 1.2
},
{
"id": "6b347ec0-fb37-4ce8-889f-2b29bc1b2e1b",
"name": "📒 Aperçu du Workflow",
"type": "n8n-nodes-base.stickyNote",
"position": [
-272,
16
],
"parameters": {
"color": 4,
"width": 480,
"height": 232,
"content": "## 🎯 Bug Bounty Tip Harvester\n\nAutomatically collects bug bounty tips from Twitter every 4 hours and saves to Google Sheets.\n\n**Setup required:**\n1. Get API key from https://twitterapi.io/\n2. Configure Google Sheets credentials\n3. Update Google Sheet ID"
},
"typeVersion": 1
},
{
"id": "fa97a28d-cb1c-4e37-8272-3b6efc7f1a44",
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"position": [
544,
80
],
"parameters": {
"url": "https://api.twitterapi.io/twitter/tweet/advanced_search",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"queryParameters": {
"parameters": [
{
"name": "query",
"value": "(#bugbountytips OR #bugbounty OR #bugbountytip) -Writeups -discount -phishing -fuck"
},
{
"name": "queryType",
"value": "Latest"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"id": "OlMRj5cL1g7C7eNH",
"name": "Twitterapi.io Xcal"
}
},
"typeVersion": 4.2
},
{
"id": "d7ef4868-ef6b-4a57-95f4-b987dbcea50c",
"name": "📒 Twitter API",
"type": "n8n-nodes-base.stickyNote",
"position": [
496,
-256
],
"parameters": {
"color": 2,
"width": 348,
"height": 198,
"content": "## 🔐 Twitter API Setup\n\n1. Sign up at https://twitterapi.io/\n2. Get your API key\n3. Add HTTP Header Auth:\n - **Header**: `x-api-key`\n - **Value**: `YOUR_API_KEY`"
},
"typeVersion": 1
},
{
"id": "e76166b2-e6e4-4543-aad2-68bc8885d231",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
752,
80
],
"parameters": {
"jsCode": "// This approach handles both single tweets and collections\n// It focuses on properly formatting the output for n8n\n\nconsole.log(\"Input item structure:\", JSON.stringify($input.item, null, 2));\n\n// Function to format the date in a more human-readable way\nfunction formatDate(dateString) {\n if (!dateString) return '';\n\n try {\n const date = new Date(dateString);\n // Format: \"March 13, 2025 at 19:25\"\n return date.toLocaleString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n } catch (error) {\n console.log(\"Error formatting date:\", error);\n return dateString; // Return original if parsing fails\n }\n}\n\n// Check if this is a Twitter Search result with multiple tweets\nif ($input.item.json.tweets && Array.isArray($input.item.json.tweets)) {\n const items = $input.item.json.tweets.map(tweet => {\n return {\n json: {\n tweetId: tweet.id || '',\n url: tweet.url || '',\n content: tweet.text || '',\n likeCount: tweet.likeCount || 0,\n retweetCount: tweet.retweetCount || 0,\n replyCount: tweet.replyCount || 0,\n quoteCount: tweet.quoteCount || 0,\n viewCount: tweet.viewCount || 0,\n createdAt: formatDate(tweet.createdAt),\n }\n };\n });\n\n console.log(`Processing ${items.length} tweets`);\n // Return all items\n return items;\n} else {\n // This is a single tweet. Just extract and return its data\n const tweetData = {\n tweetId: $input.item.json.id || '',\n url: $input.item.json.url || '',\n content: $input.item.json.text || '',\n likeCount: $input.item.json.likeCount || 0,\n retweetCount: $input.item.json.retweetCount || 0,\n replyCount: $input.item.json.replyCount || 0,\n quoteCount: $input.item.json.quoteCount || 0,\n viewCount: $input.item.json.viewCount || 0,\n createdAt: formatDate($input.item.json.createdAt)\n };\n\n console.log(\"Processing single tweet\");\n\n // Return as a single item\n return {\n json: tweetData\n };\n}"
},
"typeVersion": 2
},
{
"id": "ca01565b-ded3-42af-832c-0662f0ea2c4d",
"name": "📒 Traitement",
"type": "n8n-nodes-base.stickyNote",
"position": [
736,
368
],
"parameters": {
"color": 3,
"width": 376,
"height": 168,
"content": "## ⚙️ Data Processing\n\nExtracts tweet data and formats for Google Sheets:\n- Tweet content, URLs, engagement metrics\n- Date formatting for proper sorting\n- Handles both single tweets and collections"
},
"typeVersion": 1
},
{
"id": "ed06b8aa-c7ac-4e69-8e19-c2ce422f2bdb",
"name": "Ajouter ou mettre à jour une ligne dans la feuille",
"type": "n8n-nodes-base.googleSheets",
"position": [
992,
80
],
"parameters": {
"columns": {
"value": {
"Url": "={{ $json.url }}",
"Date": "={{ \n (() => {\n const raw = $json.createdAt; // e.g. \"July 7, 2025 at 04:43 AM\"\n const [monthStr, day, yearTime, , time, meridian] = raw.split(/[\\s,]+/);\n const months = {\n January: \"01\", February: \"02\", March: \"03\", April: \"04\", May: \"05\", June: \"06\",\n July: \"07\", August: \"08\", September: \"09\", October: \"10\", November: \"11\", December: \"12\"\n };\n\n const [hour, minute] = time.split(\":\").map(Number);\n let hh = meridian === \"PM\" && hour !== 12 ? hour + 12 : (meridian === \"AM\" && hour === 12 ? 0 : hour);\n const formattedHour = String(hh).padStart(2, '0');\n\n return `${yearTime}-${months[monthStr]}-${String(day).padStart(2, '0')} ${formattedHour}:${minute}:00`;\n })() \n}}",
"Content": "={{ $json.content }}",
"TweetID": "={{ $json.tweetId }}",
"Created At": "={{ $json.createdAt }}"
},
"schema": [
{
"id": "Content",
"type": "string",
"display": true,
"required": false,
"displayName": "Content",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TweetID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "TweetID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Url",
"type": "string",
"display": true,
"required": false,
"displayName": "Url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Created At",
"type": "string",
"display": true,
"required": false,
"displayName": "Created At",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"TweetID"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": "Your Google Sheet"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "GniS74XmPh4KjdoT",
"name": "Google Sheets beethical"
}
},
"typeVersion": 4.6
},
{
"id": "462cb2c0-136f-454e-9e32-f7fe734c51a9",
"name": "📊 Google Sheets",
"type": "n8n-nodes-base.stickyNote",
"position": [
1248,
-64
],
"parameters": {
"color": 5,
"width": 448,
"height": 198,
"content": "## 📊 Google Sheets Setup\n\n1. Create Google Sheet with columns: Date, Created At, TweetID, Content, Url\n2. Set up Google Sheets OAuth2 credentials\n3. Replace empty documentId with your Sheet ID\n\n**Prevents duplicates using TweetID matching**"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "65c1d539-9a53-41ed-af0a-330c314826b9",
"connections": {
"e76166b2-e6e4-4543-aad2-68bc8885d231": {
"main": [
[
{
"node": "ed06b8aa-c7ac-4e69-8e19-c2ce422f2bdb",
"type": "main",
"index": 0
}
]
]
},
"fa97a28d-cb1c-4e37-8272-3b6efc7f1a44": {
"main": [
[
{
"node": "e76166b2-e6e4-4543-aad2-68bc8885d231",
"type": "main",
"index": 0
}
]
]
},
"95247308-430c-4f13-bc7d-98beecb5b945": {
"main": [
[
{
"node": "fa97a28d-cb1c-4e37-8272-3b6efc7f1a44",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Intermédiaire - Étude de marché, IA Multimodale
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
Partager ce workflow