Skip to content

Commit c118bc0

Browse files
committed
Move startup jobs into separate classes
1 parent d0dd984 commit c118bc0

23 files changed

+270
-148
lines changed

pass-winmenu/src/Actions/ActionDispatcher.cs

+27-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
4+
using Autofac;
35
using PassWinmenu.Configuration;
46
using PassWinmenu.WinApi;
57

@@ -8,35 +10,28 @@ namespace PassWinmenu.Actions
810
{
911
internal class ActionDispatcher
1012
{
11-
private readonly DecryptPasswordAction decryptPasswordAction;
12-
private readonly GenerateTotpAction generateTotpAction;
13-
private readonly DecryptMetadataAction decryptMetadataAction;
14-
private readonly GetKeyAction getKeyAction;
13+
private readonly ILifetimeScope container;
1514
private readonly IDialogService dialogService;
16-
private readonly Dictionary<HotkeyAction, IAction> actions;
1715

1816
public ActionDispatcher(
19-
DecryptPasswordAction decryptPasswordAction,
20-
GenerateTotpAction generateTotpAction,
21-
DecryptMetadataAction decryptMetadataAction,
22-
GetKeyAction getKeyAction,
23-
IDialogService dialogService,
24-
Dictionary<HotkeyAction, IAction> actions)
17+
ILifetimeScope container,
18+
IDialogService dialogService)
2519
{
26-
this.decryptPasswordAction = decryptPasswordAction;
27-
this.generateTotpAction = generateTotpAction;
28-
this.decryptMetadataAction = decryptMetadataAction;
29-
this.getKeyAction = getKeyAction;
20+
this.container = container;
3021
this.dialogService = dialogService;
31-
this.actions = actions;
3222
}
3323

3424
/// <summary>
3525
/// Asks the user to choose a password file, decrypts it, and copies the resulting value to the clipboard.
3626
/// </summary>
3727
public void DecryptPassword(bool copyToClipboard, bool typeUsername, bool typePassword)
3828
{
39-
Try(() => decryptPasswordAction.Execute(copyToClipboard, typeUsername, typePassword), "Unable to decrypt password");
29+
using var scope = container.BeginLifetimeScope();
30+
var decryptPasswordAction = scope.Resolve<DecryptPasswordAction>();
31+
32+
Try(
33+
() => decryptPasswordAction.Execute(copyToClipboard, typeUsername, typePassword),
34+
"Unable to decrypt password");
4035
}
4136

4237
/// <summary>
@@ -45,21 +40,35 @@ public void DecryptPassword(bool copyToClipboard, bool typeUsername, bool typePa
4540
/// </summary>
4641
public void GenerateTotpCode(bool copyToClipboard, bool typeTotpCode)
4742
{
48-
Try(() => generateTotpAction.GenerateTotpCode(copyToClipboard, typeTotpCode), "Unable to generate TOTP code");
43+
using var scope = container.BeginLifetimeScope();
44+
var generateTotpAction = scope.Resolve<GenerateTotpAction>();
45+
46+
Try(
47+
() => generateTotpAction.GenerateTotpCode(copyToClipboard, typeTotpCode),
48+
"Unable to generate TOTP code");
4949
}
5050

5151
public void DecryptMetadata(bool copyToClipboard, bool type)
5252
{
53+
using var scope = container.BeginLifetimeScope();
54+
var decryptMetadataAction = scope.Resolve<DecryptMetadataAction>();
55+
5356
Try(() => decryptMetadataAction.DecryptMetadata(copyToClipboard, type), "Unable to decrypt metadata");
5457
}
5558

5659
public void DecryptPasswordField(bool copyToClipboard, bool type, string? fieldName = null)
5760
{
61+
using var scope = container.BeginLifetimeScope();
62+
var getKeyAction = scope.Resolve<GetKeyAction>();
63+
5864
Try(() => getKeyAction.GetKey(copyToClipboard, type, fieldName), "Unable to decrypt password field");
5965
}
6066

6167
public void Dispatch(HotkeyAction hotkeyAction)
6268
{
69+
using var scope = container.BeginLifetimeScope();
70+
var actions = scope.Resolve<IEnumerable<IAction>>().ToDictionary(a => a.ActionType);
71+
6372
if (actions.TryGetValue(hotkeyAction, out var action))
6473
{
6574
Try(() => action.Execute(), $"Action '{hotkeyAction}' failed");

pass-winmenu/src/Configuration/ConfigManager.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#nullable enable
88
namespace PassWinmenu.Configuration
99
{
10-
internal class ConfigManager : IDisposable
10+
public class ConfigManager : IDisposable
1111
{
1212
public ConfigurationFile ConfigurationFile { get; private set; }
1313

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace PassWinmenu.Configuration
22
{
3-
internal record ConfigurationFile(
3+
public record ConfigurationFile(
44
string Path,
55
Config Config);
66
}

pass-winmenu/src/Configuration/LoadResult.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace PassWinmenu.Configuration
22
{
3-
internal abstract record LoadResult
3+
public abstract record LoadResult
44
{
55
internal record Success(ConfigManager ConfigManager) : LoadResult;
66
internal record NeedsUpgrade : LoadResult;

pass-winmenu/src/Dependencies.cs

+19-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.IO.Abstractions;
4-
using System.Linq;
53
using System.Reflection;
64
using Autofac;
75
using PassWinmenu.Actions;
86
using PassWinmenu.Configuration;
97
using PassWinmenu.ExternalPrograms;
108
using PassWinmenu.ExternalPrograms.Gpg;
119
using PassWinmenu.Hotkeys;
10+
using PassWinmenu.Jobs;
1211
using PassWinmenu.Notifications;
1312
using PassWinmenu.PasswordManagement;
1413
using PassWinmenu.UpdateChecking;
@@ -24,7 +23,7 @@ internal class DependenciesBuilder
2423

2524
public DependenciesBuilder RegisterDesktopNotifications()
2625
{
27-
builder.Register(ctx => Notifications.Notifications.Create(ctx.Resolve<NotificationConfig>())).AsImplementedInterfaces().SingleInstance();
26+
builder.Register(ctx => Notifications.Notifications.Create(ctx.Resolve<ActionDispatcher>(), ctx.Resolve<NotificationConfig>())).AsImplementedInterfaces().SingleInstance();
2827
builder.RegisterType<GraphicalDialogService>().AsImplementedInterfaces();
2928

3029
return this;
@@ -48,6 +47,7 @@ public DependenciesBuilder RegisterConfiguration(ConfigManager configManager)
4847
builder.Register(_ => configManager.ConfigurationFile.Config.Git).AsSelf();
4948
builder.Register(_ => configManager.ConfigurationFile.Config.Gpg).AsSelf();
5049
builder.Register(_ => configManager.ConfigurationFile.Config.Gpg.GpgAgent).AsSelf();
50+
builder.Register(_ => configManager.ConfigurationFile.Config.Gpg.GpgAgent.Config).AsSelf();
5151
builder.Register(_ => configManager.ConfigurationFile.Config.Interface).AsSelf();
5252
builder.Register(_ => configManager.ConfigurationFile.Config.Interface.PasswordEditor).AsSelf();
5353
builder.Register(_ => configManager.ConfigurationFile.Config.Notifications).AsSelf();
@@ -84,10 +84,7 @@ public DependenciesBuilder RegisterActions()
8484
.AsSelf();
8585
builder.Register(_ => WindowsHotkeyRegistrar.Retrieve()).As<IHotkeyRegistrar>();
8686

87-
builder.RegisterType<ActionDispatcher>()
88-
.WithParameter(
89-
(p, ctx) => p.ParameterType == typeof(Dictionary<HotkeyAction, IAction>),
90-
(info, context) => context.Resolve<IEnumerable<IAction>>().ToDictionary(a => a.ActionType));
87+
builder.RegisterType<ActionDispatcher>().AsSelf();
9188

9289
return this;
9390
}
@@ -167,6 +164,21 @@ public DependenciesBuilder RegisterApplication()
167164
return this;
168165
}
169166

167+
public DependenciesBuilder RegisterJobs()
168+
{
169+
builder.RegisterTypes(
170+
typeof(AssignHotkeys),
171+
typeof(EnableConfigReloading),
172+
typeof(PreloadGpgAgent),
173+
typeof(StartRemoteUpdateChecker),
174+
typeof(StartUpdateChecker),
175+
typeof(UpdateGpgAgentConfig))
176+
.AsImplementedInterfaces()
177+
.AsSelf();
178+
179+
return this;
180+
}
181+
170182
public IContainer Build()
171183
{
172184
return builder.Build();

pass-winmenu/src/ExternalPrograms/Git/RemoteUpdateChecker.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#nullable enable
66
namespace PassWinmenu.ExternalPrograms
77
{
8-
internal class RemoteUpdateChecker: IDisposable
8+
public class RemoteUpdateChecker: IDisposable
99
{
1010
private readonly ISyncService syncService;
1111
private readonly GitConfig gitConfig;

pass-winmenu/src/ExternalPrograms/ISyncService.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace PassWinmenu.ExternalPrograms
44
{
5-
internal interface ISyncService
5+
public interface ISyncService
66
{
77
void AddPassword(string passwordFilePath);
88
void EditPassword(string passwordFilePath);

pass-winmenu/src/ExternalPrograms/ISyncStateTracker.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace PassWinmenu.ExternalPrograms
22
{
3-
internal interface ISyncStateTracker
3+
public interface ISyncStateTracker
44
{
55
void SetSyncState(SyncState state);
66
}

pass-winmenu/src/ExternalPrograms/SyncState.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace PassWinmenu.ExternalPrograms
22
{
3-
internal enum SyncState
3+
public enum SyncState
44
{
55
UpToDate,
66
Ahead,
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using PassWinmenu.Actions;
3+
using PassWinmenu.Configuration;
4+
using PassWinmenu.Hotkeys;
5+
using PassWinmenu.WinApi;
6+
7+
namespace PassWinmenu.Jobs;
8+
9+
internal class AssignHotkeys : IStartupJob
10+
{
11+
private readonly HotkeyService hotkeyService;
12+
private readonly ActionDispatcher actionDispatcher;
13+
private readonly IDialogService dialogService;
14+
private readonly Config config;
15+
16+
public AssignHotkeys(HotkeyService hotkeyService, ActionDispatcher actionDispatcher, IDialogService dialogService, Config config)
17+
{
18+
this.hotkeyService = hotkeyService;
19+
this.actionDispatcher = actionDispatcher;
20+
this.dialogService = dialogService;
21+
this.config = config;
22+
}
23+
24+
/// <summary>
25+
/// Loads keybindings from the configuration file and registers them with Windows.
26+
/// </summary>
27+
public void Run()
28+
{
29+
try
30+
{
31+
hotkeyService.AssignHotkeys(config.Hotkeys, actionDispatcher);
32+
}
33+
catch (Exception e) when (e is HotkeyException)
34+
{
35+
Log.Send("Failed to register hotkeys", LogLevel.Error);
36+
Log.ReportException(e);
37+
38+
dialogService.ShowErrorWindow(e.Message, "Could not register hotkeys");
39+
App.Exit();
40+
}
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using PassWinmenu.Configuration;
2+
3+
namespace PassWinmenu.Jobs;
4+
5+
public class EnableConfigReloading : IStartupJob
6+
{
7+
private readonly ConfigManager configManager;
8+
private readonly ApplicationConfig config;
9+
10+
public EnableConfigReloading(ConfigManager configManager, ApplicationConfig config)
11+
{
12+
this.configManager = configManager;
13+
this.config = config;
14+
}
15+
16+
public void Run()
17+
{
18+
if (config.ReloadConfig)
19+
{
20+
configManager.EnableAutoReloading();
21+
}
22+
}
23+
}

pass-winmenu/src/Jobs/IStartupJob.cs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace PassWinmenu.Jobs;
2+
3+
public interface IStartupJob
4+
{
5+
public void Run();
6+
}
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using PassWinmenu.Configuration;
4+
using PassWinmenu.ExternalPrograms.Gpg;
5+
using PassWinmenu.WinApi;
6+
7+
namespace PassWinmenu.Jobs;
8+
9+
internal class PreloadGpgAgent : IStartupJob
10+
{
11+
private readonly GPG gpg;
12+
private readonly IDialogService dialogService;
13+
private readonly GpgAgentConfig gpgAgentConfig;
14+
15+
public PreloadGpgAgent(GPG gpg, IDialogService dialogService, GpgAgentConfig gpgAgentConfig)
16+
{
17+
this.gpg = gpg;
18+
this.dialogService = dialogService;
19+
this.gpgAgentConfig = gpgAgentConfig;
20+
}
21+
22+
public void Run()
23+
{
24+
try
25+
{
26+
Log.Send("Using GPG version " + gpg.GetVersion());
27+
}
28+
catch (System.ComponentModel.Win32Exception)
29+
{
30+
dialogService.ShowErrorWindow("Could not find GPG. Make sure your gpg-path is set correctly.");
31+
App.Exit();
32+
return;
33+
}
34+
catch (Exception e)
35+
{
36+
dialogService.ShowErrorWindow($"Failed to initialise GPG. {e.GetType().Name}: {e.Message}");
37+
App.Exit();
38+
return;
39+
}
40+
41+
if (gpgAgentConfig.Preload)
42+
{
43+
Task.Run(
44+
() =>
45+
{
46+
try
47+
{
48+
gpg.StartAgent();
49+
}
50+
catch (GpgError err)
51+
{
52+
dialogService.ShowErrorWindow(err.Message);
53+
}
54+
// Ignore other exceptions. If it turns out GPG is misconfigured,
55+
// these errors will surface upon decryption/encryption.
56+
// The reason we catch GpgErrors here is so we can notify the user
57+
// if we don't detect any decryption keys.
58+
});
59+
}
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using PassWinmenu.ExternalPrograms;
2+
using PassWinmenu.Utilities;
3+
4+
namespace PassWinmenu.Jobs;
5+
6+
public class StartRemoteUpdateChecker : IStartupJob
7+
{
8+
private readonly Option<RemoteUpdateChecker> remoteUpdateChecker;
9+
10+
public StartRemoteUpdateChecker(Option<RemoteUpdateChecker> remoteUpdateChecker)
11+
{
12+
this.remoteUpdateChecker = remoteUpdateChecker;
13+
}
14+
15+
public void Run()
16+
{
17+
this.remoteUpdateChecker.Apply(c => c.Start());
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using PassWinmenu.Configuration;
2+
using PassWinmenu.UpdateChecking;
3+
4+
namespace PassWinmenu.Jobs;
5+
6+
public class StartUpdateChecker : IStartupJob
7+
{
8+
private readonly UpdateChecker updateChecker;
9+
private readonly UpdateCheckingConfig config;
10+
11+
public StartUpdateChecker(UpdateChecker updateChecker, UpdateCheckingConfig config)
12+
{
13+
this.updateChecker = updateChecker;
14+
this.config = config;
15+
}
16+
17+
public void Run()
18+
{
19+
if (config.CheckForUpdates)
20+
{
21+
updateChecker.Start();
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)