mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-11 01:35:22 +01:00
Move Bitpay authentication class in BTCPayServer.Security
This commit is contained in:
parent
037fcf93f5
commit
eac4c91820
23 changed files with 10 additions and 362 deletions
|
@ -12,7 +12,6 @@ using Xunit;
|
|||
using Xunit.Abstractions;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Data;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
|
@ -15,7 +15,6 @@ using System.IO;
|
|||
using Newtonsoft.Json.Linq;
|
||||
using BTCPayServer.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using BTCPayServer.Authentication;
|
||||
using System.Diagnostics;
|
||||
using BTCPayServer.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -60,6 +59,7 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using BTCPayServer.U2F.Models;
|
||||
using BTCPayServer.Security.Bitpay;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -64,7 +64,7 @@
|
|||
<PackageReference Include="TwentyTwenty.Storage" Version="2.11.2" />
|
||||
<PackageReference Include="TwentyTwenty.Storage.Amazon" Version="2.11.2" />
|
||||
<PackageReference Include="TwentyTwenty.Storage.Azure" Version="2.11.2" />
|
||||
<PackageReference Include="TwentyTwenty.Storage.Google" Version="2.11.2" Condition="'$(TargetFramework)' == 'netcoreapp2.1'" />
|
||||
<PackageReference Include="TwentyTwenty.Storage.Google" Version="2.11.2" Condition="'$(TargetFramework)' == 'netcoreapp2.1'" />
|
||||
<PackageReference Include="TwentyTwenty.Storage.Local" Version="2.11.2" />
|
||||
<PackageReference Include="U2F.Core" Version="1.0.4" />
|
||||
<PackageReference Include="YamlDotNet" Version="5.2.1" />
|
||||
|
@ -129,6 +129,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Authentication\" />
|
||||
<Folder Include="wwwroot\vendor\clipboard.js\" />
|
||||
<Folder Include="wwwroot\vendor\highlightjs\" />
|
||||
<Folder Include="wwwroot\vendor\summernote" />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Filters;
|
||||
using BTCPayServer.Filters;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Security.Bitpay;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
|
|
@ -11,7 +11,6 @@ using Microsoft.Extensions.Logging;
|
|||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Models.ManageViewModels;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Authentication;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
|
@ -35,7 +34,6 @@ namespace BTCPayServer.Controllers
|
|||
private readonly EmailSenderFactory _EmailSenderFactory;
|
||||
private readonly ILogger _logger;
|
||||
private readonly UrlEncoder _urlEncoder;
|
||||
TokenRepository _TokenRepository;
|
||||
IWebHostEnvironment _Env;
|
||||
private readonly U2FService _u2FService;
|
||||
private readonly BTCPayServerEnvironment _btcPayServerEnvironment;
|
||||
|
@ -49,7 +47,6 @@ namespace BTCPayServer.Controllers
|
|||
EmailSenderFactory emailSenderFactory,
|
||||
ILogger<ManageController> logger,
|
||||
UrlEncoder urlEncoder,
|
||||
TokenRepository tokenRepository,
|
||||
BTCPayWalletProvider walletProvider,
|
||||
StoreRepository storeRepository,
|
||||
IWebHostEnvironment env,
|
||||
|
@ -61,7 +58,6 @@ namespace BTCPayServer.Controllers
|
|||
_EmailSenderFactory = emailSenderFactory;
|
||||
_logger = logger;
|
||||
_urlEncoder = urlEncoder;
|
||||
_TokenRepository = tokenRepository;
|
||||
_Env = env;
|
||||
_u2FService = u2FService;
|
||||
_btcPayServerEnvironment = btcPayServerEnvironment;
|
||||
|
|
|
@ -11,11 +11,11 @@ using BTCPayServer.Services.Stores;
|
|||
using BTCPayServer.Rating;
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using BTCPayServer.Authentication;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using System.Threading;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Security.Bitpay;
|
||||
|
||||
namespace BTCPayServer.Controllers
|
||||
{
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Models;
|
||||
using BTCPayServer.Security;
|
||||
|
|
|
@ -5,7 +5,6 @@ using System.Linq;
|
|||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.HostedServices;
|
||||
|
@ -17,6 +16,7 @@ using BTCPayServer.Payments.Changelly;
|
|||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Rating;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Security.Bitpay;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Rates;
|
||||
|
|
|
@ -4,7 +4,6 @@ using System.Linq;
|
|||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Security;
|
||||
using BTCPayServer.Services.Rates;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Configuration;
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
|
|
@ -25,7 +25,6 @@ using BTCPayServer.Controllers;
|
|||
using BTCPayServer.Services.Mails;
|
||||
using System.Threading;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.HostedServices;
|
||||
using BTCPayServer.PaymentRequest;
|
||||
|
|
|
@ -7,7 +7,6 @@ using System.Text;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using BTCPayServer.Models;
|
||||
|
|
|
@ -24,7 +24,6 @@ using BTCPayServer.Security;
|
|||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using OpenIddict.EntityFrameworkCore.Models;
|
||||
using System.Net;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Security.OpenId;
|
||||
using BTCPayServer.PaymentRequest;
|
||||
using BTCPayServer.Services.Apps;
|
||||
|
|
|
@ -6,10 +6,10 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Authentication;
|
||||
using NBitcoin.DataEncoders;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.IO;
|
||||
using BTCPayServer.Security.Bitpay;
|
||||
|
||||
namespace BTCPayServer.Models
|
||||
{
|
||||
|
|
|
@ -7,7 +7,6 @@ using System.Linq;
|
|||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
|
|
@ -9,7 +9,6 @@ using System.Security.Claims;
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using BTCPayServer.Authentication;
|
||||
using BTCPayServer.Services;
|
||||
using BTCPayServer.Security.Bitpay;
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ using System.Security.Claims;
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using BTCPayServer.Authentication;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace BTCPayServer.Security
|
||||
|
|
|
@ -9,7 +9,6 @@ using System.Security.Claims;
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using BTCPayServer.Authentication;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using static BTCPayServer.Security.OpenId.RestAPIPolicies;
|
||||
using OpenIddict.Abstractions;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Authentication;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace BTCPayServer.Security
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@model BTCPayServer.Authentication.BitTokenEntity
|
||||
@model BTCPayServer.Security.Bitpay.BitTokenEntity
|
||||
@{
|
||||
Layout = "../Shared/_NavLayout.cshtml";
|
||||
ViewData.SetActivePageAndTitle(StoreNavPages.Tokens, "Access Tokens");
|
||||
|
|
Loading…
Add table
Reference in a new issue