Repository navigation
Conversation
브라우저 App Link 와 FCM data.link 가 같은 파서를 지나도록 입력을 String 으로 받는다. 목적지는 Nav2 Route 도 Navigation 3 NavKey 도 아닌 sealed NavigationTarget 이다 — 링크는 서버·브라우저·알림이 공유하는 외부 계약이라 앱 안의 navigation 엔진 교체(#1698·#1702)와 수명이 다르다. 계약 밖 입력은 전부 거절이다. 링크는 앱 밖에서 오는 입력이라 관대하게 받는 만큼이 공격면이다 — 커스텀 scheme 은 Digital Asset Links 검증을 못 받아 아무 앱이나 선점할 수 있고, https://evil@afternote.kro.kr/ 같은 userinfo 는 눈으로 우리 도메인처럼 보인다. 거절은 null 이 아니라 사유와 안전한 기본 진입을 함께 든 값이라, 호출부마다 폴백이 갈리거나 「왜 홈으로 왔는지」가 사라지지 않는다. ID 자릿수 판정에 정규식 \d 를 쓰지 않는다. Android 의 \d 는 아라비아-인도 숫자까지 물어 서버 JVM 과 다르게 판정하므로 '0'..'9' 로 직접 좁혔고, 그 경계를 테스트로 잠갔다. 파서 진입점은 아직 프로덕션 소비처가 없어 konsist 의 의도된 계약 목록에 넣는다. intent 수신 배선은 #924 가 붙인다.
🚧 리뷰 적체 가드 — 이 PR 을 닫습니다팀 리뷰 응답 대기 · 2건
이 저장소는 팀 리뷰 응답 또는 자기 PR 의 변경요청 대응을 기다리는 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136, #1679). 각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤 변경을 다시 볼 의무는 없고, 변경요청도 작성자가 같은 리뷰어에게 재요청한 뒤 실질 커밋·응답·본문 편집을 남긴 경우에만 다시 리뷰어의 몫이 됩니다. 되살리는 법위 PR 에 필요한 리뷰나 작성자 조치를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다. gh pr reopen 1859 |
🚧 리뷰 적체 가드 — 이 PR 을 닫습니다작성자 응답 대기 · 2건
이 저장소는 팀 리뷰 응답 또는 자기 PR 의 변경요청 대응을 기다리는 PR 이 1건이라도 남아 있으면 새 PR 을 열 수 없습니다 (#1136, #1679). 각 PR 에 필요한 리뷰는 한 건입니다 — 누구든 먼저 판정을 내면 그 PR 은 모두의 목록에서 빠집니다. 승인 뒤 변경을 다시 볼 의무는 없고, 변경요청도 작성자가 같은 리뷰어에게 재요청한 뒤 실질 커밋·응답·본문 편집을 남긴 경우에만 다시 리뷰어의 몫이 됩니다. 되살리는 법위 PR 에 필요한 리뷰나 작성자 조치를 끝낸 뒤 이 PR 을 다시 여세요. 브랜치는 지워지지 않았고 커밋도 그대로입니다. gh pr reopen 1859 |
Sadturtleman
left a comment
There was a problem hiding this comment.
경계가 실제로 fail-closed 인 것을 확인했습니다. java.net.URI 가 생성 시 정규화하지 않는다는 점에 기대어 rawPath 로 읽은 덕에 ..·%2F·빈 세그먼트·끝 슬래시·대문자가 전부 SEGMENT_FORMAT 에서 걸리고, 떨어지는 곳이 조용한 기본값이 아니라 사유가 붙은 Rejected(reason, Home) 라 나중에 왜 막혔는지 읽을 수 있습니다. fallback 도 LOGIN 관문을 지납니다. NavigationTargetContractTest 가 목적지 전량을 parse(canonicalUrl(t)) 로 왕복시키고 관문 불변식을 when exhaustive 로 잠근 것이 특히 좋습니다 — 목적지가 늘 때 자동으로 걸립니다. 승인합니다.
한 줄만 적어 둡니다.
[nit] 숫자 좁힘을 잠근다는 테스트가 실제로는 그 좁힘을 지나지 않는다
toResourceIdOrNull 의 「\d 대신 '0'..'9' 로 좁힌다」 주석과 「아라비아-인도 숫자는 ID 가 아니다」 테스트 이야기입니다. ١٢ 는 SEGMENT_FORMAT 에서 먼저 걸려(기대값도 UNKNOWN_PATH 라 통과합니다) 그 함수에 닿지 않습니다. 그 줄을 \d 로 되돌려도 테스트는 초록입니다. 본문의 변이 검사가 SEGMENT_FORMAT 을 푼 것이라 같은 사실을 가리킵니다. 방어적 중복 자체는 그대로 두는 게 맞고, 그 테스트가 무엇을 잠그는지만 한 줄 고쳐 두면 다음 사람이 오해하지 않습니다.
|
형제 충돌이 해소됐다 — 지금은 이 PR 과 같은 파일을 서로 다르게 고친 열린 PR 이 없다 (#1750). |
merge queue 방출 — merge group CI 실패사유 실패한 job:
고친 뒤 |
|
이 PR 은
|
|
닫는다. 코드는 feat 브랜치에 남아 있고 #924 착수 때 첫 커밋으로 가져온다. 파서 단독으로는 머지하지 않기로 했으니 열어 둘 이유가 없다. |
변경
공통 URI 입력 검증과 비수신자 목적지 6개를 엔진 중립
NavigationTarget으로 해석한다. 지원하는 경로는 홈, 작성자 애프터노트 홈·상세, 타임레터 상세, 데일리질문 작성, 알림 설정이다. 정규 URL·ID·로그인/생체인증 관문과 거절 사유를 함께 정의한다.수신자 경로는 서버 식별자·접근 정책이 미정이므로 #1951로 분리했다. 해당 목적지 3개, 로컬 SenderRegistry UUID 형식, 수신자 인증 관문, 그 성공 계약 테스트를 이 PR의 코드에서 제거했다. 현재
/received계열은 지원하지 않는 경로로 거절한다. #1951이 확정되면 그 결과 위에서 추가한다.이 PR은 #1951을 기다리지 않고 완료할 수 있다. 실제 Intent 수신과 인증 후 목적지 재개는 #924에서 구현한다.
검증
8ef216417통합.:core:common:testDebugUnitTest: 65개 통과. 미확정 수신자 경로 3종 거절 회귀 포함.:core:common:ktlintCheck,:konsist:test(54개) 통과.연결 이슈
Closes #1857
Refs #924, #1951
CI Test Plan
{"androidTest":{"mode":"none","reason":"core common의 엔진 중립 URI 파서·목적지 계약과 JVM 테스트·konsist 계약 목록만 변경한다. Android Intent 수신과 런타임 라우팅은 #924 범위다.","tests":[]}}