2024-01-03 23:02:49 +01:00
|
|
|
|
using System.Collections.Concurrent;
|
2023-10-10 17:22:39 +02:00
|
|
|
|
using System.Globalization;
|
2022-07-05 23:14:31 +02:00
|
|
|
|
using System.Text;
|
2019-04-11 20:14:34 +02:00
|
|
|
|
using Bit.Core.Abstractions;
|
|
|
|
|
using Bit.Core.Services;
|
|
|
|
|
|
|
|
|
|
namespace Bit.Core.Utilities
|
|
|
|
|
{
|
|
|
|
|
public static class ServiceContainer
|
|
|
|
|
{
|
2022-07-05 23:14:31 +02:00
|
|
|
|
public static ConcurrentDictionary<string, object> RegisteredServices { get; set; } = new ConcurrentDictionary<string, object>();
|
2019-04-11 20:14:34 +02:00
|
|
|
|
public static bool Inited { get; set; }
|
|
|
|
|
|
2020-10-13 21:39:36 +02:00
|
|
|
|
public static void Init(string customUserAgent = null, string clearCipherCacheKey = null,
|
|
|
|
|
string[] allClearCipherCacheKeys = null)
|
2019-04-11 20:14:34 +02:00
|
|
|
|
{
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (Inited)
|
2019-04-11 20:14:34 +02:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Inited = true;
|
|
|
|
|
|
|
|
|
|
var platformUtilsService = Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
|
|
|
var storageService = Resolve<IStorageService>("storageService");
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var stateService = Resolve<IStateService>("stateService");
|
2019-04-18 16:40:57 +02:00
|
|
|
|
var i18nService = Resolve<II18nService>("i18nService");
|
|
|
|
|
var messagingService = Resolve<IMessagingService>("messagingService");
|
2021-05-21 15:13:54 +02:00
|
|
|
|
var cryptoFunctionService = Resolve<ICryptoFunctionService>("cryptoFunctionService");
|
|
|
|
|
var cryptoService = Resolve<ICryptoService>("cryptoService");
|
2024-03-14 22:12:50 +01:00
|
|
|
|
var clipboardService = Resolve<IClipboardService>();
|
2022-11-15 18:36:21 +01:00
|
|
|
|
var logger = Resolve<ILogger>();
|
|
|
|
|
|
2019-04-24 22:50:34 +02:00
|
|
|
|
SearchService searchService = null;
|
2019-04-11 20:14:34 +02:00
|
|
|
|
|
2023-04-07 19:24:54 +02:00
|
|
|
|
var conditionedRunner = new ConditionedAwaiterManager();
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var tokenService = new TokenService(stateService);
|
|
|
|
|
var apiService = new ApiService(tokenService, platformUtilsService, (extras) =>
|
2019-10-22 22:30:28 +02:00
|
|
|
|
{
|
2022-02-23 18:40:17 +01:00
|
|
|
|
messagingService.Send("logout", extras);
|
2022-03-07 21:15:21 +01:00
|
|
|
|
return Task.CompletedTask;
|
2019-10-22 22:30:28 +02:00
|
|
|
|
}, customUserAgent);
|
2019-04-11 20:14:34 +02:00
|
|
|
|
var appIdService = new AppIdService(storageService);
|
2023-02-20 15:49:20 +01:00
|
|
|
|
var organizationService = new OrganizationService(stateService, apiService);
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var settingsService = new SettingsService(stateService);
|
2021-03-29 16:45:04 +02:00
|
|
|
|
var fileUploadService = new FileUploadService(apiService);
|
2023-09-28 15:00:20 +02:00
|
|
|
|
var configService = new ConfigService(apiService, stateService, logger);
|
2024-03-14 22:12:50 +01:00
|
|
|
|
var totpService = new TotpService(cryptoFunctionService);
|
2024-04-12 20:52:39 +02:00
|
|
|
|
var environmentService = new EnvironmentService(apiService, stateService, conditionedRunner);
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var cipherService = new CipherService(cryptoService, stateService, settingsService, apiService,
|
2024-03-14 22:12:50 +01:00
|
|
|
|
fileUploadService, storageService, i18nService, () => searchService, configService, totpService, clipboardService, clearCipherCacheKey,
|
2022-02-23 18:40:17 +01:00
|
|
|
|
allClearCipherCacheKeys);
|
|
|
|
|
var folderService = new FolderService(cryptoService, stateService, apiService, i18nService, cipherService);
|
|
|
|
|
var collectionService = new CollectionService(cryptoService, stateService, i18nService);
|
|
|
|
|
var sendService = new SendService(cryptoService, stateService, apiService, fileUploadService, i18nService,
|
|
|
|
|
cryptoFunctionService);
|
2021-02-11 01:50:10 +01:00
|
|
|
|
searchService = new SearchService(cipherService, sendService);
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var policyService = new PolicyService(stateService, organizationService);
|
2023-08-17 21:19:35 +02:00
|
|
|
|
var keyConnectorService = new KeyConnectorService(stateService, cryptoService, tokenService, apiService, cryptoFunctionService,
|
2022-02-23 18:40:17 +01:00
|
|
|
|
organizationService);
|
2023-08-17 21:19:35 +02:00
|
|
|
|
var userVerificationService = new UserVerificationService(apiService, platformUtilsService, i18nService,
|
|
|
|
|
cryptoService, stateService, keyConnectorService);
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var vaultTimeoutService = new VaultTimeoutService(cryptoService, stateService, platformUtilsService,
|
2023-09-27 21:26:12 +02:00
|
|
|
|
folderService, cipherService, collectionService, searchService, tokenService, userVerificationService,
|
2022-03-07 18:28:06 +01:00
|
|
|
|
(extras) =>
|
|
|
|
|
{
|
|
|
|
|
messagingService.Send("locked", extras);
|
2022-03-07 21:15:21 +01:00
|
|
|
|
return Task.CompletedTask;
|
2022-03-07 18:28:06 +01:00
|
|
|
|
},
|
|
|
|
|
(extras) =>
|
2020-05-29 18:26:36 +02:00
|
|
|
|
{
|
2022-02-23 18:40:17 +01:00
|
|
|
|
messagingService.Send("logout", extras);
|
2022-03-07 21:15:21 +01:00
|
|
|
|
return Task.CompletedTask;
|
2020-05-29 18:26:36 +02:00
|
|
|
|
});
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var syncService = new SyncService(stateService, apiService, settingsService, folderService, cipherService,
|
|
|
|
|
cryptoService, collectionService, organizationService, messagingService, policyService, sendService,
|
2022-11-15 18:36:21 +01:00
|
|
|
|
keyConnectorService, logger, (extras) =>
|
2019-10-22 22:30:28 +02:00
|
|
|
|
{
|
2022-02-23 18:40:17 +01:00
|
|
|
|
messagingService.Send("logout", extras);
|
2022-03-07 21:15:21 +01:00
|
|
|
|
return Task.CompletedTask;
|
2019-10-22 22:30:28 +02:00
|
|
|
|
});
|
2023-05-11 18:41:32 +02:00
|
|
|
|
var passwordGenerationService = new PasswordGenerationService(cryptoService, stateService, cryptoFunctionService, policyService);
|
2023-08-17 21:19:35 +02:00
|
|
|
|
var deviceTrustCryptoService = new DeviceTrustCryptoService(apiService, appIdService, cryptoFunctionService, cryptoService, stateService);
|
|
|
|
|
var passwordResetEnrollmentService = new PasswordResetEnrollmentService(apiService, cryptoService, organizationService, stateService);
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, stateService,
|
2023-08-17 21:19:35 +02:00
|
|
|
|
tokenService, appIdService, i18nService, platformUtilsService, messagingService,
|
|
|
|
|
keyConnectorService, passwordGenerationService, policyService, deviceTrustCryptoService, passwordResetEnrollmentService);
|
2021-05-28 22:16:19 +02:00
|
|
|
|
var exportService = new ExportService(folderService, cipherService, cryptoService);
|
2019-04-18 16:40:57 +02:00
|
|
|
|
var auditService = new AuditService(cryptoFunctionService, apiService);
|
2022-02-23 18:40:17 +01:00
|
|
|
|
var eventService = new EventService(apiService, stateService, organizationService, cipherService);
|
2022-08-26 20:32:02 +02:00
|
|
|
|
var usernameGenerationService = new UsernameGenerationService(cryptoService, apiService, stateService);
|
2019-04-11 20:14:34 +02:00
|
|
|
|
|
2023-04-07 19:24:54 +02:00
|
|
|
|
Register<IConditionedAwaiterManager>(conditionedRunner);
|
2019-04-11 20:14:34 +02:00
|
|
|
|
Register<ITokenService>("tokenService", tokenService);
|
2019-04-18 16:40:57 +02:00
|
|
|
|
Register<IApiService>("apiService", apiService);
|
2019-04-11 20:14:34 +02:00
|
|
|
|
Register<IAppIdService>("appIdService", appIdService);
|
2022-02-23 18:40:17 +01:00
|
|
|
|
Register<IOrganizationService>("organizationService", organizationService);
|
2019-04-18 16:40:57 +02:00
|
|
|
|
Register<ISettingsService>("settingsService", settingsService);
|
2023-09-28 15:00:20 +02:00
|
|
|
|
Register<IConfigService>(configService);
|
2019-04-18 16:40:57 +02:00
|
|
|
|
Register<ICipherService>("cipherService", cipherService);
|
|
|
|
|
Register<IFolderService>("folderService", folderService);
|
|
|
|
|
Register<ICollectionService>("collectionService", collectionService);
|
2021-02-11 01:50:10 +01:00
|
|
|
|
Register<ISendService>("sendService", sendService);
|
2019-04-24 22:50:34 +02:00
|
|
|
|
Register<ISearchService>("searchService", searchService);
|
2020-02-21 16:23:38 +01:00
|
|
|
|
Register<IPolicyService>("policyService", policyService);
|
2019-04-18 16:40:57 +02:00
|
|
|
|
Register<ISyncService>("syncService", syncService);
|
2023-08-17 21:19:35 +02:00
|
|
|
|
Register<IKeyConnectorService>("keyConnectorService", keyConnectorService);
|
|
|
|
|
Register<IUserVerificationService>(userVerificationService);
|
2020-05-29 18:26:36 +02:00
|
|
|
|
Register<IVaultTimeoutService>("vaultTimeoutService", vaultTimeoutService);
|
2019-04-18 16:40:57 +02:00
|
|
|
|
Register<IPasswordGenerationService>("passwordGenerationService", passwordGenerationService);
|
|
|
|
|
Register<ITotpService>("totpService", totpService);
|
|
|
|
|
Register<IAuthService>("authService", authService);
|
2020-02-14 22:10:58 +01:00
|
|
|
|
Register<IExportService>("exportService", exportService);
|
2019-04-18 16:40:57 +02:00
|
|
|
|
Register<IAuditService>("auditService", auditService);
|
2019-04-18 18:21:35 +02:00
|
|
|
|
Register<IEnvironmentService>("environmentService", environmentService);
|
2019-07-12 21:51:47 +02:00
|
|
|
|
Register<IEventService>("eventService", eventService);
|
2022-08-26 20:32:02 +02:00
|
|
|
|
Register<IUsernameGenerationService>(usernameGenerationService);
|
2023-08-17 21:19:35 +02:00
|
|
|
|
Register<IDeviceTrustCryptoService>(deviceTrustCryptoService);
|
|
|
|
|
Register<IPasswordResetEnrollmentService>(passwordResetEnrollmentService);
|
2019-04-11 20:14:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Register<T>(string serviceName, T obj)
|
|
|
|
|
{
|
2022-07-05 23:14:31 +02:00
|
|
|
|
if (!RegisteredServices.TryAdd(serviceName, obj))
|
2019-04-11 20:14:34 +02:00
|
|
|
|
{
|
|
|
|
|
throw new Exception($"Service {serviceName} has already been registered.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static T Resolve<T>(string serviceName, bool dontThrow = false)
|
|
|
|
|
{
|
2022-07-05 23:14:31 +02:00
|
|
|
|
if (RegisteredServices.TryGetValue(serviceName, out var service))
|
2019-04-11 20:14:34 +02:00
|
|
|
|
{
|
2022-07-05 23:14:31 +02:00
|
|
|
|
return (T)service;
|
2019-04-11 20:14:34 +02:00
|
|
|
|
}
|
2020-03-28 14:16:28 +01:00
|
|
|
|
if (dontThrow)
|
2019-04-11 20:14:34 +02:00
|
|
|
|
{
|
|
|
|
|
return (T)(object)null;
|
|
|
|
|
}
|
|
|
|
|
throw new Exception($"Service {serviceName} is not registered.");
|
|
|
|
|
}
|
2019-06-28 17:47:04 +02:00
|
|
|
|
|
2022-07-05 23:14:31 +02:00
|
|
|
|
public static void Register<T>(T obj)
|
|
|
|
|
where T : class
|
|
|
|
|
{
|
|
|
|
|
Register(typeof(T), obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Register(Type type, object obj)
|
|
|
|
|
{
|
|
|
|
|
var serviceName = GetServiceRegistrationName(type);
|
|
|
|
|
if (!RegisteredServices.TryAdd(serviceName, obj))
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"Service {serviceName} has already been registered.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static T Resolve<T>()
|
|
|
|
|
where T : class
|
|
|
|
|
{
|
|
|
|
|
return (T)Resolve(typeof(T));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static object Resolve(Type type)
|
|
|
|
|
{
|
|
|
|
|
var serviceName = GetServiceRegistrationName(type);
|
|
|
|
|
if (RegisteredServices.TryGetValue(serviceName, out var service))
|
|
|
|
|
{
|
|
|
|
|
return service;
|
|
|
|
|
}
|
|
|
|
|
throw new Exception($"Service {serviceName} is not registered.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool TryResolve<T>(out T service)
|
|
|
|
|
where T : class
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var toReturn = TryResolve(typeof(T), out var serviceObj);
|
|
|
|
|
service = (T)serviceObj;
|
|
|
|
|
return toReturn;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
service = null;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static bool TryResolve(Type type, out object service)
|
|
|
|
|
{
|
|
|
|
|
var serviceName = GetServiceRegistrationName(type);
|
|
|
|
|
return RegisteredServices.TryGetValue(serviceName, out service);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-28 17:47:04 +02:00
|
|
|
|
public static void Reset()
|
|
|
|
|
{
|
2020-05-28 21:44:27 +02:00
|
|
|
|
foreach (var service in RegisteredServices)
|
|
|
|
|
{
|
|
|
|
|
if (service.Value != null && service.Value is IDisposable disposableService)
|
|
|
|
|
{
|
|
|
|
|
disposableService.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-28 17:47:04 +02:00
|
|
|
|
Inited = false;
|
|
|
|
|
RegisteredServices.Clear();
|
2022-07-05 23:14:31 +02:00
|
|
|
|
RegisteredServices = new ConcurrentDictionary<string, object>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the service registration name
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="type">Type of the service</param>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// In order to work with already register/resolve we need to maintain the naming convention
|
|
|
|
|
/// of camelCase without the first "I" on the services interfaces
|
|
|
|
|
/// e.g. "ITokenService" -> "tokenService"
|
|
|
|
|
/// </remarks>
|
|
|
|
|
static string GetServiceRegistrationName(Type type)
|
|
|
|
|
{
|
|
|
|
|
var typeName = type.Name;
|
|
|
|
|
var sb = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
var indexToLowerCase = 0;
|
|
|
|
|
if (typeName[0] == 'I' && char.IsUpper(typeName[1]))
|
|
|
|
|
{
|
|
|
|
|
// if it's an interface then we ignore the first char
|
|
|
|
|
// and lower case the 2nd one (index 1)
|
|
|
|
|
indexToLowerCase = 1;
|
|
|
|
|
}
|
2023-10-10 17:22:39 +02:00
|
|
|
|
sb.Append(char.ToLower(typeName[indexToLowerCase], new CultureInfo("en-US")));
|
2022-07-05 23:14:31 +02:00
|
|
|
|
sb.Append(typeName.Substring(++indexToLowerCase));
|
|
|
|
|
return sb.ToString();
|
2019-06-28 17:47:04 +02:00
|
|
|
|
}
|
2019-04-11 20:14:34 +02:00
|
|
|
|
}
|
|
|
|
|
}
|