create database and auth for staging and dev #99

Merged
esteban merged 52 commits from database into main 2026-08-16 19:23:42 +00:00
6 changed files with 66 additions and 21 deletions
Showing only changes of commit e5fb968629 - Show all commits

View File

@ -37,7 +37,7 @@ jobs:
host: ${{ secrets.VPS_HOST }} host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }} username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }} key: ${{ secrets.VPS_SSH_KEY }}
source: "dist/*,package.json,pnpm-lock.yaml,pnpm-workspace.yaml,ecosystem.config.cjs" source: "dist/*,package.json,pnpm-lock.yaml,pnpm-workspace.yaml,ecosystem.config.cjs,prisma/schema.prisma,prisma/migrations,prisma.config.ts"
target: "${{ env.TARGET_DIR }}" target: "${{ env.TARGET_DIR }}"
- name: Restart PM2 - name: Restart PM2
@ -52,9 +52,9 @@ jobs:
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
npm install -g pnpm@11 2>&1 npm install -g pnpm@11 2>&1
cd ${{ env.TARGET_DIR }} cd ${{ env.TARGET_DIR }}
pnpm install --prod 2>&1
cat > .env <<'ENVEOF' cat > .env <<'ENVEOF'
DATABASE_URL="${{ secrets.DATABASE_URL }}" DATABASE_URL="${{ secrets.DATABASE_URL }}"
DIRECT_URL="${{ secrets.DIRECT_URL }}"
GOOGLE_SERVICE_ACCOUNT_EMAIL="${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}" GOOGLE_SERVICE_ACCOUNT_EMAIL="${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}"
GOOGLE_PRIVATE_KEY="${{ secrets.GOOGLE_PRIVATE_KEY }}" GOOGLE_PRIVATE_KEY="${{ secrets.GOOGLE_PRIVATE_KEY }}"
GOOGLE_SHEET_ID="${{ secrets.GOOGLE_SHEET_ID }}" GOOGLE_SHEET_ID="${{ secrets.GOOGLE_SHEET_ID }}"
@ -65,5 +65,8 @@ jobs:
CLOUDFLARE_ACCOUNT_ID="${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" CLOUDFLARE_ACCOUNT_ID="${{ secrets.CLOUDFLARE_ACCOUNT_ID }}"
ADMIN_API_KEY="${{ secrets.ADMIN_API_KEY }}" ADMIN_API_KEY="${{ secrets.ADMIN_API_KEY }}"
ENVEOF ENVEOF
pnpm install --prod 2>&1
pnpm exec prisma generate 2>&1
pnpm exec prisma migrate deploy 2>&1
pm2 reload ecosystem.config.cjs --only ${{ env.APP_NAME }} --update-env || \ pm2 reload ecosystem.config.cjs --only ${{ env.APP_NAME }} --update-env || \
pm2 start ecosystem.config.cjs --only ${{ env.APP_NAME }} --update-env pm2 start ecosystem.config.cjs --only ${{ env.APP_NAME }} --update-env

View File

@ -45,6 +45,7 @@
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/typography": "^0.5.19", "@tailwindcss/typography": "^0.5.19",
"daisyui": "^5.5.18" "daisyui": "^5.5.18",
"dotenv": "^17.4.2"
} }
} }

View File

@ -102,6 +102,9 @@ importers:
daisyui: daisyui:
specifier: ^5.5.18 specifier: ^5.5.18
version: 5.5.20 version: 5.5.20
dotenv:
specifier: ^17.4.2
version: 17.4.2
packages: packages:

View File

@ -1,11 +1,23 @@
import type { APIRoute } from "astro"; import type { APIRoute } from "astro";
import { prisma } from "../../lib/prisma"; import { prisma } from "../../lib/prisma";
import { createSession, sessionCookieFor, verifyPassword } from "../../lib/auth"; import {
createSession,
isSameOrigin,
sessionCookieFor,
verifyPassword,
} from "../../lib/auth";
export const prerender = false; export const prerender = false;
export const POST: APIRoute = async ({ request }) => { export const POST: APIRoute = async ({ request }) => {
try { try {
if (!isSameOrigin(request)) {
return Response.json(
{ success: false, message: "Origen no válido" },
{ status: 403 }
);
}
const body = await request.json(); const body = await request.json();
const identifier = String(body?.username || body?.email || "") const identifier = String(body?.username || body?.email || "")
.trim() .trim()

View File

@ -1,9 +1,13 @@
import type { APIRoute } from "astro"; import type { APIRoute } from "astro";
import { clearSessionCookie, revokeSession } from "../../lib/auth"; import { clearSessionCookie, isSameOrigin, revokeSession } from "../../lib/auth";
export const prerender = false; export const prerender = false;
export const POST: APIRoute = async ({ request }) => { export const POST: APIRoute = async ({ request }) => {
if (!isSameOrigin(request)) {
return new Response(null, { status: 403 });
}
await revokeSession(request); await revokeSession(request);
return new Response(null, { return new Response(null, {

View File

@ -69,6 +69,9 @@ function readSessionToken(request: Request): string | null {
export async function createSession(adminId: string): Promise<string> { export async function createSession(adminId: string): Promise<string> {
const token = randomBytes(32).toString("base64url"); const token = randomBytes(32).toString("base64url");
await prisma.session.deleteMany({
where: { expires_at: { lte: new Date() } },
});
await prisma.session.create({ await prisma.session.create({
data: { data: {
token_hash: sha256(token), token_hash: sha256(token),
@ -83,6 +86,7 @@ export async function getSession(request: Request): Promise<AuthSession | null>
const token = readSessionToken(request); const token = readSessionToken(request);
if (!token) return null; if (!token) return null;
try {
const session = await prisma.session.findUnique({ const session = await prisma.session.findUnique({
where: { token_hash: sha256(token) }, where: { token_hash: sha256(token) },
include: { admin: true }, include: { admin: true },
@ -102,6 +106,10 @@ export async function getSession(request: Request): Promise<AuthSession | null>
nombre: session.admin.nombre, nombre: session.admin.nombre,
rol: session.admin.rol, rol: session.admin.rol,
}; };
} catch (error) {
console.error("Error al leer la sesión:", error);
return null;
}
} }
export async function revokeSession(request: Request): Promise<void> { export async function revokeSession(request: Request): Promise<void> {
@ -127,3 +135,17 @@ export async function isApiAuthorized(request: Request): Promise<boolean> {
return timingSafeEqualStr(key, apiKey); return timingSafeEqualStr(key, apiKey);
} }
export function isSameOrigin(request: Request): boolean {
const origin = request.headers.get("origin");
const referer = request.headers.get("referer");
const host = request.headers.get("host");
if (!host) return true;
try {
if (origin) return new URL(origin).host === host;
if (referer) return new URL(referer).host === host;
} catch {
return false;
}
return true;
}