You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CopySensitiveValueUseCase가 두 정책을 한 덩어리로 수행하고 있어, 평문 값에는 적용하지 않아야 하는 상황에서 떼어낼 방법이 없습니다.
복사 후 30초 클립보드 자동 정리
짧은 시간 반복 복사를 비정상 접근으로 알림 (AbnormalAccessMonitor, 60초 5회)
조회 화면의 평문 필드(Redirect URL / Public Key / Host / Username / Scope / Renew Command)는 Secret.metadata에서 오는 암호화되지 않은 값입니다. 여기에 위 정책을 태우면:
붙여넣기 전에 클립보드가 비어버립니다. Redirect URL을 복사해 브라우저로 옮기는 데 30초가 넘게 걸리는 것은 흔합니다.
공개 정보를 여러 번 복사한 것이 비정상 접근 카운터에 쌓여 오탐 보안 경고가 뜹니다. 진짜 경고의 신뢰를 깎습니다.
#93에서 임시로 SecretClient.copyPlainValue를 두고 ClipboardServiceImpl().write()를 직접 호출하도록 우회했습니다. 앱 전체에서 UseCase를 건너뛰는 유일한 자리이므로 이 이슈에서 반드시 걷어내야 합니다.
채택 방향 — 정책 값 타입 + 호출부 선택
왜 두 정책을 같은 방식으로 파라미터화하면 안 되는가
상태의 수명이 다릅니다.
자동 정리는 복사 한 건마다 독립된 타이머입니다. 공유 상태가 없으므로 호출마다 다른 값을 줘도 됩니다.
반복 감지는 AbnormalAccessMonitor가 timestamps를 들고 여러 복사에 걸쳐 슬라이딩 윈도를 유지합니다. 호출마다 window/threshold가 달라지면 누적된 기록이 어느 창에 속하는지 말할 수 없어집니다.
따라서 자동 정리는 값을, 반복 감지는 참여 여부만 호출부가 정합니다. 이 비대칭은 의도된 것이며 정책 타입 주석에 근거를 남깁니다.
현재 상태가 이미 비대칭입니다
정책
값 위치
바꾸려면
자동 정리
clipboardClearDelay (init 주입)
조립부에서 가능
반복 감지
private static let 2개
impl 파일을 열어야 함
"각각 수정하기 편하게"가 어려운 이유의 절반이 여기 있습니다. window/threshold를 static에서 걷어내 조립 시점으로 올려야 두 정책의 값이 같은 층위에 놓입니다.
구현 형태
RevealAuthPolicy와 같은 패턴입니다. 그때 적어둔 근거 — "값으로 분리해 둔 이유는 코드를 고치지 않고 동작을 바꾸기 위해서다" — 가 여기에도 그대로 적용됩니다.
publicstructClipboardCopyPolicy:Equatable,Sendable{
/// 복사 후 이 시간이 지나도록 클립보드가 그대로면 정리한다. `nil`이면 정리하지 않는다.
publicvarautoClearAfter:Duration?
/// 반복 복사 감지에 이 복사를 포함할지.
/// 임계·윈도 값이 아니라 참여 여부만 두는 것은 감지가 **복사 여러 건에 걸친 상태**를
/// 보기 때문이다. 호출마다 창 크기가 달라지면 누적된 기록의 의미가 사라진다.
publicvarparticipatesInRepeatDetection:Boolpublicstaticletsensitive=ClipboardCopyPolicy(
autoClearAfter:.seconds(30),
participatesInRepeatDetection:true)publicstaticletplain=ClipboardCopyPolicy(
autoClearAfter:nil,
participatesInRepeatDetection:false)}
UseCase는 정책마다 private 메서드 하나씩으로 갈라둡니다. "자동 정리를 고친다"가 메서드 하나를 여는 일이 되도록 하는 것이 목적입니다.
기본값은 반드시 .sensitive로 둡니다. 새 호출부가 정책을 빠뜨려도 안전한 쪽으로 떨어집니다. .plain을 기본값으로 두면 이 이점이 뒤집힙니다.
채택하지 않은 안
Bool 파라미터 두 개 (execute(value, autoClear: true, detectRepeat: false)) — 호출부가 읽히지 않고, 정책이 늘 때마다 시그니처가 늘어납니다.
프로토콜로 협력자 분리 (ClipboardAutoClearing / CopyRepeatDetecting) — 각 정책이 독립 파일·독립 테스트가 되어 가장 깔끔하지만 타입이 셋 늘고 조립부가 복잡해집니다. 지금 impl이 30줄 남짓이라 과합니다. 정책이 셋 이상으로 늘거나 정책 하나의 테스트가 무거워지면 그때 넘어가고, 정책 값 타입에서 이쪽으로 가는 것은 호출부를 건드리지 않고 가능합니다.
함께 따라오는 것
CopySensitiveValueUseCase라는 이름이 평문도 다루게 되면 틀려집니다. CopyToClipboardUseCase 정도로 변경합니다.
설정 화면이 생기면 ClipboardCopyPolicy를 DependencyKey로 올려 RevealAuthPolicy와 같은 모양으로 맞출 수 있습니다.
✅ 작업 목록
ClipboardCopyPolicy 값 타입 추가 (autoClearAfter / participatesInRepeatDetection)
반복 감지 window·threshold를 private static let에서 조립 시점 주입으로 이동
execute를 정책별 private 메서드로 분리 (scheduleAutoClear / notifyIfRepeated)
execute(_:policy:) 기본값을 .sensitive로 지정
CopySensitiveValueUseCase → CopyToClipboardUseCase 이름 변경
정책별 단위 테스트 추가 (정리만 / 감지만 / 둘 다 / 둘 다 없음)
SecretClient.copyPlainValue 임시 경로 제거하고 .plain 정책으로 대체
📝 기능 설명
CopySensitiveValueUseCase가 두 정책을 한 덩어리로 수행하고 있어, 평문 값에는 적용하지 않아야 하는 상황에서 떼어낼 방법이 없습니다.AbnormalAccessMonitor, 60초 5회)조회 화면의 평문 필드(Redirect URL / Public Key / Host / Username / Scope / Renew Command)는
Secret.metadata에서 오는 암호화되지 않은 값입니다. 여기에 위 정책을 태우면:#93에서 임시로
SecretClient.copyPlainValue를 두고ClipboardServiceImpl().write()를 직접 호출하도록 우회했습니다. 앱 전체에서 UseCase를 건너뛰는 유일한 자리이므로 이 이슈에서 반드시 걷어내야 합니다.채택 방향 — 정책 값 타입 + 호출부 선택
왜 두 정책을 같은 방식으로 파라미터화하면 안 되는가
상태의 수명이 다릅니다.
AbnormalAccessMonitor가timestamps를 들고 여러 복사에 걸쳐 슬라이딩 윈도를 유지합니다. 호출마다 window/threshold가 달라지면 누적된 기록이 어느 창에 속하는지 말할 수 없어집니다.따라서 자동 정리는 값을, 반복 감지는 참여 여부만 호출부가 정합니다. 이 비대칭은 의도된 것이며 정책 타입 주석에 근거를 남깁니다.
현재 상태가 이미 비대칭입니다
clipboardClearDelay(init 주입)private static let2개"각각 수정하기 편하게"가 어려운 이유의 절반이 여기 있습니다. window/threshold를 static에서 걷어내 조립 시점으로 올려야 두 정책의 값이 같은 층위에 놓입니다.
구현 형태
RevealAuthPolicy와 같은 패턴입니다. 그때 적어둔 근거 — "값으로 분리해 둔 이유는 코드를 고치지 않고 동작을 바꾸기 위해서다" — 가 여기에도 그대로 적용됩니다.UseCase는 정책마다 private 메서드 하나씩으로 갈라둡니다. "자동 정리를 고친다"가 메서드 하나를 여는 일이 되도록 하는 것이 목적입니다.
기본값은 반드시
.sensitive로 둡니다. 새 호출부가 정책을 빠뜨려도 안전한 쪽으로 떨어집니다..plain을 기본값으로 두면 이 이점이 뒤집힙니다.채택하지 않은 안
execute(value, autoClear: true, detectRepeat: false)) — 호출부가 읽히지 않고, 정책이 늘 때마다 시그니처가 늘어납니다.ClipboardAutoClearing/CopyRepeatDetecting) — 각 정책이 독립 파일·독립 테스트가 되어 가장 깔끔하지만 타입이 셋 늘고 조립부가 복잡해집니다. 지금 impl이 30줄 남짓이라 과합니다.정책이 셋 이상으로 늘거나 정책 하나의 테스트가 무거워지면 그때 넘어가고, 정책 값 타입에서 이쪽으로 가는 것은 호출부를 건드리지 않고 가능합니다.
함께 따라오는 것
CopySensitiveValueUseCase라는 이름이 평문도 다루게 되면 틀려집니다.CopyToClipboardUseCase정도로 변경합니다.ClipboardCopyPolicy를DependencyKey로 올려RevealAuthPolicy와 같은 모양으로 맞출 수 있습니다.✅ 작업 목록
ClipboardCopyPolicy값 타입 추가 (autoClearAfter/participatesInRepeatDetection)private static let에서 조립 시점 주입으로 이동execute를 정책별 private 메서드로 분리 (scheduleAutoClear/notifyIfRepeated)execute(_:policy:)기본값을.sensitive로 지정CopySensitiveValueUseCase→CopyToClipboardUseCase이름 변경SecretClient.copyPlainValue임시 경로 제거하고.plain정책으로 대체Projects/DVPresentation/Sources/Dependencies/SecretClient.swift—copyPlainValuedocProjects/Devault/Sources/Composition/Dependencies/SecretClient+Live.swift— 조립부 주석Projects/DVPresentation/Sources/Features/SecretDetail/SecretDetailFeature.swift—copyPlainEffectdoc🔗 참고 링크
Projects/DVDomain/Sources/UseCase/Impl/Clipboard/CopySensitiveValueUseCaseImpl.swiftProjects/DVDomain/Sources/Service/Interface/Clipboard/AbnormalAccessMonitor.swiftProjects/DVPresentation/Sources/Features/SecretDetail/Model/RevealAuthPolicy.swift(같은 패턴 선례)