Hermod
A cross-platform, modular and fully GDPR-compliant email archival solution!
Loading...
Searching...
No Matches
EmailImporter.cs
Go to the documentation of this file.
1using System;
2
3namespace Hermod.EmailImport {
4
5 using Data;
6 using Exceptions;
7
8 using Config;
9 using Core;
10 using Core.Attributes;
11 using Core.Commands;
12 using Core.Delegation;
13 using PluginFramework;
14
15 using System.Text;
16 using System.Buffers.Text;
17
21 [Plugin(nameof(EmailImporter), "0.0.1", "Simon Cahill", "contact@simonc.eu", "https://simonc.eu")]
22 public partial class EmailImporter: Plugin {
23
24 const string GetDomainTopicAllSuffix = "all";
25 const string AddDomainTopic = "/hermod/domain/add";
26 const string GetDomainTopic = "/hermod/domain/get/+";
27 const string RemoveDomainTopic = "/hermod/domain/remove/+";
28 const string GetDomainResponseTopic = "/hermod/domain/response";
29 const string GetDomainUserTopic = "/hermod/user/get";
30 const string AddDomainUserTopic = "/hermod/user/add/+";
31 const string RemoveDomainUserTopic = "/hermod/user/remove";
32
33 private readonly string[] m_subscribeTopics = {
36 };
37
38 volatile bool m_keepThreadAlive = false;
41 Thread? m_importThread = null;
42
43 public EmailImporter(): base(nameof(EmailImporter), new Version(0, 0, 1)) {
44 PluginCommands = new List<ICommand> {
46 "get-domains", "Gets a list of all known domains",
47 "This command retrieves a list of all domains currently\n" +
48 "known to the Hermod EmailImporter.\n" +
49 "Usage: get-domains [tld [tld]] # only with these TLDs",
51 ),
53 "get-domain", "Gets information about a single domain",
54 "This command retrieves a single domain and information about it.\n" +
55 "Usage: get-domain <domain-name>",
57 ),
59 "add-domain", "Adds a new domain to the system",
60 "This command allows a new domain to be added to Hermod.\n" +
61 "Usage: add-domain <domain-name [domain-name [...]]> # domain-name is expected as tld.domain[.subdomain]",
63 ),
65 "remove-domain", "Removes one or more domains from the system",
66 "This command removes one or more domains from Hermod.\n" +
67 "Usage: remove-domain <domain-name [domain-name [...]]> # domain-name is expected as tld.domain[.subdomain]",
69 ),
71 "get-users", "Retrieves a list of all users in a domain",
72 "This command retrieves a list of all users allocated to a domain.\n" +
73 "Usage: get-users [domain-name] # domain-name is expected as tld.domain[.subdomain]",
75 ),
77 "get-user", "Gets detailled information about a single user",
78 "This command allows retrievel of detailled information,\n" +
79 "such as email address, password hash, salt and account type\n" +
80 "in a single domain.\n" +
81 "Usage: get-user <domain> <user>",
83 ),
85 "add-user", "Adds a single user to a domain",
86 "This command adds a single user to a single domain,\n" +
87 "provided info: user name, password, password salt, and account type.\n" +
88 "Usage: add-user <domain> <user> <password> <account type>\n" +
89 "Note: this is the only time Hermod will know of the user's cleartext password!",
91 ),
93 "remove-user", "Removes a single user from a domain",
94 "This command allows a single user to be removed from a domain.\n" +
95 "!! WARNING !! This process is irreversible!\n" +
96 "Usage: remove-user <domain> <user>",
98 )
99 };
100 }
101
102 public override void OnConfigChanged(ConfigChangedEventArgs e) { }
103
104 public override void OnConfigLoaded() { }
105
106 public override void OnLoad(IPluginDelegator pluginDelegator) {
107 m_pluginDelegator = pluginDelegator;
108
109 if (m_pluginDelegator.GetApplicationConfig<bool>("Accounts.UseDatabase")) {
110 // dynamic dbInfo = m_pluginDelegator.GetApplicationConfig<object>("Accounts.DatabaseInfo");
111 // m_dbConnector = new MySqlDatabaseConnector(
112 // dbInfo.Host,
113 // dbInfo.DatabaseUser,
114 // dbInfo.DatabasePass,
115 // dbInfo.DatabaseName,
116 // pluginDelegator
117 // );
118 throw new Exception("MySqlDatabaseConnector is not usable in this version!");
119 } else if (m_pluginDelegator.GetApplicationConfig<bool>("Accounts.UseJsonFile")) {
120 var filePath = m_pluginDelegator.GetApplicationConfig<string?>("Accounts.JsonFileInfo.FilePath");
121 if (filePath is null) {
122 filePath = AppInfo.GetLocalHermodDirectory().GetSubFile(".accounts.json").FullName;
123 }
124
125 byte[] encKey = null;
126 byte[] initVec = null;
127
128 void GetEncryptionData(ref byte[] encKey, ref byte[] initVec) {
129 var tmpKey = m_pluginDelegator?.GetApplicationConfig<string?>("Accounts.EncryptionKey");
130 if (string.IsNullOrEmpty(tmpKey)) {
131 m_pluginDelegator?.Information("Found invalid encryption keys! Generating new encryption data...");
132 JsonDatabaseConnector.GenerateNewAesKey(out encKey, out initVec);
133 return;
134 }
135 Base64.DecodeFromUtf8(Encoding.UTF8.GetBytes(tmpKey), encKey, out _, out _);
136
137 tmpKey = m_pluginDelegator?.GetApplicationConfig<string?>("Accounts.EncryptionInitVec");
138 if (string.IsNullOrEmpty(tmpKey)) {
139 m_pluginDelegator?.Information("Found invalid encryption keys! Generating new encryption data...");
140 JsonDatabaseConnector.GenerateNewAesKey(out encKey, out initVec);
141 return;
142 }
143
144 Base64.DecodeFromUtf8(Encoding.UTF8.GetBytes(tmpKey), initVec, out _, out _);
145 }
146
147 GetEncryptionData(ref encKey, ref initVec);
149 new FileInfo(filePath),
150 encKey, initVec
151 );
152 } else {
153 throw new InvalidDataSourceException();
154 }
155
156 m_pluginDelegator.Debug("Subscribing all topics...");
157 pluginDelegator.SubscribeTopics(m_subscribeTopics);
158
159 m_pluginDelegator.Information("Email Importer has loaded!");
160 }
161
162 public override void OnStart() {
163 m_keepThreadAlive = true;
164 m_importThread = new Thread(DoWork);
165 m_importThread.Start();
166 }
167
168 public override void OnStop() {
169 m_pluginDelegator?.Information("Stopping worker threads...");
170 m_keepThreadAlive = false;
171 }
172 }
173}
174
Event arguments for when a configuration has changed.
Static class containing basic information for and about the application.
Definition: AppInfo.cs:10
static DirectoryInfo GetLocalHermodDirectory()
Gets the application's local data directory.
Definition: AppInfo.cs:59
Represents a single command that can only be executed on the (interactive) terminal.
Defines a simple contract between the EmailImport plugin and any database connectors.
A DatabaseConnector which "connects" to an encrypted JSON file containing all domain and user informa...
static void GenerateNewAesKey(out byte[] key, out byte[] initVector)
Generates a new AES encryption key with init vector.
ICommandResult Handle_AddUser(params string[] args)
override void OnConfigChanged(ConfigChangedEventArgs e)
Method that is called when an application-wide configuration has been modified.
ICommandResult Handle_GetDomains(params string[] args)
const string GetDomainTopic
The topic EmailImport subscribes to add a new domain.
override void OnLoad(IPluginDelegator pluginDelegator)
Method that is called once the plugin has been loaded. This may be used for pre-init purposes.
IPluginDelegator? m_pluginDelegator
const string GetDomainUserTopic
The topic EmailImport publishes to when a topic was requested.
ICommandResult Handle_AddDomain(params string[] args)
ICommandResult Handle_RemoveDomain(params string[] args)
const string RemoveDomainUserTopic
The topic EmailImport subscribes to when a user is to be added to a domain.
DatabaseConnector? m_dbConnector
override void OnConfigLoaded()
Method that is called when the application-wide configurations have been loaded.
ICommandResult Handle_GetUsers(params string[] args)
ICommandResult Handle_GetSingleDomain(params string[] args)
override void OnStop()
Method that is called when Hermod is shutting down.
ICommandResult Handle_GetUser(params string[] args)
const string RemoveDomainTopic
The topic EmailImport subscribes when another plugin requests a domain.
readonly string[] m_subscribeTopics
The topic EmailImport subscribes to when a user is to be removed from a domain.
const string AddDomainUserTopic
The topic EmailImport subscribes to when a user is requested.
override void OnStart()
Method that is called once Hermod has completed its startup procedures and is ready to run.
const string GetDomainResponseTopic
The topic EmailImport subscribes to when a domain shall be removed.
ICommandResult Handle_RemoveUser(params string[] args)
Exception class that is thrown when an invalid data source was set in the application configuration.
List< ICommand > PluginCommands
A list of all commands this plugin provides.
Definition: Plugin.cs:34
Basic contract between Hermod and any laoded plugins which allows jobs to be delegated to other plugi...
void SubscribeTopics(params string[] topics)
Allows a plugin to subscribe to multiple individual topics.
void Debug(string? msg)
Logs a debug message to the logger.
void Information(string? msg)
Logs an information message to the logger.