Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
cac1edc
feat(originflow): 营销站 + 品牌替换 + 公开API + www/app/api 部署隔离
Jul 31, 2026
5d80872
feat(originflow): P1 商业化增强 — QuickStart/Usage/SEO/销售线索后台/埋点/邮件通知
Jul 31, 2026
d823098
fix(build): 修复 web/classic 因 date-fns v4 与 date-fns-tz v1 不兼容导致的构建失败
Jul 31, 2026
1ef77f3
feat(originflow): 模型商店 Model Market 后端 — 商品表/管理员CRUD/公开读取/多语言与货币
Jul 31, 2026
4f3fee0
feat(originflow): 模型商店 Model Market 前端管理后台 — 列表/新建/编辑/删除 + 侧边栏入口
Aug 1, 2026
ee031c0
feat(originflow): 模型市场公开门店页 /market
Aug 1, 2026
c6f2c0a
fix(originflow): ContactForm Select onValueChange 允许 null 导致类型错误
Aug 1, 2026
2785c08
fix(originflow): __root.tsx ensureHostIsolation 类型错误
Aug 1, 2026
625ab45
feat(p2): 企业团队空间 / SLA 状态页 / 区域路由(含选渠道逻辑)/ 分销商控制台 (#2)
peidunyue Aug 1, 2026
9ab7633
feat: Model Market — admin CRUD + public read API + storefront (#1)
peidunyue Aug 1, 2026
3319927
feat(p2): P2 前端管理页面(团队空间/区域路由/SLA/分销商)+ 团队详情路由 (#3)
peidunyue Aug 3, 2026
b08ccc7
feat(teams): add team projects tab to team detail (#4)
peidunyue Aug 3, 2026
7124099
build: 改为从本仓库源码构建并加固 bun 安装可靠性
Aug 3, 2026
000421b
branding: 统一为元点流商 OriginFlow(默认前端)
Aug 3, 2026
333c958
feat(mvp): 营销站前端 + 公开接口(域名隔离 host 切换)
Aug 3, 2026
3c333be
文案调整:中文 Hero 标题精简为「大模型统一API网关」
Aug 3, 2026
ce778ba
feat(mvp): 新增 API Quick Start 开发者接入页(P1-01)
Aug 5, 2026
34a52be
merge: integrate originflow and unify web/src on canonical frontend
Aug 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ Makefile
docs
.eslintcache
.gocache
/web/node_modules
# 依赖一律在镜像内 bun install,任何层级的 node_modules 都不需要进构建上下文
# (Dependencies are installed inside the image; no node_modules at any depth.)
**/node_modules
# web/dist 由 builder 阶段产出并 COPY --from,构建上下文里的产物一律忽略
# (web/dist is produced by the builder stage; ignore any prebuilt output here.)
/web/dist
/web/classic/dist
/web/default/dist
# 运行时目录,由 compose 以 bind mount 挂载
# (Runtime directories, provided by compose bind mounts.)
/data
/logs
!THIRD-PARTY-LICENSES.md
18 changes: 16 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
FROM oven/bun:1@sha256:0733e50325078969732ebe3b15ce4c4be5082f18c4ac1a0f0ca4839c2e4e42a7 AS builder

WORKDIR /build/web
COPY web/package.json web/bun.lock ./
RUN bun install --frozen-lockfile
# .npmrc must land before `bun install`, otherwise the registry it configures is
# ignored (it would only arrive with the later `COPY ./web ./`).
COPY web/package.json web/bun.lock web/.npmrc ./
# Point at a nearby mirror when the default registry is slow, e.g.
# docker build --build-arg NPM_REGISTRY=https://repo.huaweicloud.com/repository/npm/ .
ARG NPM_REGISTRY=
# Bun's default fetch concurrency corrupts large tarballs (react-icons is 22MB,
# @hugeicons/core-free-icons larger still) on constrained links, surfacing as
# "Integrity check failed" on a different package each run. Cap concurrency and
# retry so a single dropped connection doesn't fail the whole build.
RUN if [ -n "$NPM_REGISTRY" ]; then echo "registry=$NPM_REGISTRY" > .npmrc; fi \
&& for attempt in 1 2 3; do \
echo "bun install attempt $attempt" \
&& BUN_CONFIG_MAX_HTTP_REQUESTS=8 bun install --frozen-lockfile && break \
|| { [ "$attempt" = 3 ] && exit 1; echo "retrying..."; sleep 5; }; \
done
COPY ./web ./
COPY ./VERSION /build/VERSION
RUN DISABLE_ESLINT_PLUGIN='true' VITE_REACT_APP_VERSION=$(cat /build/VERSION) bun run build
Expand Down
2 changes: 1 addition & 1 deletion common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

var StartTime = time.Now().Unix() // unit: second
var Version = "v0.0.0" // this hard coding will be replaced automatically when building, no need to manually change
var SystemName = "New API"
var SystemName = "OriginFlow"
var Footer = ""
var Logo = ""
var TopUpLink = ""
Expand Down
28 changes: 28 additions & 0 deletions common/redirect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package common

import (
"net/url"
"strings"
)

// IsSafeRedirect 校验重定向目标是否安全,防止开放重定向(Open Redirect)。
// 允许:空串(无重定向)、同源相对路径(以 / 开头且非协议相对 //host)、指向已知官方域名。
func IsSafeRedirect(u string) bool {
u = strings.TrimSpace(u)
if u == "" {
return true
}
// 相对路径,但排除协议相对地址(//evil.com)
if strings.HasPrefix(u, "/") {
return !strings.HasPrefix(u, "//")
}
Comment on lines +15 to +18

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Reject backslash-based protocol-relative paths.

Line 16 accepts /\evil.example because it starts with / but not //. Browser URL parsing treats backslashes as path separators for special URLs. The destination can become //evil.example and bypass the origin restriction.

Normalize backslashes before the protocol-relative URL check.

Proposed fix
 if strings.HasPrefix(u, "/") {
-	return !strings.HasPrefix(u, "//")
+	return !strings.HasPrefix(strings.ReplaceAll(u, "\\", "/"), "//")
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 相对路径,但排除协议相对地址(//evil.com)
if strings.HasPrefix(u, "/") {
return !strings.HasPrefix(u, "//")
}
// 相对路径,但排除协议相对地址(//evil.com)
if strings.HasPrefix(u, "/") {
return !strings.HasPrefix(strings.ReplaceAll(u, "\\", "/"), "//")
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/redirect.go` around lines 15 - 18, Update the relative-path validation
around the strings.HasPrefix check in the redirect helper to normalize
backslashes to forward slashes before testing for protocol-relative paths.
Ensure inputs such as `/\evil.example` are rejected like `//evil.example`, while
preserving acceptance of valid single-slash relative paths.

parsed, err := url.Parse(u)
if err != nil {
return false
}
if parsed.Scheme != "http" && parsed.Scheme != "https" {
return false
}
host := parsed.Host
return host == "91flow.com" || strings.HasSuffix(host, ".91flow.com")
}
19 changes: 19 additions & 0 deletions constant/context_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,23 @@ const (
// fallback in authHelper (finishAdminAudit) skips its record to avoid
// duplicate entries.
ContextKeyAuditLogged ContextKey = "audit_logged"

// ContextKeyRequestRegion stores the normalized region of the current request,
// used by region-based channel routing (see model.ResolveRegionRouting).
// It is distinct from the vertex-specific "region" key set in the distributor.
ContextKeyRequestRegion ContextKey = "request_region"

// ContextKeyUserRegionPreference stores the authenticated user's preferred
// region (see User.RegionPreference). Region-based channel routing falls back
// to it when no X-Region header or request-region context is present.
ContextKeyUserRegionPreference ContextKey = "user_region_preference"

// ContextKeyUserTeamId stores the authenticated user's enterprise team id
// (see User.TeamId). Consume logs are stamped with it for per-team billing
// aggregation.
ContextKeyUserTeamId ContextKey = "user_team_id"
)

// HeaderRegion is the request header declaring the caller's region for
// region-based channel routing, e.g. `X-Region: cn`.
const HeaderRegion = "X-Region"
Loading
Loading