diff --git a/.github/workflows/firebasedeploy.yml b/.github/workflows/firebasedeploy.yml index 788605b..71c8f9b 100644 --- a/.github/workflows/firebasedeploy.yml +++ b/.github/workflows/firebasedeploy.yml @@ -38,8 +38,8 @@ jobs: - name: Deploy to Firebase Hosting uses: FirebaseExtended/action-hosting-deploy@v0 with: - repoToken: ${{ secrets.GITHUB_TOKEN }} + # repoToken is removed to prevent PR comments firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_DSGT }} projectId: dsgt-website channelId: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'live' }} - entryPoint: sites/mainweb + entryPoint: sites/mainweb diff --git a/docker-compose.yml b/docker-compose.yml index ed185af..3b73be6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,42 +1,15 @@ -version: '3.8' - services: - postgres: - image: postgres:15-alpine - container_name: cerebra-postgres - restart: unless-stopped + db: + image: postgres:15 + container_name: monorepo-postgres + ports: + - "5433:5432" environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres - POSTGRES_DB: cerebra_dev - POSTGRES_HOST_AUTH_METHOD: trust - ports: - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres"] - interval: 10s - timeout: 5s - retries: 5 - - pgadmin: - image: dpage/pgadmin4:latest - container_name: cerebra-pgadmin - restart: unless-stopped - environment: - PGADMIN_DEFAULT_EMAIL: admin@cerebra.local - PGADMIN_DEFAULT_PASSWORD: admin - PGADMIN_LISTEN_PORT: 80 - ports: - - "5050:80" + POSTGRES_DB: app_db volumes: - - pgadmin_data:/var/lib/pgadmin - depends_on: - - postgres + - pgdata:/var/lib/postgresql/data volumes: - postgres_data: - driver: local - pgadmin_data: - driver: local + pgdata: diff --git a/package.json b/package.json index 5ba2ff3..fd8022d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "query", "private": true, "version": "1.0.0", - "packageManager": "pnpm@10.25.0", + "packageManager": "pnpm@10.26.1", "engines": { "node": ">=20.16.0", "pnpm": ">=9" @@ -30,9 +30,8 @@ "@tailwindcss/postcss": "^4.1.18", "@tanstack/react-query": "^5.90.12", "@trpc/client": "^11.7.2", - "@trpc/next": "^11.7.2", "@trpc/react-query": "^11.7.2", - "@trpc/server": "^11.7.2", + "@trpc/server": "^11.8.0", "@turbo/gen": "^2.1.3", "@types/minimatch": "^6.0.0", "prettier": "^3.3.3", @@ -40,20 +39,21 @@ "typescript": "^5.6.3", "zod": "^3.23.8" }, + "dependencies": { + "@tanstack/react-router": "^1.141.2", + "autoprefixer": "^10.4.22", + "chart.js": "^4.5.1", + "postcss": "^8.5.6" + }, "prettier": "@query/prettier-config", "pnpm": { "overrides": { + "next": "15.5.9", "react": "^18.3.1", "react-dom": "^18.3.1", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", "@types/node": "^22.10.1" } - }, - "dependencies": { - "@tanstack/react-router": "^1.141.2", - "autoprefixer": "^10.4.22", - "chart.js": "^4.5.1", - "postcss": "^8.5.6" } -} \ No newline at end of file +} diff --git a/packages/api/src/context.ts b/packages/api/src/context.ts new file mode 100644 index 0000000..cc0626e --- /dev/null +++ b/packages/api/src/context.ts @@ -0,0 +1,15 @@ +import { auth } from "@query/auth"; +import { db } from "@query/db"; +import type { FetchCreateContextFnOptions } from "@trpc/server/adapters/fetch"; + +export async function createContext(opts?: FetchCreateContextFnOptions) { + const session = await auth(); + + return { + db, + session, + userId: session?.user?.id, + }; +} + +export type Context = Awaited>; \ No newline at end of file diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index cf9a5ab..530296e 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -1,4 +1,3 @@ -// packages/api/src/index.ts -export { appRouter, createContext } from './root'; -export type { AppRouter, Context } from './root'; -export { trpc, createTRPCRouter, publicProcedure } from './trpc'; \ No newline at end of file +export { appRouter, type AppRouter } from "./root"; +export { createContext, type Context } from "./context"; +export { createTRPCRouter, publicProcedure, protectedProcedure } from "./trpc"; \ No newline at end of file diff --git a/packages/api/src/middleware/security.ts b/packages/api/src/middleware/security.ts new file mode 100644 index 0000000..c77ab30 --- /dev/null +++ b/packages/api/src/middleware/security.ts @@ -0,0 +1,102 @@ +import { TRPCError } from "@trpc/server"; + +const rateLimitStore = new Map(); + +setInterval(() => { + const now = Date.now(); + for (const [key, value] of rateLimitStore.entries()) { + if (now > value.resetAt) { + rateLimitStore.delete(key); + } + } +}, 5 * 60 * 1000); + +export function rateLimit(identifier: string, maxRequests: number, windowMs: number): boolean { + const now = Date.now(); + const record = rateLimitStore.get(identifier); + + if (!record || now > record.resetAt) { + rateLimitStore.set(identifier, { + count: 1, + resetAt: now + windowMs, + }); + return true; + } + + if (record.count >= maxRequests) { + return false; + } + + record.count++; + return true; +} + +export function sanitizeInput(input: any): any { + if (input === null || input === undefined) { + return input; + } + + if (typeof input === 'string') { + return input + .replace(/)<[^<]*)*<\/script>/gi, '') + .replace(/javascript:/gi, '') + .replace(/on\w+\s*=/gi, '') + .replace(/data:text\/html/gi, '') + .replace(/