├── .gitignore ├── flow-pagination ├── package.json ├── README.md └── index.js ├── get-offline-devices ├── package.json ├── README.md └── index.js ├── get-rules-with-conditions ├── package.json ├── README.md └── index.js ├── pause-an-existing-rule ├── package.json ├── README.md └── index.js ├── send-alarms-to-discord ├── package.json ├── README.md └── index.js ├── get-active-alarms-by-specific-box ├── package.json ├── README.md └── index.js ├── get-top-bandwidth-usage-devices ├── package.json ├── README.md └── index.js ├── target-list-from-gaming-alarm-ips ├── create-target-list │ ├── package.json │ └── index.js ├── update-target-list │ ├── package.json │ └── index.js └── README.md ├── target-list-with-cloudflare ├── cf-real-ip-example.conf ├── README.md ├── create-target-list.sh └── update-target-list.sh ├── target-list-with-crowdsec ├── README.md ├── update-target-list.sh └── create-target-list.sh ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .token 2 | .domain 3 | .discordWebhook 4 | 5 | .DS_Store 6 | npm-debug.log 7 | Thumbs.db 8 | node_modules/ 9 | */node_modules/ 10 | */package-lock.json 11 | .vs/ 12 | -------------------------------------------------------------------------------- /flow-pagination/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /get-offline-devices/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /get-rules-with-conditions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pause-an-existing-rule/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /send-alarms-to-discord/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /get-active-alarms-by-specific-box/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /get-top-bandwidth-usage-devices/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /target-list-from-gaming-alarm-ips/create-target-list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /target-list-from-gaming-alarm-ips/update-target-list/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msp-api-examples", 3 | "type": "module", 4 | "version": "1.0.0", 5 | "description": "Examples of using Firewalla MSP API", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/firewalla/msp-api-examples" 9 | }, 10 | "author": "Firewalla Inc.", 11 | "dependencies": { 12 | "axios": "^1.4.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pause-an-existing-rule/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | 3 | Pauses an existing rule 4 | 5 | 6 | ### Quick Start 7 | 8 | Assume you've already cloned `https://github.com/firewalla/msp-api-examples.git` and `cd msp-api-examples` 9 | ```bash 10 | cd pause-an-existing-rule 11 | npm install 12 | domain="" token="" node ./index.js 13 | 14 | ``` 15 | 16 | ### Dependencies 17 | - [Node.js](https://nodejs.org/) 18 | - [npm](https://www.npmjs.com/package/npm), [pnpm](https://pnpm.io/installation), or the package manager you prefer 19 | -------------------------------------------------------------------------------- /get-offline-devices/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | 3 | Get all of offline devices on your msp. 4 | 5 | 6 | ### Quick Start 7 | 8 | Assume you've already cloned `https://github.com/firewalla/msp-api-examples.git` and `cd msp-api-examples` 9 | ```bash 10 | cd get-offline-devices 11 | npm install 12 | domain="" token="" node ./index.js 13 | 14 | ``` 15 | 16 | ### Dependencies 17 | - [Node.js](https://nodejs.org/) 18 | - [npm](https://www.npmjs.com/package/npm), [pnpm](https://pnpm.io/installation), or the package manager you prefer 19 | -------------------------------------------------------------------------------- /get-rules-with-conditions/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | 3 | Get rules with conditions 4 | 5 | 6 | ### Quick Start 7 | 8 | Assume you've already cloned `https://github.com/firewalla/msp-api-examples.git` and `cd msp-api-examples` 9 | ```bash 10 | cd get-rules-with-conditions 11 | npm install 12 | domain="" token="" node ./index.js 13 | 14 | ``` 15 | 16 | ### Dependencies 17 | - [Node.js](https://nodejs.org/) 18 | - [npm](https://www.npmjs.com/package/npm), [pnpm](https://pnpm.io/installation), or the package manager you prefer 19 | -------------------------------------------------------------------------------- /target-list-with-cloudflare/cf-real-ip-example.conf: -------------------------------------------------------------------------------- 1 | set_real_ip_from 103.21.244.0/22; 2 | set_real_ip_from 103.22.200.0/22; 3 | set_real_ip_from 103.31.4.0/22; 4 | set_real_ip_from 141.101.64.0/18; 5 | set_real_ip_from 108.162.192.0/18; 6 | set_real_ip_from 190.93.240.0/20; 7 | set_real_ip_from 188.114.96.0/20; 8 | set_real_ip_from 197.234.240.0/22; 9 | set_real_ip_from 198.41.128.0/17; 10 | set_real_ip_from 162.158.0.0/15; 11 | set_real_ip_from 104.16.0.0/13; 12 | set_real_ip_from 104.24.0.0/14; 13 | set_real_ip_from 172.64.0.0/13; 14 | set_real_ip_from 131.0.72.0/22; -------------------------------------------------------------------------------- /flow-pagination/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | Get flows count per device within a custom period on your MSP. 3 | 4 | 5 | ### Quick Start 6 | 7 | Assume you've already cloned `https://github.com/firewalla/msp-api-examples.git` and `cd msp-api-examples` 8 | 9 | ```bash 10 | cd flow-pagination 11 | npm install 12 | domain="" token="" node ./index.js 13 | 14 | ``` 15 | 16 | ### Dependencies 17 | - [Node.js](https://nodejs.org/) 18 | - [npm](https://www.npmjs.com/package/npm), [pnpm](https://pnpm.io/installation), or the package manager you prefer -------------------------------------------------------------------------------- /target-list-with-crowdsec/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | 3 | Poll the CrowdSec API for Decisions (bans) and then update the corresponding Firewalla target list. 4 | 5 | ### Quick Start 6 | 7 | You need to replace the `MSP_DOMAIN`,`API_TOKEN`,`CROWDSEC_API_TOKEN`,`CROWDSEC_API_URL`,`TARGET_LIST_ID` values in the scripts with real value, then run the scripts. 8 | 9 | ### Dependencies 10 | - [jq](https://jqlang.github.io/jq/tutorial/) 11 | - [CrowdSec](https://github.com/crowdsecurity/crowdsec), v1.5.2. 12 | 13 | 14 | Contributors: [@CozMedic](https://github.com/CozMedic) 15 | -------------------------------------------------------------------------------- /get-active-alarms-by-specific-box/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | 3 | Get active alarms by specific box. 4 | 5 | 6 | ### Quick Start 7 | 8 | Assume you've already cloned `https://github.com/firewalla/msp-api-examples.git` and `cd msp-api-examples` 9 | ```bash 10 | cd get-active-alarms-by-specific-box 11 | npm install 12 | domain="" token="" box="" node ./index.js 13 | 14 | ``` 15 | 16 | ### Dependencies 17 | - [Node.js](https://nodejs.org/) 18 | - [npm](https://www.npmjs.com/package/npm), [pnpm](https://pnpm.io/installation), or the package manager you prefer 19 | -------------------------------------------------------------------------------- /target-list-with-cloudflare/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | 3 | Lock down access to your NGINX reverse proxy to CloudFlare's IPs by doing essentially the same thing as [target-list-with-crowdsec](../target-list-with-crowdsec). Assume you have an auto-updating list of CloudFlare IPs, and once per day it checks for a change. If the list changes, it updates the list that is on your Port Forward to your server. 4 | 5 | 6 | ### Quick Start 7 | 8 | You need to replace the `MSP_DOMAIN`,`API_TOKEN`,`FILE_PATH`,`TARGET_LIST_ID` values in the scripts with real values, then run the scripts. 9 | 10 | ### Dependencies 11 | - [jq](https://jqlang.github.io/jq/tutorial/) 12 | 13 | 14 | Contributors: [@CozMedic](https://github.com/CozMedic) 15 | -------------------------------------------------------------------------------- /get-top-bandwidth-usage-devices/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | Get top bandwidth usage devices within a custom period on your MSP. If the bandwidth usage reaches the configured limit, 3 | it will be able to send a message to Discord. It functions the same as [Send alarms to Discord](../send-alarms-to-discord/README.md). 4 | 5 | ***Reminder: It is only supported on MSP 2.1.0 or later.*** 6 | 7 | 8 | ### Quick Start 9 | 10 | Assume you've already cloned `https://github.com/firewalla/msp-api-examples.git` and `cd msp-api-examples` 11 | 12 | ```bash 13 | cd get-top-bandwidth-usage-devices 14 | npm install 15 | domain="" token="" node ./index.js 16 | 17 | ``` 18 | 19 | ### Dependencies 20 | - [Node.js](https://nodejs.org/) 21 | - [npm](https://www.npmjs.com/package/npm), [pnpm](https://pnpm.io/installation), or the package manager you prefer 22 | -------------------------------------------------------------------------------- /send-alarms-to-discord/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | 3 | If you are too busy to log in to the web interface every day and check alarms, you can retrieve the alarms from the last x hours. If there are any security alarms, you can choose to receive an email or have them sent to Discord, allowing you to review the alarms at your convenience. 4 | 5 | 6 | ### Quick Start 7 | Assume you've already cloned `https://github.com/firewalla/msp-api-examples.git` and `cd msp-api-examples` 8 | 9 | ```bash 10 | cd send-alarms-to-discord 11 | npm install 12 | domain="" token="" discordWebhook="" node ./index.js 13 | 14 | ``` 15 | 16 | ### Dependencies 17 | - [Node.js](https://nodejs.org/) 18 | - [npm](https://www.npmjs.com/package/npm), [pnpm](https://pnpm.io/installation), or the package manager you prefer 19 | - [Discord Webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) 20 | -------------------------------------------------------------------------------- /target-list-with-crowdsec/update-target-list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CROWDSEC_API_URL="http://:8080/v1/alerts" 4 | CROWDSEC_API_TOKEN="Your-CrowdSec-Token" 5 | 6 | MSP_DOMAIN="" 7 | TARGET_LIST_ID="" # TL-00000000-0000-0000-0000-000000000000 8 | API_TOKEN="" 9 | 10 | banned_ips=$(curl --request GET \ 11 | --url "$CROWDSEC_API_URL" \ 12 | --header "Authorization: Bearer $CROWDSEC_API_TOKEN" \ 13 | | jq -r '.[].decisions[].value//empty') 14 | 15 | targets=$(echo -n $banned_ips | jq -cRs 'split(" ")[:2000]') # max 2000 targets 16 | 17 | json_payload="{ 18 | \"targets\": $targets 19 | }" 20 | 21 | http_code=$(curl -s -w %{http_code} -o /dev/null --request PATCH \ 22 | --url "https://$MSP_DOMAIN/v2/target-lists/$TARGET_LIST_ID" \ 23 | --header "Authorization: Token $API_TOKEN" \ 24 | --header "Content-Type: application/json" \ 25 | --data "$json_payload") 26 | 27 | if [[ "$http_code" == '200' ]]; then 28 | echo "Create target list successfully" 29 | else 30 | echo "Create target list failed" 31 | fi -------------------------------------------------------------------------------- /target-list-with-crowdsec/create-target-list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CROWDSEC_API_URL="http://:8080/v1/alerts" 4 | CROWDSEC_API_TOKEN="Your-CrowdSec-Token" 5 | 6 | MSP_DOMAIN="" 7 | API_TOKEN="" 8 | 9 | banned_ips=$(curl --request GET \ 10 | --url "$CROWDSEC_API_URL" \ 11 | --header "Authorization: Bearer $CROWDSEC_API_TOKEN" \ 12 | | jq -r '.[].decisions[].value//empty') 13 | 14 | targets=$(echo -n $banned_ips | jq -cRs 'split(" ")[:2000]') # max 2000 targets 15 | 16 | json_payload="{ 17 | \"name\": \"Target List with crowdsec\", 18 | \"notes\":\"This is a Simple Target List with crowdsec\", 19 | \"targets\": $targets 20 | }" 21 | 22 | http_code=$(curl -s -w %{http_code} -o /dev/null --request POST \ 23 | --url "https://$MSP_DOMAIN/v2/target-lists" \ 24 | --header "Authorization: Token $API_TOKEN" \ 25 | --header "Content-Type: application/json" \ 26 | --data "$json_payload") 27 | 28 | if [[ "$http_code" == '200' ]]; then 29 | echo "Create target list successfully" 30 | else 31 | echo "Create target list failed" 32 | fi -------------------------------------------------------------------------------- /target-list-from-gaming-alarm-ips/README.md: -------------------------------------------------------------------------------- 1 | ### Example 2 | 3 | If you'd like to create a Target List of all the destination IP addresses of a certain type of Alarm, you can get all the destination IPs from the past x Alarms, create a new Target List, and update the Target List periodically with these IPs. 4 | 5 | 6 | ### Quick Start 7 | Assume you've already cloned `https://github.com/firewalla/msp-api-examples.git` and `cd msp-api-examples` 8 | 9 | **Create a new Target List from Gaming Alarms** 10 | Update your MSP domain, token, and box in the files. 11 | 12 | ```bash 13 | cd target-list-from-gaming-alarm-ips/create-target-list 14 | npm install 15 | node ./index.js 16 | ``` 17 | **Update a new Target List from Gaming Alarms** 18 | Update your MSP domain, token, box, and target list IDs in the files. 19 | 20 | ```bash 21 | cd target-list-from-gaming-alarm-ips/update-target-list 22 | npm install 23 | node ./index.js 24 | ``` 25 | 26 | ### Dependencies 27 | - [Node.js](https://nodejs.org/) 28 | - [npm](https://www.npmjs.com/package/npm), [pnpm](https://pnpm.io/installation), or the package manager you prefer 29 | -------------------------------------------------------------------------------- /target-list-with-cloudflare/create-target-list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MSP_DOMAIN="" 4 | API_TOKEN="" 5 | FILE_PATH="" # /path/to/cf_real-ip.conf 6 | 7 | # Read IP addresses from cf_real-ip.conf excluding my Docker subnet 8 | ip_addresses=$(grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]{1,2})?' $FILE_PATH | \ 9 | grep -Ev '^172\.18\.') 10 | 11 | targets=$(echo -n $ip_addresses | jq -cRs 'split(" ")[:2000]') # max 2000 targets 12 | 13 | # Construct the JSON payload 14 | json_payload="{ 15 | \"name\": \"Target List with CloudFlare\", 16 | \"notes\":\"This is a Simple Target List with CloudFlare\", 17 | \"targets\": $targets 18 | }" 19 | 20 | # Make the API call 21 | http_code=$(curl -s -w %{http_code} -o /dev/null --request POST \ 22 | --url "https://$MSP_DOMAIN/v2/target-lists" \ 23 | --header "Authorization: Token $API_TOKEN" \ 24 | --header "Content-Type: application/json" \ 25 | --data "$json_payload") 26 | 27 | if [[ "$http_code" == '200' ]]; then 28 | echo "Create target list successfully" 29 | else 30 | echo "Create target list failed" 31 | fi 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Firewalla Inc. 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /target-list-with-cloudflare/update-target-list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MSP_DOMAIN="" 4 | API_TOKEN="" 5 | TARGET_LIST_ID="" # TL-00000000-0000-0000-0000-000000000000 6 | FILE_PATH="" # /path/to/cf_real-ip.conf 7 | 8 | # Read IP addresses from cf_real-ip.conf excluding my Docker subnet 9 | ip_addresses=$(grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]{1,2})?' $FILE_PATH | \ 10 | grep -Ev '^172\.18\.') 11 | 12 | # Function to check if IP list has changed 13 | ip_list_has_changed() { 14 | local new_ip_list="$1" 15 | local previous_ip_list="$2" 16 | 17 | if [ "$new_ip_list" != "$previous_ip_list" ]; then 18 | return 0 # IP list has changed 19 | else 20 | return 1 # IP list has not changed 21 | fi 22 | } 23 | 24 | # Create or read the previously stored IP list 25 | if [ -f previous_ip_list.txt ]; then 26 | previous_ip_list=$(cat previous_ip_list.txt) 27 | else 28 | touch previous_ip_list.txt 29 | previous_ip_list="" 30 | fi 31 | 32 | # Check if IP list has changed 33 | if ip_list_has_changed "$ip_addresses" "$previous_ip_list"; then 34 | echo "$ip_addresses" > previous_ip_list.txt 35 | 36 | targets=$(echo -n $ip_addresses | jq -cRs 'split(" ")[:2000]') # max 2000 targets 37 | # Construct the JSON payload 38 | json_payload="{ 39 | \"targets\": $targets 40 | }" 41 | 42 | # Make the API call 43 | http_code=$(curl -s -w %{http_code} -o /dev/null --request PATCH \ 44 | --url "https://$MSP_DOMAIN/v2/target-lists/$TARGET_LIST_ID" \ 45 | --header "Authorization: Token $API_TOKEN" \ 46 | --header "Content-Type: application/json" \ 47 | --data "$json_payload") 48 | 49 | if [[ "$http_code" == '200' ]]; then 50 | echo "Update target list successfully" 51 | else 52 | echo "Update target list failed" 53 | fi 54 | else 55 | echo "IP list has not changed. No API call needed." 56 | fi -------------------------------------------------------------------------------- /target-list-from-gaming-alarm-ips/create-target-list/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import fs from 'fs'; 3 | 4 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 5 | const msp_domain = process.env.domain || "[Your MSP Domain]"; 6 | const token = process.env.token || "[Your MSP Token]"; 7 | const box = process.env.box || "[Your box GID]"; 8 | 9 | async function main() { 10 | 11 | const httpClient = axios.create({ 12 | baseURL: `https://${msp_domain}/v2`, 13 | }) 14 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 15 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 16 | 17 | const params = { 18 | query: `status:active box:${box} type:9`, 19 | cursor: null, 20 | limit: 10 21 | } 22 | const alarms = []; 23 | const remoteIPs = new Set(); 24 | while (1) { 25 | const { results, next_cursor } = await httpClient({ 26 | method: 'get', 27 | url: `/alarms`, 28 | params: params 29 | }).then(r => r.data); 30 | alarms.push(...results); 31 | 32 | results.forEach(r => { 33 | if (r.remote?.ip) remoteIPs.add(r.remote.ip); 34 | }); 35 | if (!next_cursor) break; 36 | params.cursor = next_cursor; 37 | } 38 | const targets = [...remoteIPs]; 39 | 40 | const targetList = { 41 | "name": "Gaming IP Addresses", 42 | "targets": targets 43 | } 44 | 45 | axios({ 46 | method: "post", 47 | url: `https://${msp_domain}/v2/target-lists`, 48 | headers: { 49 | "Authorization": `Token ${token}`, 50 | "Content-Type": "application/json" 51 | }, 52 | data: targetList 53 | }).then(res => { 54 | console.log("Target List ID = ", res.data.id); 55 | }) 56 | 57 | } 58 | 59 | 60 | main().catch(err => { 61 | console.error('Failed to create Target Lis', err); 62 | process.exit(1) 63 | }) -------------------------------------------------------------------------------- /get-rules-with-conditions/index.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2024 Firewalla Inc. 2 | * 3 | * MIT License 4 | 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | import axios from 'axios'; 26 | import fs from 'fs'; 27 | 28 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 29 | const msp_domain = process.env.domain || fs.readFileSync('./.domain').toString(); 30 | const token = process.env.token || fs.readFileSync('./.token').toString(); 31 | 32 | 33 | // Related API Document 34 | // https://docs.firewalla.net/api-reference/rule/#get-rules 35 | async function main() { 36 | const httpClient = axios.create({ 37 | baseURL: `https://${msp_domain}/v2`, 38 | }) 39 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 40 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 41 | 42 | const query = `status:paused action:allow`; // get all paused allow rules 43 | const rules = await httpClient({ 44 | method: 'get', 45 | url: `/rules?query=${query}`, 46 | }).then(r => r.data); 47 | 48 | console.log('all paused allow rules', rules.results); 49 | } 50 | 51 | 52 | main().catch(err => { 53 | console.error('Failed to get rules', err); 54 | process.exit(1) 55 | }) -------------------------------------------------------------------------------- /target-list-from-gaming-alarm-ips/update-target-list/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import fs from 'fs'; 3 | 4 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 5 | const msp_domain = process.env.domain || "[Your MSP Domain]"; 6 | const token = process.env.token || "[Your MSP Token]"; 7 | const box = process.env.box || "[Your box GID]"; 8 | const id = process.env.id || "[Your Target List ID]"; 9 | 10 | async function main() { 11 | 12 | const httpClient = axios.create({ 13 | baseURL: `https://${msp_domain}/v2`, 14 | }) 15 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 16 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 17 | 18 | const params = { 19 | query: `status:active box:${box} type:9`, // get gaming activity alarms 20 | cursor: null, 21 | limit: 10 22 | } 23 | const alarms = []; 24 | const existingList = await httpClient.get(`https://${msp_domain}/v2/target-lists/${id}`).then(r => r.data); 25 | const currentIPs = existingList.targets || []; 26 | const newIPs = []; 27 | 28 | while (1) { 29 | const { results, next_cursor } = await httpClient({ 30 | method: 'get', 31 | url: `/alarms`, 32 | params: params 33 | }).then(r => r.data); 34 | alarms.push(...results); 35 | 36 | results.forEach(r => { 37 | if (r.remote?.ip) { 38 | newIPs.push(r.remote.ip); 39 | } 40 | }); 41 | if (!next_cursor) break; 42 | params.cursor = next_cursor; 43 | } 44 | 45 | const newList = Array.from(new Set([...newIPs, ...currentIPs])).slice(0,2000); // limit to 2000 46 | 47 | const targetList = { 48 | "name": existingList.name, 49 | "targets": newList 50 | } 51 | 52 | axios({ 53 | method: "patch", 54 | url: `https://${msp_domain}/v2/target-lists/${id}`, 55 | headers: { 56 | "Authorization": `Token ${token}`, 57 | "Content-Type": "application/json" 58 | }, 59 | data: targetList 60 | }).then(res => { 61 | console.log(res.data); 62 | console.log("Updated Target List Successfully."); 63 | }) 64 | 65 | } 66 | 67 | 68 | main().catch(err => { 69 | console.error('Failed to update Target List', err); 70 | process.exit(1) 71 | }) -------------------------------------------------------------------------------- /get-offline-devices/index.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2023 Firewalla Inc. 2 | * 3 | * MIT License 4 | 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | import axios from 'axios'; 26 | import fs from 'fs'; 27 | 28 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 29 | const msp_domain = process.env.domain || fs.readFileSync('./.domain').toString(); 30 | const token = process.env.token || fs.readFileSync('./.token').toString(); 31 | 32 | 33 | // Related API Document 34 | // https://docs.firewalla.net/api-reference/device/ 35 | async function main() { 36 | 37 | const httpClient = axios.create({ 38 | baseURL: `https://${msp_domain}/v2`, 39 | }) 40 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 41 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 42 | 43 | let devices = await httpClient({ 44 | method: 'get', 45 | url: `/devices`, 46 | }).then(r => r.data); 47 | 48 | devices = devices.filter(r => !r.online).map(r => { 49 | return { 50 | name: r.name, 51 | lastSeen: r.lastSeen ? new Date(r.lastSeen * 1000) : 0 52 | } 53 | }).sort((a, b) => a.lastSeen > b.lastSeen ? -1 : 1) 54 | 55 | console.table(devices, ['name', 'lastSeen']); 56 | } 57 | 58 | 59 | main().catch(err => { 60 | console.error('Failed to get flows', err); 61 | process.exit(1) 62 | }) -------------------------------------------------------------------------------- /get-active-alarms-by-specific-box/index.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2023 Firewalla Inc. 2 | * 3 | * MIT License 4 | 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | import axios from 'axios'; 26 | import fs from 'fs'; 27 | 28 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 29 | const msp_domain = process.env.domain || fs.readFileSync('./.domain').toString(); 30 | const token = process.env.token || fs.readFileSync('./.token').toString(); 31 | const box = process.env.box; 32 | 33 | 34 | // Related API Document 35 | // https://docs.firewalla.net/api-reference/alarm/ FYI: doc is out of date now, will update in recent 36 | async function main() { 37 | 38 | const httpClient = axios.create({ 39 | baseURL: `https://${msp_domain}/v2`, 40 | }) 41 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 42 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 43 | 44 | const params = { 45 | query: `status:active box:${box}`, 46 | cursor: null, 47 | limit: 10 48 | } 49 | const alarms = []; 50 | while (1) { 51 | const { results, next_cursor } = await httpClient({ 52 | method: 'get', 53 | url: `/alarms`, 54 | params: params 55 | }).then(r => r.data); 56 | alarms.push(...results); 57 | if (!next_cursor) break; 58 | params.cursor = next_cursor; 59 | } 60 | console.table(alarms, ['message']); 61 | } 62 | 63 | 64 | main().catch(err => { 65 | console.error('Failed to get alarms', err); 66 | process.exit(1) 67 | }) -------------------------------------------------------------------------------- /get-top-bandwidth-usage-devices/index.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2023 Firewalla Inc. 2 | * 3 | * MIT License 4 | 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | import axios from 'axios'; 26 | import fs from 'fs'; 27 | 28 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 29 | const msp_domain = process.env.domain || fs.readFileSync('./.domain').toString(); 30 | const token = process.env.token || fs.readFileSync('./.token').toString(); 31 | 32 | const begin = process.env.begin || Date.now() / 1000 - 24 * 3600; // last 24 hours 33 | let end = process.env.end || Date.now() / 1000; 34 | 35 | 36 | // Related API Document 37 | // https://docs.firewalla.net/api-reference/flow/ 38 | 39 | 40 | async function main() { 41 | 42 | const httpClient = axios.create({ 43 | baseURL: `https://${msp_domain}/v2`, 44 | }) 45 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 46 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 47 | 48 | const resp = await httpClient({ 49 | method: 'get', 50 | url: `/flows`, 51 | params: { 52 | query: `ts:${begin}-${end}`, 53 | limit: 5, 54 | sortBy: "total:desc", 55 | groupBy: "device" 56 | }, 57 | }).then(r => r.data) 58 | 59 | const results = resp.results.map(f => { return { deviceName: f.device.name, total: f.total, download: f.download, upload: f.upload } }); 60 | console.table(results, ["deviceName", "download", "upload", "total"]) 61 | } 62 | 63 | 64 | main().catch(err => { 65 | console.error('Failed to get flows', err); 66 | process.exit(1) 67 | }) 68 | -------------------------------------------------------------------------------- /flow-pagination/index.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2023 Firewalla Inc. 2 | * 3 | * MIT License 4 | 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | import axios from 'axios'; 26 | import fs from 'fs'; 27 | 28 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 29 | const msp_domain = process.env.domain || fs.readFileSync('./.domain').toString(); 30 | const token = process.env.token || fs.readFileSync('./.token').toString(); 31 | const begin = process.env.begin || Date.now() / 1000 - 10 * 60; 32 | let end = process.env.end || Date.now() / 1000; 33 | 34 | 35 | // Related API Document 36 | // https://docs.firewalla.net/api-reference/flow/ FYI: doc is out of date now, will update in recent 37 | 38 | 39 | async function main() { 40 | 41 | const httpClient = axios.create({ 42 | baseURL: `https://${msp_domain}/v2`, 43 | }) 44 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 45 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 46 | 47 | const params = { 48 | query: `ts:${begin}-${end}`, // it will query last 24 hours flows by default if time-period doesn't set 49 | cursor: null, 50 | limit: 100 // defaults to 200 if it is unset 51 | } 52 | 53 | const flows = []; 54 | while (1) { 55 | const { results, next_cursor } = await httpClient({ 56 | method: 'get', 57 | url: `/flows`, 58 | params: params 59 | }).then(r => r.data); 60 | flows.push(...results); 61 | if (!next_cursor) break; 62 | console.log(next_cursor) 63 | params.cursor = next_cursor; 64 | } 65 | console.log('count: %d', flows.length) 66 | } 67 | 68 | 69 | main().catch(err => { 70 | console.error('Failed to get flows', err); 71 | process.exit(1) 72 | }) 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Firewalla Managed Security Portal (MSP) API Examples 2 | 3 | This repository contains code examples that demonstrate how to use [Firewalla MSP API](https://docs.firewalla.net/) to interact with [Firewalla MSP](https://firewalla.net/). You can read, play with, or adapt from these examples to create your own applications. 4 | 5 | ## Prerequisites 6 | 7 | - A Firewalla MSP account and a valid [plan](https://firewalla.net/plans) 8 | - Access token from your MSP account, check the [document](https://docs.firewalla.net/#create-your-personal-access-token) for details 9 | 10 | ## Quick Start 11 | 12 | You can use either file or environment variable to setup your MSP domain and credential, check each example for details 13 | 14 | ```bash 15 | git clone https://github.com/firewalla/msp-api-examples.git 16 | cd msp-api-examples/flow-pagination 17 | npm install 18 | domain="" token="" node ./flow-pagination/index.js 19 | 20 | ``` 21 | 22 | ## Examples 23 | 24 | | Example | Firewalla MSP API Document | Contributors| 25 | | ------ | ----- | ----- | 26 | | [Flow Pagination](./flow-pagination/index.js) | [Flow](https://docs.firewalla.net/api-reference/flow/) | | 27 | | [Get Active Alarms By Specific Box](./get-active-alarms-by-specific-box/index.js) | [Alarm](https://docs.firewalla.net/api-reference/alarm/) | | 28 | | [Send alarms to Discord](./send-alarms-to-discord/README.md) | [Alarm](https://docs.firewalla.net/api-reference/alarm/) | | 29 | | [Get Offline Devices](./get-offline-devices/README.md) | [Device](https://docs.firewalla.net/api-reference/device/) | | 30 | | [Get Top Bandwidth Usage Devices](./get-top-bandwidth-usage-devices/README.md) | TBD | | 31 | | [Target List from Gaming Alarm IPs](./target-list-from-gaming-alarm-ips/README.md) | [Alarm](https://docs.firewalla.net/api-reference/alarm/), [Target List](https://docs.firewalla.net/api-reference/target-lists/) | | 32 | | [Target list with CloudFlare](./target-list-with-cloudflare/README.md) | [Target List](https://docs.firewalla.net/api-reference/target-lists/) | [@CozMedic](https://github.com/CozMedic) | 33 | | [Target list with CrowdSec](./target-list-with-crowdsec/README.md) | [Target List](https://docs.firewalla.net/api-reference/target-lists/) | [@CozMedic](https://github.com/CozMedic) | 34 | | [Get Rules With Conditions](./get-rules-with-conditions/README.md) _2.7.0 or later_ | [Rule](https://docs.firewalla.net/api-reference/rule/#get-rules) | | 35 | | [Pause An Existing Rule](./pause-an-existing-rule/README.md) | [Rule](https://docs.firewalla.net/api-reference/rule/#pause-a-rule) | | 36 | 37 | ## Disclaimer 38 | 39 | As Firewalla MSP API will operate directly on your data, please be careful about what you are writing. 40 | 41 | # Contributing 42 | 43 | Pull requests are welcome. The latest development happens on `main` branch 44 | 45 | You might also want to check our user community on [firewalla.com](https://help.firewalla.com/hc/en-us/community/topics) and [reddit](https://www.reddit.com/r/firewalla/) 46 | -------------------------------------------------------------------------------- /pause-an-existing-rule/index.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2024 Firewalla Inc. 2 | * 3 | * MIT License 4 | 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | import axios from 'axios'; 26 | import fs from 'fs'; 27 | 28 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 29 | const msp_domain = process.env.domain || fs.readFileSync('./.domain').toString(); 30 | const token = process.env.token || fs.readFileSync('./.token').toString(); 31 | 32 | 33 | // Related API Document 34 | // https://docs.firewalla.net/api-reference/rule/#pause-a-rule 35 | async function main() { 36 | 37 | 38 | // get rule list, this API(v1/rule/list) will be deprecated 39 | // the data model of the rule will be changed in the future release 40 | // just an example about how to get the rule id from the list 41 | const httpClient = axios.create({ 42 | baseURL: `https://${msp_domain}/v1`, 43 | }) 44 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 45 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 46 | 47 | const rules = await httpClient({ 48 | method: 'get', 49 | url: `/rule/list`, 50 | }).then(r => r.data); 51 | 52 | const pick_a_rule = rules[0]; // pick the first one as an example 53 | if (!pick_a_rule) return; // should have a rule at least 54 | 55 | // console.log('the rule', pick_a_rule); 56 | // how to pause a rule 57 | const httpClient1 = axios.create({ 58 | baseURL: `https://${msp_domain}/v2`, 59 | }) 60 | httpClient1.defaults.headers.common['Authorization'] = 'Token ' + token; 61 | httpClient1.defaults.headers.common['Content-Type'] = 'application/json' 62 | const result = await httpClient1({ 63 | method: 'post', 64 | url: `/rules/${pick_a_rule.id}/pause`, 65 | }).then(r => r.data); 66 | console.log('Paused the rule.', result); 67 | } 68 | 69 | 70 | main().catch(err => { 71 | console.error('Failed to pause the rule', err); 72 | process.exit(1) 73 | }) -------------------------------------------------------------------------------- /send-alarms-to-discord/index.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2023 Firewalla Inc. 2 | * 3 | * MIT License 4 | 5 | * Permission is hereby granted, free of charge, to any person obtaining 6 | * a copy of this software and associated documentation files (the 7 | * "Software"), to deal in the Software without restriction, including 8 | * without limitation the rights to use, copy, modify, merge, publish, 9 | * distribute, sublicense, and/or sell copies of the Software, and to 10 | * permit persons to whom the Software is furnished to do so, subject to 11 | * the following conditions: 12 | 13 | * The above copyright notice and this permission notice shall be 14 | * included in all copies or substantial portions of the Software. 15 | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | import axios from 'axios'; 26 | import fs from 'fs'; 27 | 28 | // Create .token and .domain file or use environment variables to setup your MSP domain and credential 29 | const msp_domain = process.env.domain || fs.readFileSync('./.domain').toString(); 30 | const token = process.env.token || fs.readFileSync('./.token').toString(); 31 | 32 | // How to get discord webhook https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks 33 | const discordWebhook = process.env.discordWebhook || fs.readFileSync('./.discordWebhook').toString(); 34 | const begin = process.env.begin || Date.now() / 1000 - 24 * 3600; 35 | let end = process.env.end || Date.now() / 1000; 36 | 37 | 38 | // Related API Document 39 | // https://docs.firewalla.net/api-reference/alarm/ 40 | 41 | 42 | async function main() { 43 | const httpClient = axios.create({ 44 | baseURL: `https://${msp_domain}/v2`, 45 | }) 46 | httpClient.defaults.headers.common['Authorization'] = 'Token ' + token; 47 | httpClient.defaults.headers.common['Content-Type'] = 'application/json' 48 | 49 | const alarms = []; 50 | 51 | // pagination, keep fetching until next returned as null 52 | do { 53 | const resp = await httpClient({ 54 | method: 'get', 55 | url: `/alarms`, 56 | params: { 57 | type: 1, // 1 means Security Alarm, https://docs.firewalla.net/data-models/alarm/#alarmtype 58 | begin, 59 | end, 60 | limit: 500, 61 | }, 62 | }).then(r => r.data) 63 | end = resp.next 64 | alarms.push(...resp.results); 65 | } while (end) 66 | 67 | console.log(`${alarms.length} security alarms fetched`) 68 | 69 | if (alarms.length > 0) { 70 | // send the alarms to discord channel 71 | const webHookClient = axios.create({ baseURL: discordWebhook }); 72 | let count = 0; 73 | for (const alarm of alarms) { 74 | try { 75 | await webHookClient({ 76 | method: 'POST', 77 | data: { 78 | "embeds": [{ 79 | title: "Security Alarm", 80 | description: alarm.message, 81 | url: `https://${msp_domain}/alarms?gid=${alarm.gid}&aid=${alarm.aid}` 82 | }] 83 | } 84 | }) 85 | count++; 86 | } catch (e) { 87 | console.error(e); 88 | } 89 | } 90 | console.log(`${count} security alarms sent to Discord`) 91 | } 92 | } 93 | 94 | 95 | main().catch(err => { 96 | console.error('Failed to get flows', err); 97 | process.exit(1) 98 | }) --------------------------------------------------------------------------------