527 lines
21 KiB
Plaintext
527 lines
21 KiB
Plaintext
@page "/vpki/manager"
|
|
@using DB.VPKI_DataDB
|
|
@using System.Text
|
|
@using SystemX.Core.Communication
|
|
@using VPKI.Library.Packet
|
|
@using VPKI.Library.Static
|
|
|
|
@inject ApiService ApiService
|
|
@inject VpkiDialogService DialogService
|
|
@inject IJSRuntime JS
|
|
@inject NotificationService NotiService
|
|
@inject TooltipService TooltipService
|
|
|
|
<h3>VPKI MANAGER</h3>
|
|
|
|
<AuthorizeView Roles="@($"{UserRole.Admin.ToString()},{UserRole.SuperUser.ToString()}")">
|
|
<Authorized Context="AuthContext">
|
|
<RadzenFieldset Style="margin-bottom: 10px;" Text="Server Info">
|
|
<div style="margin-bottom: 10px;">
|
|
<RadzenLabel Style="width: 130px;" Text="Server Address"></RadzenLabel>
|
|
<RadzenTextBox Style="margin-right: 10px;" @bind-Value="@ServerAddress"></RadzenTextBox>
|
|
</div>
|
|
</RadzenFieldset>
|
|
|
|
<RadzenFieldset Style="margin-bottom: 10px;" Text="View Options">
|
|
<div style="margin-bottom: 10px;">
|
|
<!--date-->
|
|
<RadzenLabel Style="margin-right: 5px;" Text="Date"></RadzenLabel>
|
|
<RadzenDatePicker Style="margin-right: 5px;" @bind-Value="@SearchStartDate" DateFormat="yyyy/MM/dd" />
|
|
|
|
<RadzenLabel Style="margin-right: 5px;" Text="~"></RadzenLabel>
|
|
<RadzenDatePicker Style="margin-right: 10px;" @bind-Value="@SearchEndDate" DateFormat="yyyy/MM/dd" />
|
|
|
|
<RadzenButton Style="margin-right: 30px;" Click="@(()=>Search(0))">Search</RadzenButton>
|
|
|
|
<!--vew Count-->
|
|
<RadzenLabel Style="margin-right: 5px;" Text="ViewCount (20~100)"></RadzenLabel>
|
|
<RadzenNumeric @bind-Value=@ViewCount Min=20 Max=100></RadzenNumeric>
|
|
</div>
|
|
</RadzenFieldset>
|
|
<br />
|
|
<!--count-->
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 0.7rem;">
|
|
<div style="display: flex; align-items:center;">
|
|
<RadzenLabel Style="color:#BA68C8; font-weight: 600; font-size: 1.1rem; margin-right: 1.2rem;" Text=@($"Total Count: {history.Count}")></RadzenLabel>
|
|
<RadzenLabel Style="color:#64B5F6; font-weight: 600; font-size: 1.1rem;" Text=@($"Filter Count: {grid.View.Count()}")></RadzenLabel>
|
|
</div>
|
|
<div>
|
|
<RadzenButton Style="background: #7E57C2; margin-right: 0.5rem;" Text="Export CSV(Full Data)" Click="@(()=>OnClickExportCSV(false))"></RadzenButton>
|
|
<RadzenButton Style="background: #1976D2;" Text="Export CSV(Filter Data)" Click="@(()=>OnClickExportCSV(true))"></RadzenButton>
|
|
</div>
|
|
</div>
|
|
|
|
<RadzenDataGrid @ref="@grid" Data="@history" TItem="CertificateHistoryModel" AllowFiltering FilterMode="FilterMode.Simple"
|
|
AllowPaging PageNumbersCount="10" PageSize="@ViewCount" PagerHorizontalAlign="HorizontalAlign.Center" AllowSorting RowExpand="@((args)=>OnExpand(args))"
|
|
FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" Filter="@OnChangeFilter" FilterCleared="@OnChangeFilter">
|
|
<Columns>
|
|
|
|
<!--index or no-->
|
|
@* <RadzenDataGridColumn Title="No">
|
|
<Template>
|
|
@(history.IndexOf(context)+1)
|
|
</Template>
|
|
</RadzenDataGridColumn> *@
|
|
|
|
<!--data-->
|
|
@foreach (var prop in typeof(TTbscsr).GetProperties())
|
|
{
|
|
if (prop.Name.ToLower().Contains("hashedtbscsr") || prop.Name.ToLower().Contains("publickey") || prop.Name.ToLower().Contains("origintbscsr")
|
|
|| prop.Name.ToLower().Contains("csrsignature") || prop.Name.ToLower().Contains("datetime") || prop.Name.ToLower().Contains("cdn"))
|
|
continue;
|
|
|
|
string propName = $"{prop.Name}";
|
|
<RadzenDataGridColumn Title="@propName" Property=@($"TTbscsr.{propName}") />
|
|
}
|
|
<!--date time-->
|
|
<RadzenDataGridColumn Width="9rem" Title="CDATETIME">
|
|
<Template>
|
|
@{
|
|
<div style="font-size: 0.8rem;">
|
|
<RadzenLabel Text="Tbscsr DateTime"></RadzenLabel>
|
|
<br />
|
|
<RadzenLabel Text="@context?.TTbscsr?.CDateTime.ToString("yyyy-MM-dd HH:mm:ss")"></RadzenLabel>
|
|
<br />
|
|
<RadzenLabel Text="Certificate DateTime"></RadzenLabel>
|
|
<br />
|
|
<RadzenLabel Text="@context?.TCertificate?.CDateTime.ToString("yyyy-MM-dd HH:mm:ss")"></RadzenLabel>
|
|
</div>
|
|
}
|
|
</Template>
|
|
</RadzenDataGridColumn>
|
|
|
|
<!--Reissue, Revoke-->
|
|
@* <RadzenDataGridColumn Title="Reissue">
|
|
<Template>
|
|
@{
|
|
bool canReissue = string.IsNullOrEmpty($"{context.TCertificate?.CCsr}");
|
|
|
|
<RadzenButton Style="width:100%; color:black;" Text="Reissue" Disabled=@canReissue
|
|
ButtonStyle="ButtonStyle.Warning" Click="@(()=>OnClickReissue(context))"></RadzenButton>
|
|
}
|
|
</Template>
|
|
</RadzenDataGridColumn> *@
|
|
@* <RadzenDataGridColumn Title="Revoke">
|
|
<Template>
|
|
@{
|
|
bool canRevoke = true;
|
|
canRevoke = !(context.TCertificate?.CIssueCount > 0);
|
|
}
|
|
<RadzenButton Style="width:100%; color: black;" Text="Revoke" Disabled=@canRevoke
|
|
ButtonStyle="ButtonStyle.Danger" Click="@(()=>OnClickRevoke(context))"></RadzenButton>
|
|
</Template>
|
|
</RadzenDataGridColumn> *@
|
|
</Columns>
|
|
<Template>
|
|
<!--tbscsr-->
|
|
<div style="display:flex; align-items: center; margin-bottom: 0.2rem;">
|
|
<RadzenLabel Text="Tbscsr" Style="margin-right: 0.5rem;"></RadzenLabel>
|
|
<RadzenIcon Icon="description" Style="cursor: pointer;" MouseEnter="@(args => TooltipService.Open(args, "Copy"))" @onclick="@(()=>OnClickCopy(context?.TTbscsr?.ToJson()))"></RadzenIcon>
|
|
</div>
|
|
<div>
|
|
<RadzenTextArea Style="width:100%; height:10rem;" Value="@context?.TTbscsr?.ToJson()" ReadOnly></RadzenTextArea>
|
|
</div>
|
|
<br />
|
|
|
|
<!--certificate-->
|
|
<RadzenLabel Text="TCertificate"></RadzenLabel>
|
|
<div>
|
|
<RadzenTextArea Style="width:100%; height:10rem;" Value="@context?.TCertificate?.ToJson()" ReadOnly></RadzenTextArea>
|
|
</div>
|
|
@{
|
|
bool canDownload = string.IsNullOrEmpty($"{context.TCertificate?.CCert}");
|
|
}
|
|
<RadzenButton Style="background: #7E57C2;" Text="Certificate Download" Click="@(()=>OnClickExportCertificate(context))" Disabled="@canDownload"></RadzenButton>
|
|
<RadzenButton Style="background: #1976D2;" Text="SubCA Certificate Download" Click="@(()=>OnClickExportSubCACertificate(context))" Disabled="@canDownload"></RadzenButton>
|
|
<br />
|
|
<br />
|
|
<!--verify result-->
|
|
<RadzenLabel Text="TVerifyResult"></RadzenLabel>
|
|
<div>
|
|
<RadzenTextArea Style="width:100%; height:10rem;" Value="@context?.TVerifyResult?.ToJson()" ReadOnly></RadzenTextArea>
|
|
</div>
|
|
<br />
|
|
|
|
@if (context.TTbscsr.CCertType == VpkiType.prov_v1.ToString())
|
|
{
|
|
<!--certificate info-->
|
|
<RadzenLabel Text="TOcsp"></RadzenLabel>
|
|
<div>
|
|
<RadzenTextArea Style="width:100%; height:10rem;" Value="@context.TOcsp?.ToJson()" ReadOnly></RadzenTextArea>
|
|
</div>
|
|
<br />
|
|
|
|
<!--ocsp-->
|
|
<RadzenLabel Text="OCSP"></RadzenLabel>
|
|
<div>
|
|
<RadzenTextArea Style="width:100%; height:10rem;" Value="@context.TOcsp?.COcsp" ReadOnly></RadzenTextArea>
|
|
</div>
|
|
<RadzenButton Style="background: #7E57C2;" Text="OCSP Download" Click="@(()=>OnClickOcspDownload(context))"></RadzenButton>
|
|
}
|
|
</Template>
|
|
</RadzenDataGrid>
|
|
</Authorized>
|
|
<NotAuthorized>
|
|
<RadzenLabel Text="Not Authorized"></RadzenLabel>
|
|
</NotAuthorized>
|
|
</AuthorizeView>
|
|
|
|
@code {
|
|
private string ServerAddress = "127.0.0.1:8080";
|
|
|
|
private DateOnly SearchStartDate = DateOnly.FromDateTime(DateTime.Now.AddDays(-7));
|
|
private DateOnly SearchEndDate = DateOnly.FromDateTime(DateTime.Now);
|
|
|
|
private string FilterIft = string.Empty;
|
|
private string FilterWMI = string.Empty;
|
|
private string FilterDC = string.Empty;
|
|
private string FilterCertType = string.Empty;
|
|
|
|
private int ViewCount = 20;
|
|
|
|
List<CertificateHistoryModel> history = new List<CertificateHistoryModel>();
|
|
RadzenDataGrid<CertificateHistoryModel> grid = new();
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (firstRender)
|
|
{
|
|
//await Search(0);
|
|
}
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
private async Task Search(int startCcuid)
|
|
{
|
|
DialogService.OpenIndicator("Search History");
|
|
|
|
string requestUrl = $"https://{ServerAddress}/history?";
|
|
|
|
//Default filter
|
|
requestUrl += $"startDate={SearchStartDate}&";
|
|
requestUrl += $"endDate={SearchEndDate}&";
|
|
// requestUrl += $"startCcuid={startCcuid}&";
|
|
|
|
//optional filter
|
|
// if (string.IsNullOrEmpty(FilterIft) == false)
|
|
// {
|
|
// requestUrl += $"ift={FilterIft}&";
|
|
// }
|
|
// if (string.IsNullOrEmpty(FilterWMI) == false)
|
|
// {
|
|
// requestUrl += $"wmi={FilterWMI}&";
|
|
// }
|
|
// if (string.IsNullOrEmpty(FilterDC) == false)
|
|
// {
|
|
// requestUrl += $"dc={FilterDC}&";
|
|
// }
|
|
// if (string.IsNullOrEmpty(FilterCertType) == false)
|
|
// {
|
|
// requestUrl += $"certType={FilterCertType}&";
|
|
// }
|
|
|
|
history?.Clear();
|
|
var http = new Http();
|
|
var result = await http.GetJsonAsync<List<CertificateHistoryModel>>(requestUrl);
|
|
if (result != null)
|
|
{
|
|
history.AddRange(result);
|
|
history.Reverse();
|
|
}
|
|
grid?.Reload();
|
|
|
|
DialogService.CloseIndicator();
|
|
}
|
|
|
|
private async Task OnClickReissue(CertificateHistoryModel args)
|
|
{
|
|
var confirmRsult = await DialogService.Confirm("Reissue", "Are you sure certificate reissue?");
|
|
if (confirmRsult == false)
|
|
return;
|
|
|
|
DialogService.OpenIndicator("Reissue");
|
|
|
|
Request_Certificate requestReissue = new Request_Certificate
|
|
{
|
|
iftid = args.TTbscsr.CIftid,
|
|
csrsignature = args.TCertificate.CCsrsignature,
|
|
tierCode = args.TCertificate.CTierCode,
|
|
unitCode = args.TCertificate.CUnitCode,
|
|
vehicleCode = args.TCertificate.CVehicleCode,
|
|
localCode = args.TCertificate.CLocalCode,
|
|
brandCode = args.TCertificate.CBrandCode
|
|
};
|
|
|
|
string api = string.Empty;
|
|
if (args.TTbscsr.CCertType.ToLower() == VpkiType.prov_v1.ToString())
|
|
{
|
|
api = "api/v1/reissue";
|
|
}
|
|
else if (args.TTbscsr.CCertType.ToLower() == VpkiType.prov_cert.ToString())
|
|
{
|
|
api = "api/v2/prov/reissue";
|
|
}
|
|
else if (args.TTbscsr.CCertType.ToLower() == VpkiType.vehicle_cert.ToString())
|
|
{
|
|
api = "api/v2/vehicle/reissue";
|
|
}
|
|
|
|
var http = new Http();
|
|
var result = await http.PostJsonAsync<Request_Certificate, Response_Certificate>($"https://{ServerAddress}/{api}", requestReissue);
|
|
if (result != null)
|
|
{
|
|
string requestUrl = $"https://{ServerAddress}/history/ccuid?ccuid={args.TTbscsr.CCuid}";
|
|
var updateResult = await http.GetJsonAsync<CertificateHistoryModel>(requestUrl);
|
|
if (updateResult != null)
|
|
{
|
|
args.TTbscsr = updateResult.TTbscsr;
|
|
args.TCertificate = updateResult.TCertificate;
|
|
args.TVerifyResult = updateResult.TVerifyResult;
|
|
args.TOcsp = updateResult.TOcsp;
|
|
}
|
|
NotiService.Notify(NotificationSeverity.Success, "Reissue", "Reissue Success");
|
|
}
|
|
else
|
|
{
|
|
NotiService.Notify(NotificationSeverity.Error, "Reissue", "Reissue Failed");
|
|
}
|
|
|
|
await grid?.CollapseAll();
|
|
await grid?.Reload();
|
|
|
|
StateHasChanged();
|
|
DialogService.CloseIndicator();
|
|
}
|
|
|
|
private async Task OnClickRevoke(CertificateHistoryModel args)
|
|
{
|
|
var confirmRsult = await DialogService.Confirm("Revoke", "Are you sure certificate revoke?");
|
|
if (confirmRsult == false)
|
|
return;
|
|
|
|
DialogService.OpenIndicator("Revoke");
|
|
Request_CertificateRevokeOEM requestRevoke = new Request_CertificateRevokeOEM
|
|
{
|
|
dn = args.TTbscsr.CDn
|
|
};
|
|
|
|
string api = string.Empty;
|
|
if (args.TTbscsr.CCertType.ToLower() == VpkiType.prov_v1.ToString())
|
|
{
|
|
api = "api/v1/revoke";
|
|
}
|
|
else if (args.TTbscsr.CCertType.ToLower() == VpkiType.prov_cert.ToString())
|
|
{
|
|
api = "api/v2/prov/revoke";
|
|
}
|
|
else if (args.TTbscsr.CCertType.ToLower() == VpkiType.vehicle_cert.ToString())
|
|
{
|
|
api = "api/v2/vehicle/revoke";
|
|
}
|
|
|
|
var http = new Http();
|
|
var result = await http.PostJsonAsync<Request_CertificateRevokeOEM, Response_CertificateRevokeOEM>($"https://{ServerAddress}/{api}", requestRevoke);
|
|
if (result != null)
|
|
{
|
|
string requestUrl = $"https://{ServerAddress}/history/ccuid?ccuid={args.TTbscsr.CCuid}";
|
|
var updateResult = await http.GetJsonAsync<CertificateHistoryModel>(requestUrl);
|
|
if (updateResult != null)
|
|
{
|
|
args.TTbscsr = updateResult.TTbscsr;
|
|
args.TCertificate = updateResult.TCertificate;
|
|
args.TVerifyResult = updateResult.TVerifyResult;
|
|
args.TOcsp = updateResult.TOcsp;
|
|
}
|
|
NotiService.Notify(NotificationSeverity.Success, "Revoke", "Revoke Success");
|
|
}
|
|
else
|
|
{
|
|
NotiService.Notify(NotificationSeverity.Error, "Revoke", "Revoke Failed");
|
|
}
|
|
|
|
await grid?.CollapseAll();
|
|
await grid?.Reload();
|
|
StateHasChanged();
|
|
DialogService.CloseIndicator();
|
|
}
|
|
|
|
async Task OnClickExportCSV(bool isFilter = false)
|
|
{
|
|
DialogService.OpenIndicator("Export to CSV");
|
|
List<string> exportData = new List<string>();
|
|
|
|
if (isFilter == true)
|
|
{
|
|
//필터링된 데이터만
|
|
exportData.AddRange(grid.View.ToList().ConvertToCsvFile());
|
|
}
|
|
else
|
|
{
|
|
//전체 데이터
|
|
exportData.AddRange(history.ConvertToCsvFile());
|
|
}
|
|
|
|
if (exportData?.Count > 0)
|
|
{
|
|
string fileName = $"VPKI_{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.csv";
|
|
bool exportResult = await JS.InvokeAsync<bool>("openSaveFileCSV", fileName, exportData.ToJson());
|
|
if (exportResult == true)
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Success,
|
|
Summary = "Success",
|
|
Detail = "CSV Export Success"
|
|
});
|
|
}
|
|
else
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Error,
|
|
Summary = "Failed",
|
|
Detail = "CSV Export Failed",
|
|
});
|
|
}
|
|
}
|
|
|
|
DialogService.CloseIndicator();
|
|
}
|
|
|
|
void OnChangeFilter()
|
|
{
|
|
StateHasChanged();
|
|
}
|
|
|
|
async Task OnClickExportCertificate(CertificateHistoryModel? certificate)
|
|
{
|
|
DialogService.OpenIndicator("Export to Prov Certificate");
|
|
|
|
if (certificate != null)
|
|
{
|
|
string fileName = $"{certificate?.TTbscsr?.CPcid}.pem";
|
|
bool exportResult = await JS.InvokeAsync<bool>("openSaveFileStr", fileName, certificate?.TCertificate?.CCert);
|
|
if (exportResult == true)
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Success,
|
|
Summary = "Success",
|
|
Detail = "Certificate Export Success"
|
|
});
|
|
}
|
|
else
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Error,
|
|
Summary = "Failed",
|
|
Detail = "Certificate Export Failed",
|
|
});
|
|
}
|
|
}
|
|
|
|
DialogService.CloseIndicator();
|
|
}
|
|
|
|
async Task OnClickExportSubCACertificate(CertificateHistoryModel? certificate)
|
|
{
|
|
DialogService.OpenIndicator("Export to Prov Certificate");
|
|
|
|
if (certificate != null)
|
|
{
|
|
var http = new Http();
|
|
|
|
string requestUrl = $"https://{ServerAddress}/certificate/GetProv?vpkiType={certificate.TTbscsr.CCertType}";
|
|
var response = await http.GetJsonAsync<string>(requestUrl);
|
|
|
|
string fileName = $"SubCA.pem";
|
|
bool exportResult = await JS.InvokeAsync<bool>("openSaveFileStr", fileName, response);
|
|
if (exportResult == true)
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Success,
|
|
Summary = "Success",
|
|
Detail = "SubCA Certificate Export Success"
|
|
});
|
|
}
|
|
else
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Error,
|
|
Summary = "Failed",
|
|
Detail = "SubCA Certificate Export Failed",
|
|
});
|
|
}
|
|
}
|
|
|
|
DialogService.CloseIndicator();
|
|
}
|
|
|
|
async Task OnClickOcspDownload(CertificateHistoryModel? certificate)
|
|
{
|
|
DialogService.OpenIndicator("Export to Prov Certificate");
|
|
|
|
if (certificate != null)
|
|
{
|
|
string fileName = $"OCSP_{certificate.TTbscsr.CPcid}.txt";
|
|
bool exportResult = await JS.InvokeAsync<bool>("openSaveFileStr", fileName, certificate.TOcsp.COcsp);
|
|
if (exportResult == true)
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Success,
|
|
Summary = "Success",
|
|
Detail = "OCSP Export Success"
|
|
});
|
|
}
|
|
else
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Error,
|
|
Summary = "Failed",
|
|
Detail = "OCSP Certificate Export Failed",
|
|
});
|
|
}
|
|
}
|
|
|
|
DialogService.CloseIndicator();
|
|
}
|
|
|
|
private async Task OnExpand(CertificateHistoryModel history)
|
|
{
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
private async Task OnClickCopy(string? text)
|
|
{
|
|
await CopyToClipboard(text);
|
|
}
|
|
|
|
private async Task CopyToClipboard(string? text)
|
|
{
|
|
bool result = await JS.InvokeAsync<bool>("copyTextToClipboard", text);
|
|
if (result == true)
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Success,
|
|
Summary = "Success",
|
|
Detail = "Copy To Clipboard Success."
|
|
});
|
|
}
|
|
else
|
|
{
|
|
NotiService.Notify(new NotificationMessage
|
|
{
|
|
Severity = NotificationSeverity.Error,
|
|
Summary = "Failed",
|
|
Detail = "Copy To Clipboard Failed.",
|
|
});
|
|
}
|
|
}
|
|
}
|