Add MedMind recovery and Steam authentication
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
using System.Security.Cryptography;
|
||||
using GameAuthApi.Models;
|
||||
using MongoDB.Driver;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace GameAuthApi.Services;
|
||||
|
||||
public class PasswordResetService
|
||||
{
|
||||
private readonly IMongoCollection<PasswordResetChallenge> _challenges;
|
||||
|
||||
public PasswordResetService(IConfiguration config)
|
||||
{
|
||||
var client = new MongoClient(config["MongoDB:ConnectionString"]);
|
||||
var database = client.GetDatabase(config["MongoDB:DatabaseName"]);
|
||||
_challenges = database.GetCollection<PasswordResetChallenge>("PasswordResetChallenges");
|
||||
}
|
||||
|
||||
public virtual async Task<string> CreateAsync(string userId)
|
||||
{
|
||||
await _challenges.UpdateManyAsync(x => x.UserId == userId && !x.Used,
|
||||
Builders<PasswordResetChallenge>.Update.Set(x => x.Used, true));
|
||||
var code = RandomNumberGenerator.GetInt32(0, 1_000_000).ToString("D6");
|
||||
await _challenges.InsertOneAsync(new PasswordResetChallenge
|
||||
{
|
||||
UserId = userId,
|
||||
CodeHash = BCrypt.Net.BCrypt.HashPassword(code),
|
||||
CreatedUtc = DateTime.UtcNow,
|
||||
ExpiresUtc = DateTime.UtcNow.AddMinutes(15)
|
||||
});
|
||||
return code;
|
||||
}
|
||||
|
||||
public virtual async Task<bool> ConsumeAsync(string userId, string code)
|
||||
{
|
||||
var challenge = await _challenges.Find(x => x.UserId == userId && !x.Used && x.ExpiresUtc > DateTime.UtcNow)
|
||||
.SortByDescending(x => x.CreatedUtc).FirstOrDefaultAsync();
|
||||
if (challenge == null || challenge.FailedAttempts >= 5)
|
||||
return false;
|
||||
if (!BCrypt.Net.BCrypt.Verify(code, challenge.CodeHash))
|
||||
{
|
||||
await _challenges.UpdateOneAsync(x => x.Id == challenge.Id,
|
||||
Builders<PasswordResetChallenge>.Update.Inc(x => x.FailedAttempts, 1));
|
||||
return false;
|
||||
}
|
||||
await _challenges.UpdateOneAsync(x => x.Id == challenge.Id,
|
||||
Builders<PasswordResetChallenge>.Update.Set(x => x.Used, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task EnsureIndexesAsync() => await _challenges.Indexes.CreateOneAsync(
|
||||
new CreateIndexModel<PasswordResetChallenge>(
|
||||
Builders<PasswordResetChallenge>.IndexKeys.Ascending(x => x.ExpiresUtc),
|
||||
new CreateIndexOptions { ExpireAfter = TimeSpan.Zero, Name = "password_reset_ttl" }));
|
||||
}
|
||||
Reference in New Issue
Block a user