Files
Gnuboard7/templates/_bundled/sirsoft-basic/layouts/board/form.json
T
HeuJung 9cf9c3ff8c fix(core,board,ecommerce,payments,basic): KVE-2026 보안 게이트 6묶음 + 자격증명 전송로 정합
KISA 제보 취약점(KVE-2026-1914/1919/2019/2029/2041/2042/2043/2044)과
그 수정 과정에서 드러난 자격증명 전송로 결함을 함께 해소한다.

globalHeaders 는 데이터소스와 apiCall 핸들러에만 적용되는데, 코어 ApiClient 를
직접 부르는 경로들이 그 사실을 모른 채 게이트된 엔드포인트를 호출하고 있었다.
서버는 정당한 사용자를 거부하고 화면은 이미 버튼을 내준 뒤라, 예외도 로그도 없이
그 자리만 비는 형태로만 드러났다. 전송로 10축을 전수 열거해 6건을 고치고,
같은 실수가 반복되지 않도록 규정과 coverage 에 등재했다.

아웃바운드 프록시가 사이트 자기 자신으로 가는 내부 요청까지 가로채 저장이 수십 초씩
걸리던 문제도 함께 고쳤다. 실패가 폴백으로 삼켜져 화면에는 지연으로만 나타났다.
2026-09-06 00:42:29 +09:00

123 lines
4.6 KiB
JSON

{
"version": "1.0.0",
"layout_name": "board/form",
"permissions": [],
"extends": "_user_base",
"meta": {
"title": "{{route.id ? '$t:board.edit_post' : '$t:board.new_post'}} - {{form_meta?.data?.board?.name || ''}}",
"description": "{{route.id ? '$t:board.edit_post_description' : '$t:board.new_post_description'}}"
},
"data_sources": [
{
"id": "form_data",
"label_key": "$t:editor.data_source.form_data",
"type": "api",
"endpoint": "/api/modules/sirsoft-board/boards/{{route.slug}}/posts/form-data",
"method": "GET",
"auto_fetch": true,
"auth_mode": "optional",
"cache": false,
"refetchOnMount": true,
"initLocal": "form",
"loading_strategy": "blocking",
"_comment_verify_token": "검증 토큰은 자격증명이라 헤더로 보낸다 — 쿼리로 실으면 웹서버 접근 기록과 Referer 에 그대로 남는다. 빈 값은 엔진이 헤더에서 제외한다.",
"headers": {
"X-Board-Post-Verify-Token": "{{_local.verificationToken ?? ''}}"
},
"params": {
"post_id": "{{route?.id ?? ''}}",
"parent_id": "{{query?.parent_id ?? ''}}"
},
"onSuccess": {
"comment": "refetch 후 _local.form을 응답값으로 직접 덮어씌우기 (비밀글 content 반영)",
"handler": "setState",
"params": {
"target": "local",
"form": "{{response.data.data}}"
}
},
"errorHandling": {
"403": {
"comment": "권한 없음 - 에러 페이지 표시 (errorHandling에서 route 컨텍스트 미지원)",
"handler": "showErrorPage",
"params": {
"target": "content"
}
},
"404": {
"handler": "showErrorPage",
"params": {
"target": "content"
}
}
}
},
{
"id": "form_meta",
"label_key": "$t:editor.data_source.form_meta",
"type": "api",
"endpoint": "/api/modules/sirsoft-board/boards/{{route.slug}}/posts/form-meta",
"method": "GET",
"auto_fetch": true,
"auth_mode": "optional",
"cache": false,
"refetchOnMount": true,
"_comment_verify_token": "검증 토큰은 자격증명이라 헤더로 보낸다 — 쿼리로 실으면 웹서버 접근 기록과 Referer 에 그대로 남는다. 빈 값은 엔진이 헤더에서 제외한다.",
"headers": {
"X-Board-Post-Verify-Token": "{{_local.verificationToken ?? ''}}"
},
"params": {
"post_id": "{{route?.id ?? ''}}",
"parent_id": "{{query?.parent_id ?? ''}}"
},
"errorHandling": {
"403": {
"comment": "권한 없음 - 에러 페이지 표시 (errorHandling에서 route 컨텍스트 미지원)",
"handler": "showErrorPage",
"params": {
"target": "content"
}
},
"404": {
"handler": "showErrorPage",
"params": {
"target": "content"
}
}
}
}
],
"init_actions": [
{
"comment": "tempKey 생성",
"handler": "setState",
"params": {
"target": "local",
"tempKey": "{{('temp_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9))}}"
}
}
],
"slots": {
"content": [
{
"comment": "비회원 수정 시 비밀번호 확인 모달",
"partial": "partials/board/form/_password_verify_modal.json"
},
{
"type": "layout",
"name": "Container",
"blur_until_loaded": true,
"dataKey": "form",
"trackChanges": true,
"props": {
"className": "py-8 max-w-4xl mx-auto"
},
"children": [
{
"partial": "partials/board/form/_type_renderer.json"
}
]
}
]
}
}