using System;
using System.Linq;
using xIds.Helpers;
using System.Threading;
using xCommons.Extensions;
using xIdentityModels.Dtos;
using xExceptions.Constants;
using System.Threading.Tasks;
using xIdentityModels.Models;
using System.Collections.Generic;
using System.Security.Cryptography;
namespace xIds.Providers
{
public partial class XApplicationProvider
{
//
#region Custom Actions ...
///
/// Generate a New ApiKey and Add It to DB ...
///
///
///
///
///
///
///
///
///
public async Task CreateApiKey(
int applicationId,
TimeSpan? expiration = null,
IEnumerable scopes = null,
IEnumerable allowedIPs = null,
int? rateLimit = null,
XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
if (
userInfo.IsNullOrDefault() ||
!applicationId.IsValidIntId()
)
{
XException.InvalidArgs.Throw();
}
//
// Check Application Exists ...
var application = await GetApplicationAsync(
id: applicationId,
userInfo: userInfo,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (application.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
// Validate Owner ...
if (!IsOwned(application, userInfo))
{
XException.NotAllowed.Throw();
}
//
// Normalizing ...
if (!rateLimit.HasValue)
{
rateLimit = apiKeyConfiguration.DefaultRateLimit;
}
if (!expiration.HasValue)
{
expiration = TimeSpan.FromMinutes(apiKeyConfiguration.DefaultExpirationMinutes);
}
else if (expiration.Value > TimeSpan.FromMinutes(apiKeyConfiguration.MaxExpirationMinutes))
{
expiration = TimeSpan.FromMinutes(apiKeyConfiguration.MaxExpirationMinutes);
}
//
// Generate New Key ...
(string plainKey, string keyHash, string prefix) = XApiKeyHelper.Generate();
var expireAt = DateTime.UtcNow.Add(expiration.Value);
//
var _allowedScopes = scopes.ToJSON();
var _allowedIPs = allowedIPs.ToListString();
//
// Instance Dto Item ...
var result = new XApiKeyDto
{
RevokedAt = null,
KeyHash = keyHash,
LastUsedAt = null,
KeyPrefix = prefix,
ExpiresAt = expireAt,
RevokedBy = string.Empty,
AllowedIPs = _allowedIPs,
CreatedOn = DateTime.UtcNow,
ApplicationId = applicationId,
AllowedScopes = _allowedScopes,
RateLimitPerMinute = rateLimit.Value
};
//
// Add Item to Database ...
result = await AddApiKeyAsync(
item: item,
userInfo: userInfo,
cancellationToken: cancellationToken
);
//
return result;
}
///
/// Revoke Specified Api Key ...
///
///
///
///
///
public async Task RevokeApiKey(
Guid apiKeyId,
XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
if (
apiKeyId.IsDefaultGuid() ||
userInfo.IsNullOrDefault())
{
XException.InvalidArgs.Throw();
}
//
// Retrieve ApiKey ...
var item = await GetApiKeyAsync(
id: apiKeyId,
userInfo: userInfo,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (item.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
// Permission Checking ...
var application = await GetApplicationAsync(
userInfo: userInfo,
includeBuilder: null,
id: item.ApplicationId,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (application.IsNullOrDefault())
{
XException.NotFound.Throw();
}
if (!IsOwned(application, userInfo))
{
XException.NotAllowed.Throw();
}
//
// Update Revoke Info ...
item.RevokedAt = DateTime.UtcNow;
item.RevokedBy = userInfo.UserId;
//
item = await UpdateApiKeyAsync(
id: item.Id,
item: item,
userInfo: userInfo,
cancellationToken: cancellationToken
);
//
var result = !item.IsNullOrDefault();
return result;
}
///
/// Renew Specified Api Key ...
///
///
///
///
///
///
public async Task RotateApiKey(
Guid apiKeyId,
TimeSpan? newExpiration = null,
XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
if (
apiKeyId.IsDefaultGuid() ||
userInfo.IsNullOrDefault()
)
{
XException.InvalidArgs.Throw();
}
//
// Retrieve Item ...
var result = await GetApiKeyAsync(
id: apiKeyId,
userInfo: userInfo,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (result.IsNullOrDefault())
{
XException.NotFound.Throw();
}
//
// Expired Date ...
DateTime? expiredDate = null;
if (!newExpiration.HasValue)
{
//
newExpiration = TimeSpan
.FromMinutes(apiKeyConfiguration.DefaultExpirationMinutes);
expiredDate = DateTime.UtcNow.Add(newExpiration.Value);
}
if (!expiredDate.HasValue)
{
XException.InvalidArgs.Throw();
}
//
// Update Item ...
result.ExpiresAt = expiredDate.Value;
//
result = await UpdateApiKeyAsync(
item: result,
id: result.Id,
userInfo: userInfo,
cancellationToken: cancellationToken
);
//
return result;
}
///
/// Retrieve All Api Keys for Specified Application ...
///
///
///
///
///
public async Task> GetApplicationApiKeys(
int applicationId,
XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
if (
userInfo.IsNullOrDefault() ||
!applicationId.IsValidIntId()
)
{
XException.InvalidArgs.Throw();
}
//
// Permission Checking ...
var application = await GetApplicationAsync(
userInfo: userInfo,
includeBuilder: null,
id: applicationId,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken
);
if (application.IsNullOrDefault())
{
XException.NotFound.Throw();
}
if (!IsOwned(application, userInfo))
{
XException.NotAllowed.Throw();
}
//
var result = await FindManyApiKeyAsync(
userInfo: userInfo,
includeBuilder: null,
ignoreSoftDeleteds: true,
cancellationToken: cancellationToken,
orderBuilder: x => x.OrderBy(y => y.Id),
predicate: x => x.ApplicationId == applicationId
);
//
return result;
}
///
/// Validate Specified Api Key in based on ClientIP ...
///
///
///
///
///
///
public async Task ValidateApiKey(
string apiKey,
string clientIP,
XUserClaimsInfoDto userInfo = null,
CancellationToken cancellationToken = default
)
{
//
}
#endregion
}
}