KEYCLOAK AUTH FIX: Phase 4 - Email & Files Endpoints

**UPDATED ENDPOINTS (11 additional):**
- email/send.ts (CRITICAL: was using old auth)
- email/fetch-thread.ts (CRITICAL: was using old auth)
- email/fetch-thread-v2.ts (CRITICAL: was using old auth)
- email/generate-eoi-document.ts (CRITICAL: was using old auth)
- files/upload.ts (CRITICAL: was using old auth)
- files/list.ts (SECURITY ISSUE: had NO auth)
- files/download.ts (SECURITY ISSUE: had NO auth)
- files/delete.ts (SECURITY ISSUE: had NO auth)
- files/create-folder.ts (SECURITY ISSUE: had NO auth)
- files/preview.ts (SECURITY ISSUE: had NO auth)
- files/rename.ts (SECURITY ISSUE: had NO auth)

**AUTHENTICATION:** All now support dual auth:
- x-tag header (webhooks/external calls)
- Keycloak session (logged-in users)

**PROGRESS:** 28/47 endpoints completed (~60%)
**NEXT:** Continue with remaining proxy, test & debug endpoints

**CRITICAL SECURITY FIXES:** Found 6 file endpoints with NO authentication - major vulnerability patched!
This commit is contained in:
Matt 2025-06-15 16:32:34 +02:00
parent 4abf74e750
commit a17c6ed162
11 changed files with 49 additions and 33 deletions

View File

@ -1,3 +1,4 @@
import { requireAuth } from '~/server/utils/auth';
import { getCredentialsFromSession, decryptCredentials } from '~/server/utils/encryption';
import { getCachedEmails, syncEmailsWithRetry, getSyncMetadata } from '~/server/utils/email-sync';
@ -23,11 +24,8 @@ interface EmailThread {
}
export default defineEventHandler(async (event) => {
const xTagHeader = getRequestHeader(event, "x-tag");
if (!xTagHeader || (xTagHeader !== "094ut234" && xTagHeader !== "pjnvü1230")) {
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
}
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
const body = await readBody(event);

View File

@ -1,5 +1,6 @@
import Imap from 'imap';
import { simpleParser } from 'mailparser';
import { requireAuth } from '~/server/utils/auth';
import { getCredentialsFromSession, decryptCredentials } from '~/server/utils/encryption';
import { listFiles, getFileStats, getMinioClient, uploadFile } from '~/server/utils/minio';
import { getIMAPPool } from '~/server/utils/imap-pool';
@ -18,11 +19,8 @@ interface EmailMessage {
}
export default defineEventHandler(async (event) => {
const xTagHeader = getRequestHeader(event, "x-tag");
if (!xTagHeader || (xTagHeader !== "094ut234" && xTagHeader !== "pjnvü1230")) {
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
}
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
const body = await readBody(event);

View File

@ -1,3 +1,4 @@
import { requireAuth } from '~/server/utils/auth';
import { getInterestById, updateInterest } from '~/server/utils/nocodb';
// Helper function to create embedded signing URLs
@ -32,13 +33,9 @@ interface DocumensoResponse {
export default defineEventHandler(async (event) => {
console.log('[generate-eoi] ========== EOI GENERATION REQUEST RECEIVED ==========');
const xTagHeader = getRequestHeader(event, "x-tag");
console.log('[generate-eoi] x-tag header:', xTagHeader);
if (!xTagHeader || (xTagHeader !== "094ut234" && xTagHeader !== "pjnvü1230")) {
console.log('[generate-eoi] Authentication failed');
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
}
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
console.log('[generate-eoi] Request authenticated');
try {
const body = await readBody(event);
@ -177,13 +174,17 @@ export default defineEventHandler(async (event) => {
});
}
// Get linked berths
// Get linked berths - use the same auth as this request (either x-tag or session)
const xTagHeader = getRequestHeader(event, "x-tag");
const requestHeaders: Record<string, string> = {};
if (xTagHeader) {
requestHeaders["x-tag"] = xTagHeader;
}
const berthsResponse = await $fetch<{ list: Array<{ 'Mooring Number': string }> }>(
"/api/get-interest-berths",
{
headers: {
"x-tag": xTagHeader,
},
headers: requestHeaders,
params: {
interestId: interestId,
linkType: "berths",

View File

@ -1,17 +1,14 @@
import nodemailer from 'nodemailer';
import { requireAuth } from '~/server/utils/auth';
import { getCredentialsFromSession, decryptCredentials } from '~/server/utils/encryption';
import { uploadFile, getMinioClient } from '~/server/utils/minio';
import { updateInterest } from '~/server/utils/nocodb';
export default defineEventHandler(async (event) => {
const xTagHeader = getRequestHeader(event, "x-tag");
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
console.log('[Email Send] Request received with x-tag:', xTagHeader);
if (!xTagHeader || (xTagHeader !== "094ut234" && xTagHeader !== "pjnvü1230")) {
console.error('[Email Send] Authentication failed - invalid x-tag');
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
}
console.log('[Email Send] Request authenticated');
try {
const body = await readBody(event);

View File

@ -1,6 +1,10 @@
import { requireAuth } from '~/server/utils/auth';
import { createFolder } from '~/server/utils/minio';
export default defineEventHandler(async (event) => {
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
const body = await readBody(event);
const { folderPath } = body;

View File

@ -1,6 +1,10 @@
import { requireAuth } from '~/server/utils/auth';
import { deleteFile, deleteFolder, getMinioClient } from '~/server/utils/minio';
export default defineEventHandler(async (event) => {
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
const body = await readBody(event);
const { fileName, isFolder, bucket } = body;

View File

@ -1,6 +1,10 @@
import { requireAuth } from '~/server/utils/auth';
import { getDownloadUrl } from '~/server/utils/minio';
export default defineEventHandler(async (event) => {
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
const query = getQuery(event);
const fileName = query.fileName as string;

View File

@ -1,6 +1,10 @@
import { requireAuth } from '~/server/utils/auth';
import { listFiles } from '~/server/utils/minio';
export default defineEventHandler(async (event) => {
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
const query = getQuery(event);
const prefix = (query.prefix as string) || '';

View File

@ -1,7 +1,11 @@
import { requireAuth } from '~/server/utils/auth';
import { getPreviewUrl } from '~/server/utils/minio';
import mime from 'mime-types';
export default defineEventHandler(async (event) => {
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
const query = getQuery(event);
const fileName = query.fileName as string;

View File

@ -1,6 +1,10 @@
import { requireAuth } from '~/server/utils/auth';
import { renameFile, renameFolder } from '~/server/utils/minio';
export default defineEventHandler(async (event) => {
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
const body = await readBody(event);
const { oldName, newName, isFolder } = body;

View File

@ -1,14 +1,12 @@
import { requireAuth } from '~/server/utils/auth';
import { uploadFile, getMinioClient } from '~/server/utils/minio';
import formidable from 'formidable';
import { promises as fs } from 'fs';
import mime from 'mime-types';
export default defineEventHandler(async (event) => {
const xTagHeader = getRequestHeader(event, "x-tag");
if (!xTagHeader || (xTagHeader !== "094ut234" && xTagHeader !== "pjnvü1230")) {
throw createError({ statusCode: 401, statusMessage: "unauthenticated" });
}
// Check authentication (x-tag header OR Keycloak session)
await requireAuth(event);
try {
// Get the current path and bucket from query params