From 8172769249aa6c52bd657b90fff0a34548ac149b Mon Sep 17 00:00:00 2001 From: Douglas Barone Date: Thu, 24 Mar 2022 12:31:56 -0400 Subject: [PATCH] Cisco APs OK --- .../migration.sql | 58 ++++++++++++ server/prisma/migrations/migration_lock.toml | 3 + server/prisma/schema.prisma | 51 +++++++---- server/src/lib/accessPoints.js | 23 +++++ server/src/lib/ciscoController.js | 89 ++++++++++++++----- server/src/resolvers/Mutation/index.js | 18 +++- server/src/typeDefs.js | 20 +++++ 7 files changed, 224 insertions(+), 38 deletions(-) create mode 100644 server/prisma/migrations/20220324161331_add_access_point_model/migration.sql create mode 100644 server/prisma/migrations/migration_lock.toml create mode 100644 server/src/lib/accessPoints.js diff --git a/server/prisma/migrations/20220324161331_add_access_point_model/migration.sql b/server/prisma/migrations/20220324161331_add_access_point_model/migration.sql new file mode 100644 index 0000000..5ef522c --- /dev/null +++ b/server/prisma/migrations/20220324161331_add_access_point_model/migration.sql @@ -0,0 +1,58 @@ +-- DropForeignKey +ALTER TABLE "PAHost" DROP CONSTRAINT "PAHost_ownerId_fkey"; + +-- DropForeignKey +ALTER TABLE "ResetToken" DROP CONSTRAINT "ResetToken_creatorId_fkey"; + +-- DropForeignKey +ALTER TABLE "ResetToken" DROP CONSTRAINT "ResetToken_userId_fkey"; + +-- AlterTable +ALTER TABLE "WifiDevice" ADD COLUMN "accessPointId" INTEGER; + +-- CreateTable +CREATE TABLE "AccessPoint" ( + "id" SERIAL NOT NULL, + "mac" TEXT NOT NULL, + "hostname" TEXT NOT NULL, + "name" TEXT, + "local" TEXT, + "notes" TEXT, + "uptime" TEXT, + "controller" TEXT, + "model" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "AccessPoint_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "AccessPoint_mac_key" ON "AccessPoint"("mac"); + +-- CreateIndex +CREATE UNIQUE INDEX "AccessPoint_hostname_key" ON "AccessPoint"("hostname"); + +-- AddForeignKey +ALTER TABLE "ResetToken" ADD CONSTRAINT "ResetToken_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ResetToken" ADD CONSTRAINT "ResetToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "WifiDevice" ADD CONSTRAINT "WifiDevice_accessPointId_fkey" FOREIGN KEY ("accessPointId") REFERENCES "AccessPoint"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PAHost" ADD CONSTRAINT "PAHost_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- RenameIndex +ALTER INDEX "PAHost.cidr_unique" RENAME TO "PAHost_cidr_key"; + +-- RenameIndex +ALTER INDEX "ResetToken.token_unique" RENAME TO "ResetToken_token_key"; + +-- RenameIndex +ALTER INDEX "User.sAMAccountName_unique" RENAME TO "User_sAMAccountName_key"; + +-- RenameIndex +ALTER INDEX "WifiDevice.mac_unique" RENAME TO "WifiDevice_mac_key"; diff --git a/server/prisma/migrations/migration_lock.toml b/server/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..fbffa92 --- /dev/null +++ b/server/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (i.e. Git) +provider = "postgresql" \ No newline at end of file diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma index 143fad4..d2c06db 100644 --- a/server/prisma/schema.prisma +++ b/server/prisma/schema.prisma @@ -73,22 +73,24 @@ model User { } model WifiDevice { - id Int @id @default(autoincrement()) - oui String? - mac String @unique - hostname String? - firstSeen DateTime? @default(now()) - lastSeen DateTime? - essid String? - ip String? - uptime String? - apName String? - status Status? - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - userId Int? - controller String @default("unknown") - user User? @relation("wifidevice_to_user", fields: [userId], references: [id]) + id Int @id @default(autoincrement()) + oui String? + mac String @unique + hostname String? + firstSeen DateTime? @default(now()) + lastSeen DateTime? + essid String? + ip String? + uptime String? + apName String? + accessPointId Int? + accessPoint AccessPoint? @relation("wifidevice_to_ap", fields: [accessPointId], references: [id]) + status Status? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + userId Int? + controller String @default("unknown") + user User? @relation("wifidevice_to_user", fields: [userId], references: [id]) } enum Status { @@ -137,3 +139,20 @@ model PAHost { ownerId Int owner User @relation("pahost_to_user", fields: [ownerId], references: [id]) } + +model AccessPoint { + id Int @id @default(autoincrement()) + mac String @unique + hostname String @unique + name String? + local String? + notes String? + uptime String? + controller String? + model String? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + WifiDevices WifiDevice[] @relation("wifidevice_to_ap") +} diff --git a/server/src/lib/accessPoints.js b/server/src/lib/accessPoints.js new file mode 100644 index 0000000..3f48361 --- /dev/null +++ b/server/src/lib/accessPoints.js @@ -0,0 +1,23 @@ +import prisma from '../prisma' +import { getAccessPoints as getCiscoAccessPoints } from './ciscoController' + +async function getAccessPoints() { + const ciscoAccessPoints = await getCiscoAccessPoints() + + return ciscoAccessPoints +} + +async function updateDB(accessPoints) { + for (const accessPoint of accessPoints) { + await prisma.accessPoint.upsert({ + where: { mac: accessPoint.mac }, + create: accessPoint, + update: accessPoint + }) + } +} + +export async function updateAccessPoints() { + const accessPoints = await getAccessPoints() + await updateDB(accessPoints) +} diff --git a/server/src/lib/ciscoController.js b/server/src/lib/ciscoController.js index b933069..c4078f6 100644 --- a/server/src/lib/ciscoController.js +++ b/server/src/lib/ciscoController.js @@ -6,25 +6,25 @@ import { logError } from './logger' const TIMEOUT_IN_MS = 120000 const REQUEST_TIMEOUT_IN_MS = 20000 -const getUri = (skip, page, take) => +const getDevicesUri = (skip, page, take) => `https://${process.env.CISCO_HOST}/data/client-table.html?columns=524287&take=${take}&skip=${skip}&page=${page}&pageSize=50&sort[0][field]=ST&sort[0][dir]=desc` +const httpsAgent = new https.Agent({ + rejectUnauthorized: false, + ciphers: 'AES256-SHA' // That's necessary to connect to a TLS 1.0 server. Run node with --tls-min-v1.0 +}) + +const ciscoAxios = create({ + httpsAgent: httpsAgent, + timeout: REQUEST_TIMEOUT_IN_MS, + auth: { + username: process.env.CISCO_USER, + password: process.env.CISCO_PASSWORD + } +}) + function getDevices() { return new Promise(async (resolve, reject) => { - const httpsAgent = new https.Agent({ - rejectUnauthorized: false, - ciphers: 'AES256-SHA' // That's necessary to connect to a TLS 1.0 server. Run node with --tls-min-v1.0 - }) - - const axios = create({ - httpsAgent: httpsAgent, - timeout: REQUEST_TIMEOUT_IN_MS, - auth: { - username: process.env.CISCO_USER, - password: process.env.CISCO_PASSWORD - } - }) - const source = CancelToken.source() const timeout = setTimeout(() => { @@ -43,9 +43,12 @@ function getDevices() { const responsesPromises = [] try { - const firstResponse = await axios.get(getUri(skip, page, take), { - cancelToken: source.token - }) + const firstResponse = await ciscoAxios.get( + getDevicesUri(skip, page, take), + { + cancelToken: source.token + } + ) const { total, data: page1devices } = firstResponse.data @@ -54,7 +57,7 @@ function getDevices() { while (total > skip) { responsesPromises.push( - axios.get(getUri(skip, page, take), { + ciscoAxios.get(getDevicesUri(skip, page, take), { cancelToken: source.token }) ) @@ -90,7 +93,7 @@ export async function getOnlineWifiDevices() { const now = new Date() - const hydratedOnlineDevices = onlineDevices.map(client => ({ + const restructuredOnlineDevices = onlineDevices.map(client => ({ user: client.Name == 'unknown' ? null : client.Name, oui: ouiFinder(client.macaddr), mac: client.macaddr, @@ -105,5 +108,49 @@ export async function getOnlineWifiDevices() { controller: 'Cisco' })) - return hydratedOnlineDevices + return restructuredOnlineDevices +} + +export async function getAccessPoints() { + const source = CancelToken.source() + + const timeout = setTimeout(() => { + source.cancel('timeout') + reject( + new Error( + 'A operação getDevices foi cancelada pois atingiu o tempo limite' + ) + ) + }, TIMEOUT_IN_MS) + + try { + const { + data: { Data: accessPoints } + } = await ciscoAxios.get( + `https://${process.env.CISCO_HOST}/data/ap-attributes-slot0.html?columns=28157`, + { + cancelToken: source.token + } + ) + + clearTimeout(timeout) + + const restructuredAccessPoints = accessPoints.map(({ Nm, Mc, Md, Ut }) => ({ + mac: Mc, + hostname: Nm, + uptime: Ut.toString(), + controller: 'Cisco', + model: Md + })) + + return restructuredAccessPoints + } catch (e) { + logError({ + tags: ['cisco', 'accessPoints'], + message: e.message, + data: { ...e, config: { ...e.config, auth: '*****' } } + }) + + throw e + } } diff --git a/server/src/resolvers/Mutation/index.js b/server/src/resolvers/Mutation/index.js index 9120f00..c520fac 100644 --- a/server/src/resolvers/Mutation/index.js +++ b/server/src/resolvers/Mutation/index.js @@ -4,7 +4,10 @@ import { ResetToken } from '../../classes/ResetToken' import { updateDevicesInfo } from '../../lib/wifiDevices' import { updateUserIdMappings, addHost } from '../../lib/paloalto' -import { logInfo, logSuccess } from '../../lib/logger' +import { logInfo, logSuccess, logError } from '../../lib/logger' + +import { updateAccessPoints } from '../../lib/accessPoints' + import prisma from '../../prisma' const Mutation = { @@ -82,6 +85,19 @@ const Mutation = { throw new Error('Você não pode apagar o host de outro usuário') return prisma.pAHost.delete({ where: { id } }) + }, + + async updateAccessPoints() { + try { + await updateAccessPoints() + return 'Atualização concluída' + } catch (e) { + logError({ + tags: ['accessPoints'], + message: `Erro tentando atualizar os pontos de acesso: ${e.message}`, + data: { error: e } + }) + } } } diff --git a/server/src/typeDefs.js b/server/src/typeDefs.js index 7b85468..2e83653 100644 --- a/server/src/typeDefs.js +++ b/server/src/typeDefs.js @@ -51,7 +51,11 @@ const typeDefs = gql` limit: Int = 200 ): [Log]! @auth(roles: ["superAdmin"]) + "All PA hosts" pAHosts: [PAHost!]! @auth(roles: ["superAdmin"]) + + "All Access Points" + accessPoints: [AccessPoint!]! @auth(roles: ["superAdmin"]) } type Mutation { @@ -89,6 +93,9 @@ const typeDefs = gql` "Remove a PA host" delPAHost(id: Int!): PAHost! @auth(roles: ["superAdmin"]) + + "Update Access Points" + updateAccessPoints: String! @auth(roles: ["superAdmin"]) } type Subscription { @@ -279,6 +286,19 @@ const typeDefs = gql` updatedAt: String } + "A Wireless Access Point" + type AccessPoint { + id: ID! + mac: String! + hostname: String + name: String + local: String + notes: String + createdAt: String + updatedAt: String + WifiDevices: [WifiDevice] + } + input LoginInput { username: String! password: String!