From 80f81b40133815dbfd20e9327e080658e2c05d11 Mon Sep 17 00:00:00 2001 From: Douglas Barone Date: Thu, 14 Jan 2021 15:12:37 -0400 Subject: [PATCH] Add PA Host OK --- server/package-lock.json | 11 +++ server/package.json | 1 + .../20210114134149_add_panos/migration.sql | 4 +- server/prisma/schema.prisma | 4 +- server/src/lib/paloalto.js | 84 ++++++++++++------- server/src/resolvers/Mutation/index.js | 4 +- server/src/typeDefs.js | 4 +- 7 files changed, 73 insertions(+), 39 deletions(-) diff --git a/server/package-lock.json b/server/package-lock.json index a34f914..91f4ab7 100755 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -20,6 +20,7 @@ "date-fns": "^2.16.1", "dotenv": "^8.2.0", "graphql": "^14.6.0", + "ip": "^1.1.5", "jsonwebtoken": "^8.5.1", "ldapjs": "^2.2.1", "node-cron": "^2.0.3", @@ -5857,6 +5858,11 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -13822,6 +13828,11 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", diff --git a/server/package.json b/server/package.json index 3e24b7d..b6635df 100755 --- a/server/package.json +++ b/server/package.json @@ -46,6 +46,7 @@ "date-fns": "^2.16.1", "dotenv": "^8.2.0", "graphql": "^14.6.0", + "ip": "^1.1.5", "jsonwebtoken": "^8.5.1", "ldapjs": "^2.2.1", "node-cron": "^2.0.3", diff --git a/server/prisma/migrations/20210114134149_add_panos/migration.sql b/server/prisma/migrations/20210114134149_add_panos/migration.sql index 9c50585..3cb7636 100644 --- a/server/prisma/migrations/20210114134149_add_panos/migration.sql +++ b/server/prisma/migrations/20210114134149_add_panos/migration.sql @@ -1,8 +1,8 @@ -- CreateTable -CREATE TABLE "PanOS" ( +CREATE TABLE "PAHost" ( "id" SERIAL, + "cidr" TEXT NOT NULL, "description" TEXT NOT NULL, - "ip" TEXT NOT NULL, "encryptedKey" TEXT NOT NULL, "note" TEXT, "user" TEXT NOT NULL, diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 1cd36a3..c47719d 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -123,11 +123,11 @@ model Statistic { onlineWifiDevices Int } -model PanOS { +model PAHost { id Int @id @default(autoincrement()) user String description String - ip String @unique + cidr String @unique encryptedKey String note String? createdAt DateTime @default(now()) diff --git a/server/src/lib/paloalto.js b/server/src/lib/paloalto.js index c9f3c22..b69d13f 100644 --- a/server/src/lib/paloalto.js +++ b/server/src/lib/paloalto.js @@ -1,14 +1,18 @@ // Ref.: https://docs.paloaltonetworks.com/pan-os/9-1/pan-os-panorama-api/pan-os-xml-api-request-types/apply-user-id-mapping-and-populate-dynamic-address-groups-api.html import axios from 'axios' -import prisma from '../prisma' import https from 'https' -import { subMinutes } from 'date-fns' +import { isIPv4 } from 'net' import qs from 'qs' +import { add, subMinutes } from 'date-fns' import { logError, logSuccess } from './logger' import { AES, enc } from 'crypto-js' +import ip from 'ip' + +import prisma from '../prisma' const TIMEOUT_IN_MINUTES = '3' +const CIDR_RE = /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/ const httpsAgent = new https.Agent({ rejectUnauthorized: false @@ -92,49 +96,67 @@ async function updateUserIdMappings() { } } -async function getUserKey({ ip, user, password }) { - const result = await axios({ - url: `https://${ip}/api/`, - method: 'POST', - params: { type: 'keygen', user, password }, - httpsAgent - }) +async function getUserKey({ ipAddr, user, password }) { + try { + const result = await axios({ + url: `https://${ipAddr}/api/`, + method: 'POST', + params: { type: 'keygen', user, password }, + httpsAgent + }) - return result.data.split('')[1].split('')[0] + return result.data.split('')[1].split('')[0] + } catch (e) { + throw new Error(e.message) + } } -async function addHost({ ip, user, password, description, note }) { +function encryptKey(key) { + return AES.encrypt(key, process.env.CRYPT_SECRET).toString() +} + +function decryptKey(encryptedKey) { + return AES.decrypt(encryptedKey, process.env.CRYPT_SECRET).toString(enc.Utf8) +} + +async function addHost({ cidr, user, password, description, note }) { try { - const key = await getUserKey({ ip, user, password }) + if (!CIDR_RE.test(cidr)) throw new Error('Este não é um CIDR válido') - const encryptedKey = AES.encrypt(key, process.env.CRYPT_SECRET).toString() + const ipAddr = cidr.split('/')[0] - // const decryptedKey = AES.decrypt( - // encryptedKey, - // process.env.CRYPT_SECRET - // ).toString(enc.Utf8) + if (!isIPv4(ipAddr)) throw new Error('Este não é um IPv4 válido') - const host = await prisma.panOS.create({ - data: { - ip, - encryptedKey, - user, - description, - note - } + const net = ip.cidrSubnet(cidr) + + if (net.subnetMaskLength > 32 || net.networkAddress == '0.0.0.0') + throw new Error('Esta não é uma combinação de IP/máscara IPv4 válida') + + const key = await getUserKey({ ipAddr, user, password }) + + const encryptedKey = encryptKey(key) + + const pAHost = { + cidr, + encryptedKey, + user, + description, + note + } + + const host = await prisma.pAHost.upsert({ + where: { cidr: cidr }, + create: pAHost, + update: pAHost }) return { ...host, - key: `${key.slice( - 0, - 8 - )}************************************************************************************************` + key: `${key.slice(0, 5)}` } } catch (e) { logError({ - message: `Não foi possível adicionar o host ${ip}.`, - data: e.message, + message: `Não foi possível adicionar o host ${cidr}. ${e?.message}`, tags: ['paloalto'] }) throw new Error(e.message) diff --git a/server/src/resolvers/Mutation/index.js b/server/src/resolvers/Mutation/index.js index 6d12197..8356555 100644 --- a/server/src/resolvers/Mutation/index.js +++ b/server/src/resolvers/Mutation/index.js @@ -46,8 +46,8 @@ const Mutation = { return updateUserIdMappings() }, - async addPAHost(_, { data: { ip, user, password, description, note } }) { - return addHost({ ip, user, password, description, note }) + async addPAHost(_, { data: { cidr, user, password, description, note } }) { + return addHost({ cidr, user, password, description, note }) } } diff --git a/server/src/typeDefs.js b/server/src/typeDefs.js index 1f0dc82..36e50f4 100644 --- a/server/src/typeDefs.js +++ b/server/src/typeDefs.js @@ -260,7 +260,7 @@ const typeDefs = gql` type PAHost { id: ID! description: String - ip: String + cidr: String key: String note: String createdAt: String @@ -303,7 +303,7 @@ const typeDefs = gql` } input AddPAHostInput { - ip: String! + cidr: String! user: String! password: String! description: String!