diff options
Diffstat (limited to 'Emby.Server.Implementations/Security')
3 files changed, 324 insertions, 266 deletions
diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index b1877d776..45f7f1e95 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -11,19 +11,21 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; using SQLitePCL.pretty; using MediaBrowser.Model.Extensions; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Devices; namespace Emby.Server.Implementations.Security { public class AuthenticationRepository : BaseSqliteRepository, IAuthenticationRepository { - private readonly IServerApplicationPaths _appPaths; + private readonly IServerConfigurationManager _config; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - public AuthenticationRepository(ILogger logger, IServerApplicationPaths appPaths) + public AuthenticationRepository(ILogger logger, IServerConfigurationManager config) : base(logger) { - _appPaths = appPaths; - DbFilePath = Path.Combine(appPaths.DataPath, "authentication.db"); + _config = config; + DbFilePath = Path.Combine(config.ApplicationPaths.DataPath, "authentication.db"); } public void Initialize() @@ -32,99 +34,171 @@ namespace Emby.Server.Implementations.Security { RunDefaultInitialization(connection); + var tableNewlyCreated = !TableExists(connection, "Tokens"); + string[] queries = { - "create table if not exists AccessTokens (Id GUID PRIMARY KEY NOT NULL, AccessToken TEXT NOT NULL, DeviceId TEXT NOT NULL, AppName TEXT NOT NULL, AppVersion TEXT NOT NULL, DeviceName TEXT NOT NULL, UserId TEXT, IsActive BIT NOT NULL, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)", - "create index if not exists idx_AccessTokens on AccessTokens(Id)" + "create table if not exists Tokens (Id INTEGER PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT NOT NULL, AppName TEXT NOT NULL, AppVersion TEXT NOT NULL, DeviceName TEXT NOT NULL, UserId TEXT, UserName TEXT, IsActive BIT NOT NULL, DateCreated DATETIME NOT NULL, DateLastActivity DATETIME NOT NULL)", + "create table if not exists Devices (Id TEXT NOT NULL PRIMARY KEY, CustomName TEXT, Capabilities TEXT)", + + "drop index if exists idx_AccessTokens", + "drop index if exists Tokens1", + "drop index if exists Tokens2", + "create index if not exists Tokens3 on Tokens (AccessToken, DateLastActivity)", + "create index if not exists Tokens4 on Tokens (Id, DateLastActivity)", + "create index if not exists Devices1 on Devices (Id)" }; connection.RunQueries(queries); - connection.RunInTransaction(db => + TryMigrate(connection, tableNewlyCreated); + } + } + + private void TryMigrate(ManagedConnection connection, bool tableNewlyCreated) + { + try + { + if (tableNewlyCreated && TableExists(connection, "AccessTokens")) { - var existingColumnNames = GetColumnNames(db, "AccessTokens"); + connection.RunInTransaction(db => + { + var existingColumnNames = GetColumnNames(db, "AccessTokens"); + + AddColumn(db, "AccessTokens", "UserName", "TEXT", existingColumnNames); + AddColumn(db, "AccessTokens", "DateLastActivity", "DATETIME", existingColumnNames); + AddColumn(db, "AccessTokens", "AppVersion", "TEXT", existingColumnNames); - AddColumn(db, "AccessTokens", "AppVersion", "TEXT", existingColumnNames); + }, TransactionMode); - }, TransactionMode); + connection.RunQueries(new[] + { + "update accesstokens set DateLastActivity=DateCreated where DateLastActivity is null", + "update accesstokens set DeviceName='Unknown' where DeviceName is null", + "update accesstokens set AppName='Unknown' where AppName is null", + "update accesstokens set AppVersion='1' where AppVersion is null", + "INSERT INTO Tokens (AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity) SELECT AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity FROM AccessTokens where deviceid not null and devicename not null and appname not null and isactive=1" + }); + } + } + catch (Exception ex) + { + Logger.ErrorException("Error migrating authentication database", ex); } } - public void Create(AuthenticationInfo info, CancellationToken cancellationToken) + public void Create(AuthenticationInfo info) { - info.Id = Guid.NewGuid().ToString("N"); + if (info == null) + { + throw new ArgumentNullException("info"); + } + + using (WriteLock.Write()) + { + using (var connection = CreateConnection()) + { + connection.RunInTransaction(db => + { + using (var statement = db.PrepareStatement("insert into Tokens (AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity) values (@AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @UserName, @IsActive, @DateCreated, @DateLastActivity)")) + { + statement.TryBind("@AccessToken", info.AccessToken); + + statement.TryBind("@DeviceId", info.DeviceId); + statement.TryBind("@AppName", info.AppName); + statement.TryBind("@AppVersion", info.AppVersion); + statement.TryBind("@DeviceName", info.DeviceName); + statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N"))); + statement.TryBind("@UserName", info.UserName); + statement.TryBind("@IsActive", true); + statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue()); + statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue()); + + statement.MoveNext(); + } - Update(info, cancellationToken); + }, TransactionMode); + } + } } - public void Update(AuthenticationInfo info, CancellationToken cancellationToken) + public void Update(AuthenticationInfo info) { if (info == null) { - throw new ArgumentNullException("info"); + throw new ArgumentNullException("entry"); } - cancellationToken.ThrowIfCancellationRequested(); - using (WriteLock.Write()) { using (var connection = CreateConnection()) { connection.RunInTransaction(db => { - using (var statement = db.PrepareStatement("replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)")) + using (var statement = db.PrepareStatement("Update Tokens set AccessToken=@AccessToken, DeviceId=@DeviceId, AppName=@AppName, AppVersion=@AppVersion, DeviceName=@DeviceName, UserId=@UserId, UserName=@UserName, DateCreated=@DateCreated, DateLastActivity=@DateLastActivity where Id=@Id")) { - statement.TryBind("@Id", info.Id.ToGuidBlob()); + statement.TryBind("@Id", info.Id); + statement.TryBind("@AccessToken", info.AccessToken); statement.TryBind("@DeviceId", info.DeviceId); statement.TryBind("@AppName", info.AppName); statement.TryBind("@AppVersion", info.AppVersion); statement.TryBind("@DeviceName", info.DeviceName); - statement.TryBind("@UserId", info.UserId); - statement.TryBind("@IsActive", info.IsActive); + statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N"))); + statement.TryBind("@UserName", info.UserName); statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue()); - - if (info.DateRevoked.HasValue) - { - statement.TryBind("@DateRevoked", info.DateRevoked.Value.ToDateTimeParamValue()); - } - else - { - statement.TryBindNull("@DateRevoked"); - } + statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue()); statement.MoveNext(); } + }, TransactionMode); + } + } + } + + public void Delete(AuthenticationInfo info) + { + if (info == null) + { + throw new ArgumentNullException("entry"); + } + using (WriteLock.Write()) + { + using (var connection = CreateConnection()) + { + connection.RunInTransaction(db => + { + using (var statement = db.PrepareStatement("Delete from Tokens where Id=@Id")) + { + statement.TryBind("@Id", info.Id); + + statement.MoveNext(); + } }, TransactionMode); } } } - private const string BaseSelectText = "select Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked from AccessTokens"; + private const string BaseSelectText = "select Tokens.Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, DateCreated, DateLastActivity, Devices.CustomName from Tokens left join Devices on Tokens.DeviceId=Devices.Id"; private void BindAuthenticationQueryParams(AuthenticationInfoQuery query, IStatement statement) { - if (!string.IsNullOrWhiteSpace(query.AccessToken)) + if (!string.IsNullOrEmpty(query.AccessToken)) { statement.TryBind("@AccessToken", query.AccessToken); } - if (!string.IsNullOrWhiteSpace(query.UserId)) + if (!query.UserId.Equals(Guid.Empty)) { - statement.TryBind("@UserId", query.UserId); + statement.TryBind("@UserId", query.UserId.ToString("N")); } - if (!string.IsNullOrWhiteSpace(query.DeviceId)) + if (!string.IsNullOrEmpty(query.DeviceId)) { statement.TryBind("@DeviceId", query.DeviceId); } - - if (query.IsActive.HasValue) - { - statement.TryBind("@IsActive", query.IsActive.Value); - } } public QueryResult<AuthenticationInfo> Get(AuthenticationInfoQuery query) @@ -138,26 +212,19 @@ namespace Emby.Server.Implementations.Security var whereClauses = new List<string>(); - var startIndex = query.StartIndex ?? 0; - - if (!string.IsNullOrWhiteSpace(query.AccessToken)) + if (!string.IsNullOrEmpty(query.AccessToken)) { whereClauses.Add("AccessToken=@AccessToken"); } - if (!string.IsNullOrWhiteSpace(query.UserId)) - { - whereClauses.Add("UserId=@UserId"); - } - - if (!string.IsNullOrWhiteSpace(query.DeviceId)) + if (!string.IsNullOrEmpty(query.DeviceId)) { whereClauses.Add("DeviceId=@DeviceId"); } - if (query.IsActive.HasValue) + if (!query.UserId.Equals(Guid.Empty)) { - whereClauses.Add("IsActive=@IsActive"); + whereClauses.Add("UserId=@UserId"); } if (query.HasUser.HasValue) @@ -176,28 +243,23 @@ namespace Emby.Server.Implementations.Security string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); - if (startIndex > 0) - { - var pagingWhereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); - - whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})", - pagingWhereText, - startIndex.ToString(_usCulture))); - } + commandText += whereTextWithoutPaging; - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray(whereClauses.Count)); + commandText += " ORDER BY DateLastActivity desc"; - commandText += whereText; + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var offset = query.StartIndex ?? 0; - commandText += " ORDER BY DateCreated"; + if (query.Limit.HasValue || offset > 0) + { + commandText += " LIMIT " + (query.Limit ?? int.MaxValue).ToString(CultureInfo.InvariantCulture); + } - if (query.Limit.HasValue) - { - commandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); + if (offset > 0) + { + commandText += " OFFSET " + offset.ToString(CultureInfo.InvariantCulture); + } } var list = new List<AuthenticationInfo>(); @@ -212,7 +274,7 @@ namespace Emby.Server.Implementations.Security var statementTexts = new List<string>(); statementTexts.Add(commandText); - statementTexts.Add("select count (Id) from AccessTokens" + whereTextWithoutPaging); + statementTexts.Add("select count (Id) from Tokens" + whereTextWithoutPaging); var statements = PrepareAllSafe(db, statementTexts) .ToList(); @@ -244,38 +306,11 @@ namespace Emby.Server.Implementations.Security } } - public AuthenticationInfo Get(string id) - { - if (string.IsNullOrEmpty(id)) - { - throw new ArgumentNullException("id"); - } - - using (WriteLock.Read()) - { - using (var connection = CreateConnection(true)) - { - var commandText = BaseSelectText + " where Id=@Id"; - - using (var statement = connection.PrepareStatement(commandText)) - { - statement.BindParameters["@Id"].Bind(id.ToGuidBlob()); - - foreach (var row in statement.ExecuteQuery()) - { - return Get(row); - } - return null; - } - } - } - } - private AuthenticationInfo Get(IReadOnlyList<IResultSetValue> reader) { var info = new AuthenticationInfo { - Id = reader[0].ReadGuidFromBlob().ToString("N"), + Id = reader[0].ToInt64(), AccessToken = reader[1].ToString() }; @@ -301,18 +336,95 @@ namespace Emby.Server.Implementations.Security if (reader[6].SQLiteType != SQLiteType.Null) { - info.UserId = reader[6].ToString(); + info.UserId = new Guid(reader[6].ToString()); + } + + if (reader[7].SQLiteType != SQLiteType.Null) + { + info.UserName = reader[7].ToString(); } - info.IsActive = reader[7].ToBool(); info.DateCreated = reader[8].ReadDateTime(); if (reader[9].SQLiteType != SQLiteType.Null) { - info.DateRevoked = reader[9].ReadDateTime(); + info.DateLastActivity = reader[9].ReadDateTime(); + } + else + { + info.DateLastActivity = info.DateCreated; + } + + if (reader[10].SQLiteType != SQLiteType.Null) + { + info.DeviceName = reader[10].ToString(); } return info; } + + public DeviceOptions GetDeviceOptions(string deviceId) + { + using (WriteLock.Read()) + { + using (var connection = CreateConnection(true)) + { + return connection.RunInTransaction(db => + { + using (var statement = PrepareStatementSafe(db, "select CustomName from Devices where Id=@DeviceId")) + { + statement.TryBind("@DeviceId", deviceId); + + var result = new DeviceOptions(); + + foreach (var row in statement.ExecuteQuery()) + { + if (row[0].SQLiteType != SQLiteType.Null) + { + result.CustomName = row[0].ToString(); + } + } + + return result; + } + + }, ReadTransactionMode); + } + } + } + + public void UpdateDeviceOptions(string deviceId, DeviceOptions options) + { + if (options == null) + { + throw new ArgumentNullException("options"); + } + + using (WriteLock.Write()) + { + using (var connection = CreateConnection()) + { + connection.RunInTransaction(db => + { + using (var statement = db.PrepareStatement("replace into devices (Id, CustomName, Capabilities) VALUES (@Id, @CustomName, (Select Capabilities from Devices where Id=@Id))")) + { + statement.TryBind("@Id", deviceId); + + if (string.IsNullOrWhiteSpace(options.CustomName)) + { + statement.TryBindNull("@CustomName"); + } + else + { + statement.TryBind("@CustomName", options.CustomName); + } + + statement.MoveNext(); + } + + }, TransactionMode); + } + } + } } } diff --git a/Emby.Server.Implementations/Security/MBLicenseFile.cs b/Emby.Server.Implementations/Security/MBLicenseFile.cs index dc0e8b161..1810cbcd2 100644 --- a/Emby.Server.Implementations/Security/MBLicenseFile.cs +++ b/Emby.Server.Implementations/Security/MBLicenseFile.cs @@ -22,12 +22,8 @@ namespace Emby.Server.Implementations.Security get { return _regKey; } set { - if (value != _regKey) - { - //if key is changed - clear out our saved validations - _updateRecords.Clear(); - _regKey = value; - } + _updateRecords.Clear(); + _regKey = value; } } @@ -114,14 +110,14 @@ namespace Emby.Server.Implementations.Security { lock (_fileLock) { - _fileSystem.WriteAllBytes(licenseFile, new byte[] { }); + _fileSystem.WriteAllBytes(licenseFile, Array.Empty<byte>()); } } catch (IOException) { lock (_fileLock) { - _fileSystem.WriteAllBytes(licenseFile, new byte[] { }); + _fileSystem.WriteAllBytes(licenseFile, Array.Empty<byte>()); } } } diff --git a/Emby.Server.Implementations/Security/PluginSecurityManager.cs b/Emby.Server.Implementations/Security/PluginSecurityManager.cs index 615ffa1f4..c9c68703e 100644 --- a/Emby.Server.Implementations/Security/PluginSecurityManager.cs +++ b/Emby.Server.Implementations/Security/PluginSecurityManager.cs @@ -26,30 +26,11 @@ namespace Emby.Server.Implementations.Security private const string MBValidateUrl = "https://mb3admin.com/admin/service/registration/validate"; private const string AppstoreRegUrl = /*MbAdmin.HttpsUrl*/ "https://mb3admin.com/admin/service/appstore/register"; - /// <summary> - /// The _is MB supporter - /// </summary> - private bool? _isMbSupporter; - /// <summary> - /// The _is MB supporter initialized - /// </summary> - private bool _isMbSupporterInitialized; - /// <summary> - /// The _is MB supporter sync lock - /// </summary> - private object _isMbSupporterSyncLock = new object(); - - /// <summary> - /// Gets a value indicating whether this instance is MB supporter. - /// </summary> - /// <value><c>true</c> if this instance is MB supporter; otherwise, <c>false</c>.</value> - public bool IsMBSupporter + public async Task<bool> IsSupporter() { - get - { - LazyInitializer.EnsureInitialized(ref _isMbSupporter, ref _isMbSupporterInitialized, ref _isMbSupporterSyncLock, () => GetSupporterRegistrationStatus().Result.IsRegistered); - return _isMbSupporter.Value; - } + var result = await GetRegistrationStatusInternal("MBSupporter", false, _appHost.ApplicationVersion.ToString(), CancellationToken.None).ConfigureAwait(false); + + return result.IsRegistered; } private MBLicenseFile _licenseFile; @@ -66,15 +47,6 @@ namespace Emby.Server.Implementations.Security private readonly IFileSystem _fileSystem; private readonly ICryptoProvider _cryptographyProvider; - private IEnumerable<IRequiresRegistration> _registeredEntities; - protected IEnumerable<IRequiresRegistration> RegisteredEntities - { - get - { - return _registeredEntities ?? (_registeredEntities = _appHost.GetExports<IRequiresRegistration>()); - } - } - /// <summary> /// Initializes a new instance of the <see cref="PluginSecurityManager" /> class. /// </summary> @@ -96,45 +68,12 @@ namespace Emby.Server.Implementations.Security } /// <summary> - /// Load all registration info for all entities that require registration - /// </summary> - /// <returns></returns> - public async Task LoadAllRegistrationInfo() - { - var tasks = new List<Task>(); - - ResetSupporterInfo(); - tasks.AddRange(RegisteredEntities.Select(i => i.LoadRegistrationInfoAsync())); - await Task.WhenAll(tasks); - } - - /// <summary> /// Gets the registration status. /// This overload supports existing plug-ins. /// </summary> - /// <param name="feature">The feature.</param> - /// <param name="mb2Equivalent">The MB2 equivalent.</param> - /// <returns>Task{MBRegistrationRecord}.</returns> - public Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent = null) - { - return GetRegistrationStatusInternal(feature, mb2Equivalent); - } - - /// <summary> - /// Gets the registration status. - /// </summary> - /// <param name="feature">The feature.</param> - /// <param name="mb2Equivalent">The MB2 equivalent.</param> - /// <param name="version">The version of this feature</param> - /// <returns>Task{MBRegistrationRecord}.</returns> - public Task<MBRegistrationRecord> GetRegistrationStatus(string feature, string mb2Equivalent, string version) - { - return GetRegistrationStatusInternal(feature, mb2Equivalent, version); - } - - private Task<MBRegistrationRecord> GetSupporterRegistrationStatus() + public Task<MBRegistrationRecord> GetRegistrationStatus(string feature) { - return GetRegistrationStatusInternal("MBSupporter", null, _appHost.ApplicationVersion.ToString()); + return GetRegistrationStatusInternal(feature, false, null, CancellationToken.None); } /// <summary> @@ -149,20 +88,24 @@ namespace Emby.Server.Implementations.Security } set { - var newValue = value; - if (newValue != null) - { - newValue = newValue.Trim(); - } + throw new Exception("Please call UpdateSupporterKey"); + } + } - if (newValue != LicenseFile.RegKey) - { - LicenseFile.RegKey = newValue; - LicenseFile.Save(); + public async Task UpdateSupporterKey(string newValue) + { + if (newValue != null) + { + newValue = newValue.Trim(); + } - // re-load registration info - Task.Run(() => LoadAllRegistrationInfo()); - } + if (!string.Equals(newValue, LicenseFile.RegKey, StringComparison.Ordinal)) + { + LicenseFile.RegKey = newValue; + LicenseFile.Save(); + + // Reset this + await GetRegistrationStatusInternal("MBSupporter", true, _appHost.ApplicationVersion.ToString(), CancellationToken.None).ConfigureAwait(false); } } @@ -187,7 +130,7 @@ namespace Emby.Server.Implementations.Security { using (var response = await _httpClient.Post(options).ConfigureAwait(false)) { - var reg = _jsonSerializer.DeserializeFromStream<RegRecord>(response.Content); + var reg = await _jsonSerializer.DeserializeFromStreamAsync<RegRecord>(response.Content).ConfigureAwait(false); if (reg == null) { @@ -197,7 +140,7 @@ namespace Emby.Server.Implementations.Security } if (!String.IsNullOrEmpty(reg.key)) { - SupporterKey = reg.key; + await UpdateSupporterKey(reg.key).ConfigureAwait(false); } } @@ -241,97 +184,113 @@ namespace Emby.Server.Implementations.Security } } - private async Task<MBRegistrationRecord> GetRegistrationStatusInternal(string feature, - string mb2Equivalent = null, - string version = null) - { - var regInfo = LicenseFile.GetRegInfo(feature); - var lastChecked = regInfo == null ? DateTime.MinValue : regInfo.LastChecked; - var expDate = regInfo == null ? DateTime.MinValue : regInfo.ExpirationDate; + private SemaphoreSlim _regCheckLock = new SemaphoreSlim(1, 1); - var maxCacheDays = 14; - var nextCheckDate = new [] { expDate, lastChecked.AddDays(maxCacheDays) }.Min(); + private async Task<MBRegistrationRecord> GetRegistrationStatusInternal(string feature, bool forceCallToServer, string version, CancellationToken cancellationToken) + { + await _regCheckLock.WaitAsync(cancellationToken).ConfigureAwait(false); - if (nextCheckDate > DateTime.UtcNow.AddDays(maxCacheDays)) + try { - nextCheckDate = DateTime.MinValue; - } + var regInfo = LicenseFile.GetRegInfo(feature); + var lastChecked = regInfo == null ? DateTime.MinValue : regInfo.LastChecked; + var expDate = regInfo == null ? DateTime.MinValue : regInfo.ExpirationDate; - //check the reg file first to alleviate strain on the MB admin server - must actually check in every 30 days tho - var reg = new RegRecord - { - // Cache the result for up to a week - registered = regInfo != null && nextCheckDate >= DateTime.UtcNow && expDate >= DateTime.UtcNow, - expDate = expDate - }; + var maxCacheDays = 14; + var nextCheckDate = new[] { expDate, lastChecked.AddDays(maxCacheDays) }.Min(); - var success = reg.registered; + if (nextCheckDate > DateTime.UtcNow.AddDays(maxCacheDays)) + { + nextCheckDate = DateTime.MinValue; + } - if (!(lastChecked > DateTime.UtcNow.AddDays(-1)) || !reg.registered) - { - var data = new Dictionary<string, string> + //check the reg file first to alleviate strain on the MB admin server - must actually check in every 30 days tho + var reg = new RegRecord { - { "feature", feature }, - { "key", SupporterKey }, - { "mac", _appHost.SystemId }, - { "systemid", _appHost.SystemId }, - { "mb2equiv", mb2Equivalent }, - { "ver", version }, - { "platform", _appHost.OperatingSystemDisplayName } + // Cache the result for up to a week + registered = regInfo != null && nextCheckDate >= DateTime.UtcNow && expDate >= DateTime.UtcNow, + expDate = expDate }; - try + var key = SupporterKey; + + if (!forceCallToServer && string.IsNullOrWhiteSpace(key)) { - var options = new HttpRequestOptions - { - Url = MBValidateUrl, + return new MBRegistrationRecord(); + } - // Seeing block length errors - EnableHttpCompression = false, - BufferContent = false - }; + var success = reg.registered; - options.SetPostData(data); + if (!(lastChecked > DateTime.UtcNow.AddDays(-1)) || (!reg.registered)) + { + var data = new Dictionary<string, string> + { + { "feature", feature }, + { "key", key }, + { "mac", _appHost.SystemId }, + { "systemid", _appHost.SystemId }, + { "ver", version }, + { "platform", _appHost.OperatingSystemDisplayName } + }; - using (var response = (await _httpClient.Post(options).ConfigureAwait(false))) + try { - using (var json = response.Content) + var options = new HttpRequestOptions { - reg = _jsonSerializer.DeserializeFromStream<RegRecord>(json); - success = true; + Url = MBValidateUrl, + + // Seeing block length errors + EnableHttpCompression = false, + BufferContent = false, + CancellationToken = cancellationToken + }; + + options.SetPostData(data); + + using (var response = (await _httpClient.Post(options).ConfigureAwait(false))) + { + using (var json = response.Content) + { + reg = await _jsonSerializer.DeserializeFromStreamAsync<RegRecord>(json).ConfigureAwait(false); + success = true; + } + } + + if (reg.registered) + { + _logger.Info("Registered for feature {0}", feature); + LicenseFile.AddRegCheck(feature, reg.expDate); + } + else + { + _logger.Info("Not registered for feature {0}", feature); + LicenseFile.RemoveRegCheck(feature); } - } - if (reg.registered) - { - _logger.Info("Registered for feature {0}", feature); - LicenseFile.AddRegCheck(feature, reg.expDate); } - else + catch (Exception e) { - _logger.Info("Not registered for feature {0}", feature); - LicenseFile.RemoveRegCheck(feature); + _logger.ErrorException("Error checking registration status of {0}", e, feature); } - - } - catch (Exception e) - { - _logger.ErrorException("Error checking registration status of {0}", e, feature); } - } - var record = new MBRegistrationRecord - { - IsRegistered = reg.registered, - ExpirationDate = reg.expDate, - RegChecked = true, - RegError = !success - }; + var record = new MBRegistrationRecord + { + IsRegistered = reg.registered, + ExpirationDate = reg.expDate, + RegChecked = true, + RegError = !success + }; - record.TrialVersion = IsInTrial(reg.expDate, record.RegChecked, record.IsRegistered); - record.IsValid = !record.RegChecked || record.IsRegistered || record.TrialVersion; + record.TrialVersion = IsInTrial(reg.expDate, record.RegChecked, record.IsRegistered); + record.IsValid = !record.RegChecked || record.IsRegistered || record.TrialVersion; - return record; + return record; + } + finally + { + _regCheckLock.Release(); + } } private bool IsInTrial(DateTime expirationDate, bool regChecked, bool isRegistered) @@ -346,14 +305,5 @@ namespace Emby.Server.Implementations.Security return isInTrial && !isRegistered; } - - /// <summary> - /// Resets the supporter info. - /// </summary> - private void ResetSupporterInfo() - { - _isMbSupporter = null; - _isMbSupporterInitialized = false; - } } }
\ No newline at end of file |
