feat: Google Drive backup OAuth (Faz 1 — backend)
PRD "AyrisLegal Google Drive Backup & Recovery" kapsamında sadece backend altyapısı: OAuth connect/callback/status/disconnect/refresh uç noktaları, AES-256-GCM token şifreleme (tokenCrypto.ts), tek kullanımlık CSRF state (oauthState.ts), drive.file scope ile AyrisLegal/Davalar klasör oluşturma (googleDriveClient.ts). Electron tarafı (dosya tarama/kuyruk/UI) ayrı bir aşamada. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
9618ff4513
commit
328aef91bd
@@ -0,0 +1,36 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
// Google OAuth "state" parametresi: CSRF'e karşı kriptografik olarak rastgele,
|
||||
// kısa ömürlü, tek kullanımlık (bkz. PRD §20). Bellek-içi Map yeterli — OAuth
|
||||
// akışı saniyeler/dakikalar içinde tamamlanıyor, kalıcı depolamaya gerek yok.
|
||||
// NOT: backend birden fazla instance'la (load balancer arkasında) çalışırsa bu
|
||||
// state farklı bir instance'a düşebilir — o zaman paylaşımlı bir store (Redis
|
||||
// vb.) gerekir. Şu an tek instance varsayımıyla yazıldı.
|
||||
interface StateEntry { userId: string; expiresAt: number; }
|
||||
|
||||
const STATE_TTL_MS = 10 * 60 * 1000; // 10 dakika
|
||||
const stateStore = new Map<string, StateEntry>();
|
||||
|
||||
function cleanupExpired() {
|
||||
const now = Date.now();
|
||||
for (const [key, entry] of stateStore.entries()) {
|
||||
if (entry.expiresAt < now) stateStore.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
export function createState(userId: string): string {
|
||||
cleanupExpired();
|
||||
const state = crypto.randomBytes(32).toString('hex');
|
||||
stateStore.set(state, { userId, expiresAt: Date.now() + STATE_TTL_MS });
|
||||
return state;
|
||||
}
|
||||
|
||||
// Tek kullanımlık — çağrıldığı anda store'dan siliniyor, ikinci kullanım (replay)
|
||||
// her zaman null döner.
|
||||
export function consumeState(state: string): string | null {
|
||||
const entry = stateStore.get(state);
|
||||
if (!entry) return null;
|
||||
stateStore.delete(state);
|
||||
if (entry.expiresAt < Date.now()) return null;
|
||||
return entry.userId;
|
||||
}
|
||||
Reference in New Issue
Block a user