node-firewalla
Version:
Package to talk your firewalla box & API
121 lines (120 loc) • 4.92 kB
JavaScript
import { Networker } from "./Networker.js";
import { AuthApi } from "./AuthApi.js";
import { SecureUtil } from '../utils/index.js';
import fetch from "node-fetch";
import { FWGroup } from "../models/index.js";
import FWWebLoginAPI from "./FWWebLoginAPI.js";
import querystring from 'node:querystring';
const sleep = ms => new Promise(r => setTimeout(r, ms));
class FWGroupApi extends AuthApi {
static _instance;
constructor() {
if (FWGroupApi._instance) {
return FWGroupApi._instance;
}
super();
FWGroupApi._instance = this;
let serverInstance = "v2";
this.setApiNetworker(new Networker(`https://firewalla.encipher.io/app/api/${serverInstance}`));
}
async receiveMessageFromGroup(fwGroup, count = 1, since = 0) {
let query = querystring.encode({
count,
peerId: fwGroup.gid,
since,
});
return this.getApiNetworker().authGetRelative(`/service/message/${fwGroup.aid}/${fwGroup.gid}/eptgroup/${fwGroup.eid}?${query}`);
}
async startRendezVous(rendezVousId, license) {
return this.getApiNetworker().authPostRelative(`/ept/rendezvous/me`, {
rid: rendezVousId,
evalue: JSON.stringify({ license })
});
}
/**
* @param qrcode - The QR code JSON isible in the Firewalla App -> Select your box -> Settings -> Advanced -> Allow Additional Pairing -> Turn on Additional Pairing
* @param email - The email that should be linked to the ETP token (visible in the app)
* @param localIp - The IP of the box you want to connect to
*/
async joinGroup(qrcode, email, localIp) {
let firstTime = false; // where to get this?
let prefix = firstTime ? "cybersecuritymadesimple" : qrcode.license.substring(0, 8);
let aesKey = prefix + qrcode.seed;
let rid = SecureUtil.aesDecrypt(qrcode.ek, aesKey);
let { access_token } = await this.login(email);
this.setAuth(access_token);
await this.startRendezVous(rid, qrcode.license);
let maxTries = 10;
let currTry = 0;
let newGroup = undefined;
do {
if (currTry >= maxTries) {
throw "Handshake failed, max tries exceeded";
}
await sleep(currTry == 0 ? 0 : 3000);
let response = await this.login(email);
newGroup = response.groups.filter(e => e._id == qrcode.gid)[0];
currTry++;
} while (!newGroup);
return FWGroup.fromJson(newGroup, localIp);
}
/**
* @param email - The email that should be linked to the ETP token (Only required when first creating your ETP token)
*/
async login(email = "") {
let body = {
assertion: {
name: email,
info: { name: "circle" },
publicKey: SecureUtil.publicKey,
appId: "com.rottiesoft.circle",
appSecret: "fbb05afa-9145-41f1-8076-9de8be56f104",
signature: ""
}
};
let response = await fetch("https://firewalla.encipher.io/app/api/v2/login/eptoken", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(body)
}).then((r) => r.json());
this.setAuth(response.access_token);
return response;
}
/**
*
* @param fwGroup - The Firewalla Group/Box the token needs access to
* @param validDays - How many days the token should be valid for
* @returns WebLoginTokenResponse
*/
/** */
async getFireguardToken(fwGroup, validDays = 1) {
let token = crypto.randomUUID();
let response = await this.getApiNetworker().authPost(`https://my.firewalla.com/v1/auth/authorize/${token}?days=${validDays}`, [{
gid: fwGroup.gid
}]);
FWWebLoginAPI.setAuth(response.token);
return response;
}
async sendMessageToBox(fwGroup, fwMessage) {
let url = fwGroup.getMessageUrl();
let encryptionKey = fwGroup.getSymmetricKey();
let messageString = JSON.stringify(fwMessage.toJSON(fwGroup.eid));
let message = SecureUtil.aesEncrypt(messageString, encryptionKey);
let timestamp = Math.floor(Number(new Date()) / 1000);
let response = await this.getApiNetworker().authPost(url, {
timestamp,
message
});
if (response.error) {
throw response.error;
}
response = JSON.parse(SecureUtil.aesDecrypt(response.message, encryptionKey));
if (response.code !== 200) {
throw response;
}
return response.data;
}
}
export default new FWGroupApi();