Linux admin mode

This commit is contained in:
2023-08-30 01:04:05 +02:00
parent 7df9c28172
commit 880180f16a
9 changed files with 106 additions and 20 deletions

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"dotnet.defaultSolution": "src/FileTime.sln"
}

View File

@@ -1,3 +1,4 @@
using System.Runtime.InteropServices;
using FileTime.App.Core.UserCommand; using FileTime.App.Core.UserCommand;
using FileTime.Providers.LocalAdmin; using FileTime.Providers.LocalAdmin;
using GeneralInputKey; using GeneralInputKey;
@@ -12,9 +13,12 @@ public class MainConfiguration
static MainConfiguration() static MainConfiguration()
{ {
var serverFileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? "FileTime.Server.exe"
: "FileTime.Server";
Configuration = new() Configuration = new()
{ {
{AdminElevationConfiguration.SectionName + ":" + nameof(AdminElevationConfiguration.ServerExecutablePath), "FileTime.Server.exe"}, {AdminElevationConfiguration.SectionName + ":" + nameof(AdminElevationConfiguration.ServerExecutablePath), serverFileName},
}; };
PopulateDefaultEditorPrograms(Configuration); PopulateDefaultEditorPrograms(Configuration);

View File

@@ -1,10 +1,17 @@
namespace FileTime.ConsoleUI.App; using FileTime.Providers.LocalAdmin;
namespace FileTime.ConsoleUI.App;
public class MainConsoleConfiguration public class MainConsoleConfiguration
{ {
public static Dictionary<string, string?> Configuration { get; } public static Dictionary<string, string?> Configuration { get; }
static MainConsoleConfiguration() static MainConsoleConfiguration()
{ {
Configuration = new(); Configuration = new()
{
{
AdminElevationConfiguration.SectionName + ":" + nameof(AdminElevationConfiguration.LinuxElevationTool), "sudo"
},
};
} }
} }

View File

@@ -0,0 +1,18 @@
using FileTime.Providers.LocalAdmin;
namespace FileTime.GuiApp.App.Configuration;
public class MainGuiConfiguration
{
public static Dictionary<string, string?> Configuration { get; }
static MainGuiConfiguration()
{
Configuration = new()
{
{
AdminElevationConfiguration.SectionName + ":" + nameof(AdminElevationConfiguration.LinuxElevationTool), "pkexec"
},
};
}
}

View File

@@ -55,6 +55,7 @@
<ProjectReference Include="..\FileTime.GuiApp.App.Abstractions\FileTime.GuiApp.App.Abstractions.csproj" /> <ProjectReference Include="..\FileTime.GuiApp.App.Abstractions\FileTime.GuiApp.App.Abstractions.csproj" />
<ProjectReference Include="..\FileTime.GuiApp.DesignPreview\FileTime.GuiApp.DesignPreview.csproj" /> <ProjectReference Include="..\FileTime.GuiApp.DesignPreview\FileTime.GuiApp.DesignPreview.csproj" />
<ProjectReference Include="..\FileTime.GuiApp.Font.Abstractions\FileTime.GuiApp.Font.Abstractions.csproj" /> <ProjectReference Include="..\FileTime.GuiApp.Font.Abstractions\FileTime.GuiApp.Font.Abstractions.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -5,6 +5,7 @@ using FileTime.App.Core.Configuration;
using FileTime.App.Core.Services; using FileTime.App.Core.Services;
using FileTime.App.Core.ViewModels; using FileTime.App.Core.ViewModels;
using FileTime.Core.Interactions; using FileTime.Core.Interactions;
using FileTime.GuiApp.App.Configuration;
using FileTime.GuiApp.CustomImpl.ViewModels; using FileTime.GuiApp.CustomImpl.ViewModels;
using FileTime.GuiApp.App.IconProviders; using FileTime.GuiApp.App.IconProviders;
using FileTime.GuiApp.App.InstanceManagement; using FileTime.GuiApp.App.InstanceManagement;
@@ -26,6 +27,7 @@ public static class Startup
{ {
var configurationBuilder = new ConfigurationBuilder() var configurationBuilder = new ConfigurationBuilder()
.AddInMemoryCollection(MainConfiguration.Configuration) .AddInMemoryCollection(MainConfiguration.Configuration)
.AddInMemoryCollection(MainGuiConfiguration.Configuration)
.AddJsonFile("appsettings.json", optional: true) .AddJsonFile("appsettings.json", optional: true)
.AddJsonFile($"appsettings.{Program.EnvironmentName}.json", true) .AddJsonFile($"appsettings.{Program.EnvironmentName}.json", true)
.AddJsonFile("appsettings.Local.json", optional: true); .AddJsonFile("appsettings.Local.json", optional: true);

View File

@@ -4,6 +4,7 @@ public class AdminElevationConfiguration
{ {
public const string SectionName = "AdminElevation"; public const string SectionName = "AdminElevation";
public string ServerExecutablePath { get; set; } public string ServerExecutablePath { get; set; }
public string LinuxElevationTool { get; set; }
public int? ServerPort { get; set; } public int? ServerPort { get; set; }
public bool? StartProcess { get; set; } public bool? StartProcess { get; set; }
} }

View File

@@ -1,6 +1,7 @@
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using FileTime.App.Core.Services; using FileTime.App.Core.Services;
using FileTime.Core.Interactions; using FileTime.Core.Interactions;
using FileTime.Core.Timeline; using FileTime.Core.Timeline;
@@ -73,30 +74,28 @@ public class AdminElevationManager : IAdminElevationManager, INotifyPropertyChan
var port = _configuration.CurrentValue.ServerPort; var port = _configuration.CurrentValue.ServerPort;
_logger.LogTrace("Admin server port is {Port}", port is null ? "<not set>" : $"{port}"); _logger.LogTrace("Admin server port is {Port}", port is null ? "<not set>" : $"{port}");
if (StartProcess || port is null) if (StartProcess || port is null)
{ {
var portFileName = Path.GetTempFileName(); var portFileName = Path.GetTempFileName();
var process = new Process File.Delete(portFileName);
{
StartInfo = new() var process = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
{ ? CreateWindowsAdminProcess(portFileName)
FileName = _configuration.CurrentValue.ServerExecutablePath, : CreateLinuxAdminProcess(portFileName);
ArgumentList =
{
"--PortWriter:FileName",
portFileName
},
UseShellExecute = true,
Verb = "runas"
},
EnableRaisingEvents = true
};
process.Exited += ProcessExitHandler; process.Exited += ProcessExitHandler;
process.Start(); process.Start();
_adminProcess = process; _adminProcess = process;
//TODO: timeout //TODO: timeout
while (!File.Exists(portFileName) || new FileInfo(portFileName).Length == 0) while (!File.Exists(portFileName) || new FileInfo(portFileName).Length == 0)
{
await Task.Delay(10); await Task.Delay(10);
if (process.HasExited)
{
throw new Exception(
$"Server process exited with code {process.ExitCode} without creating the port file"
);
}
}
var content = await File.ReadAllLinesAsync(portFileName); var content = await File.ReadAllLinesAsync(portFileName);
if (int.TryParse(content.FirstOrDefault(), out var parsedPort)) if (int.TryParse(content.FirstOrDefault(), out var parsedPort))
@@ -132,6 +131,42 @@ public class AdminElevationManager : IAdminElevationManager, INotifyPropertyChan
} }
} }
private Process CreateWindowsAdminProcess(string portFileName)
=> new()
{
StartInfo = new()
{
FileName = _configuration.CurrentValue.ServerExecutablePath,
ArgumentList =
{
"--PortWriter:FileName",
portFileName
},
UseShellExecute = true,
Verb = "runas"
},
EnableRaisingEvents = true
};
private Process CreateLinuxAdminProcess(string portFileName)
{
return new Process
{
StartInfo = new()
{
FileName = _configuration.CurrentValue.LinuxElevationTool,
ArgumentList =
{
_configuration.CurrentValue.ServerExecutablePath,
"--PortWriter:FileName",
portFileName
},
CreateNoWindow = true
},
EnableRaisingEvents = true
};
}
//Note: this does not have to return a task //Note: this does not have to return a task
public Task<IRemoteContentProvider> GetRemoteContentProviderAsync() public Task<IRemoteContentProvider> GetRemoteContentProviderAsync()
{ {

View File

@@ -44,7 +44,6 @@ public class PortWriterService : IHostedService
return; return;
} }
using var tempFileStream = File.CreateText(filename);
var address = GetAddress(); var address = GetAddress();
if (address is null) if (address is null)
{ {
@@ -59,7 +58,23 @@ public class PortWriterService : IHostedService
return; return;
} }
_logger.LogInformation("Writing port to {PortFile}", filename);
using var tempFileStream = File.CreateText(filename);
tempFileStream.Write(port.ToString()); tempFileStream.Write(port.ToString());
Task.Run(async () =>
{
await Task.Delay(5000);
try
{
_logger.LogInformation("Deleting port file {PortFile}", filename);
File.Delete(filename);
}
catch (Exception e)
{
_logger.LogError(e, "Error while deleting port file {PortFile}", filename);
}
});
} }
catch (Exception ex) catch (Exception ex)
{ {