API güvenliği sağlandı

This commit is contained in:
2025-11-17 19:29:33 +03:00
parent b581df0774
commit 1949aefdf0
4 changed files with 60 additions and 5 deletions

View File

@@ -8,6 +8,7 @@ SUPABASE_URL=""
SUPABASE_SERVICE_ROLE_KEY=""
SUPABASE_USERS_TABLE="users"
JWT_SECRET="change-me"
# Allowed frontend origins (comma-separated, include scheme)
CLIENT_ORIGIN="http://localhost:5173"
# GLM / Anthropic çeviri servisi

View File

@@ -27,7 +27,32 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
const app = express();
const PORT = process.env.PORT || 4000;
const ORIGIN = process.env.CLIENT_ORIGIN || 'http://localhost:5173';
const allowedOrigins = ORIGIN.split(',').map((origin) => origin.trim());
const allowedOrigins = ORIGIN.split(',').map((origin) => origin.trim()).filter(Boolean);
const normalizeOrigin = (value = '') => {
try {
return new URL(value).origin;
} catch (error) {
return value.replace(/\/$/, '');
}
};
const trustedOrigins = allowedOrigins.map(normalizeOrigin).filter(Boolean);
const enforceClientOrigin = (req, res, next) => {
if (!trustedOrigins.length) {
return next();
}
const header = req.get('origin') || req.get('referer');
if (!header) {
return res.status(403).json({ message: 'Bu istemciye izin verilmiyor.' });
}
const requestOrigin = normalizeOrigin(header);
if (!requestOrigin || !trustedOrigins.includes(requestOrigin)) {
return res.status(403).json({ message: 'Bu istemciye izin verilmiyor.' });
}
return next();
};
const USERS_TABLE = process.env.SUPABASE_USERS_TABLE || 'users';
const JWT_SECRET = process.env.JWT_SECRET;
@@ -85,6 +110,7 @@ const authMiddleware = (req, res, next) => {
};
const authRouter = express.Router();
authRouter.use(enforceClientOrigin);
authRouter.post('/register', async (req, res) => {
const { name, email, password } = req.body || {};
@@ -256,7 +282,7 @@ authRouter.post('/forgot-password', async (req, res) => {
app.use('/auth', authRouter);
app.post('/translate', async (req, res) => {
app.post('/translate', authMiddleware, async (req, res) => {
const { text } = req.body || {};
if (!text || !text.trim()) {
return res.status(400).json({ message: 'Çevrilecek metin bulunamadı.' });
@@ -273,7 +299,7 @@ app.post('/translate', async (req, res) => {
}
});
app.post('/generate-epub', async (req, res) => {
app.post('/generate-epub', authMiddleware, async (req, res) => {
const { text, meta, cover } = req.body || {};
if (!text || !text.trim()) {
return res.status(400).json({ message: 'text is required' });

View File

@@ -1,3 +1,5 @@
import { useAppStore } from '../store/useAppStore';
const base64ToBlob = (base64, mimeType) => {
const binary = atob(base64);
const len = binary.length;
@@ -26,6 +28,14 @@ const blobToBase64 = (blob) =>
const API_BASE = import.meta.env.VITE_API_BASE_URL || 'http://localhost:4000';
const getAuthToken = () => {
const { authToken } = useAppStore.getState();
if (!authToken) {
throw new Error('EPUB oluşturmak için giriş yapmalısın.');
}
return authToken;
};
const slugify = (value = '') =>
value
.toLowerCase()
@@ -63,9 +73,13 @@ export const createEpubFromOcr = async (text, coverImage, meta = {}) => {
filename: resolvedFilename,
};
const token = getAuthToken();
const response = await fetch(`${API_BASE}/generate-epub`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
text,
meta: {

View File

@@ -1,13 +1,27 @@
import { useAppStore } from '../store/useAppStore';
const API_BASE = import.meta.env.VITE_API_BASE_URL || 'http://localhost:4000';
const getAuthToken = () => {
const { authToken } = useAppStore.getState();
if (!authToken) {
throw new Error('Çeviri için giriş yapmalısın.');
}
return authToken;
};
export const translateChunkToTurkish = async (text) => {
if (!text?.trim()) {
throw new Error('Çevrilecek metin bulunamadı.');
}
const token = getAuthToken();
const response = await fetch(`${API_BASE}/translate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ text }),
});