Move Bitpay authentication class in BTCPayServer.Security

This commit is contained in:
nicolas.dorier 2019-10-19 00:54:20 +09:00
parent 037fcf93f5
commit eac4c91820
No known key found for this signature in database
GPG key ID: 6618763EF09186FE
23 changed files with 10 additions and 362 deletions

View file

@ -12,7 +12,6 @@ using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using BTCPayServer.Authentication;
using BTCPayServer.Data; using BTCPayServer.Data;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;

View file

@ -15,7 +15,6 @@ using System.IO;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using BTCPayServer.Authentication;
using System.Diagnostics; using System.Diagnostics;
using BTCPayServer.Data; using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -60,6 +59,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NBXplorer.DerivationStrategy; using NBXplorer.DerivationStrategy;
using BTCPayServer.U2F.Models; using BTCPayServer.U2F.Models;
using BTCPayServer.Security.Bitpay;
namespace BTCPayServer.Tests namespace BTCPayServer.Tests
{ {

View file

@ -1,45 +0,0 @@
using NBitcoin;
using System;
using System.Collections.Generic;
using System.Text;
using NBitpayClient;
namespace BTCPayServer.Authentication
{
public class BitTokenEntity
{
public string Value
{
get; set;
}
public string StoreId
{
get; set;
}
public string Label
{
get; set;
}
public DateTimeOffset PairingTime
{
get; set;
}
public string SIN
{
get;
set;
}
public BitTokenEntity Clone(Facade facade)
{
return new BitTokenEntity()
{
Label = Label,
StoreId = StoreId,
PairingTime = PairingTime,
SIN = SIN,
Value = Value
};
}
}
}

View file

@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BTCPayServer.Authentication
{
public class PairingCodeEntity
{
public string Id
{
get;
set;
}
public string Label
{
get;
set;
}
public string SIN
{
get;
set;
}
public DateTimeOffset CreatedTime
{
get;
set;
}
public DateTimeOffset Expiration
{
get;
set;
}
public string TokenValue
{
get;
set;
}
public bool IsExpired()
{
return DateTimeOffset.UtcNow > Expiration;
}
}
}

View file

@ -1,247 +0,0 @@
using BTCPayServer.Data;
using DBriize;
using NBitcoin;
using NBitcoin.DataEncoders;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using System.Linq;
namespace BTCPayServer.Authentication
{
public enum PairingResult
{
Partial,
Complete,
ReusedKey,
Expired
}
public class TokenRepository
{
ApplicationDbContextFactory _Factory;
public TokenRepository(ApplicationDbContextFactory dbFactory)
{
if (dbFactory == null)
throw new ArgumentNullException(nameof(dbFactory));
_Factory = dbFactory;
}
public async Task<BitTokenEntity[]> GetTokens(string sin)
{
if (sin == null)
return Array.Empty<BitTokenEntity>();
using (var ctx = _Factory.CreateContext())
{
return (await ctx.PairedSINData.Where(p => p.SIN == sin)
.ToArrayAsync())
.Select(p => CreateTokenEntity(p))
.ToArray();
}
}
public async Task<String> GetStoreIdFromAPIKey(string apiKey)
{
using (var ctx = _Factory.CreateContext())
{
return await ctx.ApiKeys.Where(o => o.Id == apiKey).Select(o => o.StoreId).FirstOrDefaultAsync();
}
}
public async Task GenerateLegacyAPIKey(string storeId)
{
// It is legacy support and Bitpay generate string of unknown format, trying to replicate them
// as good as possible. The string below got generated for me.
var chars = "ERo0vkBMOYhyU0ZHvirCplbLDIGWPdi1ok77VnW7QdE";
var rand = new Random(Math.Abs(RandomUtils.GetInt32()));
var generated = new char[chars.Length];
for (int i = 0; i < generated.Length; i++)
{
generated[i] = chars[rand.Next(0, generated.Length)];
}
using (var ctx = _Factory.CreateContext())
{
var existing = await ctx.ApiKeys.Where(o => o.StoreId == storeId).FirstOrDefaultAsync();
if (existing != null)
{
ctx.ApiKeys.Remove(existing);
}
ctx.ApiKeys.Add(new APIKeyData() { Id = new string(generated), StoreId = storeId });
await ctx.SaveChangesAsync().ConfigureAwait(false);
}
}
public async Task<string[]> GetLegacyAPIKeys(string storeId)
{
using (var ctx = _Factory.CreateContext())
{
return await ctx.ApiKeys.Where(o => o.StoreId == storeId).Select(c => c.Id).ToArrayAsync();
}
}
private BitTokenEntity CreateTokenEntity(PairedSINData data)
{
return new BitTokenEntity()
{
Label = data.Label,
Value = data.Id,
SIN = data.SIN,
PairingTime = data.PairingTime,
StoreId = data.StoreDataId
};
}
public async Task<string> CreatePairingCodeAsync()
{
string pairingCodeId = null;
while (true)
{
pairingCodeId = Encoders.Base58.EncodeData(RandomUtils.GetBytes(6));
if (pairingCodeId.Length == 7) // woocommerce plugin check for exactly 7 digits
break;
}
using (var ctx = _Factory.CreateContext())
{
var now = DateTime.UtcNow;
var expiration = DateTime.UtcNow + TimeSpan.FromMinutes(15);
ctx.PairingCodes.Add(new PairingCodeData()
{
Id = pairingCodeId,
DateCreated = now,
Expiration = expiration,
TokenValue = Encoders.Base58.EncodeData(RandomUtils.GetBytes(32))
});
await ctx.SaveChangesAsync();
}
return pairingCodeId;
}
public async Task<PairingCodeEntity> UpdatePairingCode(PairingCodeEntity pairingCodeEntity)
{
using (var ctx = _Factory.CreateContext())
{
var pairingCode = await ctx.PairingCodes.FindAsync(pairingCodeEntity.Id);
pairingCode.Label = pairingCodeEntity.Label;
await ctx.SaveChangesAsync();
return CreatePairingCodeEntity(pairingCode);
}
}
public async Task<PairingResult> PairWithStoreAsync(string pairingCodeId, string storeId)
{
using (var ctx = _Factory.CreateContext())
{
var pairingCode = await ctx.PairingCodes.FindAsync(pairingCodeId);
if (pairingCode == null || pairingCode.Expiration < DateTimeOffset.UtcNow)
return PairingResult.Expired;
pairingCode.StoreDataId = storeId;
var result = await ActivateIfComplete(ctx, pairingCode);
await ctx.SaveChangesAsync();
return result;
}
}
public async Task<PairingResult> PairWithSINAsync(string pairingCodeId, string sin)
{
using (var ctx = _Factory.CreateContext())
{
var pairingCode = await ctx.PairingCodes.FindAsync(pairingCodeId);
if (pairingCode == null || pairingCode.Expiration < DateTimeOffset.UtcNow)
return PairingResult.Expired;
pairingCode.SIN = sin;
var result = await ActivateIfComplete(ctx, pairingCode);
await ctx.SaveChangesAsync();
return result;
}
}
private async Task<PairingResult> ActivateIfComplete(ApplicationDbContext ctx, PairingCodeData pairingCode)
{
if (!string.IsNullOrEmpty(pairingCode.SIN) && !string.IsNullOrEmpty(pairingCode.StoreDataId))
{
ctx.PairingCodes.Remove(pairingCode);
// Can have concurrency issues... but no harm can be done
var alreadyUsed = await ctx.PairedSINData.Where(p => p.SIN == pairingCode.SIN && p.StoreDataId != pairingCode.StoreDataId).AnyAsync();
if (alreadyUsed)
return PairingResult.ReusedKey;
await ctx.PairedSINData.AddAsync(new PairedSINData()
{
Id = pairingCode.TokenValue,
PairingTime = DateTime.UtcNow,
Label = pairingCode.Label,
StoreDataId = pairingCode.StoreDataId,
SIN = pairingCode.SIN
});
return PairingResult.Complete;
}
return PairingResult.Partial;
}
public async Task<BitTokenEntity[]> GetTokensByStoreIdAsync(string storeId)
{
using (var ctx = _Factory.CreateContext())
{
return (await ctx.PairedSINData.Where(p => p.StoreDataId == storeId).ToListAsync())
.Select(c => CreateTokenEntity(c))
.ToArray();
}
}
public async Task<PairingCodeEntity> GetPairingAsync(string pairingCode)
{
using (var ctx = _Factory.CreateContext())
{
return CreatePairingCodeEntity(await ctx.PairingCodes.FindAsync(pairingCode));
}
}
private PairingCodeEntity CreatePairingCodeEntity(PairingCodeData data)
{
if (data == null)
return null;
return new PairingCodeEntity()
{
Id = data.Id,
Label = data.Label,
Expiration = data.Expiration,
CreatedTime = data.DateCreated,
TokenValue = data.TokenValue,
SIN = data.SIN
};
}
public async Task<bool> DeleteToken(string tokenId)
{
using (var ctx = _Factory.CreateContext())
{
var token = await ctx.PairedSINData.FindAsync(tokenId);
if (token == null)
return false;
ctx.PairedSINData.Remove(token);
await ctx.SaveChangesAsync();
return true;
}
}
public async Task<BitTokenEntity> GetToken(string tokenId)
{
using (var ctx = _Factory.CreateContext())
{
var token = await ctx.PairedSINData.FindAsync(tokenId);
if (token == null)
return null;
return CreateTokenEntity(token);
}
}
}
}

View file

@ -129,6 +129,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Authentication\" />
<Folder Include="wwwroot\vendor\clipboard.js\" /> <Folder Include="wwwroot\vendor\clipboard.js\" />
<Folder Include="wwwroot\vendor\highlightjs\" /> <Folder Include="wwwroot\vendor\highlightjs\" />
<Folder Include="wwwroot\vendor\summernote" /> <Folder Include="wwwroot\vendor\summernote" />

View file

@ -1,7 +1,7 @@
using BTCPayServer.Authentication; using BTCPayServer.Filters;
using BTCPayServer.Filters;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Security.Bitpay;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View file

@ -11,7 +11,6 @@ using Microsoft.Extensions.Logging;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.ManageViewModels; using BTCPayServer.Models.ManageViewModels;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Authentication;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets; using BTCPayServer.Services.Wallets;
@ -35,7 +34,6 @@ namespace BTCPayServer.Controllers
private readonly EmailSenderFactory _EmailSenderFactory; private readonly EmailSenderFactory _EmailSenderFactory;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly UrlEncoder _urlEncoder; private readonly UrlEncoder _urlEncoder;
TokenRepository _TokenRepository;
IWebHostEnvironment _Env; IWebHostEnvironment _Env;
private readonly U2FService _u2FService; private readonly U2FService _u2FService;
private readonly BTCPayServerEnvironment _btcPayServerEnvironment; private readonly BTCPayServerEnvironment _btcPayServerEnvironment;
@ -49,7 +47,6 @@ namespace BTCPayServer.Controllers
EmailSenderFactory emailSenderFactory, EmailSenderFactory emailSenderFactory,
ILogger<ManageController> logger, ILogger<ManageController> logger,
UrlEncoder urlEncoder, UrlEncoder urlEncoder,
TokenRepository tokenRepository,
BTCPayWalletProvider walletProvider, BTCPayWalletProvider walletProvider,
StoreRepository storeRepository, StoreRepository storeRepository,
IWebHostEnvironment env, IWebHostEnvironment env,
@ -61,7 +58,6 @@ namespace BTCPayServer.Controllers
_EmailSenderFactory = emailSenderFactory; _EmailSenderFactory = emailSenderFactory;
_logger = logger; _logger = logger;
_urlEncoder = urlEncoder; _urlEncoder = urlEncoder;
_TokenRepository = tokenRepository;
_Env = env; _Env = env;
_u2FService = u2FService; _u2FService = u2FService;
_btcPayServerEnvironment = btcPayServerEnvironment; _btcPayServerEnvironment = btcPayServerEnvironment;

View file

@ -11,11 +11,11 @@ using BTCPayServer.Services.Stores;
using BTCPayServer.Rating; using BTCPayServer.Rating;
using Newtonsoft.Json; using Newtonsoft.Json;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using BTCPayServer.Authentication;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using System.Threading; using System.Threading;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Security.Bitpay;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
{ {

View file

@ -1,5 +1,4 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Authentication;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Security; using BTCPayServer.Security;

View file

@ -5,7 +5,6 @@ using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Authentication;
using BTCPayServer.Configuration; using BTCPayServer.Configuration;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
@ -17,6 +16,7 @@ using BTCPayServer.Payments.Changelly;
using BTCPayServer.Payments.Lightning; using BTCPayServer.Payments.Lightning;
using BTCPayServer.Rating; using BTCPayServer.Rating;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Security.Bitpay;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;

View file

@ -4,7 +4,6 @@ using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Authentication;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Security; using BTCPayServer.Security;
using BTCPayServer.Services.Rates; using BTCPayServer.Services.Rates;

View file

@ -1,5 +1,4 @@
using BTCPayServer.Authentication; using BTCPayServer.Configuration;
using BTCPayServer.Configuration;
using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View file

@ -25,7 +25,6 @@ using BTCPayServer.Controllers;
using BTCPayServer.Services.Mails; using BTCPayServer.Services.Mails;
using System.Threading; using System.Threading;
using BTCPayServer.Services.Wallets; using BTCPayServer.Services.Wallets;
using BTCPayServer.Authentication;
using BTCPayServer.Logging; using BTCPayServer.Logging;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.PaymentRequest; using BTCPayServer.PaymentRequest;

View file

@ -7,7 +7,6 @@ using System.Text;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO; using System.IO;
using BTCPayServer.Authentication;
using BTCPayServer.Logging; using BTCPayServer.Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using BTCPayServer.Models; using BTCPayServer.Models;

View file

@ -24,7 +24,6 @@ using BTCPayServer.Security;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using OpenIddict.EntityFrameworkCore.Models; using OpenIddict.EntityFrameworkCore.Models;
using System.Net; using System.Net;
using BTCPayServer.Authentication;
using BTCPayServer.Security.OpenId; using BTCPayServer.Security.OpenId;
using BTCPayServer.PaymentRequest; using BTCPayServer.PaymentRequest;
using BTCPayServer.Services.Apps; using BTCPayServer.Services.Apps;

View file

@ -6,10 +6,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Authentication;
using NBitcoin.DataEncoders; using NBitcoin.DataEncoders;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using System.IO; using System.IO;
using BTCPayServer.Security.Bitpay;
namespace BTCPayServer.Models namespace BTCPayServer.Models
{ {

View file

@ -7,7 +7,6 @@ using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Authentication;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;

View file

@ -9,7 +9,6 @@ using System.Security.Claims;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using BTCPayServer.Authentication;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Security.Bitpay; using BTCPayServer.Security.Bitpay;

View file

@ -9,7 +9,6 @@ using System.Security.Claims;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using BTCPayServer.Authentication;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
namespace BTCPayServer.Security namespace BTCPayServer.Security

View file

@ -9,7 +9,6 @@ using System.Security.Claims;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using BTCPayServer.Authentication;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using static BTCPayServer.Security.OpenId.RestAPIPolicies; using static BTCPayServer.Security.OpenId.RestAPIPolicies;
using OpenIddict.Abstractions; using OpenIddict.Abstractions;

View file

@ -2,7 +2,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Authentication;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
namespace BTCPayServer.Security namespace BTCPayServer.Security

View file

@ -1,4 +1,4 @@
@model BTCPayServer.Authentication.BitTokenEntity @model BTCPayServer.Security.Bitpay.BitTokenEntity
@{ @{
Layout = "../Shared/_NavLayout.cshtml"; Layout = "../Shared/_NavLayout.cshtml";
ViewData.SetActivePageAndTitle(StoreNavPages.Tokens, "Access Tokens"); ViewData.SetActivePageAndTitle(StoreNavPages.Tokens, "Access Tokens");