fix: 放行固定资产盘点免登回跳

This commit is contained in:
WuYongJie 2026-07-17 17:39:13 +08:00
parent b54fa5c6ae
commit 47b6768306
4 changed files with 84 additions and 4 deletions

View File

@ -104,7 +104,7 @@ POST /v1/auth/tickets/redeem
"login": {
"enabled": true,
"callbackUrl": "https://asset.jiansun.vip/api/dingtalk/broker-login",
"allowedRedirectPathPrefixes": ["/workflows/disposals", "/dashboard"]
"allowedRedirectPathPrefixes": ["/workflows/disposals", "/dashboard", "/inventory"]
}
}
```

View File

@ -143,7 +143,7 @@ def secret_for(code):
return old if len(old) >= 24 else secrets.token_hex(32)
def project_with_preserved_login(code, name, allowed_hosts):
def project_with_preserved_login(code, name, allowed_hosts, required_redirect_prefixes=()):
project = {
'code': code,
'name': name,
@ -152,7 +152,15 @@ def project_with_preserved_login(code, name, allowed_hosts):
}
old_login = by_code.get(code, {}).get('login')
if isinstance(old_login, dict):
project['login'] = old_login
login = dict(old_login)
existing_prefixes = login.get('allowedRedirectPathPrefixes')
if isinstance(existing_prefixes, list):
prefixes = [str(prefix).strip() for prefix in existing_prefixes if str(prefix).strip()]
for prefix in required_redirect_prefixes:
if prefix not in prefixes:
prefixes.append(prefix)
login['allowedRedirectPathPrefixes'] = prefixes
project['login'] = login
return project
@ -166,6 +174,16 @@ projects = [
'fixed_asset',
'固定资产',
['asset.jiansun.vip', 'www.jsgdzc.cn', 'jsgdzc.cn'],
[
'/workflows/disposals',
'/maintenance',
'/my-assets',
'/equipment',
'/assets',
'/notifications',
'/dashboard',
'/inventory',
],
),
]
if any(item.get('login', {}).get('enabled') is True for item in projects) and not corp_id:

View File

@ -108,6 +108,64 @@ stamp="$(date +%Y%m%d%H%M%S)"
cp -a .env "$backup_root/env-before-git-release-$stamp"
chmod 600 "$backup_root/env-before-git-release-$stamp"
# 盘点任务通过统一 H5 免登入口打开,必须显式保留 /inventory 白名单;不放宽为全站路径。
python3 - <<'PY'
from pathlib import Path
import json
def parse_env_value(raw: str) -> str:
value = raw.strip()
if value.startswith('"') and value.endswith('"'):
return json.loads(value)
if value.startswith("'") and value.endswith("'"):
return value[1:-1]
return value
env_path = Path('.env')
lines = env_path.read_text(encoding='utf-8').splitlines()
projects_index = next(
(
index
for index, line in enumerate(lines)
if not line.lstrip().startswith('#') and line.startswith('YYD_NOTIFICATION_PROJECTS_JSON=')
),
None,
)
if projects_index is None:
raise SystemExit('通知中心缺少 YYD_NOTIFICATION_PROJECTS_JSON,拒绝放宽或猜测免登配置')
key, raw_value = lines[projects_index].split('=', 1)
projects = json.loads(parse_env_value(raw_value))
if not isinstance(projects, list):
raise SystemExit('通知中心项目配置不是数组,拒绝修改')
fixed_asset = next(
(item for item in projects if isinstance(item, dict) and item.get('code') == 'fixed_asset'),
None,
)
if not isinstance(fixed_asset, dict):
raise SystemExit('通知中心缺少 fixed_asset 项目配置,拒绝修改')
login = fixed_asset.get('login')
if isinstance(login, dict) and login.get('enabled') is True:
prefixes = login.get('allowedRedirectPathPrefixes')
if not isinstance(prefixes, list):
raise SystemExit('fixed_asset 免登白名单格式无效,拒绝修改')
normalized = [str(prefix).strip() for prefix in prefixes if str(prefix).strip()]
if '/inventory' not in normalized:
normalized.append('/inventory')
login['allowedRedirectPathPrefixes'] = normalized
lines[projects_index] = key + '=' + json.dumps(
json.dumps(projects, ensure_ascii=False, separators=(',', ':')),
ensure_ascii=False,
)
env_path.write_text('\n'.join(lines) + '\n', encoding='utf-8')
env_path.chmod(0o600)
print('fixed_asset 免登回跳白名单已核对 /inventory')
PY
if docker container inspect youyidian-notification-center >/dev/null 2>&1; then
was_running="$(docker inspect -f '{{.State.Running}}' youyidian-notification-center)"
if [ "$was_running" = true ]; then

View File

@ -19,7 +19,7 @@ const projects = loadProjectConfigs(JSON.stringify([
login: {
enabled: true,
callbackUrl: 'https://asset.example.com/api/dingtalk/broker-login',
allowedRedirectPathPrefixes: ['/workflows/disposals', '/dashboard'],
allowedRedirectPathPrefixes: ['/workflows/disposals', '/dashboard', '/inventory'],
},
},
{
@ -36,6 +36,10 @@ test('内部回跳路径拒绝外链、编码斜杠和相似前缀绕过', () =>
validateRedirectPath('/workflows/disposals/53?tab=detail#items', project),
'/workflows/disposals/53?tab=detail#items',
)
assert.equal(
validateRedirectPath('/inventory/task/public-token-123', project),
'/inventory/task/public-token-123',
)
for (const value of [
'//evil.example.com/path',
'/%2f%2fevil.example.com/path',