diff --git a/src/TableCloth.Shared/Models/Configuration/X509CertPair.cs b/src/TableCloth.Shared/Models/Configuration/X509CertPair.cs index 4c337076..642c2c42 100644 --- a/src/TableCloth.Shared/Models/Configuration/X509CertPair.cs +++ b/src/TableCloth.Shared/Models/Configuration/X509CertPair.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Cryptography.X509Certificates; +using TableCloth.Resources; namespace TableCloth.Models.Configuration { @@ -84,6 +85,34 @@ public X509CertPair(byte[] publicKey, byte[] privateKey) public DateTime NotAfter { get; } public DateTime NotBefore { get; } + public bool IsValid + => NotBefore <= DateTime.Now && DateTime.Now <= NotAfter; + + public bool HasExpired + => DateTime.Now > NotAfter; + + public bool SoonExpire + => DateTime.Now > NotAfter.Add(StringResources.Cert_ExpireWindow); + + public string Availability + { + get + { + var now = DateTime.Now; + var expireWindow = StringResources.Cert_ExpireWindow; + + if (now < NotBefore) + return StringResources.Cert_Availability_MayTooEarly(now, NotBefore); + + if (now > NotAfter) + return StringResources.Cert_Availability_Expired; + else if (now > NotAfter.Add(expireWindow)) + return StringResources.Cert_Availability_ExpireSoon(now, NotAfter, expireWindow); + + return StringResources.Cert_Availability_Available; + } + } + public string SubjectNameForNpkiApp => string.Join(",", Subject.Select(x => $"{x.Key.ToLowerInvariant()}={x.Value}")); diff --git a/src/TableCloth.Shared/Resources/StringResources.cs b/src/TableCloth.Shared/Resources/StringResources.cs index c24efc1f..db0f61f6 100644 --- a/src/TableCloth.Shared/Resources/StringResources.cs +++ b/src/TableCloth.Shared/Resources/StringResources.cs @@ -110,6 +110,31 @@ internal static string Get_AppVersion() } } + // 공동 인증서 관련 문자열들 + partial class StringResources + { + internal static readonly TimeSpan Cert_ExpireWindow = TimeSpan.FromDays(-3d); + + internal static string Cert_Availability_MayTooEarly(DateTime now, DateTime notBefore) + => $"{(int)Math.Truncate((notBefore - now).TotalDays)}일 후 사용 가능"; + + internal static string Cert_Availability_ExpireSoon(DateTime now, DateTime notAfter, TimeSpan expireWindow) + => $"{(int)Math.Truncate((now - (notAfter - expireWindow)).TotalDays)}일 후 만료"; + + internal static readonly string Cert_Availability_Expired = "만료됨"; + + internal static readonly string Cert_Availability_Available = "사용 가능"; + + internal static string Error_Cert_MayTooEarly(DateTime now, DateTime notBefore) + => $"선택하신 공동 인증서는 {(int)Math.Truncate((notBefore - now).TotalDays)}일 후부터 사용 가능합니다."; + + internal static string Error_Cert_ExpireSoon(DateTime now, DateTime notAfter, TimeSpan expireWindow) + => $"{(int)Math.Truncate((now - (notAfter - expireWindow)).TotalDays)}일 후에 만료됩니다. 새로운 공동 인증서로 교체가 필요합니다."; + + internal static readonly string Error_Cert_Expired + = $"선택하신 공동 인증서는 만료되었습니다. 다른 공동 인증서를 선택하거나, 새로운 공동 인증서로 교체 발급해야 합니다."; + } + // 비 사용자 인터페이스 문자열들 partial class StringResources { @@ -301,15 +326,6 @@ internal static string Error_Cannot_Prepare_AppContents(Exception ex) internal static readonly string Info_ShortcutSuccess = "바탕 화면에 바로 가기를 생성했습니다."; - - internal static string Error_Cert_MayTooEarly(DateTime notBefore) - => $"선택하신 공동 인증서는 {notBefore:yyyy년 M월 d일 tt h시 m분} 이후부터 사용 가능한 공동 인증서입니다. 인증서 사용이 불가능할 수 있습니다."; - - internal static string Error_Cert_MayExpired(DateTime notAfter) - => $"선택하신 공동 인증서는 {notAfter:yyyy년 M월 d일 tt h시 m분} 이후부터는 사용이 불가능한 공동 인증서입니다. 인증서 사용이 불가능할 수 있습니다."; - - internal static string Error_Cert_ExpireSoon(DateTime notAfter) - => $"선택하신 공동 인증서는 {notAfter:yyyy년 M월 d일 tt h시 m분} 이후부터는 사용이 불가능한 공동 인증서입니다. 공동 인증서 갱신을 준비하는 것이 좋습니다."; } // 스크립트 내에서 사용되는 문자열들 diff --git a/src/TableCloth/CertSelectWindow.xaml b/src/TableCloth/CertSelectWindow.xaml index 4504e115..af6ccbf5 100644 --- a/src/TableCloth/CertSelectWindow.xaml +++ b/src/TableCloth/CertSelectWindow.xaml @@ -6,7 +6,7 @@ mc:Ignorable="d" Style="{DynamicResource MainWindowStyle}" Title="{StaticResource CertSelectWindow_Title}" Width="480" Height="320" - MinWidth="480" MinHeight="320" + MinWidth="640" MinHeight="480" DataContext="{Binding CertSelectWindowViewModel, Source={StaticResource ViewModelLocator}}" TextOptions.TextFormattingMode="Display" TextOptions.TextRenderingMode="ClearType"> @@ -26,9 +26,23 @@ + + + + @@ -40,11 +54,11 @@ -