fix: enforce compliance mode for managed deployments

This commit is contained in:
kuekhaoyang
2026-04-02 21:42:00 +08:00
parent 9762e0a6b5
commit 5829a79ee3
15 changed files with 308 additions and 159 deletions
+11
View File
@@ -0,0 +1,11 @@
export type DeploymentProvider = 'self-hosted' | 'vercel' | 'cloudflare';
export interface RuntimeFeatures {
deploymentProvider: DeploymentProvider;
deploymentProviderLabel: string;
restrictedManagedDeployment: boolean;
mediaProxyEnabled: boolean;
iptvEnabled: boolean;
restrictionSummary: string | null;
}
+51
View File
@@ -0,0 +1,51 @@
import 'server-only';
import type { RuntimeFeatures } from '@/lib/config/runtime-features';
function isVercelDeployment(): boolean {
return process.env.VERCEL === '1' || Boolean(process.env.VERCEL_ENV);
}
function isCloudflareDeployment(): boolean {
return (
process.env.CF_PAGES === '1' ||
Boolean(process.env.CF_PAGES_URL) ||
Boolean(process.env.CLOUDFLARE_ACCOUNT_ID) ||
Boolean(process.env.CF_ACCOUNT_ID) ||
Boolean(process.env.WORKERS_CI)
);
}
function getRestrictedFeatures(
deploymentProvider: RuntimeFeatures['deploymentProvider'],
deploymentProviderLabel: string
): RuntimeFeatures {
return {
deploymentProvider,
deploymentProviderLabel,
restrictedManagedDeployment: true,
mediaProxyEnabled: false,
iptvEnabled: false,
restrictionSummary: `${deploymentProviderLabel} 托管部署会启用合规模式:关闭外部媒体代理、热链转发和 IPTV 流中继。需要这些能力时请改用 Docker 或传统 Node.js 自托管。`,
};
}
export function getRuntimeFeatures(): RuntimeFeatures {
if (isVercelDeployment()) {
return getRestrictedFeatures('vercel', 'Vercel');
}
if (isCloudflareDeployment()) {
return getRestrictedFeatures('cloudflare', 'Cloudflare');
}
return {
deploymentProvider: 'self-hosted',
deploymentProviderLabel: '自托管',
restrictedManagedDeployment: false,
mediaProxyEnabled: true,
iptvEnabled: true,
restrictionSummary: null,
};
}
+16 -9
View File
@@ -103,17 +103,24 @@ export function parseSourcesFromJson(jsonString: string): ImportResult {
* Fetch and parse sources from a URL
*/
export async function fetchSourcesFromUrl(url: string): Promise<ImportResult> {
// If we're in the browser and it's an external URL, use our proxy to avoid CORS issues
const headers = {
'Accept': 'application/json',
};
const isExternal = url.startsWith('http') && (typeof window !== 'undefined' && !url.includes(window.location.host));
const fetchUrl = isExternal
? `/api/proxy?url=${encodeURIComponent(url)}`
: url;
const response = await fetch(fetchUrl, {
headers: {
'Accept': 'application/json',
},
});
let response: Response;
try {
response = await fetch(url, { headers });
} catch (directError) {
if (!isExternal) {
throw directError;
}
response = await fetch(`/api/proxy?url=${encodeURIComponent(url)}`, {
headers,
});
}
if (!response.ok) {
throw new Error(`获取失败: ${response.status} ${response.statusText}`);