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 @@
-
-
+
+
-
+
diff --git a/src/TableCloth/MainWindow.xaml.cs b/src/TableCloth/MainWindow.xaml.cs
index d39168a9..a5b0eb2e 100644
--- a/src/TableCloth/MainWindow.xaml.cs
+++ b/src/TableCloth/MainWindow.xaml.cs
@@ -81,15 +81,16 @@ private void RunSandbox(TableClothConfiguration config)
{
if (config.CertPair != null)
{
- var today = DateTime.Now;
+ var now = DateTime.Now;
+ var expireWindow = StringResources.Cert_ExpireWindow;
- if (today < config.CertPair.NotBefore)
- ViewModel.AppMessageBox.DisplayError(StringResources.Error_Cert_MayTooEarly(config.CertPair.NotBefore), false);
+ if (now < config.CertPair.NotBefore)
+ ViewModel.AppMessageBox.DisplayError(StringResources.Error_Cert_MayTooEarly(now, config.CertPair.NotBefore), false);
- if (today > config.CertPair.NotAfter)
- ViewModel.AppMessageBox.DisplayError(StringResources.Error_Cert_MayExpired(config.CertPair.NotAfter), false);
- else if (today > config.CertPair.NotAfter.AddDays(-3d))
- ViewModel.AppMessageBox.DisplayInfo(StringResources.Error_Cert_ExpireSoon(config.CertPair.NotAfter));
+ if (now > config.CertPair.NotAfter)
+ ViewModel.AppMessageBox.DisplayError(StringResources.Error_Cert_Expired, false);
+ else if (now > config.CertPair.NotAfter.Add(expireWindow))
+ ViewModel.AppMessageBox.DisplayInfo(StringResources.Error_Cert_ExpireSoon(now, config.CertPair.NotAfter, expireWindow));
}
var tempPath = ViewModel.SharedLocations.GetTempPath();
diff --git a/src/TableCloth/Pages/DetailPage.xaml.cs b/src/TableCloth/Pages/DetailPage.xaml.cs
index 2fc20332..4d49b25f 100644
--- a/src/TableCloth/Pages/DetailPage.xaml.cs
+++ b/src/TableCloth/Pages/DetailPage.xaml.cs
@@ -70,15 +70,16 @@ private void RunSandbox(TableClothConfiguration config)
{
if (config.CertPair != null)
{
- var today = DateTime.Now;
+ var now = DateTime.Now;
+ var expireWindow = StringResources.Cert_ExpireWindow;
- if (today < config.CertPair.NotBefore)
- ViewModel.AppMessageBox.DisplayError(StringResources.Error_Cert_MayTooEarly(config.CertPair.NotBefore), false);
+ if (now < config.CertPair.NotBefore)
+ ViewModel.AppMessageBox.DisplayError(StringResources.Error_Cert_MayTooEarly(now, config.CertPair.NotBefore), false);
- if (today > config.CertPair.NotAfter)
- ViewModel.AppMessageBox.DisplayError(StringResources.Error_Cert_MayExpired(config.CertPair.NotAfter), false);
- else if (today > config.CertPair.NotAfter.AddDays(-3d))
- ViewModel.AppMessageBox.DisplayInfo(StringResources.Error_Cert_ExpireSoon(config.CertPair.NotAfter));
+ if (now > config.CertPair.NotAfter)
+ ViewModel.AppMessageBox.DisplayError(StringResources.Error_Cert_Expired, false);
+ else if (now > config.CertPair.NotAfter.Add(expireWindow))
+ ViewModel.AppMessageBox.DisplayInfo(StringResources.Error_Cert_ExpireSoon(now, config.CertPair.NotAfter, expireWindow));
}
var tempPath = ViewModel.SharedLocations.GetTempPath();
diff --git a/src/TableCloth/UIStringResources.xaml b/src/TableCloth/UIStringResources.xaml
index 465cdb46..f18bdd52 100644
--- a/src/TableCloth/UIStringResources.xaml
+++ b/src/TableCloth/UIStringResources.xaml
@@ -211,6 +211,10 @@
소유자
+
+ 사용 가능 여부
+
+
기관