feat(sora): 新增 Sora 平台支持并修复高危安全和性能问题

新增功能:
- 新增 Sora 账号管理和 OAuth 认证
- 新增 Sora 视频/图片生成 API 网关
- 新增 Sora 任务调度和缓存机制
- 新增 Sora 使用统计和计费支持
- 前端增加 Sora 平台配置界面

安全修复(代码审核):
- [SEC-001] 限制媒体下载响应体大小(图片 20MB、视频 200MB),防止 DoS 攻击
- [SEC-002] 限制 SDK API 响应大小(1MB),防止内存耗尽
- [SEC-003] 修复 SSRF 风险,添加 URL 验证并强制使用代理配置

BUG 修复(代码审核):
- [BUG-001] 修复 for 循环内 defer 累积导致的资源泄漏
- [BUG-002] 修复图片并发槽位获取失败时已持有锁未释放的永久泄漏

性能优化(代码审核):
- [PERF-001] 添加 Sentinel Token 缓存(3 分钟有效期),减少 PoW 计算开销

技术细节:
- 使用 io.LimitReader 限制所有外部输入的大小
- 添加 urlvalidator 验证防止 SSRF 攻击
- 使用 sync.Map 实现线程安全的包级缓存
- 优化并发槽位管理,添加 releaseAll 模式防止泄漏

影响范围:
- 后端:新增 Sora 相关数据模型、服务、网关和管理接口
- 前端:新增 Sora 平台配置、账号管理和监控界面
- 配置:新增 Sora 相关配置项和环境变量

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
yangjianbo
2026-01-29 16:18:38 +08:00
parent bece1b5201
commit 13262a5698
97 changed files with 29541 additions and 68 deletions

View File

@@ -0,0 +1,278 @@
// Code generated by ent, DO NOT EDIT.
package soraaccount
import (
"time"
"entgo.io/ent/dialect/sql"
)
const (
// Label holds the string label denoting the soraaccount type in the database.
Label = "sora_account"
// FieldID holds the string denoting the id field in the database.
FieldID = "id"
// FieldCreatedAt holds the string denoting the created_at field in the database.
FieldCreatedAt = "created_at"
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
FieldUpdatedAt = "updated_at"
// FieldAccountID holds the string denoting the account_id field in the database.
FieldAccountID = "account_id"
// FieldAccessToken holds the string denoting the access_token field in the database.
FieldAccessToken = "access_token"
// FieldSessionToken holds the string denoting the session_token field in the database.
FieldSessionToken = "session_token"
// FieldRefreshToken holds the string denoting the refresh_token field in the database.
FieldRefreshToken = "refresh_token"
// FieldClientID holds the string denoting the client_id field in the database.
FieldClientID = "client_id"
// FieldEmail holds the string denoting the email field in the database.
FieldEmail = "email"
// FieldUsername holds the string denoting the username field in the database.
FieldUsername = "username"
// FieldRemark holds the string denoting the remark field in the database.
FieldRemark = "remark"
// FieldUseCount holds the string denoting the use_count field in the database.
FieldUseCount = "use_count"
// FieldPlanType holds the string denoting the plan_type field in the database.
FieldPlanType = "plan_type"
// FieldPlanTitle holds the string denoting the plan_title field in the database.
FieldPlanTitle = "plan_title"
// FieldSubscriptionEnd holds the string denoting the subscription_end field in the database.
FieldSubscriptionEnd = "subscription_end"
// FieldSoraSupported holds the string denoting the sora_supported field in the database.
FieldSoraSupported = "sora_supported"
// FieldSoraInviteCode holds the string denoting the sora_invite_code field in the database.
FieldSoraInviteCode = "sora_invite_code"
// FieldSoraRedeemedCount holds the string denoting the sora_redeemed_count field in the database.
FieldSoraRedeemedCount = "sora_redeemed_count"
// FieldSoraRemainingCount holds the string denoting the sora_remaining_count field in the database.
FieldSoraRemainingCount = "sora_remaining_count"
// FieldSoraTotalCount holds the string denoting the sora_total_count field in the database.
FieldSoraTotalCount = "sora_total_count"
// FieldSoraCooldownUntil holds the string denoting the sora_cooldown_until field in the database.
FieldSoraCooldownUntil = "sora_cooldown_until"
// FieldCooledUntil holds the string denoting the cooled_until field in the database.
FieldCooledUntil = "cooled_until"
// FieldImageEnabled holds the string denoting the image_enabled field in the database.
FieldImageEnabled = "image_enabled"
// FieldVideoEnabled holds the string denoting the video_enabled field in the database.
FieldVideoEnabled = "video_enabled"
// FieldImageConcurrency holds the string denoting the image_concurrency field in the database.
FieldImageConcurrency = "image_concurrency"
// FieldVideoConcurrency holds the string denoting the video_concurrency field in the database.
FieldVideoConcurrency = "video_concurrency"
// FieldIsExpired holds the string denoting the is_expired field in the database.
FieldIsExpired = "is_expired"
// Table holds the table name of the soraaccount in the database.
Table = "sora_accounts"
)
// Columns holds all SQL columns for soraaccount fields.
var Columns = []string{
FieldID,
FieldCreatedAt,
FieldUpdatedAt,
FieldAccountID,
FieldAccessToken,
FieldSessionToken,
FieldRefreshToken,
FieldClientID,
FieldEmail,
FieldUsername,
FieldRemark,
FieldUseCount,
FieldPlanType,
FieldPlanTitle,
FieldSubscriptionEnd,
FieldSoraSupported,
FieldSoraInviteCode,
FieldSoraRedeemedCount,
FieldSoraRemainingCount,
FieldSoraTotalCount,
FieldSoraCooldownUntil,
FieldCooledUntil,
FieldImageEnabled,
FieldVideoEnabled,
FieldImageConcurrency,
FieldVideoConcurrency,
FieldIsExpired,
}
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
if column == Columns[i] {
return true
}
}
return false
}
var (
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
DefaultUpdatedAt func() time.Time
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
UpdateDefaultUpdatedAt func() time.Time
// DefaultUseCount holds the default value on creation for the "use_count" field.
DefaultUseCount int
// DefaultSoraSupported holds the default value on creation for the "sora_supported" field.
DefaultSoraSupported bool
// DefaultSoraRedeemedCount holds the default value on creation for the "sora_redeemed_count" field.
DefaultSoraRedeemedCount int
// DefaultSoraRemainingCount holds the default value on creation for the "sora_remaining_count" field.
DefaultSoraRemainingCount int
// DefaultSoraTotalCount holds the default value on creation for the "sora_total_count" field.
DefaultSoraTotalCount int
// DefaultImageEnabled holds the default value on creation for the "image_enabled" field.
DefaultImageEnabled bool
// DefaultVideoEnabled holds the default value on creation for the "video_enabled" field.
DefaultVideoEnabled bool
// DefaultImageConcurrency holds the default value on creation for the "image_concurrency" field.
DefaultImageConcurrency int
// DefaultVideoConcurrency holds the default value on creation for the "video_concurrency" field.
DefaultVideoConcurrency int
// DefaultIsExpired holds the default value on creation for the "is_expired" field.
DefaultIsExpired bool
)
// OrderOption defines the ordering options for the SoraAccount queries.
type OrderOption func(*sql.Selector)
// ByID orders the results by the id field.
func ByID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldID, opts...).ToFunc()
}
// ByCreatedAt orders the results by the created_at field.
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
}
// ByUpdatedAt orders the results by the updated_at field.
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
}
// ByAccountID orders the results by the account_id field.
func ByAccountID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldAccountID, opts...).ToFunc()
}
// ByAccessToken orders the results by the access_token field.
func ByAccessToken(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldAccessToken, opts...).ToFunc()
}
// BySessionToken orders the results by the session_token field.
func BySessionToken(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSessionToken, opts...).ToFunc()
}
// ByRefreshToken orders the results by the refresh_token field.
func ByRefreshToken(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldRefreshToken, opts...).ToFunc()
}
// ByClientID orders the results by the client_id field.
func ByClientID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldClientID, opts...).ToFunc()
}
// ByEmail orders the results by the email field.
func ByEmail(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldEmail, opts...).ToFunc()
}
// ByUsername orders the results by the username field.
func ByUsername(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUsername, opts...).ToFunc()
}
// ByRemark orders the results by the remark field.
func ByRemark(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldRemark, opts...).ToFunc()
}
// ByUseCount orders the results by the use_count field.
func ByUseCount(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUseCount, opts...).ToFunc()
}
// ByPlanType orders the results by the plan_type field.
func ByPlanType(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldPlanType, opts...).ToFunc()
}
// ByPlanTitle orders the results by the plan_title field.
func ByPlanTitle(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldPlanTitle, opts...).ToFunc()
}
// BySubscriptionEnd orders the results by the subscription_end field.
func BySubscriptionEnd(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSubscriptionEnd, opts...).ToFunc()
}
// BySoraSupported orders the results by the sora_supported field.
func BySoraSupported(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSoraSupported, opts...).ToFunc()
}
// BySoraInviteCode orders the results by the sora_invite_code field.
func BySoraInviteCode(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSoraInviteCode, opts...).ToFunc()
}
// BySoraRedeemedCount orders the results by the sora_redeemed_count field.
func BySoraRedeemedCount(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSoraRedeemedCount, opts...).ToFunc()
}
// BySoraRemainingCount orders the results by the sora_remaining_count field.
func BySoraRemainingCount(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSoraRemainingCount, opts...).ToFunc()
}
// BySoraTotalCount orders the results by the sora_total_count field.
func BySoraTotalCount(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSoraTotalCount, opts...).ToFunc()
}
// BySoraCooldownUntil orders the results by the sora_cooldown_until field.
func BySoraCooldownUntil(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldSoraCooldownUntil, opts...).ToFunc()
}
// ByCooledUntil orders the results by the cooled_until field.
func ByCooledUntil(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCooledUntil, opts...).ToFunc()
}
// ByImageEnabled orders the results by the image_enabled field.
func ByImageEnabled(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldImageEnabled, opts...).ToFunc()
}
// ByVideoEnabled orders the results by the video_enabled field.
func ByVideoEnabled(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldVideoEnabled, opts...).ToFunc()
}
// ByImageConcurrency orders the results by the image_concurrency field.
func ByImageConcurrency(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldImageConcurrency, opts...).ToFunc()
}
// ByVideoConcurrency orders the results by the video_concurrency field.
func ByVideoConcurrency(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldVideoConcurrency, opts...).ToFunc()
}
// ByIsExpired orders the results by the is_expired field.
func ByIsExpired(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldIsExpired, opts...).ToFunc()
}

File diff suppressed because it is too large Load Diff