Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Security.Principal;
using fiskaltrust.storage.serialization.V0;
using Microsoft.Extensions.Logging;

namespace fiskaltrust.Middleware.Queue.Test.Launcher.Helpers
{
/// <summary>
/// Verifies that http/https URLs configured for the queues (e.g. retrieved from Helipad)
/// have a matching netsh URL ACL reservation, so hosting does not fail at runtime.
/// </summary>
public static class UrlReservationChecker
{
public static void CheckQueueUrlReservations(ftCashBoxConfiguration cashBoxConfiguration, ILogger logger)
{
if (cashBoxConfiguration?.ftQueues == null)
{
return;
}

// Already elevated: HttpListener can self-register, no need to warn.
if (IsRunningAsAdministrator())
{
return;
}

string aclOutput = null;
var checkedPorts = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

foreach (var queue in cashBoxConfiguration.ftQueues)
{
if (queue?.Url == null)
{
continue;
}

foreach (var rawUrl in queue.Url)
{
if (string.IsNullOrWhiteSpace(rawUrl))
{
continue;
}

var httpUrl = rawUrl.Replace("rest://", "http://");
if (!Uri.TryCreate(httpUrl, UriKind.Absolute, out var uri))
{
continue;
}

if (!string.Equals(uri.Scheme, "http", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase))
{
continue;
}

var key = uri.Scheme.ToLowerInvariant() + ":" + uri.Port.ToString(CultureInfo.InvariantCulture);
if (!checkedPorts.Add(key))
{
continue;
}

aclOutput ??= QueryUrlAcls();

if (HasReservationForPort(aclOutput, uri.Scheme, uri.Port))
{
logger.LogDebug("URL reservation found for {Scheme}://+:{Port}/", uri.Scheme, uri.Port);
continue;
}

var urlPrefix = $"{uri.Scheme}://+:{uri.Port}{uri.AbsolutePath}";
if (!urlPrefix.EndsWith("/", StringComparison.Ordinal))
{
urlPrefix += "/";
}

var userName = WindowsIdentity.GetCurrent().Name;
logger.LogWarning(
"No URL reservation found for port {Port} (configured URL: {Url}). Run the following command once as administrator: netsh http add urlacl url={UrlPrefix} user={User}",
uri.Port, rawUrl, urlPrefix, userName);
}
}
}

private static bool IsRunningAsAdministrator()
{
try
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch
{
return false;
}
}

private static string QueryUrlAcls()
{
try
{
var psi = new ProcessStartInfo("netsh", "http show urlacl")
{
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
using var process = Process.Start(psi);
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit(5000);
return output ?? string.Empty;
}
catch
{
return string.Empty;
}
}

private static bool HasReservationForPort(string aclOutput, string scheme, int port)
{
if (string.IsNullOrEmpty(aclOutput))
{
return false;
}

var portToken = ":" + port.ToString(CultureInfo.InvariantCulture) + "/";
foreach (var rawLine in aclOutput.Split('\n'))
{
var line = rawLine.Trim();
var schemeIdx = line.IndexOf(scheme + "://", StringComparison.OrdinalIgnoreCase);
if (schemeIdx < 0)
{
continue;
}
if (line.IndexOf(portToken, schemeIdx, StringComparison.Ordinal) >= 0)
{
return true;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ public static void Main(string configurationFilePath = "", string serviceFolder
serviceFolder = Directory.GetCurrentDirectory();
}

var serviceCollectionForChecker = new ServiceCollection();
serviceCollectionForChecker.AddStandardLoggers(LogLevel.Debug);
using (var checkerProvider = serviceCollectionForChecker.BuildServiceProvider())
{
var checkerLogger = checkerProvider.GetRequiredService<ILoggerFactory>()
.CreateLogger(typeof(Helpers.UrlReservationChecker).FullName);
Helpers.UrlReservationChecker.CheckQueueUrlReservations(cashBoxConfiguration, checkerLogger);
}

var config = cashBoxConfiguration.ftQueues[0];

config.Configuration.Add("cashboxid", cashBoxConfiguration.ftCashBoxId);
Expand Down Expand Up @@ -173,4 +182,4 @@ private static void ConfigureEF(PackageConfiguration queue, ServiceCollection se
bootStrapper.ConfigureServices(serviceCollection);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ private void TryAddUrlReservation(Uri baseAddress)
urlPrefix += "/";
}

if (HasUrlReservation(urlPrefix))
if (HasUrlReservationForPort(baseAddress.Scheme, baseAddress.Port))
{
return;
}
Expand All @@ -159,7 +159,7 @@ private void TryAddUrlReservation(Uri baseAddress)
_logger.LogWarning("No URL reservation found for {Url}. Run the following command once as administrator: netsh http add urlacl url={Url} user={User}", urlPrefix, urlPrefix, userName);
}

private bool HasUrlReservation(string urlPrefix)
private bool HasUrlReservationForPort(string scheme, int port)
{
try
{
Expand All @@ -172,7 +172,24 @@ private bool HasUrlReservation(string urlPrefix)
var process = Process.Start(psi);
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit(5000);
return output.IndexOf(urlPrefix, StringComparison.OrdinalIgnoreCase) >= 0;

// Consider any reservation on the same scheme and port as sufficient,
// regardless of the path portion of the URL.
var portToken = ":" + port.ToString(System.Globalization.CultureInfo.InvariantCulture) + "/";
foreach (var rawLine in output.Split('\n'))
{
var line = rawLine.Trim();
var schemeIdx = line.IndexOf(scheme + "://", StringComparison.OrdinalIgnoreCase);
if (schemeIdx < 0)
{
continue;
}
if (line.IndexOf(portToken, schemeIdx, StringComparison.Ordinal) >= 0)
{
return true;
}
}
return false;
}
catch
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ private void TryAddUrlReservation(Uri baseAddress)
urlPrefix += "/";
}

if (HasUrlReservation(urlPrefix))
if (HasUrlReservationForPort(baseAddress.Scheme, baseAddress.Port))
{
return;
}
Expand All @@ -171,7 +171,7 @@ private void TryAddUrlReservation(Uri baseAddress)
_logger.LogWarning("No URL reservation found for {Url}. Run the following command once as administrator: netsh http add urlacl url={Url} user={User}", urlPrefix, urlPrefix, userName);
}

private bool HasUrlReservation(string urlPrefix)
private bool HasUrlReservationForPort(string scheme, int port)
{
try
{
Expand All @@ -184,7 +184,24 @@ private bool HasUrlReservation(string urlPrefix)
var process = Process.Start(psi);
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit(5000);
return output.IndexOf(urlPrefix, StringComparison.OrdinalIgnoreCase) >= 0;

// Consider any reservation on the same scheme and port as sufficient,
// regardless of the path portion of the URL.
var portToken = ":" + port.ToString(System.Globalization.CultureInfo.InvariantCulture) + "/";
foreach (var rawLine in output.Split('\n'))
{
var line = rawLine.Trim();
var schemeIdx = line.IndexOf(scheme + "://", StringComparison.OrdinalIgnoreCase);
if (schemeIdx < 0)
{
continue;
}
if (line.IndexOf(portToken, schemeIdx, StringComparison.Ordinal) >= 0)
{
return true;
}
}
return false;
}
catch
{
Expand Down
34 changes: 17 additions & 17 deletions scu-de/fiskaltrust.Middleware.SCU.DE.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31521.260
# Visual Studio Version 18
VisualStudioVersion = 18.6.11822.322
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2F690A2B-96D1-45AC-BD36-E27D68422352}"
EndProject
Expand Down Expand Up @@ -29,8 +29,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fiskaltrust.Middleware.SCU.
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Helpers", "Helpers", "{860D3016-9A5C-4162-ACC8-B2031B80F697}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fiskaltrust.Middleware.SCU.DE.Swissbit", "src\fiskaltrust.Middleware.SCU.DE.Swissbit\fiskaltrust.Middleware.SCU.DE.Swissbit.csproj", "{13BBFBA8-0991-484C-8626-A62062119E38}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fiskaltrust.Middleware.SCU.DE.Test.Launcher", "test\Manual\fiskaltrust.Middleware.SCU.DE.Test.Launcher\fiskaltrust.Middleware.SCU.DE.Test.Launcher.csproj", "{C00787F3-B5C1-413B-813A-57E6168E7661}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Manual", "Manual", "{800DAE8D-CCF0-43E6-A974-916FB22C112A}"
Expand Down Expand Up @@ -65,6 +63,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fiskaltrust.Middleware.SCU.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "fiskaltrust.Middleware.SCU.DE.FiskalyCertified.UnitTest", "test\fiskaltrust.Middleware.SCU.DE.FiskalyCertified.UnitTest\fiskaltrust.Middleware.SCU.DE.FiskalyCertified.UnitTest.csproj", "{4DAA4C67-C0B0-48C3-B41F-851759D86DFB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "fiskaltrust.Middleware.SCU.DE.Swissbit", "src\fiskaltrust.Middleware.SCU.DE.Swissbit\fiskaltrust.Middleware.SCU.DE.Swissbit.csproj", "{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -147,18 +147,6 @@ Global
{0AECD929-369B-4644-AF9A-16824AD9FFEE}.Release|x64.Build.0 = Release|Any CPU
{0AECD929-369B-4644-AF9A-16824AD9FFEE}.Release|x86.ActiveCfg = Release|Any CPU
{0AECD929-369B-4644-AF9A-16824AD9FFEE}.Release|x86.Build.0 = Release|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Debug|x64.ActiveCfg = Debug|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Debug|x64.Build.0 = Debug|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Debug|x86.ActiveCfg = Debug|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Debug|x86.Build.0 = Debug|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Release|Any CPU.Build.0 = Release|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Release|x64.ActiveCfg = Release|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Release|x64.Build.0 = Release|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Release|x86.ActiveCfg = Release|Any CPU
{13BBFBA8-0991-484C-8626-A62062119E38}.Release|x86.Build.0 = Release|Any CPU
{C00787F3-B5C1-413B-813A-57E6168E7661}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C00787F3-B5C1-413B-813A-57E6168E7661}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C00787F3-B5C1-413B-813A-57E6168E7661}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -351,6 +339,18 @@ Global
{4DAA4C67-C0B0-48C3-B41F-851759D86DFB}.Release|x64.Build.0 = Release|Any CPU
{4DAA4C67-C0B0-48C3-B41F-851759D86DFB}.Release|x86.ActiveCfg = Release|Any CPU
{4DAA4C67-C0B0-48C3-B41F-851759D86DFB}.Release|x86.Build.0 = Release|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Debug|x64.ActiveCfg = Debug|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Debug|x64.Build.0 = Debug|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Debug|x86.ActiveCfg = Debug|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Debug|x86.Build.0 = Debug|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Release|Any CPU.Build.0 = Release|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Release|x64.ActiveCfg = Release|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Release|x64.Build.0 = Release|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Release|x86.ActiveCfg = Release|Any CPU
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -363,7 +363,6 @@ Global
{115522DE-DEC8-461B-AEDD-9D68631F9E57} = {7201C6FB-C25C-45DB-9C0B-1355FEF13939}
{0AECD929-369B-4644-AF9A-16824AD9FFEE} = {2F690A2B-96D1-45AC-BD36-E27D68422352}
{860D3016-9A5C-4162-ACC8-B2031B80F697} = {2F690A2B-96D1-45AC-BD36-E27D68422352}
{13BBFBA8-0991-484C-8626-A62062119E38} = {2F690A2B-96D1-45AC-BD36-E27D68422352}
{C00787F3-B5C1-413B-813A-57E6168E7661} = {800DAE8D-CCF0-43E6-A974-916FB22C112A}
{800DAE8D-CCF0-43E6-A974-916FB22C112A} = {7201C6FB-C25C-45DB-9C0B-1355FEF13939}
{DFAC4C0A-A019-4E09-B9A1-0CBEF132335E} = {7201C6FB-C25C-45DB-9C0B-1355FEF13939}
Expand All @@ -381,6 +380,7 @@ Global
{61F3E070-5E01-4EBE-B6FC-64D05472CB19} = {2F690A2B-96D1-45AC-BD36-E27D68422352}
{0728A325-37E5-4E23-AAC5-DB2860BB75F3} = {7201C6FB-C25C-45DB-9C0B-1355FEF13939}
{4DAA4C67-C0B0-48C3-B41F-851759D86DFB} = {7201C6FB-C25C-45DB-9C0B-1355FEF13939}
{AB1DAD78-6EF3-72DD-D37A-D8A5089CCF3A} = {2F690A2B-96D1-45AC-BD36-E27D68422352}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C5E269B8-4A21-4B1B-8805-C8193C08FE3E}
Expand Down
4 changes: 2 additions & 2 deletions scu-de/src/fiskaltrust.Middleware.SCU.DE.Swissbit/.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
<!-- native binaries used by fiskaltrust-launcher out of lib/ folder -->
<!-- the subfolders are not created on output and not used by visual-studio, project.asset.json is not updated -->
<!-- directory-structure runtimes\{runtime-identifier}\native should follow .net5 System.Runtime.InteropServices.NativeLibrary -->
<file src="bin\Release\net461\runtimes\**" target="lib\net461\runtimes "/>
<file src="bin\Release\netstandard2.0\runtimes\**" target="lib\netstandard2.0\runtimes "/>
<file src="bin\Release\net461\runtimesv2\**" target="lib\net461\runtimesv2 "/>
<file src="bin\Release\netstandard2.0\runtimesv2\**" target="lib\netstandard2.0\runtimesv2 "/>
<file src="bin\Release\net461\LICENSES\**" target="LICENSES "/>
</files>
</package>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
namespace fiskaltrust.Middleware.SCU.DE.Swissbit.Interop

namespace fiskaltrust.Middleware.SCU.DE.Swissbit.Interop
{
public class FunctionPointerFactory : INativeFunctionPointerFactory
{
Expand All @@ -22,9 +23,6 @@ public class FunctionPointerFactory : INativeFunctionPointerFactory
func_worm_info_isExportEnabledIfCspTestFails = NativeWormAPI.worm_info_isExportEnabledIfCspTestFails,
func_worm_info_initializationState = NativeWormAPI.worm_info_initializationState,
func_worm_info_isDataImportInProgress = NativeWormAPI.worm_info_isDataImportInProgress,
func_worm_info_hasChangedPuk = NativeWormAPI.worm_info_hasChangedPuk,
func_worm_info_hasChangedAdminPin = NativeWormAPI.worm_info_hasChangedAdminPin,
func_worm_info_hasChangedTimeAdminPin = NativeWormAPI.worm_info_hasChangedTimeAdminPin,
func_worm_info_timeUntilNextSelfTest = NativeWormAPI.worm_info_timeUntilNextSelfTest,
func_worm_info_startedTransactions = NativeWormAPI.worm_info_startedTransactions,
func_worm_info_maxStartedTransactions = NativeWormAPI.worm_info_maxStartedTransactions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,8 @@ public interface ISwissbitProxy : IDisposable
public Task ExportTarFilteredTransactionAsync(Stream stream, UInt64 startTransactionNumber, UInt64 endTransactionNumber, string clientId);
public Task<byte[]> GetLogMessageCertificateAsync();
public Task DeleteStoredDataAsync();

public Task TseFactoryReset(bool throwException = true);
public Task<bool> IsV2Async();
}
}
Loading
Loading