using Grpc.Core;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Svrnty.CQRS.Altcha.Abstractions;
namespace Svrnty.CQRS.Altcha.Grpc;
///
/// Default backed by gRPC. Calls
/// AltchaService.CreateChallenge on the configured endpoint and
/// projects the response onto .
///
public sealed class AltchaGrpcChallengeProvider : IAltchaChallengeProvider
{
private readonly AltchaService.AltchaServiceClient _client;
private readonly IOptions _options;
private readonly ILogger _logger;
public AltchaGrpcChallengeProvider(
AltchaService.AltchaServiceClient client,
IOptions options,
ILogger logger)
{
_client = client;
_options = options;
_logger = logger;
}
public async Task CreateAsync(CancellationToken cancellationToken = default)
{
var opts = _options.Value;
var metadata = await AltchaCallCredentials.BuildMetadataAsync(opts, cancellationToken);
var deadline = DateTime.UtcNow.Add(opts.CallTimeout);
try
{
var response = await _client.CreateChallengeAsync(
new CreateChallengeRequest(),
headers: metadata,
deadline: deadline,
cancellationToken: cancellationToken);
return new AltchaChallenge
{
Algorithm = response.Algorithm,
Challenge = response.ChallengeHash,
Salt = response.Salt,
Signature = response.Signature,
MaxNumber = response.Maxnumber
};
}
catch (RpcException ex)
{
_logger.LogError(ex, "Altcha create-challenge failed against {Endpoint}: {Status}", opts.Endpoint, ex.StatusCode);
throw;
}
}
}