chore: 初始提交 Fonu 1.0.2

- 公网反代:Nginx 状态卡片(版本 / 运行状态 / 配置校验 / 端口监听)
- 部署设置第一、二梯队(HTTPS 开关、安全头、限流、连接数、仅中国大陆 IP)
- 隧道检测兼容 frps v0.68 / v0.71(V2 与旧版端点)
- 恢复被清空的 internal/frp/store.go、internal/api/ddns_handler.go、web/src/views/DdnsView.vue
This commit is contained in:
2026-09-23 09:40:59 +08:00
commit 278f8267b7
333 changed files with 53562 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
export const GITHUB_REPO = 'O96u/Fonu'
export const GITHUB_REPO_URL = `https://github.com/${GITHUB_REPO}`
export const GITHUB_REPO_DISPLAY = `github.com/${GITHUB_REPO}`
export const GITHUB_RELEASES_URL = `${GITHUB_REPO_URL}/releases`
+26
View File
@@ -0,0 +1,26 @@
/** Mirrors internal/proxy.DefaultPrivateCIDRs — always exempt from china_only / global allow. */
export const DEFAULT_PRIVATE_CIDRS = [
'10.0.0.0/8',
'127.0.0.0/8',
'172.16.0.0/12',
'192.168.0.0/16',
'::1/128',
'fc00::/7',
]
export function mergeIPList(defaults: string[], custom: string[]): string[] {
const seen = new Set<string>()
const out: string[] = []
for (const cidr of [...defaults, ...custom]) {
const value = cidr.trim()
if (!value || seen.has(value)) continue
seen.add(value)
out.push(value)
}
return out
}
export function stripDefaultIPList(defaults: string[], list: string[]): string[] {
const defaultSet = new Set(defaults)
return list.map((item) => item.trim()).filter((item) => item && !defaultSet.has(item))
}
+81
View File
@@ -0,0 +1,81 @@
export interface NotifyEventOption {
key: string
label: string
hint?: string
hasThreshold?: boolean
thresholdKey?: 'ip_frequent' | 'login_failure'
}
export interface NotifyEventGroup {
title: string
events: NotifyEventOption[]
}
export const NOTIFY_EVENT_GROUPS: NotifyEventGroup[] = [
{
title: 'DDNS',
events: [
{
key: 'on_ddns_ip_change',
label: 'IP 变更',
hint: '公网 IP 变更并成功同步到 DNS',
},
{
key: 'on_ddns_failure',
label: '更新失败',
},
],
},
{
title: '证书',
events: [
{
key: 'on_cert_expiry',
label: '即将到期',
hint: '进入续签阈值后每天提醒一次',
},
{
key: 'on_cert_renew_success',
label: '续签成功',
},
{
key: 'on_cert_renew_failure',
label: '续签失败',
},
],
},
{
title: '安全',
events: [
{
key: 'on_ip_frequent_access',
label: 'IP 频繁访问',
hint: '同一 IP 在统计窗口内超过阈值',
hasThreshold: true,
thresholdKey: 'ip_frequent',
},
{
key: 'on_login_failure',
label: '登录异常',
hint: '同一 IP 在窗口内多次登录失败',
hasThreshold: true,
thresholdKey: 'login_failure',
},
],
},
{
title: '系统',
events: [
{
key: 'on_nginx_reload_failure',
label: 'Nginx 重载失败',
hint: '保存反代或证书后 Nginx 未能成功重载',
},
],
},
]
export const DEFAULT_IP_FREQUENT_THRESHOLD = 100
export const DEFAULT_IP_FREQUENT_WINDOW_SEC = 60
export const DEFAULT_LOGIN_FAILURE_THRESHOLD = 5
export const DEFAULT_LOGIN_FAILURE_WINDOW_SEC = 300
+19
View File
@@ -0,0 +1,19 @@
import type { NotifyType, WebhookProvider } from '../api/types'
export const NOTIFY_TYPE_OPTIONS: { label: string; value: NotifyType }[] = [
{ label: '关闭', value: '' },
{ label: '邮件(SMTP)', value: 'email' },
{ label: 'Webhook', value: 'webhook' },
{ label: 'Telegram 机器人', value: 'telegram' },
]
export const WEBHOOK_PROVIDER_OPTIONS: { label: string; value: WebhookProvider }[] = [
{ label: 'Bark', value: 'bark' },
{ label: 'ntfy', value: 'ntfy' },
{ label: 'Gotify', value: 'gotify' },
{ label: '自定义 Webhook', value: 'custom' },
]
export const DEFAULT_BARK_SERVER = 'https://api.day.app'
export const DEFAULT_NTFY_SERVER = 'https://ntfy.sh'
export const MASKED_SECRET = '********'
+3
View File
@@ -0,0 +1,3 @@
/** 敏感凭据字段:标签与占位符全站统一 */
export const CONFIGURED_SECRET_TAG = '已配置'
export const CONFIGURED_SECRET_PLACEHOLDER = '已配置,留空表示不修改'