/// <summary> /// DO NOT USE this from your code. Use <see cref="IGlobalXService.SafeAddOrUpdateGlobalXApiToken(GlobalXApiToken)"/> /// instead, because it will safely request a lock before calling this method. /// /// Adds or updates the supplied <see cref="GlobalXApiToken"/>. A lock must be requested before you can add or update /// a token, so you must supply a valid <see cref="GlobalXApiTokenLockInfo"/>. /// </summary> /// <param name="apiToken"></param> /// <param name="lockInfo"></param> /// <returns></returns> /// <exception cref="CannotUpdateGlobalXApiTokenWithoutLockException">If there is no existing lock for this token.</exception> /// <exception cref="GlobalXApiTokenLockIdMismatchException"> /// If the <see cref="GlobalXApiTokenLockInfo"/> supplied doesn't match the one stored for the token. /// </exception> public async Task AddOrUpdateGlobalXApiToken(GlobalXApiToken apiToken, GlobalXApiTokenLockInfo lockInfo, bool overrideAndClearLock = false) { if (apiToken is null) { throw new ArgumentNullException(nameof(apiToken)); } if (lockInfo is null && !overrideAndClearLock) { throw new ArgumentNullException(nameof(lockInfo), $"Must not be null if {nameof(overrideAndClearLock)} is false."); } if (!(lockInfo is null)) { var existingLock = await GetLock(lockInfo?.UserId); if (overrideAndClearLock) { await DeleteLock(existingLock); } else { if (existingLock is null) { throw new CannotUpdateGlobalXApiTokenWithoutLockException(apiToken); } if (existingLock.LockId != lockInfo.LockId) { throw new GlobalXApiTokenLockIdMismatchException(existingLock, lockInfo, apiToken); } } } _telemetry.TrackEvent(nameof(AddOrUpdateGlobalXApiToken), new Dictionary <string, string>() { { "Access Token User Id", apiToken.UserId }, { "Access Token Expires At", apiToken.AccessTokenExpiryUtc.ToString() }, }); // Store or update the expiry dates in table storage as a read model for quicker enumeration tokens nearing expiry DateTimeOffset?revokedAt = null; if (apiToken.RevokedAt.HasValue) { revokedAt = apiToken.RevokedAt.Value.ToDateTimeOffset(); } await _expiryTableReference.ExecuteAsync(TableOperation.InsertOrReplace(new TokenExpiryTableEntity( apiToken.RefreshTokenExpiryUtc.ToDateTimeUtc(), apiToken.AccessTokenExpiryUtc.ToDateTimeUtc(), apiToken.UserId, revokedAt))); // Store the actual token data await _keyVaultClient.SetSecretAsync( _appSettings.CredentialAzureKeyVaultUrl, GenerateTokenId(apiToken.UserId), JsonConvert.SerializeObject(apiToken)); }
public async Task SafeAddOrUpdateGlobalXApiToken(GlobalXApiToken globalXApiToken) { if (globalXApiToken is null) { throw new ArgumentNullException(nameof(globalXApiToken)); } using (var lockInfo = await RequestApiTokenLock(globalXApiToken.UserId)) { await _globalXApiTokenRepository.AddOrUpdateGlobalXApiToken(globalXApiToken, lockInfo); } }