크라우니클라우드(cloud:9611) 기능버그 3건 수정
개요
정본 분석문서
2026-07-25-크라우니클라우드-API정본-v1.md의 CRITICAL-1/2/3 권고를 구현.
서버 정본 =
/Users/ef/crowny-services/서비스서버.한선(+
블롭스트림.한선 가져오기) → hanseonc_high STRICT 컴파일 →
서비스서버.toau → cloud:9611(crownyc 단일 프로세스).
전부 실구현(정직차단 0건). 라이브 재기동 PID 61052→11638, 단일 리스너 유지.
버그별 수정
BUG1 — 파일목록 API (CRITICAL-1) — 실구현
- 서버: 신규
files처리() + /api/files 라우트. X-Crowny-Owner로 data/merge/<owner>/cloud_items_v1.json 읽어 items 배열만 추출해 {"items":[...]}(순수배열, 이중중첩 제거) 반환. 없으면 {"items":[]}. key=고정 리터럴(사용자입력 아님)→셸 미결합, owner=소유자유효() 검증.
- 신규 헬퍼
JSON배열추출(json,키) — 균형괄호+문자열/이스케이프 인식으로 "키":[...] 추출.
- 리터럴 프록시
/api/cloud/files→(crowny-ai server.js 1:1)→/api/files 도달.
- 소비처:
cloud-connect.js upstreamPath files:'/api/store'→'/api/files', fetchRecentFiles path /api/store?o=→/api/files?o=(crowny-ai+chansong 동일). widget-cloud.js 파싱은 이미 "첫 배열값" 분기로 {items:[...]} 처리 → 무수정.
- merge GET도 이중중첩(
items.items, WARN-3) 해소: items 배열만 추출 반환.
- 실측: merge에 F1 POST 후
/api/files→{"items":[{"id":"F1","name":"doc.txt",...}]} ✓
BUG2 — ZIP·blob공유 501 (CRITICAL-2) — 둘 다 실구현
- blob-share: share POST
kind=blob→ blob해시안전(sha256)+파일존재 검증 후 메타 {owner,kind:blob,sha256,name,exp} 저장, 토큰=SHA256(owner+ts) 앞24자 반환. share GET kind=blob→ 메타의 owner/sha256(재검증)로 기존 blob_다운로드/blob_range(블롭스트림.한선 opcode 856/859) 재사용 스트리밍. Range 206 동작. note-share와 동일 패턴, 만료 처리 동일.
- ZIP:
zip처리() + zip CLI 실구현. shell-safe: 셸 결합값은 (a)검증 owner (b)blob해시안전 통과 sha256 (c)파일명정제(안전문자만+idx접두, traversal차단) 임시파일명뿐. 원본 이름/mime은 셸 미결합(정제되어 ASCII 안전문자만, 한글은 _, 폴더구조 평탄화). blob들을 cp로 임시디렉에 복사→cd tmp && zip -q -r→파일소켓전송 스트리밍→rm -rf 정리.
- 소비처:
cloud/index.html zipFolder는 이미 {entries} POST+blob 수신 → 무수정. shareItem은 j.token으로 URL 구성하도록 변경(crowny-ai+chansong: /api/cloud/share?t=; crowny-services판은 서버가 url 필드도 반환해 무수정 유지).
- 실측: blob 업로드→share POST 200(token)→GET 본문 수신, Range bytes=0-4→206 "hello" ✓. ZIP POST 200,
unzip -t 무결성 OK(2파일) ✓.
BUG3 — merge 眞 LWW (CRITICAL-3) — 실구현
- 서버 merge POST: 저장 직전 기존파일 읽어 id기준 실제 LWW 병합. 신규+기존 items를 id별 최신 ts 승자로 union, deleted 툼스톤(삭제ts≥항목ts면 제외) 적용, deleted도 id별 최신ts union 누적저장. 결과
{"ok":true,"items":[...]} 반환.
- 신규 헬퍼:
항목수집(배열→id/ts/원문 분해, 넘겨받은 배열 직접변형=지역배열 없음→2회째호출 오염 회피), 원소인덱스, 툼스톤판정. 스칼라 길이 추적으로 꺼내 OOB 회피.
- 구형식 하위호환:
"items" 키 없는 통짜 배열([...])도 관용 파싱.
- 클라 mergeSync(): 이미
if(j&&j.items){items=j.items;...} 처리 → 무수정.
- 실측(라이브 순차): 3a 최신 ts 승(name old→new) / 3b stale 무시 / 3c 툼스톤 제거 / 3d 툼스톤 미만 재추가 유지삭제 / 3e 툼스톤 초과 부활 / 3f 레거시 바레배열 L1+L2 병합 — 전부 통과 ✓.
안전
- 백업:
*.bak-기능버그수정(.한선/.toau/블롭스트림.한선 + 소비처 6파일).
- 순차단일: 서버변경→STRICT 컴파일(exit0, 신규경고0)→temp포트 19611 스모크→cloud 단독 재기동(9611만, manage.sh 미사용)→라이브 curl→소비처.
- RCE 재확인(라이브): blob 비-hex id→400, files owner 셸주입→401, merge bad key→
{"error":"bad key"}, zip 셸주입 entry(;touch;·$(touch))→400+파일 미생성. 회귀0.
- 새
체계( 추가분(zip cp/mkdir/rm) 전부 화이트리스트 통과값만 결합.
- 하위호환: store/quota/anchor/note-share/기존 blob Range 정상. 구형 merge 통짜파일 관용파싱.
관련 파일
- 서버:
/Users/ef/crowny-services/서비스서버.한선(신규 files처리·zip처리·JSON배열추출·항목수집·원소인덱스·툼스톤판정·파일명정제·제이슨안전, merge처리 LWW 재작성, share처리 blob 분기 실구현)
- 실행:
/Users/ef/crowny-services/서비스서버.toau(재컴파일 1.49MB)
- 소비처:
crowny-ai+chansong.crowny.org 각 engine/cloud-connect.js, public/cloud/index.html(양측 byte-identical 유지, diff exit0)
잔여/주의
- 대용량 목록: VM 문자열 65535B 캡 + 읽기() 16KB 캡 → 수천 항목 초과 시 truncation 위험(기존 코드 한계 동일). 현 파일메타 목록 규모에선 안전.
- ZIP 원본 파일명 한글은
_ 치환(셸안전 우선), 폴더구조 평탄화. 필요시 후속 개선.
- crowny-services판 index.html shareItem은 서버
url 필드로 동작(무수정). 별건 P0-③ 실인증·blob 무인증 공개URL은 범위 밖.