mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
Refactor registration and dashboard features to support invite codes and Bunny uploads
- Moved registration logic to a new client component for better separation of concerns. - Integrated invite code requirement based on feature flags in the registration process. - Enhanced dashboard functionality to conditionally enable Bunny uploads based on feature flags. - Updated various components and API routes to check for Bunny uploads and Stripe billing feature flags. - Added new feature flag utilities for managing feature toggles in the application.
This commit is contained in:
@@ -4,6 +4,7 @@ import bcrypt from 'bcryptjs';
|
||||
import { acceptInvitationTokenForUser, getValidInvitationByToken } from '@/lib/invitations';
|
||||
import { checkRateLimit, getClientIp, rateLimitHeaders, RATE_LIMIT_CONFIGS } from '@/lib/rate-limit';
|
||||
import { apiErrors, successResponse, withCacheControl } from '@/lib/api-response';
|
||||
import { isInviteCodeRequired } from '@/lib/feature-flags';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
@@ -49,7 +50,7 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!invitationIsValid) {
|
||||
if (!invitationIsValid && isInviteCodeRequired()) {
|
||||
// Validate invite code using constant-time comparison to prevent timing attacks
|
||||
const validInviteCode = process.env.INVITE_CODE;
|
||||
if (!validInviteCode || !inviteCode) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
getStripeCheckoutState,
|
||||
} from '@/lib/billing';
|
||||
import { rateLimit } from '@/lib/rate-limit';
|
||||
import { isStripeFeatureEnabled } from '@/lib/feature-flags';
|
||||
import { getStripe, getStripePriceId, isStripeConfigured } from '@/lib/stripe';
|
||||
import { isTrustedSameOriginRequest } from '@/lib/request-origin';
|
||||
|
||||
@@ -35,6 +36,10 @@ export async function POST(request: NextRequest) {
|
||||
return apiErrors.unauthorized();
|
||||
}
|
||||
|
||||
if (!isStripeFeatureEnabled()) {
|
||||
return apiErrors.badRequest('Stripe billing is disabled by this host');
|
||||
}
|
||||
|
||||
if (!isStripeConfigured()) {
|
||||
return apiErrors.internalError('Stripe billing is not configured');
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { auth } from '@/lib/auth';
|
||||
import { apiErrors, successResponse, withCacheControl } from '@/lib/api-response';
|
||||
import { getBillingOverview } from '@/lib/billing';
|
||||
import { rateLimit } from '@/lib/rate-limit';
|
||||
import { isStripeFeatureEnabled } from '@/lib/feature-flags';
|
||||
import { getStripe, isStripeConfigured } from '@/lib/stripe';
|
||||
import { isTrustedSameOriginRequest } from '@/lib/request-origin';
|
||||
|
||||
@@ -31,6 +32,10 @@ export async function POST(request: NextRequest) {
|
||||
return apiErrors.unauthorized();
|
||||
}
|
||||
|
||||
if (!isStripeFeatureEnabled()) {
|
||||
return apiErrors.badRequest('Stripe billing is disabled by this host');
|
||||
}
|
||||
|
||||
if (!isStripeConfigured()) {
|
||||
return apiErrors.internalError('Stripe billing is not configured');
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { auth } from '@/lib/auth';
|
||||
import { apiErrors, successResponse, withCacheControl } from '@/lib/api-response';
|
||||
import { getBillingOverview } from '@/lib/billing';
|
||||
import { isStripeConfigured } from '@/lib/stripe';
|
||||
import { isStripeFeatureEnabled } from '@/lib/feature-flags';
|
||||
import { hasStripeRuntimeConfig, isStripeConfigured } from '@/lib/stripe';
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
@@ -11,8 +12,12 @@ export async function GET() {
|
||||
}
|
||||
|
||||
const billing = await getBillingOverview(session.user.id);
|
||||
const isEnabled = isStripeFeatureEnabled();
|
||||
const isConfigured = hasStripeRuntimeConfig();
|
||||
const response = successResponse({
|
||||
isConfigured: isStripeConfigured(),
|
||||
isEnabled,
|
||||
isConfigured,
|
||||
status: !isEnabled ? 'disabled' : isStripeConfigured() ? 'ready' : 'misconfigured',
|
||||
checkoutAvailable: isStripeConfigured() && !billing.subscription.hasActiveSubscription,
|
||||
portalAvailable: isStripeConfigured() && Boolean(billing.subscription.stripeCustomerId),
|
||||
subscription: {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { rateLimit } from '@/lib/rate-limit';
|
||||
import crypto from 'crypto';
|
||||
import { cleanupBunnyStreamVideos } from '@/lib/bunny-stream-cleanup';
|
||||
import { createBunnyUploadToken, verifyBunnyUploadToken } from '@/lib/bunny-upload-token';
|
||||
import { isBunnyUploadsFeatureEnabled } from '@/lib/feature-flags';
|
||||
|
||||
type RouteParams = { params: Promise<{ projectId: string }> };
|
||||
|
||||
@@ -50,6 +51,10 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
return apiErrors.badRequest('Title is required');
|
||||
}
|
||||
|
||||
if (!isBunnyUploadsFeatureEnabled()) {
|
||||
return apiErrors.badRequest('Direct uploads are disabled by this host');
|
||||
}
|
||||
|
||||
const apiKey = process.env.BUNNY_STREAM_API_KEY;
|
||||
const libraryId = process.env.BUNNY_STREAM_LIBRARY_ID || process.env.NEXT_PUBLIC_BUNNY_STREAM_LIBRARY_ID;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
enforceGuestUploadQuota,
|
||||
verifyGuestUploadToken,
|
||||
} from '@/lib/guest-upload-token';
|
||||
import { isBunnyUploadsFeatureEnabled } from '@/lib/feature-flags';
|
||||
import { getShareSessionFromRequest } from '@/lib/share-session';
|
||||
import { getVideoAssetAccessContext, SAFE_BUNNY_VIDEO_ID } from '@/lib/video-assets';
|
||||
|
||||
@@ -30,6 +31,10 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
const title = typeof body?.title === 'string' ? body.title.trim() : '';
|
||||
if (!title) return apiErrors.badRequest('Title is required');
|
||||
|
||||
if (!isBunnyUploadsFeatureEnabled()) {
|
||||
return apiErrors.badRequest('Direct uploads are disabled by this host');
|
||||
}
|
||||
|
||||
const shareSession = getShareSessionFromRequest(request, context.video.id);
|
||||
if (!context.viewerUserId) {
|
||||
const quotaError = await enforceGuestUploadQuota(request, context.video.id, 'bunny', shareSession?.token ?? null);
|
||||
|
||||
Reference in New Issue
Block a user