인증서 생성기 화면 및 관련 작업
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,10 +13,10 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("OpcPks.Collector")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("OpcPks.Collector")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+171aaf6115cde8e9e930d14886fafa5fe4c1e4c0")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+4e006a5a5f65f597fafaa3777b8a1073944eada2")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("OpcPks.Collector")]
|
[assembly: System.Reflection.AssemblyProductAttribute("OpcPks.Collector")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("OpcPks.Collector")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("OpcPks.Collector")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|
||||||
// Generated by the MSBuild WriteCodeFragment class.
|
// MSBuild WriteCodeFragment 클래스에서 생성되었습니다.
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
209bb3a0d499ad79d64f5d7a0d7d5751da0a096972f0887479fd6077018132d3
|
cc5c3e28019345878790a222ce17c89ce44d1c1d74447a18859ea42c9a3adb70
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
21
OpcPksPlatform/OpcPks.Core/Models/CertRequestModel.cs
Normal file
21
OpcPksPlatform/OpcPks.Core/Models/CertRequestModel.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace OpcPks.Core.Models
|
||||||
|
{
|
||||||
|
public class CertRequestModel
|
||||||
|
{
|
||||||
|
public string ApplicationName { get; set; } = "OpcPksClient";
|
||||||
|
public bool IsRedundant { get; set; } = false;
|
||||||
|
|
||||||
|
// 서버 호스트네임 (예: HONPKS)
|
||||||
|
public string PrimaryHostName { get; set; } = "";
|
||||||
|
public string SecondaryHostName { get; set; } = ""; // Redundant일 때 필수
|
||||||
|
|
||||||
|
// FTE 네트워크 구조 반영 (네트워크 대역 분리)
|
||||||
|
public string PrimaryIpA { get; set; } = ""; // 192.168.0.x 대역
|
||||||
|
public string PrimaryIpB { get; set; } = ""; // 192.168.1.x 대역 (FTE 이중화 시)
|
||||||
|
|
||||||
|
public string SecondaryIpA { get; set; } = ""; // 192.168.0.y 대역
|
||||||
|
public string SecondaryIpB { get; set; } = ""; // 192.168.1.y 대역
|
||||||
|
|
||||||
|
public int ValidityYears { get; set; } = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
121
OpcPksPlatform/OpcPks.Core/Services/CertificateGenerator.cs
Normal file
121
OpcPksPlatform/OpcPks.Core/Services/CertificateGenerator.cs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
using Opc.Ua;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using OpcPks.Core.Models;
|
||||||
|
|
||||||
|
namespace OpcPks.Core.Services
|
||||||
|
{
|
||||||
|
public class CertificateGenerator
|
||||||
|
{
|
||||||
|
private readonly string _pfxPath;
|
||||||
|
private readonly string _ownCertPath;
|
||||||
|
|
||||||
|
public CertificateGenerator(string baseDataPath)
|
||||||
|
{
|
||||||
|
// 경로 설정 (현재 tree 구조 반영)
|
||||||
|
_pfxPath = Path.Combine(baseDataPath, "pki/own/private/OpcTestClient.pfx");
|
||||||
|
_ownCertPath = Path.Combine(baseDataPath, "pki/own/certs/OpcTestClient.der");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CreateHoneywellCertificateAsync(CertRequestModel model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1. [중요] 기존 인증서 백업
|
||||||
|
BackupExistingCertificate();
|
||||||
|
|
||||||
|
Console.WriteLine("🔐 하니웰 맞춤형 인증서 생성을 시작합니다...");
|
||||||
|
|
||||||
|
// SAN 리스트 구축 (localhost 기본 포함)
|
||||||
|
var subjectAlternativeNames = new List<string> { "localhost", "127.0.0.1" };
|
||||||
|
|
||||||
|
// Primary 정보 (FTE Yellow/Green)
|
||||||
|
if (!string.IsNullOrEmpty(model.PrimaryHostName))
|
||||||
|
{
|
||||||
|
subjectAlternativeNames.Add(model.PrimaryHostName);
|
||||||
|
subjectAlternativeNames.Add($"{model.PrimaryHostName}A");
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(model.PrimaryIpA)) subjectAlternativeNames.Add(model.PrimaryIpA);
|
||||||
|
if (!string.IsNullOrEmpty(model.PrimaryIpB)) subjectAlternativeNames.Add(model.PrimaryIpB);
|
||||||
|
|
||||||
|
// Secondary 정보 (Redundant 선택 시)
|
||||||
|
if (model.IsRedundant)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(model.SecondaryHostName))
|
||||||
|
{
|
||||||
|
subjectAlternativeNames.Add(model.SecondaryHostName);
|
||||||
|
subjectAlternativeNames.Add($"{model.SecondaryHostName}B");
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(model.SecondaryIpA)) subjectAlternativeNames.Add(model.SecondaryIpA);
|
||||||
|
if (!string.IsNullOrEmpty(model.SecondaryIpB)) subjectAlternativeNames.Add(model.SecondaryIpB);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 인증서 생성 (KeySize 2048, 하니웰 규격)
|
||||||
|
// var certificate = CertificateFactory.CreateCertificate(
|
||||||
|
// model.ApplicationName,
|
||||||
|
// model.ApplicationName,
|
||||||
|
// null,
|
||||||
|
// subjectAlternativeNames,
|
||||||
|
// null,
|
||||||
|
// 2048,
|
||||||
|
// DateTime.UtcNow.AddDays(-1),
|
||||||
|
// model.ValidityYears * 12,
|
||||||
|
// null
|
||||||
|
// );
|
||||||
|
|
||||||
|
// 2. 인증서 생성 (로그에 표시된 15개 인자 서명 순서 엄격 준수)
|
||||||
|
ushort keySize = 2048;
|
||||||
|
ushort lifetimeInMonths = (ushort)(model.ValidityYears * 12);
|
||||||
|
|
||||||
|
var certificate = CertificateFactory.CreateCertificate(
|
||||||
|
"Directory", // 1. storeType (string)
|
||||||
|
Path.GetDirectoryName(_pfxPath), // 2. storePath (string)
|
||||||
|
null, // 3. password (string)
|
||||||
|
$"urn:localhost:{model.ApplicationName}", // 4. applicationUri (string)
|
||||||
|
model.ApplicationName, // 5. applicationName (string)
|
||||||
|
model.ApplicationName, // 6. subjectName (string)
|
||||||
|
subjectAlternativeNames, // 7. domainNames (IList<string>)
|
||||||
|
keySize, // 8. keySize (ushort)
|
||||||
|
DateTime.UtcNow.AddDays(-1), // 9. startTime (DateTime)
|
||||||
|
lifetimeInMonths, // 10. lifetimeInMonths (ushort)
|
||||||
|
(ushort)256, // 11. hashSizeInBits (ushort)
|
||||||
|
false, // 12. isCA (bool)
|
||||||
|
null, // 13. issuer (X509Certificate2)
|
||||||
|
null, // 14. privateKey (byte[])
|
||||||
|
0 // 15. hashAlgorithm (int)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// 3. 파일 저장
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(_pfxPath)!);
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(_ownCertPath)!);
|
||||||
|
|
||||||
|
// PFX (개인키 포함) 저장
|
||||||
|
byte[] pfxBytes = certificate.Export(X509ContentType.Pfx, "");
|
||||||
|
await File.WriteAllBytesAsync(_pfxPath, pfxBytes);
|
||||||
|
|
||||||
|
// DER (공개키만) 저장 - 하니웰 서버에 수동으로 신뢰 등록할 때 필요할 수 있음
|
||||||
|
byte[] derBytes = certificate.Export(X509ContentType.Cert);
|
||||||
|
await File.WriteAllBytesAsync(_ownCertPath, derBytes);
|
||||||
|
|
||||||
|
Console.WriteLine($"✅ 새 인증서 생성 완료 및 백업 성공.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"❌ 인증서 생성 실패: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BackupExistingCertificate()
|
||||||
|
{
|
||||||
|
if (File.Exists(_pfxPath))
|
||||||
|
{
|
||||||
|
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||||
|
string backupPath = _pfxPath + "." + timestamp + ".bak";
|
||||||
|
File.Copy(_pfxPath, backupPath, true);
|
||||||
|
Console.WriteLine($"📦 기존 인증서 백업됨: {Path.GetFileName(backupPath)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -13,10 +13,10 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("OpcPks.Core")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("OpcPks.Core")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+171aaf6115cde8e9e930d14886fafa5fe4c1e4c0")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+4e006a5a5f65f597fafaa3777b8a1073944eada2")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("OpcPks.Core")]
|
[assembly: System.Reflection.AssemblyProductAttribute("OpcPks.Core")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("OpcPks.Core")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("OpcPks.Core")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|
||||||
// Generated by the MSBuild WriteCodeFragment class.
|
// MSBuild WriteCodeFragment 클래스에서 생성되었습니다.
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
fb717191c02dff3f083190ed14d847598609d6461f7931778b4e474636da4508
|
c75e210b6893d92e0b1636a6b8f564c5a308ff97701a72ccf681ea4473190030
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
2304a9d0dd6384b5068ce141d8c63b025727e909890abc7b08e5f2fff4bf5261
|
cea4cbfb0b4d3fd205bf727dfb75d0c31872eee74f74e79b0a11980153badb1b
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,11 +10,11 @@
|
|||||||
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
||||||
"projectName": "OpcPks.Core",
|
"projectName": "OpcPks.Core",
|
||||||
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
||||||
"packagesPath": "/home/pacer/.nuget/packages/",
|
"packagesPath": "/root/.nuget/packages/",
|
||||||
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/obj/",
|
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/obj/",
|
||||||
"projectStyle": "PackageReference",
|
"projectStyle": "PackageReference",
|
||||||
"configFilePaths": [
|
"configFilePaths": [
|
||||||
"/home/pacer/.nuget/NuGet/NuGet.Config"
|
"/root/.nuget/NuGet/NuGet.Config"
|
||||||
],
|
],
|
||||||
"originalTargetFrameworks": [
|
"originalTargetFrameworks": [
|
||||||
"net8.0"
|
"net8.0"
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/home/pacer/.nuget/packages/</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/root/.nuget/packages/</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/home/pacer/.nuget/packages/</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/root/.nuget/packages/</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.8.1</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.8.1</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="/home/pacer/.nuget/packages/" />
|
<SourceRoot Include="/root/.nuget/packages/" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -555,7 +555,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"packageFolders": {
|
"packageFolders": {
|
||||||
"/home/pacer/.nuget/packages/": {}
|
"/root/.nuget/packages/": {}
|
||||||
},
|
},
|
||||||
"project": {
|
"project": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -563,11 +563,11 @@
|
|||||||
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
||||||
"projectName": "OpcPks.Core",
|
"projectName": "OpcPks.Core",
|
||||||
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
||||||
"packagesPath": "/home/pacer/.nuget/packages/",
|
"packagesPath": "/root/.nuget/packages/",
|
||||||
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/obj/",
|
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/obj/",
|
||||||
"projectStyle": "PackageReference",
|
"projectStyle": "PackageReference",
|
||||||
"configFilePaths": [
|
"configFilePaths": [
|
||||||
"/home/pacer/.nuget/NuGet/NuGet.Config"
|
"/root/.nuget/NuGet/NuGet.Config"
|
||||||
],
|
],
|
||||||
"originalTargetFrameworks": [
|
"originalTargetFrameworks": [
|
||||||
"net8.0"
|
"net8.0"
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"dgSpecHash": "4hhhTNv5rdj9W8LEgtqRzvNnobbH+nWA4apshlgfd3j4OdsEpRlMXC2Q3X2ScEegniOPFgZFJJ9l+i9qtr7LrA==",
|
"dgSpecHash": "Yr08mh1oXg2H9eup6pJDv3DAEJIeIlBI+QyHLkFeXakigkBdjFhrDkS0UWc3z6IMWBK5yeeRM5RBBASJtTIrbA==",
|
||||||
"success": true,
|
"success": true,
|
||||||
"projectFilePath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
"projectFilePath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
||||||
"expectedPackageFiles": [
|
"expectedPackageFiles": [
|
||||||
"/home/pacer/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/8.0.1/microsoft.extensions.dependencyinjection.abstractions.8.0.1.nupkg.sha512",
|
"/root/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/8.0.1/microsoft.extensions.dependencyinjection.abstractions.8.0.1.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/microsoft.extensions.logging.abstractions/8.0.1/microsoft.extensions.logging.abstractions.8.0.1.nupkg.sha512",
|
"/root/.nuget/packages/microsoft.extensions.logging.abstractions/8.0.1/microsoft.extensions.logging.abstractions.8.0.1.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512",
|
"/root/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/npgsql/8.0.4/npgsql.8.0.4.nupkg.sha512",
|
"/root/.nuget/packages/npgsql/8.0.4/npgsql.8.0.4.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/opcfoundation.netstandard.opc.ua.client/1.5.374.78/opcfoundation.netstandard.opc.ua.client.1.5.374.78.nupkg.sha512",
|
"/root/.nuget/packages/opcfoundation.netstandard.opc.ua.client/1.5.374.78/opcfoundation.netstandard.opc.ua.client.1.5.374.78.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/opcfoundation.netstandard.opc.ua.configuration/1.5.374.78/opcfoundation.netstandard.opc.ua.configuration.1.5.374.78.nupkg.sha512",
|
"/root/.nuget/packages/opcfoundation.netstandard.opc.ua.configuration/1.5.374.78/opcfoundation.netstandard.opc.ua.configuration.1.5.374.78.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/opcfoundation.netstandard.opc.ua.core/1.5.374.78/opcfoundation.netstandard.opc.ua.core.1.5.374.78.nupkg.sha512",
|
"/root/.nuget/packages/opcfoundation.netstandard.opc.ua.core/1.5.374.78/opcfoundation.netstandard.opc.ua.core.1.5.374.78.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/opcfoundation.netstandard.opc.ua.security.certificates/1.5.374.78/opcfoundation.netstandard.opc.ua.security.certificates.1.5.374.78.nupkg.sha512",
|
"/root/.nuget/packages/opcfoundation.netstandard.opc.ua.security.certificates/1.5.374.78/opcfoundation.netstandard.opc.ua.security.certificates.1.5.374.78.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/system.formats.asn1/8.0.1/system.formats.asn1.8.0.1.nupkg.sha512",
|
"/root/.nuget/packages/system.formats.asn1/8.0.1/system.formats.asn1.8.0.1.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/system.security.cryptography.cng/5.0.0/system.security.cryptography.cng.5.0.0.nupkg.sha512"
|
"/root/.nuget/packages/system.security.cryptography.cng/5.0.0/system.security.cryptography.cng.5.0.0.nupkg.sha512"
|
||||||
],
|
],
|
||||||
"logs": []
|
"logs": []
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Npgsql;
|
using Npgsql;
|
||||||
using OpcPks.Core.Data;
|
using OpcPks.Core.Data;
|
||||||
using OpcPks.Core.Services;
|
using OpcPks.Core.Services;
|
||||||
|
using OpcPks.Core.Models; // CertRequestModel 참조 추가
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -10,13 +11,18 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace OpcPks.Web.Controllers;
|
namespace OpcPks.Web.Controllers;
|
||||||
|
|
||||||
[Route("Engineering")] // 🚨 경로를 명시적으로 고정
|
[Route("Engineering")]
|
||||||
public class EngineeringController : Controller
|
public class EngineeringController : Controller
|
||||||
{
|
{
|
||||||
[HttpGet("TagExplorer")] // Engineering/TagExplorer
|
// 하니웰 데이터 및 PKI 경로 고정
|
||||||
|
private readonly string _basePath = "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/Data";
|
||||||
|
|
||||||
|
#region [기존 기능: 태그 탐사 및 관리]
|
||||||
|
|
||||||
|
[HttpGet("TagExplorer")]
|
||||||
public IActionResult TagExplorer() => View();
|
public IActionResult TagExplorer() => View();
|
||||||
|
|
||||||
[HttpGet("Admin")] // Engineering/Admin
|
[HttpGet("Admin")]
|
||||||
public IActionResult Admin() => View();
|
public IActionResult Admin() => View();
|
||||||
|
|
||||||
[HttpPost("SearchByFilter")]
|
[HttpPost("SearchByFilter")]
|
||||||
@@ -100,34 +106,20 @@ public class EngineeringController : Controller
|
|||||||
[HttpPost("RunCrawler")]
|
[HttpPost("RunCrawler")]
|
||||||
public async Task<IActionResult> RunCrawler()
|
public async Task<IActionResult> RunCrawler()
|
||||||
{
|
{
|
||||||
Console.WriteLine("\n[API] === RunCrawler 요청 수신됨 ===");
|
try {
|
||||||
try
|
|
||||||
{
|
|
||||||
var sessionManager = new OpcSessionManager();
|
var sessionManager = new OpcSessionManager();
|
||||||
var session = await sessionManager.GetSessionAsync();
|
var session = await sessionManager.GetSessionAsync();
|
||||||
|
|
||||||
if (session == null || !session.Connected)
|
if (session == null || !session.Connected)
|
||||||
{
|
|
||||||
Console.WriteLine("❌ [API] 세션 연결 실패!");
|
|
||||||
return BadRequest(new { message = "하니웰 서버 연결 실패." });
|
return BadRequest(new { message = "하니웰 서버 연결 실패." });
|
||||||
}
|
|
||||||
|
|
||||||
var crawler = new HoneywellCrawler(session);
|
var crawler = new HoneywellCrawler(session);
|
||||||
string csvPath = @"/home/pacer/projects/OpcPksPlatform/OpcPks.Core/Data/Honeywell_FullMap.csv";
|
string csvPath = Path.Combine(_basePath, "Honeywell_FullMap.csv");
|
||||||
|
|
||||||
string dir = Path.GetDirectoryName(csvPath);
|
|
||||||
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
|
|
||||||
|
|
||||||
await crawler.RunAsync("ns=1;s=$assetmodel", csvPath);
|
await crawler.RunAsync("ns=1;s=$assetmodel", csvPath);
|
||||||
|
|
||||||
Console.WriteLine("✅ [API] 모든 탐사 공정 완료!");
|
|
||||||
return Ok(new { message = "탐사 및 CSV 생성 완료!" });
|
return Ok(new { message = "탐사 및 CSV 생성 완료!" });
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex) { return BadRequest(new { message = ex.Message }); }
|
||||||
{
|
|
||||||
Console.WriteLine($"❌ [API] 치명적 오류: {ex.Message}");
|
|
||||||
return BadRequest(new { message = ex.Message });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("ImportCsv")]
|
[HttpPost("ImportCsv")]
|
||||||
@@ -136,10 +128,11 @@ public class EngineeringController : Controller
|
|||||||
try {
|
try {
|
||||||
using var conn = new NpgsqlConnection(DbConfig.ConnectionString);
|
using var conn = new NpgsqlConnection(DbConfig.ConnectionString);
|
||||||
await conn.OpenAsync();
|
await conn.OpenAsync();
|
||||||
var sql = @"TRUNCATE raw_node_map;
|
string csvPath = Path.Combine(_basePath, "Honeywell_FullMap.csv");
|
||||||
COPY raw_node_map(level, node_class, name, node_id)
|
var sql = $@"TRUNCATE raw_node_map;
|
||||||
FROM '/home/pacer/projects/OpcPksPlatform/OpcPks.Core/Data/Honeywell_FullMap.csv'
|
COPY raw_node_map(level, node_class, name, node_id)
|
||||||
DELIMITER ',' CSV HEADER;";
|
FROM '{csvPath}'
|
||||||
|
DELIMITER ',' CSV HEADER;";
|
||||||
using var cmd = new NpgsqlCommand(sql, conn);
|
using var cmd = new NpgsqlCommand(sql, conn);
|
||||||
await cmd.ExecuteNonQueryAsync();
|
await cmd.ExecuteNonQueryAsync();
|
||||||
return Ok(new { message = "DB 동기화 완료" });
|
return Ok(new { message = "DB 동기화 완료" });
|
||||||
@@ -147,6 +140,48 @@ public class EngineeringController : Controller
|
|||||||
catch (Exception ex) { return BadRequest(ex.Message); }
|
catch (Exception ex) { return BadRequest(ex.Message); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region [신규 기능: 하니웰 전용 인증서 관리]
|
||||||
|
|
||||||
|
[HttpGet("CertManager")]
|
||||||
|
public IActionResult CertManager()
|
||||||
|
{
|
||||||
|
string pfxPath = Path.Combine(_basePath, "pki/own/private/OpcTestClient.pfx");
|
||||||
|
|
||||||
|
// 파일 존재 여부를 ViewData에 담아 보냅니다.
|
||||||
|
ViewBag.IsCertExists = System.IO.File.Exists(pfxPath);
|
||||||
|
|
||||||
|
ViewBag.SuccessMsg = TempData["Success"];
|
||||||
|
ViewBag.ErrorMsg = TempData["Error"];
|
||||||
|
return View(new CertRequestModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("GenerateCertificate")]
|
||||||
|
public async Task<IActionResult> GenerateCertificate(CertRequestModel model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var generator = new CertificateGenerator(_basePath);
|
||||||
|
var success = await generator.CreateHoneywellCertificateAsync(model);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
TempData["Success"] = "하니웰 FTE 대응 인증서가 생성 및 백업되었습니다.";
|
||||||
|
return RedirectToAction("CertManager");
|
||||||
|
}
|
||||||
|
|
||||||
|
TempData["Error"] = "인증서 생성 중 오류가 발생했습니다.";
|
||||||
|
return RedirectToAction("CertManager");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
TempData["Error"] = ex.Message;
|
||||||
|
return RedirectToAction("CertManager");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public class SearchRequest { public string TagTerm { get; set; } public List<string> Suffixes { get; set; } }
|
public class SearchRequest { public string TagTerm { get; set; } public List<string> Suffixes { get; set; } }
|
||||||
public class TagRegistrationRequest { public string TagName { get; set; } public string NodeId { get; set; } public string DataType { get; set; } }
|
public class TagRegistrationRequest { public string TagName { get; set; } public string NodeId { get; set; } public string DataType { get; set; } }
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,107 @@
|
|||||||
<div class="card border-danger">
|
@{
|
||||||
<div class="card-header bg-danger text-white">System Engineering - Discovery Mode</div>
|
ViewData["Title"] = "System Admin";
|
||||||
<div class="card-body">
|
}
|
||||||
<h5>1. 하니웰 자산 모델 탐사 (Crawler)</h5>
|
|
||||||
<p class="text-muted">서버의 모든 노드를 훑어 CSV 파일을 생성합니다. (시간이 오래 걸릴 수 있음)</p>
|
|
||||||
<button id="btnRunCrawler" class="btn btn-danger" onclick="runCrawler()">🚀 탐사 및 CSV 생성 시작</button>
|
|
||||||
|
|
||||||
<hr>
|
<div class="container mt-4">
|
||||||
|
<div class="card border-danger shadow">
|
||||||
|
<div class="card-header bg-danger text-white">
|
||||||
|
<h4 class="mb-0">🛠️ System Engineering - Discovery Mode</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<section class="mb-5">
|
||||||
|
<h5>1. 하니웰 Asset 모델 탐사 (Crawler)</h5>
|
||||||
|
<p class="text-muted">서버의 모든 노드를 훑어 <code>Honeywell_FullMap.csv</code> 파일을 생성합니다. <br>
|
||||||
|
<small class="text-danger">* 주의: 노드 수가 많을 경우 하니웰 서버와 네트워크에 부하가 발생할 수 있습니다.</small></p>
|
||||||
|
|
||||||
<h5>2. DB 동기화 (CSV to Database)</h5>
|
<button id="btnRunCrawler" class="btn btn-danger btn-lg" onclick="runCrawler()">
|
||||||
<p class="text-muted">생성된 Honeywell_FullMap.csv 파일을 읽어 DB에 일괄 저장합니다.</p>
|
<span id="spinnerCrawler" class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
|
||||||
<button id="btnImportCsv" class="btn btn-warning" onclick="importCsvToDb()">📥 CSV 데이터를 DB로 가져오기</button>
|
🚀 탐사 및 CSV 생성 시작
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<section class="mt-4">
|
||||||
|
<h5>2. DB 동기화 (CSV to Database)</h5>
|
||||||
|
<p class="text-muted">생성된 CSV 파일을 읽어 PostgreSQL <code>raw_node_map</code> 테이블에 일괄 저장합니다.</p>
|
||||||
|
<button id="btnImportCsv" class="btn btn-warning btn-lg" onclick="importCsvToDb()">
|
||||||
|
<span id="spinnerImport" class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
|
||||||
|
📥 CSV 데이터를 DB로 가져오기
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer bg-light">
|
||||||
|
<div id="statusMessage" class="fw-bold"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
<script>
|
<script>
|
||||||
function runCrawler() {
|
async function runCrawler() {
|
||||||
if(!confirm("전체 노드 탐사를 시작하시겠습니까? 하니웰 서버에 부하가 갈 수 있습니다.")) return;
|
const btn = document.getElementById('btnRunCrawler');
|
||||||
// API 호출: /Engineering/RunCrawler
|
const spinner = document.getElementById('spinnerCrawler');
|
||||||
|
const status = document.getElementById('statusMessage');
|
||||||
|
|
||||||
|
if (!confirm("전체 노드 탐사를 시작하시겠습니까? (ns=1;s=$assetmodel 기준)")) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 버튼 비활성화 및 로딩 시작
|
||||||
|
btn.disabled = true;
|
||||||
|
spinner.classList.remove('d-none');
|
||||||
|
status.innerText = "⏳ 하니웰 서버 탐사 중... 잠시만 기다려 주세요.";
|
||||||
|
status.className = "text-primary fw-bold";
|
||||||
|
|
||||||
|
const response = await fetch('/Engineering/RunCrawler', { method: 'POST' });
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
alert("✅ 성공: " + result.message);
|
||||||
|
status.innerText = "✅ 탐사 완료: " + result.message;
|
||||||
|
status.className = "text-success fw-bold";
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || "탐사 실패");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert("❌ 에러 발생: " + error.message);
|
||||||
|
status.innerText = "❌ 오류: " + error.message;
|
||||||
|
status.className = "text-danger fw-bold";
|
||||||
|
} finally {
|
||||||
|
btn.disabled = false;
|
||||||
|
spinner.classList.add('d-none');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function importCsvToDb() {
|
|
||||||
// API 호출: /Engineering/ImportCsv
|
async function importCsvToDb() {
|
||||||
|
const btn = document.getElementById('btnImportCsv');
|
||||||
|
const spinner = document.getElementById('spinnerImport');
|
||||||
|
const status = document.getElementById('statusMessage');
|
||||||
|
|
||||||
|
if (!confirm("CSV 데이터를 DB에 덮어씌우시겠습니까? (기존 데이터는 삭제됩니다.)")) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
btn.disabled = true;
|
||||||
|
spinner.classList.remove('d-none');
|
||||||
|
status.innerText = "⏳ DB 동기화 작업 중...";
|
||||||
|
|
||||||
|
const response = await fetch('/Engineering/ImportCsv', { method: 'POST' });
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
alert("✅ 성공: " + result.message);
|
||||||
|
status.innerText = "✅ DB 동기화 완료!";
|
||||||
|
status.className = "text-success fw-bold";
|
||||||
|
} else {
|
||||||
|
throw new Error(result.message || "동기화 실패");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert("❌ 에러 발생: " + error.message);
|
||||||
|
status.innerText = "❌ 오류: " + error.message;
|
||||||
|
status.className = "text-danger fw-bold";
|
||||||
|
} finally {
|
||||||
|
btn.disabled = false;
|
||||||
|
spinner.classList.add('d-none');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
}
|
||||||
128
OpcPksPlatform/OpcPks.Web/Views/Engineering/CertManager.cshtml
Normal file
128
OpcPksPlatform/OpcPks.Web/Views/Engineering/CertManager.cshtml
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
@model OpcPks.Core.Models.CertRequestModel
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="card shadow">
|
||||||
|
<div class="card-header bg-primary text-white">
|
||||||
|
<h4>🛡️ 하니웰 Experion 전용 인증서 생성기</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form asp-action="GenerateCertificate" method="post">
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label fw-bold">시스템 구성</label>
|
||||||
|
<select asp-for="IsRedundant" class="form-select" id="systemType">
|
||||||
|
<option value="false">Standalone (단일 서버)</option>
|
||||||
|
<option value="true">Redundant (이중화 서버)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label fw-bold">어플리케이션 이름</label>
|
||||||
|
<input asp-for="ApplicationName" class="form-control" placeholder="OpcPksClient" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<h5 class="text-secondary"><span class="badge bg-info">Primary</span> 서버 정보</h5>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">Host Name</label>
|
||||||
|
<input asp-for="PrimaryHostName" class="form-control" placeholder="예: HONPKS" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label text-warning">IP Address (Yellow)</label>
|
||||||
|
<input asp-for="PrimaryIpA" class="form-control" placeholder="192.168.0.20" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label text-success">IP Address (Green)</label>
|
||||||
|
<input asp-for="PrimaryIpB" class="form-control" placeholder="192.168.1.20" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="text-secondary mt-4"><span class="badge bg-secondary" id="secondaryBadge">Secondary</span> 서버 정보</h5>
|
||||||
|
<div class="row mb-3" id="secondaryFields">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">Host Name</label>
|
||||||
|
<input asp-for="SecondaryHostName" class="form-control sec-input" placeholder="예: HONPKS" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label text-warning">IP Address (Yellow)</label>
|
||||||
|
<input asp-for="SecondaryIpA" class="form-control sec-input" placeholder="192.168.0.21" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label text-success">IP Address (Green)</label>
|
||||||
|
<input asp-for="SecondaryIpB" class="form-control sec-input" placeholder="192.168.1.21" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card bg-light border-warning mt-5">
|
||||||
|
<div class="card-body">
|
||||||
|
@if (ViewBag.IsCertExists == true)
|
||||||
|
{
|
||||||
|
<div class="alert alert-warning d-flex align-items-center">
|
||||||
|
<span class="fs-4 me-3">⚠️</span>
|
||||||
|
<div>
|
||||||
|
<strong>기존 인증서가 이미 존재합니다!</strong><br />
|
||||||
|
새로 생성 시 기존 서버와의 통신 신뢰관계(Trust)가 깨질 수 있습니다.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" id="chkUnlock" onchange="toggleCertBtn()">
|
||||||
|
<label class="form-check-label text-danger fw-bold" for="chkUnlock">
|
||||||
|
[위험 인지] 기존 인증서를 무시하고 새로 생성하는 것에 동의합니다.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" id="btnGenerate" class="btn btn-danger btn-lg w-100" disabled>
|
||||||
|
🔒 인증서가 이미 존재하여 잠겨있습니다
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="submit" id="btnGenerate" class="btn btn-primary btn-lg w-100">
|
||||||
|
🚀 인증서 생성 및 자동 적용 시작
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@section Scripts {
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
// 1. 이중화 선택 로직
|
||||||
|
$('#systemType').change(function () {
|
||||||
|
const isRedundant = $(this).val() === 'true';
|
||||||
|
$('.sec-input').prop('disabled', !isRedundant);
|
||||||
|
|
||||||
|
if(isRedundant) {
|
||||||
|
$('#secondaryBadge').removeClass('bg-secondary').addClass('bg-info');
|
||||||
|
} else {
|
||||||
|
$('#secondaryBadge').removeClass('bg-info').addClass('bg-secondary');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#systemType').trigger('change');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. 버튼 잠금 해제 로직
|
||||||
|
function toggleCertBtn() {
|
||||||
|
const isChecked = document.getElementById('chkUnlock').checked;
|
||||||
|
const btn = document.getElementById('btnGenerate');
|
||||||
|
|
||||||
|
if(isChecked) {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.innerText = "🔥 인증서 새로 생성 (강제 실행)";
|
||||||
|
btn.classList.replace('btn-danger', 'btn-warning');
|
||||||
|
} else {
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.innerText = "🔒 인증서가 이미 존재하여 잠겨있습니다";
|
||||||
|
btn.classList.replace('btn-warning', 'btn-danger');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<header>
|
<header>
|
||||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">OpcPks.Web</a>
|
<a class="navbar-brand fw-bold" asp-area="" asp-controller="Home" asp-action="Index">🚀 OpcPks Platform</a>
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||||
aria-expanded="false" aria-label="Toggle navigation">
|
aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
@@ -22,7 +22,24 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
|
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
|
<span class="nav-link text-muted">|</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-primary" asp-area="" asp-controller="Engineering" asp-action="TagExplorer">🔍 Tag Explorer</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-success" asp-area="" asp-controller="Engineering" asp-action="Admin">⚙️ DB Admin</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link text-danger" asp-area="" asp-controller="Engineering" asp-action="CertManager">🛡️ Cert Manager</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
|
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -30,7 +47,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
@if (TempData["Success"] != null)
|
||||||
|
{
|
||||||
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
|
<strong>성공!</strong> @TempData["Success"]
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (TempData["Error"] != null)
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
|
<strong>오류!</strong> @TempData["Error"]
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<main role="main" class="pb-3">
|
<main role="main" class="pb-3">
|
||||||
@RenderBody()
|
@RenderBody()
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,10 +13,10 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("OpcPks.Web")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("OpcPks.Web")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+171aaf6115cde8e9e930d14886fafa5fe4c1e4c0")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+4e006a5a5f65f597fafaa3777b8a1073944eada2")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("OpcPks.Web")]
|
[assembly: System.Reflection.AssemblyProductAttribute("OpcPks.Web")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("OpcPks.Web")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("OpcPks.Web")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|
||||||
// Generated by the MSBuild WriteCodeFragment class.
|
// MSBuild WriteCodeFragment 클래스에서 생성되었습니다.
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
69146d785d05a31782563e3020fd0b70195b5ca5af2eb9bc318d486b90f84fe9
|
e1494e87c92c732759b5281464380da6aa825fc12aba342324181898b9f0d33d
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ build_property._RazorSourceGeneratorDebug =
|
|||||||
build_metadata.AdditionalFiles.TargetPath = Vmlld3MvRW5naW5lZXJpbmcvQWRtaW4uY3NodG1s
|
build_metadata.AdditionalFiles.TargetPath = Vmlld3MvRW5naW5lZXJpbmcvQWRtaW4uY3NodG1s
|
||||||
build_metadata.AdditionalFiles.CssScope =
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
|
|
||||||
|
[/home/pacer/projects/OpcPksPlatform/OpcPks.Web/Views/Engineering/CertManager.cshtml]
|
||||||
|
build_metadata.AdditionalFiles.TargetPath = Vmlld3MvRW5naW5lZXJpbmcvQ2VydE1hbmFnZXIuY3NodG1s
|
||||||
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
|
|
||||||
[/home/pacer/projects/OpcPksPlatform/OpcPks.Web/Views/Engineering/TagExplorer.cshtml]
|
[/home/pacer/projects/OpcPksPlatform/OpcPks.Web/Views/Engineering/TagExplorer.cshtml]
|
||||||
build_metadata.AdditionalFiles.TargetPath = Vmlld3MvRW5naW5lZXJpbmcvVGFnRXhwbG9yZXIuY3NodG1s
|
build_metadata.AdditionalFiles.TargetPath = Vmlld3MvRW5naW5lZXJpbmcvVGFnRXhwbG9yZXIuY3NodG1s
|
||||||
build_metadata.AdditionalFiles.CssScope =
|
build_metadata.AdditionalFiles.CssScope =
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
211409f9c66f4d86deef10e146a286bf43dcff595588425d60ad90ee2a7fd32f
|
da88b9ec6f30d3a67ed38dde28b0fbcd513cedae3a9742b74a5f06636cf1a15e
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
ef34cdd3c41169ab6b411993059073056d84145d36a38b4aea950172aff7d741
|
6467bb07a49b01c95068173444a1866c77670de41eed0f2a920478da9d4c65bc
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,11 +10,11 @@
|
|||||||
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
||||||
"projectName": "OpcPks.Core",
|
"projectName": "OpcPks.Core",
|
||||||
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/OpcPks.Core.csproj",
|
||||||
"packagesPath": "/home/pacer/.nuget/packages/",
|
"packagesPath": "/root/.nuget/packages/",
|
||||||
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/obj/",
|
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/obj/",
|
||||||
"projectStyle": "PackageReference",
|
"projectStyle": "PackageReference",
|
||||||
"configFilePaths": [
|
"configFilePaths": [
|
||||||
"/home/pacer/.nuget/NuGet/NuGet.Config"
|
"/root/.nuget/NuGet/NuGet.Config"
|
||||||
],
|
],
|
||||||
"originalTargetFrameworks": [
|
"originalTargetFrameworks": [
|
||||||
"net8.0"
|
"net8.0"
|
||||||
@@ -73,11 +73,11 @@
|
|||||||
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
||||||
"projectName": "OpcPks.Web",
|
"projectName": "OpcPks.Web",
|
||||||
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
||||||
"packagesPath": "/home/pacer/.nuget/packages/",
|
"packagesPath": "/root/.nuget/packages/",
|
||||||
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/obj/",
|
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/obj/",
|
||||||
"projectStyle": "PackageReference",
|
"projectStyle": "PackageReference",
|
||||||
"configFilePaths": [
|
"configFilePaths": [
|
||||||
"/home/pacer/.nuget/NuGet/NuGet.Config"
|
"/root/.nuget/NuGet/NuGet.Config"
|
||||||
],
|
],
|
||||||
"originalTargetFrameworks": [
|
"originalTargetFrameworks": [
|
||||||
"net8.0"
|
"net8.0"
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
|
||||||
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
|
||||||
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
|
||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/home/pacer/.nuget/packages/</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/root/.nuget/packages/</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/home/pacer/.nuget/packages/</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/root/.nuget/packages/</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.8.1</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.8.1</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="/home/pacer/.nuget/packages/" />
|
<SourceRoot Include="/root/.nuget/packages/" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -574,7 +574,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"packageFolders": {
|
"packageFolders": {
|
||||||
"/home/pacer/.nuget/packages/": {}
|
"/root/.nuget/packages/": {}
|
||||||
},
|
},
|
||||||
"project": {
|
"project": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -582,11 +582,11 @@
|
|||||||
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
"projectUniqueName": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
||||||
"projectName": "OpcPks.Web",
|
"projectName": "OpcPks.Web",
|
||||||
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
"projectPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
||||||
"packagesPath": "/home/pacer/.nuget/packages/",
|
"packagesPath": "/root/.nuget/packages/",
|
||||||
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/obj/",
|
"outputPath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/obj/",
|
||||||
"projectStyle": "PackageReference",
|
"projectStyle": "PackageReference",
|
||||||
"configFilePaths": [
|
"configFilePaths": [
|
||||||
"/home/pacer/.nuget/NuGet/NuGet.Config"
|
"/root/.nuget/NuGet/NuGet.Config"
|
||||||
],
|
],
|
||||||
"originalTargetFrameworks": [
|
"originalTargetFrameworks": [
|
||||||
"net8.0"
|
"net8.0"
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"dgSpecHash": "Lhk78ivUpJSYUca9AozBeOWL1MSXwG/J03crkR8ohPXr0Jr13fI6SjcPbbT0IMW8j7gHacAchV4I/6FtcYipBA==",
|
"dgSpecHash": "1ODJAJibZeCWjDB9k93/7u2tzIkxUKCpt4LpJwtoyk9SPN+V9Z00ioG5BCZSRPJv0f/i3y9/JoZYPrLxXjCawQ==",
|
||||||
"success": true,
|
"success": true,
|
||||||
"projectFilePath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
"projectFilePath": "/home/pacer/projects/OpcPksPlatform/OpcPks.Web/OpcPks.Web.csproj",
|
||||||
"expectedPackageFiles": [
|
"expectedPackageFiles": [
|
||||||
"/home/pacer/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/8.0.1/microsoft.extensions.dependencyinjection.abstractions.8.0.1.nupkg.sha512",
|
"/root/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/8.0.1/microsoft.extensions.dependencyinjection.abstractions.8.0.1.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/microsoft.extensions.logging.abstractions/8.0.1/microsoft.extensions.logging.abstractions.8.0.1.nupkg.sha512",
|
"/root/.nuget/packages/microsoft.extensions.logging.abstractions/8.0.1/microsoft.extensions.logging.abstractions.8.0.1.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512",
|
"/root/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/npgsql/8.0.4/npgsql.8.0.4.nupkg.sha512",
|
"/root/.nuget/packages/npgsql/8.0.4/npgsql.8.0.4.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/opcfoundation.netstandard.opc.ua.client/1.5.374.78/opcfoundation.netstandard.opc.ua.client.1.5.374.78.nupkg.sha512",
|
"/root/.nuget/packages/opcfoundation.netstandard.opc.ua.client/1.5.374.78/opcfoundation.netstandard.opc.ua.client.1.5.374.78.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/opcfoundation.netstandard.opc.ua.configuration/1.5.374.78/opcfoundation.netstandard.opc.ua.configuration.1.5.374.78.nupkg.sha512",
|
"/root/.nuget/packages/opcfoundation.netstandard.opc.ua.configuration/1.5.374.78/opcfoundation.netstandard.opc.ua.configuration.1.5.374.78.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/opcfoundation.netstandard.opc.ua.core/1.5.374.78/opcfoundation.netstandard.opc.ua.core.1.5.374.78.nupkg.sha512",
|
"/root/.nuget/packages/opcfoundation.netstandard.opc.ua.core/1.5.374.78/opcfoundation.netstandard.opc.ua.core.1.5.374.78.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/opcfoundation.netstandard.opc.ua.security.certificates/1.5.374.78/opcfoundation.netstandard.opc.ua.security.certificates.1.5.374.78.nupkg.sha512",
|
"/root/.nuget/packages/opcfoundation.netstandard.opc.ua.security.certificates/1.5.374.78/opcfoundation.netstandard.opc.ua.security.certificates.1.5.374.78.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/system.formats.asn1/8.0.1/system.formats.asn1.8.0.1.nupkg.sha512",
|
"/root/.nuget/packages/system.formats.asn1/8.0.1/system.formats.asn1.8.0.1.nupkg.sha512",
|
||||||
"/home/pacer/.nuget/packages/system.security.cryptography.cng/5.0.0/system.security.cryptography.cng.5.0.0.nupkg.sha512"
|
"/root/.nuget/packages/system.security.cryptography.cng/5.0.0/system.security.cryptography.cng.5.0.0.nupkg.sha512"
|
||||||
],
|
],
|
||||||
"logs": []
|
"logs": []
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user