Guard 에 간단한 이메일 형식인지 확인하는 isValidEmail(String s) 를 추가하세요. @ 가 정확히 1개이고, 앞뒤에 최소 1글자씩 있어야 통과합니다.
public static boolean isValidEmail(String s) {
if (s == null) return false;
int at = s.indexOf('@');
if (at <= 0 || at != s.lastIndexOf('@')) return false;
return at < s.length() - 1;
}정규식도 가능하지만, 사내 데모에서는 이 정도 단순 검사로도 형식 오류 대부분을 걸러냅니다.
handleDownload 가 .txt, .pdf 이외의 확장자는 403 으로 막도록 바꿔 보세요. Guard 에 isAllowedDownloadExt(String name) 을 추가해 재사용합니다.
private static final Set<String> DOWNLOAD_EXT = Set.of("txt", "pdf");
public static boolean isAllowedDownloadExt(String name) {
int dot = name.lastIndexOf('.');
if (dot < 0) return false;
return DOWNLOAD_EXT.contains(name.substring(dot + 1).toLowerCase());
}경로 탐색 검증(safePath)과 확장자 검증은 서로 다른 문제이므로 두 검사를 모두 통과해야 합니다.
4.3 의 failCount 예제에 잠금 상태일 때 남은 시간(초)을 함께 안내하도록 바꿔 보세요. 힌트: Cache 에 expireAt(key) 를 추가한 18 레슨 문제 1 을 재사용합니다.
long expireAt = failCount.expireAt(loginId);
long remainSec = Math.max(0, (expireAt - System.currentTimeMillis()) / 1000);
throw new LockedException(remainSec + "초 후 다시 시도하세요");캐시 만료 시각을 그대로 안내에 쓰면 별도 타이머 없이도 잠금 해제 시간을 알려줄 수 있습니다.