diff --git a/.gitignore b/.gitignore index 1e1fe79..52a8539 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,5 @@ pnpm-debug.log* .env /src/server/db +/data/ deploy.sh diff --git a/package-lock.json b/package-lock.json index bf2c4e1..ed3d2a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@mdi/font": "7.0.96", + "@prisma/client": "^5.4.2", "@trpc/client": "^10.38.5", "@trpc/server": "^10.38.5", "@types/cors": "^2.8.14", @@ -31,6 +32,7 @@ "@types/webfontloader": "^1.6.35", "@vitejs/plugin-vue": "^4.0.0", "concurrently": "^8.2.1", + "prisma": "^5.4.2", "rimraf": "^5.0.5", "tsx": "^3.13.0", "typescript": "^5.2.2", @@ -540,6 +542,38 @@ "node": ">=14" } }, + "node_modules/@prisma/client": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.4.2.tgz", + "integrity": "sha512-2xsPaz4EaMKj1WS9iW6MlPhmbqtBsXAOeVttSePp8vTFTtvzh2hZbDgswwBdSCgPzmmwF+tLB259QzggvCmJqA==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines-version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574" + }, + "engines": { + "node": ">=16.13" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/engines": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.4.2.tgz", + "integrity": "sha512-fqeucJ3LH0e1eyFdT0zRx+oETLancu5+n4lhiYECyEz6H2RDskPJHJYHkVc0LhkU4Uv7fuEnppKU3nVKNzMh8g==", + "devOptional": true, + "hasInstallScript": true + }, + "node_modules/@prisma/engines-version": { + "version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574.tgz", + "integrity": "sha512-wvupDL4AA1vf4TQNANg7kR7y98ITqPsk6aacfBxZKtrJKRIsWjURHkZCGcQliHdqCiW/hGreO6d6ZuSv9MhdAA==" + }, "node_modules/@trpc/client": { "version": "10.38.5", "resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.5.tgz", @@ -2064,6 +2098,22 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prisma": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.4.2.tgz", + "integrity": "sha512-GDMZwZy7mysB2oXU+angQqJ90iaPFdD0rHaZNkn+dio5NRkGLmMqmXs31//tg/qXT3iB0cTQwnGGQNuirhSTZg==", + "devOptional": true, + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "5.4.2" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -3090,6 +3140,25 @@ "dev": true, "optional": true }, + "@prisma/client": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.4.2.tgz", + "integrity": "sha512-2xsPaz4EaMKj1WS9iW6MlPhmbqtBsXAOeVttSePp8vTFTtvzh2hZbDgswwBdSCgPzmmwF+tLB259QzggvCmJqA==", + "requires": { + "@prisma/engines-version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574" + } + }, + "@prisma/engines": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.4.2.tgz", + "integrity": "sha512-fqeucJ3LH0e1eyFdT0zRx+oETLancu5+n4lhiYECyEz6H2RDskPJHJYHkVc0LhkU4Uv7fuEnppKU3nVKNzMh8g==", + "devOptional": true + }, + "@prisma/engines-version": { + "version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574.tgz", + "integrity": "sha512-wvupDL4AA1vf4TQNANg7kR7y98ITqPsk6aacfBxZKtrJKRIsWjURHkZCGcQliHdqCiW/hGreO6d6ZuSv9MhdAA==" + }, "@trpc/client": { "version": "10.38.5", "resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.38.5.tgz", @@ -4251,6 +4320,15 @@ "source-map-js": "^1.0.2" } }, + "prisma": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.4.2.tgz", + "integrity": "sha512-GDMZwZy7mysB2oXU+angQqJ90iaPFdD0rHaZNkn+dio5NRkGLmMqmXs31//tg/qXT3iB0cTQwnGGQNuirhSTZg==", + "devOptional": true, + "requires": { + "@prisma/engines": "5.4.2" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", diff --git a/package.json b/package.json index 8bca7f7..29fd4ee 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "@mdi/font": "7.0.96", + "@prisma/client": "^5.4.2", "@trpc/client": "^10.38.5", "@trpc/server": "^10.38.5", "@types/cors": "^2.8.14", @@ -37,6 +38,7 @@ "@types/webfontloader": "^1.6.35", "@vitejs/plugin-vue": "^4.0.0", "concurrently": "^8.2.1", + "prisma": "^5.4.2", "rimraf": "^5.0.5", "tsx": "^3.13.0", "typescript": "^5.2.2", diff --git a/prisma/migrations/20231023193523_init/migration.sql b/prisma/migrations/20231023193523_init/migration.sql new file mode 100644 index 0000000..34a8ae8 --- /dev/null +++ b/prisma/migrations/20231023193523_init/migration.sql @@ -0,0 +1,10 @@ +-- CreateTable +CREATE TABLE "PaHost" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "name" TEXT, + "ip" TEXT NOT NULL, + "key" TEXT NOT NULL +); + +-- CreateIndex +CREATE UNIQUE INDEX "PaHost_ip_key" ON "PaHost"("ip"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..e5e5c47 --- /dev/null +++ b/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 = "sqlite" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..a620f53 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,19 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "sqlite" + url = "file:../data/smartcp.sqlite" + // url = env("DATABASE_URL") +} + +model PaHost { + id Int @id @default(autoincrement()) + name String? + ip String @unique + key String +} diff --git a/src/server/lib/login.ts b/src/server/lib/login.ts index 010c72b..3c38770 100644 --- a/src/server/lib/login.ts +++ b/src/server/lib/login.ts @@ -2,8 +2,7 @@ import { Client } from 'ldapts' import { LdapAuth } from '../auth/LdapAuth' import { PaFirewall } from '../services/PaFirewall' - -import { paHosts } from '../db/pa' +import { db } from '../prisma' export async function login(username: string, password: string, ip: string) { const ldapClient = new Client({ @@ -15,6 +14,8 @@ export async function login(username: string, password: string, ip: string) { try { const user = await ldapAuth.login(username, password) + const paHosts = await db.paHost.findMany() + const pa = new PaFirewall(paHosts[0].ip, paHosts[0].key) await pa.login(username, ip, user.domain) diff --git a/src/server/lib/logout.ts b/src/server/lib/logout.ts index 1ebc39e..29d185a 100644 --- a/src/server/lib/logout.ts +++ b/src/server/lib/logout.ts @@ -1,9 +1,10 @@ +import { db } from '../prisma' import { PaFirewall } from '../services/PaFirewall' -import { paHosts } from '../db/pa' - export async function logout(username: string, domain: string, ip: string) { try { + const paHosts = await db.paHost.findMany() + const pa = new PaFirewall(paHosts[0].ip, paHosts[0].key) await pa.logout(username, ip, domain) diff --git a/src/server/prisma.ts b/src/server/prisma.ts new file mode 100644 index 0000000..020681b --- /dev/null +++ b/src/server/prisma.ts @@ -0,0 +1,3 @@ +import { PrismaClient } from '@prisma/client' + +export const db = new PrismaClient() diff --git a/src/server/services/PaFirewall.ts b/src/server/services/PaFirewall.ts index ca2782f..ce903b1 100644 --- a/src/server/services/PaFirewall.ts +++ b/src/server/services/PaFirewall.ts @@ -1,4 +1,5 @@ import { XMLParser } from 'fast-xml-parser' +import { db } from '../prisma' const MAP_TIMEOUT_IN_MINUTES = process.env.MAPPING_TIMEOUT || '720' // 12 horas @@ -83,4 +84,33 @@ export class PaFirewall { ` } + + static async addFirewall(ip: string, username: string, password: string) { + const response = await fetch( + `https://${ip}/api/?type=keygen&user=${username}&password=${password}` + ) + + const data = await response.text() + + const parsedData = xmlParser.parse(data) + + if (parsedData.response.attr_status !== 'success') { + console.log(data) + throw new Error('Failed to generate API key') + } + + const key: string = parsedData.response.result.key + + await db.paHost.upsert({ + where: { ip }, + create: { + ip, + key, + name: ip + }, + update: { + key + } + }) + } } diff --git a/src/server/trpc.ts b/src/server/trpc.ts index 8ac445b..1761a5d 100644 --- a/src/server/trpc.ts +++ b/src/server/trpc.ts @@ -5,6 +5,7 @@ import { z } from 'zod' import { login } from './lib/login' import { getIpFromContext } from './lib/getIpFromContext' import { logout } from './lib/logout' +import { PaFirewall } from './services/PaFirewall' // Created for each request function createContext({ req, res }: trpcExpress.CreateExpressContextOptions) { @@ -29,6 +30,22 @@ export const appRouter = t.router({ .input(z.object({ username: z.string(), domain: z.string() })) .mutation(async ({ input, ctx }) => { return await logout(input.username, input.domain, getIpFromContext(ctx)) + }), + + addFirewall: t.procedure + .input( + z.object({ + ip: z.string().ip(), + username: z.string().min(1), + password: z.string().min(5) + }) + ) + .mutation(async ({ input }) => { + const { ip, username, password } = input + + await PaFirewall.addFirewall(ip, username, password) + + return true }) })