fix: 放行固定资产盘点免登回跳
This commit is contained in:
parent
b54fa5c6ae
commit
47b6768306
@ -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"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user