Start using JSONB column instead of app side compressed data (#4574)

This commit is contained in:
Nicolas Dorier
2023-02-21 15:06:34 +09:00
committed by GitHub
parent 5c61de3ae9
commit 2bd8227e20
61 changed files with 669 additions and 300 deletions

View File

@@ -1,7 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Data.Data;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design; using Microsoft.EntityFrameworkCore.Design;
@@ -90,23 +89,23 @@ namespace BTCPayServer.Data
// some of the data models don't have OnModelCreating for now, commenting them // some of the data models don't have OnModelCreating for now, commenting them
ApplicationUser.OnModelCreating(builder); ApplicationUser.OnModelCreating(builder, Database);
AddressInvoiceData.OnModelCreating(builder); AddressInvoiceData.OnModelCreating(builder);
APIKeyData.OnModelCreating(builder); APIKeyData.OnModelCreating(builder, Database);
AppData.OnModelCreating(builder); AppData.OnModelCreating(builder);
CustodianAccountData.OnModelCreating(builder); CustodianAccountData.OnModelCreating(builder, Database);
//StoredFile.OnModelCreating(builder); //StoredFile.OnModelCreating(builder);
InvoiceEventData.OnModelCreating(builder); InvoiceEventData.OnModelCreating(builder);
InvoiceSearchData.OnModelCreating(builder); InvoiceSearchData.OnModelCreating(builder);
InvoiceWebhookDeliveryData.OnModelCreating(builder); InvoiceWebhookDeliveryData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder); InvoiceData.OnModelCreating(builder, Database);
NotificationData.OnModelCreating(builder); NotificationData.OnModelCreating(builder, Database);
//OffchainTransactionData.OnModelCreating(builder); //OffchainTransactionData.OnModelCreating(builder);
BTCPayServer.Data.PairedSINData.OnModelCreating(builder); BTCPayServer.Data.PairedSINData.OnModelCreating(builder);
PairingCodeData.OnModelCreating(builder); PairingCodeData.OnModelCreating(builder);
//PayjoinLock.OnModelCreating(builder); //PayjoinLock.OnModelCreating(builder);
PaymentRequestData.OnModelCreating(builder); PaymentRequestData.OnModelCreating(builder, Database);
PaymentData.OnModelCreating(builder); PaymentData.OnModelCreating(builder, Database);
PayoutData.OnModelCreating(builder); PayoutData.OnModelCreating(builder);
PendingInvoiceData.OnModelCreating(builder); PendingInvoiceData.OnModelCreating(builder);
//PlannedTransaction.OnModelCreating(builder); //PlannedTransaction.OnModelCreating(builder);
@@ -117,7 +116,7 @@ namespace BTCPayServer.Data
StoreWebhookData.OnModelCreating(builder); StoreWebhookData.OnModelCreating(builder);
StoreData.OnModelCreating(builder, Database); StoreData.OnModelCreating(builder, Database);
U2FDevice.OnModelCreating(builder); U2FDevice.OnModelCreating(builder);
Fido2Credential.OnModelCreating(builder); Fido2Credential.OnModelCreating(builder, Database);
BTCPayServer.Data.UserStore.OnModelCreating(builder); BTCPayServer.Data.UserStore.OnModelCreating(builder);
//WalletData.OnModelCreating(builder); //WalletData.OnModelCreating(builder);
WalletObjectData.OnModelCreating(builder, Database); WalletObjectData.OnModelCreating(builder, Database);
@@ -125,10 +124,10 @@ namespace BTCPayServer.Data
#pragma warning disable CS0612 // Type or member is obsolete #pragma warning disable CS0612 // Type or member is obsolete
WalletTransactionData.OnModelCreating(builder); WalletTransactionData.OnModelCreating(builder);
#pragma warning restore CS0612 // Type or member is obsolete #pragma warning restore CS0612 // Type or member is obsolete
WebhookDeliveryData.OnModelCreating(builder); WebhookDeliveryData.OnModelCreating(builder, Database);
LightningAddressData.OnModelCreating(builder); LightningAddressData.OnModelCreating(builder, Database);
PayoutProcessorData.OnModelCreating(builder); PayoutProcessorData.OnModelCreating(builder, Database);
//WebhookData.OnModelCreating(builder); WebhookData.OnModelCreating(builder, Database);
FormData.OnModelCreating(builder, Database); FormData.OnModelCreating(builder, Database);

View File

@@ -1,9 +1,11 @@
using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public class APIKeyData public class APIKeyData : IHasBlob<APIKeyBlob>
{ {
[MaxLength(50)] [MaxLength(50)]
public string Id { get; set; } public string Id { get; set; }
@@ -16,13 +18,15 @@ namespace BTCPayServer.Data
public APIKeyType Type { get; set; } = APIKeyType.Legacy; public APIKeyType Type { get; set; } = APIKeyType.Legacy;
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public StoreData StoreData { get; set; } public StoreData StoreData { get; set; }
public ApplicationUser User { get; set; } public ApplicationUser User { get; set; }
public string Label { get; set; } public string Label { get; set; }
internal static void OnModelCreating(ModelBuilder builder) internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<APIKeyData>() builder.Entity<APIKeyData>()
.HasOne(o => o.StoreData) .HasOne(o => o.StoreData)
@@ -36,6 +40,13 @@ namespace BTCPayServer.Data
builder.Entity<APIKeyData>() builder.Entity<APIKeyData>()
.HasIndex(o => o.StoreId); .HasIndex(o => o.StoreId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<APIKeyData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
} }

View File

@@ -2,11 +2,13 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
// Add profile data for application users by adding properties to the ApplicationUser class // Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser public class ApplicationUser : IdentityUser, IHasBlob<UserBlob>
{ {
public bool RequiresEmailConfirmation { get; set; } public bool RequiresEmailConfirmation { get; set; }
public List<StoredFile> StoredFiles { get; set; } public List<StoredFile> StoredFiles { get; set; }
@@ -20,15 +22,28 @@ namespace BTCPayServer.Data
public List<UserStore> UserStores { get; set; } public List<UserStore> UserStores { get; set; }
public List<Fido2Credential> Fido2Credentials { get; set; } public List<Fido2Credential> Fido2Credentials { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public List<IdentityUserRole<string>> UserRoles { get; set; } public List<IdentityUserRole<string>> UserRoles { get; set; }
public static void OnModelCreating(ModelBuilder builder) public static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<ApplicationUser>() builder.Entity<ApplicationUser>()
.HasMany<IdentityUserRole<string>>(user => user.UserRoles) .HasMany<IdentityUserRole<string>>(user => user.UserRoles)
.WithOne().HasForeignKey(role => role.UserId); .WithOne().HasForeignKey(role => role.UserId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<ApplicationUser>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
} }
} }
}
public class UserBlob
{
public bool ShowInvoiceStatusChangeHint { get; set; }
}
} }

View File

@@ -1,11 +1,13 @@
using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data; namespace BTCPayServer.Data;
public class CustodianAccountData public class CustodianAccountData : IHasBlob<JObject>
{ {
[Required] [Required]
[MaxLength(50)] [MaxLength(50)]
@@ -24,19 +26,29 @@ public class CustodianAccountData
public string Name { get; set; } public string Name { get; set; }
[JsonIgnore] [JsonIgnore]
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
[JsonIgnore]
public string Blob2 { get; set; }
[JsonIgnore] [JsonIgnore]
public StoreData StoreData { get; set; } public StoreData StoreData { get; set; }
internal static void OnModelCreating(ModelBuilder builder) internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<CustodianAccountData>() builder.Entity<CustodianAccountData>()
.HasOne(o => o.StoreData) .HasOne(o => o.StoreData)
.WithMany(i => i.CustodianAccounts) .WithMany(i => i.CustodianAccounts)
.HasForeignKey(i => i.StoreId).OnDelete(DeleteBehavior.Cascade); .HasForeignKey(i => i.StoreId).OnDelete(DeleteBehavior.Cascade);
builder.Entity<APIKeyData>() builder.Entity<CustodianAccountData>()
.HasIndex(o => o.StoreId); .HasIndex(o => o.StoreId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<CustodianAccountData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
} }

View File

@@ -2,10 +2,11 @@ using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public class Fido2Credential public class Fido2Credential : IHasBlobUntyped
{ {
public string Name { get; set; } public string Name { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
@@ -14,6 +15,7 @@ namespace BTCPayServer.Data
public string ApplicationUserId { get; set; } public string ApplicationUserId { get; set; }
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public CredentialType Type { get; set; } public CredentialType Type { get; set; }
public enum CredentialType public enum CredentialType
{ {
@@ -22,12 +24,18 @@ namespace BTCPayServer.Data
[Display(Name = "Lightning node (LNURL Auth)")] [Display(Name = "Lightning node (LNURL Auth)")]
LNURLAuth LNURLAuth
} }
public static void OnModelCreating(ModelBuilder builder) public static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<Fido2Credential>() builder.Entity<Fido2Credential>()
.HasOne(o => o.ApplicationUser) .HasOne(o => o.ApplicationUser)
.WithMany(i => i.Fido2Credentials) .WithMany(i => i.Fido2Credentials)
.HasForeignKey(i => i.ApplicationUserId).OnDelete(DeleteBehavior.Cascade); .HasForeignKey(i => i.ApplicationUserId).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<Fido2Credential>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
public ApplicationUser ApplicationUser { get; set; } public ApplicationUser ApplicationUser { get; set; }

View File

@@ -1,8 +1,8 @@
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data.Data; namespace BTCPayServer.Data;
public class FormData public class FormData
{ {

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BTCPayServer.Data
{
public interface IHasBlob<T>
{
[Obsolete("Use Blob2 instead")]
byte[] Blob { get; set; }
string Blob2 { get; set; }
}
public interface IHasBlob
{
[Obsolete("Use Blob2 instead")]
byte[] Blob { get; set; }
string Blob2 { get; set; }
public Type Type { get; set; }
}
public interface IHasBlobUntyped
{
[Obsolete("Use Blob2 instead")]
byte[] Blob { get; set; }
string Blob2 { get; set; }
}
}

View File

@@ -2,10 +2,11 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public class InvoiceData public class InvoiceData : IHasBlobUntyped
{ {
public string Id { get; set; } public string Id { get; set; }
@@ -16,7 +17,9 @@ namespace BTCPayServer.Data
public List<PaymentData> Payments { get; set; } public List<PaymentData> Payments { get; set; }
public List<InvoiceEventData> Events { get; set; } public List<InvoiceEventData> Events { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public string ItemCode { get; set; } public string ItemCode { get; set; }
public string OrderId { get; set; } public string OrderId { get; set; }
public string Status { get; set; } public string Status { get; set; }
@@ -32,7 +35,7 @@ namespace BTCPayServer.Data
public RefundData CurrentRefund { get; set; } public RefundData CurrentRefund { get; set; }
internal static void OnModelCreating(ModelBuilder builder) internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<InvoiceData>() builder.Entity<InvoiceData>()
.HasOne(o => o.StoreData) .HasOne(o => o.StoreData)
@@ -42,6 +45,13 @@ namespace BTCPayServer.Data
builder.Entity<InvoiceData>() builder.Entity<InvoiceData>()
.HasOne(o => o.CurrentRefund); .HasOne(o => o.CurrentRefund);
builder.Entity<InvoiceData>().HasIndex(o => o.Created); builder.Entity<InvoiceData>().HasIndex(o => o.Created);
if (databaseFacade.IsNpgsql())
{
builder.Entity<InvoiceData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
} }
} }

View File

@@ -1,17 +1,21 @@
using System;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data; namespace BTCPayServer.Data;
public class LightningAddressData public class LightningAddressData : IHasBlob<LightningAddressDataBlob>
{ {
public string Username { get; set; } public string Username { get; set; }
public string StoreDataId { get; set; } public string StoreDataId { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public StoreData Store { get; set; } public StoreData Store { get; set; }
internal static void OnModelCreating(ModelBuilder builder) internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<LightningAddressData>() builder.Entity<LightningAddressData>()
.HasOne(o => o.Store) .HasOne(o => o.Store)
@@ -20,6 +24,12 @@ public class LightningAddressData
.IsRequired() .IsRequired()
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
builder.Entity<LightningAddressData>().HasKey(o => o.Username); builder.Entity<LightningAddressData>().HasKey(o => o.Username);
if (databaseFacade.IsNpgsql())
{
builder.Entity<LightningAddressData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
} }

View File

@@ -1,10 +1,12 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public class NotificationData public class NotificationData : IHasBlobUntyped
{ {
[MaxLength(36)] [MaxLength(36)]
public string Id { get; set; } public string Id { get; set; }
@@ -17,14 +19,23 @@ namespace BTCPayServer.Data
[Required] [Required]
public string NotificationType { get; set; } public string NotificationType { get; set; }
public bool Seen { get; set; } public bool Seen { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<NotificationData>() builder.Entity<NotificationData>()
.HasOne(o => o.ApplicationUser) .HasOne(o => o.ApplicationUser)
.WithMany(n => n.Notifications) .WithMany(n => n.Notifications)
.HasForeignKey(k => k.ApplicationUserId).OnDelete(DeleteBehavior.Cascade); .HasForeignKey(k => k.ApplicationUserId).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<NotificationData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
} }
} }

View File

@@ -1,24 +1,34 @@
using System;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public class PaymentData public class PaymentData : IHasBlobUntyped
{ {
public string Id { get; set; } public string Id { get; set; }
public string InvoiceDataId { get; set; } public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; } public InvoiceData InvoiceData { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public string Type { get; set; }
public bool Accounted { get; set; } public bool Accounted { get; set; }
internal static void OnModelCreating(ModelBuilder builder) internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<PaymentData>() builder.Entity<PaymentData>()
.HasOne(o => o.InvoiceData) .HasOne(o => o.InvoiceData)
.WithMany(i => i.Payments).OnDelete(DeleteBehavior.Cascade); .WithMany(i => i.Payments).OnDelete(DeleteBehavior.Cascade);
builder.Entity<PaymentData>() builder.Entity<PaymentData>()
.HasIndex(o => o.InvoiceDataId); .HasIndex(o => o.InvoiceDataId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<PaymentData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
} }
} }

View File

@@ -1,9 +1,10 @@
using System; using System;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public class PaymentRequestData public class PaymentRequestData : IHasBlobUntyped
{ {
public string Id { get; set; } public string Id { get; set; }
public DateTimeOffset Created { get; set; } public DateTimeOffset Created { get; set; }
@@ -14,10 +15,12 @@ namespace BTCPayServer.Data
public Client.Models.PaymentRequestData.PaymentRequestStatus Status { get; set; } public Client.Models.PaymentRequestData.PaymentRequestStatus Status { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
internal static void OnModelCreating(ModelBuilder builder) internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<PaymentRequestData>() builder.Entity<PaymentRequestData>()
.HasOne(o => o.StoreData) .HasOne(o => o.StoreData)
@@ -28,6 +31,13 @@ namespace BTCPayServer.Data
.HasDefaultValue(new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)); .HasDefaultValue(new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero));
builder.Entity<PaymentRequestData>() builder.Entity<PaymentRequestData>()
.HasIndex(o => o.Status); .HasIndex(o => o.Status);
if (databaseFacade.IsNpgsql())
{
builder.Entity<PaymentRequestData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
} }
} }

View File

@@ -1,9 +1,15 @@
using System;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data.Data; namespace BTCPayServer.Data;
public class PayoutProcessorData public class AutomatedPayoutBlob
{
public TimeSpan Interval { get; set; } = TimeSpan.FromHours(1);
}
public class PayoutProcessorData : IHasBlobUntyped
{ {
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; } public string Id { get; set; }
@@ -12,14 +18,22 @@ public class PayoutProcessorData
public string PaymentMethod { get; set; } public string PaymentMethod { get; set; }
public string Processor { get; set; } public string Processor { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
internal static void OnModelCreating(ModelBuilder builder) internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<PayoutProcessorData>() builder.Entity<PayoutProcessorData>()
.HasOne(o => o.Store) .HasOne(o => o.Store)
.WithMany(data => data.PayoutProcessors).OnDelete(DeleteBehavior.Cascade); .WithMany(data => data.PayoutProcessors).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<PayoutProcessorData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
public override string ToString() public override string ToString()

View File

@@ -3,11 +3,10 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Text; using System.Text;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData; using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {

View File

@@ -1,15 +1,29 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public class WebhookData public class WebhookData : IHasBlobUntyped
{ {
[Key] [Key]
[MaxLength(25)] [MaxLength(25)]
public string Id { get; set; } public string Id { get; set; }
[Required] [Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public List<WebhookDeliveryData> Deliveries { get; set; } public List<WebhookDeliveryData> Deliveries { get; set; }
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
if (databaseFacade.IsNpgsql())
{
builder.Entity<WebhookData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
} }
} }

View File

@@ -1,10 +1,11 @@
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public class WebhookDeliveryData public class WebhookDeliveryData : IHasBlobUntyped
{ {
[Key] [Key]
[MaxLength(25)] [MaxLength(25)]
@@ -16,17 +17,24 @@ namespace BTCPayServer.Data
[Required] [Required]
public DateTimeOffset Timestamp { get; set; } public DateTimeOffset Timestamp { get; set; }
[Obsolete("Use Blob2 instead")]
[Required]
public byte[] Blob { get; set; } public byte[] Blob { get; set; }
public string Blob2 { get; set; }
internal static void OnModelCreating(ModelBuilder builder) internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{ {
builder.Entity<WebhookDeliveryData>() builder.Entity<WebhookDeliveryData>()
.HasOne(o => o.Webhook) .HasOne(o => o.Webhook)
.WithMany(a => a.Deliveries).OnDelete(DeleteBehavior.Cascade); .WithMany(a => a.Deliveries).OnDelete(DeleteBehavior.Cascade);
builder.Entity<WebhookDeliveryData>().HasIndex(o => o.WebhookId); builder.Entity<WebhookDeliveryData>().HasIndex(o => o.WebhookId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<WebhookDeliveryData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
} }
} }
} }

View File

@@ -0,0 +1,150 @@
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20230130040047_blob2")]
public partial class blob2 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
var type = migrationBuilder.IsNpgsql() ? "JSONB" : "TEXT";
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Webhooks",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "WebhookDeliveries",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "PaymentRequests",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Notifications",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "LightningAddresses",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Fido2Credentials",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "AspNetUsers",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "ApiKeys",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Invoices",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "Payments",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "PayoutProcessors",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Blob2",
table: "CustodianAccount",
type: type,
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Type",
table: "Payments",
type: "TEXT",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Blob2",
table: "Webhooks");
migrationBuilder.DropColumn(
name: "Blob2",
table: "WebhookDeliveries");
migrationBuilder.DropColumn(
name: "Blob2",
table: "PaymentRequests");
migrationBuilder.DropColumn(
name: "Blob2",
table: "Notifications");
migrationBuilder.DropColumn(
name: "Blob2",
table: "LightningAddresses");
migrationBuilder.DropColumn(
name: "Blob2",
table: "Fido2Credentials");
migrationBuilder.DropColumn(
name: "Blob2",
table: "AspNetUsers");
migrationBuilder.DropColumn(
name: "Blob2",
table: "ApiKeys");
migrationBuilder.DropColumn(
name: "Blob2",
table: "Invoices");
migrationBuilder.DropColumn(
name: "Blob2",
table: "Payments");
migrationBuilder.DropColumn(
name: "Blob2",
table: "PayoutProcessors");
migrationBuilder.DropColumn(
name: "Blob2",
table: "CustodianAccount");
migrationBuilder.DropColumn(
name: "Type",
table: "Payments");
}
}
}

View File

@@ -45,6 +45,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("Label") b.Property<string>("Label")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@@ -109,6 +112,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp") b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken() .IsConcurrencyToken()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@@ -183,6 +189,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("CustodianCode") b.Property<string>("CustodianCode")
.IsRequired() .IsRequired()
.HasMaxLength(50) .HasMaxLength(50)
@@ -205,7 +214,7 @@ namespace BTCPayServer.Migrations
b.ToTable("CustodianAccount"); b.ToTable("CustodianAccount");
}); });
modelBuilder.Entity("BTCPayServer.Data.Data.FormData", b => modelBuilder.Entity("BTCPayServer.Data.FormData", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -230,7 +239,7 @@ namespace BTCPayServer.Migrations
b.ToTable("Forms"); b.ToTable("Forms");
}); });
modelBuilder.Entity("BTCPayServer.Data.Data.PayoutProcessorData", b => modelBuilder.Entity("BTCPayServer.Data.PayoutProcessorData", b =>
{ {
b.Property<string>("Id") b.Property<string>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -267,6 +276,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("Name") b.Property<string>("Name")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@@ -291,6 +303,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Created") b.Property<DateTimeOffset>("Created")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@@ -401,6 +416,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("StoreDataId") b.Property<string>("StoreDataId")
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@@ -426,6 +444,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Created") b.Property<DateTimeOffset>("Created")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@@ -537,9 +558,15 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<string>("InvoiceDataId") b.Property<string>("InvoiceDataId")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<string>("Type")
.HasColumnType("TEXT");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("InvoiceDataId"); b.HasIndex("InvoiceDataId");
@@ -558,6 +585,9 @@ namespace BTCPayServer.Migrations
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Created") b.Property<DateTimeOffset>("Created")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("TEXT") .HasColumnType("TEXT")
@@ -945,9 +975,11 @@ namespace BTCPayServer.Migrations
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.IsRequired()
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("Webhooks"); b.ToTable("Webhooks");
@@ -960,9 +992,11 @@ namespace BTCPayServer.Migrations
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<byte[]>("Blob") b.Property<byte[]>("Blob")
.IsRequired()
.HasColumnType("BLOB"); .HasColumnType("BLOB");
b.Property<string>("Blob2")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Timestamp") b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
@@ -1154,7 +1188,7 @@ namespace BTCPayServer.Migrations
b.Navigation("StoreData"); b.Navigation("StoreData");
}); });
modelBuilder.Entity("BTCPayServer.Data.Data.FormData", b => modelBuilder.Entity("BTCPayServer.Data.FormData", b =>
{ {
b.HasOne("BTCPayServer.Data.StoreData", "Store") b.HasOne("BTCPayServer.Data.StoreData", "Store")
.WithMany("Forms") .WithMany("Forms")
@@ -1164,7 +1198,7 @@ namespace BTCPayServer.Migrations
b.Navigation("Store"); b.Navigation("Store");
}); });
modelBuilder.Entity("BTCPayServer.Data.Data.PayoutProcessorData", b => modelBuilder.Entity("BTCPayServer.Data.PayoutProcessorData", b =>
{ {
b.HasOne("BTCPayServer.Data.StoreData", "Store") b.HasOne("BTCPayServer.Data.StoreData", "Store")
.WithMany("PayoutProcessors") .WithMany("PayoutProcessors")

View File

@@ -1696,7 +1696,9 @@ namespace BTCPayServer.Tests
var db = tester.PayTester.GetService<Data.ApplicationDbContextFactory>(); var db = tester.PayTester.GetService<Data.ApplicationDbContextFactory>();
using var ctx = db.CreateContext(); using var ctx = db.CreateContext();
var dbInvoice = await ctx.Invoices.FindAsync(oldInvoice.Id); var dbInvoice = await ctx.Invoices.FindAsync(oldInvoice.Id);
#pragma warning disable CS0618 // Type or member is obsolete
dbInvoice.Blob = ZipUtils.Zip(invoiceV1); dbInvoice.Blob = ZipUtils.Zip(invoiceV1);
#pragma warning restore CS0618 // Type or member is obsolete
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
var newInvoice = await AssertInvoiceMetadata(); var newInvoice = await AssertInvoiceMetadata();
@@ -1998,7 +2000,7 @@ namespace BTCPayServer.Tests
//get //get
var invoice = await viewOnly.GetInvoice(user.StoreId, newInvoice.Id); var invoice = await viewOnly.GetInvoice(user.StoreId, newInvoice.Id);
Assert.Equal(newInvoice.Metadata, invoice.Metadata); Assert.True(JObject.DeepEquals(newInvoice.Metadata, invoice.Metadata));
var paymentMethods = await viewOnly.GetInvoicePaymentMethods(user.StoreId, newInvoice.Id); var paymentMethods = await viewOnly.GetInvoicePaymentMethods(user.StoreId, newInvoice.Id);
Assert.Single(paymentMethods); Assert.Single(paymentMethods);
var paymentMethod = paymentMethods.First(); var paymentMethod = paymentMethods.First();

View File

@@ -11,6 +11,7 @@ using BTCPayServer.Security;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using StoreData = BTCPayServer.Data.StoreData; using StoreData = BTCPayServer.Data.StoreData;
using PayoutProcessorData = BTCPayServer.Client.Models.PayoutProcessorData;
namespace BTCPayServer.Controllers.Greenfield namespace BTCPayServer.Controllers.Greenfield
{ {

View File

@@ -4,15 +4,14 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors; using BTCPayServer.PayoutProcessors;
using BTCPayServer.PayoutProcessors.Lightning; using BTCPayServer.PayoutProcessors.Lightning;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData; using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.Controllers.Greenfield namespace BTCPayServer.Controllers.Greenfield
{ {
@@ -55,7 +54,7 @@ namespace BTCPayServer.Controllers.Greenfield
return new LightningAutomatedPayoutSettings() return new LightningAutomatedPayoutSettings()
{ {
PaymentMethod = data.PaymentMethod, PaymentMethod = data.PaymentMethod,
IntervalSeconds = InvoiceRepository.FromBytes<AutomatedPayoutBlob>(data.Blob).Interval IntervalSeconds = data.HasTypedBlob<AutomatedPayoutBlob>().GetBlob()!.Interval
}; };
} }
@@ -81,7 +80,7 @@ namespace BTCPayServer.Controllers.Greenfield
})) }))
.FirstOrDefault(); .FirstOrDefault();
activeProcessor ??= new PayoutProcessorData(); activeProcessor ??= new PayoutProcessorData();
activeProcessor.Blob = InvoiceRepository.ToBytes(FromModel(request)); activeProcessor.HasTypedBlob<AutomatedPayoutBlob>().SetBlob(FromModel(request));
activeProcessor.StoreId = storeId; activeProcessor.StoreId = storeId;
activeProcessor.PaymentMethod = paymentMethod; activeProcessor.PaymentMethod = paymentMethod;
activeProcessor.Processor = LightningAutomatedPayoutSenderFactory.ProcessorName; activeProcessor.Processor = LightningAutomatedPayoutSenderFactory.ProcessorName;

View File

@@ -4,15 +4,14 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors; using BTCPayServer.PayoutProcessors;
using BTCPayServer.PayoutProcessors.OnChain; using BTCPayServer.PayoutProcessors.OnChain;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData; using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.Controllers.Greenfield namespace BTCPayServer.Controllers.Greenfield
{ {
@@ -87,7 +86,7 @@ namespace BTCPayServer.Controllers.Greenfield
})) }))
.FirstOrDefault(); .FirstOrDefault();
activeProcessor ??= new PayoutProcessorData(); activeProcessor ??= new PayoutProcessorData();
activeProcessor.Blob = InvoiceRepository.ToBytes(FromModel(request)); activeProcessor.HasTypedBlob<OnChainAutomatedPayoutBlob>().SetBlob(FromModel(request));
activeProcessor.StoreId = storeId; activeProcessor.StoreId = storeId;
activeProcessor.PaymentMethod = paymentMethod; activeProcessor.PaymentMethod = paymentMethod;
activeProcessor.Processor = OnChainAutomatedPayoutSenderFactory.ProcessorName; activeProcessor.Processor = OnChainAutomatedPayoutSenderFactory.ProcessorName;

View File

@@ -26,7 +26,9 @@ namespace BTCPayServer.Controllers.Greenfield
private LightningAddressData ToModel(BTCPayServer.Data.LightningAddressData data) private LightningAddressData ToModel(BTCPayServer.Data.LightningAddressData data)
{ {
var blob = data.Blob.GetBlob<LightningAddressDataBlob>(); var blob = data.GetBlob();
if (blob is null)
return new LightningAddressData();
return new LightningAddressData() return new LightningAddressData()
{ {
Username = data.Username, Max = blob.Max, Min = blob.Min, CurrencyCode = blob.CurrencyCode Username = data.Username, Max = blob.Max, Min = blob.Min, CurrencyCode = blob.CurrencyCode
@@ -79,12 +81,13 @@ namespace BTCPayServer.Controllers.Greenfield
if (await _lightningAddressService.Set(new Data.LightningAddressData() if (await _lightningAddressService.Set(new Data.LightningAddressData()
{ {
StoreDataId = storeId, StoreDataId = storeId,
Username = username, Username = username
Blob = new LightningAddressDataBlob() }.SetBlob(new LightningAddressDataBlob()
{ {
Max = data.Max, Min = data.Min, CurrencyCode = data.CurrencyCode Max = data.Max,
}.SerializeBlob() Min = data.Min,
})) CurrencyCode = data.CurrencyCode
})))
{ {
return await GetStoreLightningAddress(storeId, username); return await GetStoreLightningAddress(storeId, username);
} }

View File

@@ -34,6 +34,7 @@ using PullPaymentData = BTCPayServer.Client.Models.PullPaymentData;
using StoreData = BTCPayServer.Client.Models.StoreData; using StoreData = BTCPayServer.Client.Models.StoreData;
using StoreWebhookData = BTCPayServer.Client.Models.StoreWebhookData; using StoreWebhookData = BTCPayServer.Client.Models.StoreWebhookData;
using WebhookDeliveryData = BTCPayServer.Client.Models.WebhookDeliveryData; using WebhookDeliveryData = BTCPayServer.Client.Models.WebhookDeliveryData;
using PayoutProcessorData = BTCPayServer.Client.Models.PayoutProcessorData;
namespace BTCPayServer.Controllers.Greenfield namespace BTCPayServer.Controllers.Greenfield
{ {

View File

@@ -336,7 +336,7 @@ namespace BTCPayServer
return NotFound("Unknown username"); return NotFound("Unknown username");
} }
var blob = lightningAddressSettings.Blob.GetBlob<LightningAddressDataBlob>(); var blob = lightningAddressSettings.GetBlob();
return await GetLNURL("BTC", lightningAddressSettings.StoreDataId, blob.CurrencyCode, blob.Min, blob.Max, return await GetLNURL("BTC", lightningAddressSettings.StoreDataId, blob.CurrencyCode, blob.Min, blob.Max,
() => (username, null, null, null, null, true)); () => (username, null, null, null, null, true));
} }
@@ -684,7 +684,7 @@ namespace BTCPayServer
{ {
Items = addresses.Select(s => Items = addresses.Select(s =>
{ {
var blob = s.Blob.GetBlob<LightningAddressDataBlob>(); var blob = s.GetBlob();
return new EditLightningAddressVM.EditLightningAddressItem return new EditLightningAddressVM.EditLightningAddressItem
{ {
Max = blob.Max, Max = blob.Max,
@@ -722,14 +722,13 @@ namespace BTCPayServer
if (await _lightningAddressService.Set(new LightningAddressData() if (await _lightningAddressService.Set(new LightningAddressData()
{ {
StoreDataId = storeId, StoreDataId = storeId,
Username = vm.Add.Username, Username = vm.Add.Username
Blob = new LightningAddressDataBlob() }.SetBlob(new LightningAddressDataBlob()
{ {
Max = vm.Add.Max, Max = vm.Add.Max,
Min = vm.Add.Min, Min = vm.Add.Min,
CurrencyCode = vm.Add.CurrencyCode CurrencyCode = vm.Add.CurrencyCode
}.SerializeBlob() })))
}))
{ {
TempData.SetStatusMessageModel(new StatusMessageModel TempData.SetStatusMessageModel(new StatusMessageModel
{ {

View File

@@ -107,10 +107,8 @@ namespace BTCPayServer.Controllers
var blob = user.GetBlob(); var blob = user.GetBlob();
blob.ShowInvoiceStatusChangeHint = false; blob.ShowInvoiceStatusChangeHint = false;
if (user.SetBlob(blob)) user.SetBlob(blob);
{
await _userManager.UpdateAsync(user); await _userManager.UpdateAsync(user);
}
return RedirectToAction(nameof(Index)); return RedirectToAction(nameof(Index));
} }

View File

@@ -1,37 +0,0 @@
using System.Linq;
using NBXplorer;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data
{
public static class APIKeyDataExtensions
{
public static APIKeyBlob GetBlob(this APIKeyData apiKeyData)
{
return GetBlob<APIKeyBlob>(apiKeyData.Blob);
}
public static bool SetBlob(this APIKeyData apiKeyData, APIKeyBlob blob)
{
var newBlob = SerializeBlob(blob);
if (apiKeyData?.Blob?.SequenceEqual(newBlob) is true)
return false;
apiKeyData.Blob = newBlob;
return true;
}
public static T GetBlob<T>(this byte[] data)
{
var result = data == null
? default
: JObject.Parse(ZipUtils.Unzip(data)).ToObject<T>();
return result;
}
public static byte[] SerializeBlob<T>(this T blob)
{
var newBlob = new Serializer(null).ToString(blob);
return ZipUtils.Zip(newBlob);
}
}
}

View File

@@ -1,3 +1,4 @@
#nullable enable
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -7,19 +8,6 @@ public static class CustodianAccountDataExtensions
{ {
public static JObject GetBlob(this CustodianAccountData custodianAccountData) public static JObject GetBlob(this CustodianAccountData custodianAccountData)
{ {
var result = custodianAccountData.Blob == null return ((IHasBlob<JObject>)custodianAccountData).GetBlob() ?? new JObject();
? new JObject()
: InvoiceRepository.FromBytes<JObject>(custodianAccountData.Blob);
return result;
}
public static bool SetBlob(this CustodianAccountData custodianAccountData, JObject blob)
{
var original = custodianAccountData.GetBlob();
if (JToken.DeepEquals(original, blob))
return false;
custodianAccountData.Blob = blob is null ? null : InvoiceRepository.ToBytes(blob);
return true;
} }
} }

View File

@@ -0,0 +1,92 @@
#nullable enable
using System;
using System.Collections;
using System.Linq;
using System.Reflection.Metadata;
using NBXplorer;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data
{
public static class IHasBlobExtensions
{
static readonly JsonSerializerSettings DefaultSerializer;
static IHasBlobExtensions()
{
DefaultSerializer = new JsonSerializerSettings()
{
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
Formatting = Formatting.None
};
NBitcoin.JsonConverters.Serializer.RegisterFrontConverters(DefaultSerializer);
}
class HasBlobWrapper<B> : IHasBlob<B>
{
IHasBlobUntyped data;
public HasBlobWrapper(IHasBlobUntyped data)
{
this.data = data;
}
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get { return data.Blob; } set { data.Blob = value; } }
public string Blob2 { get { return data.Blob2; } set { data.Blob2 = value; } }
}
class HasBlobWrapper : IHasBlob
{
IHasBlobUntyped data;
private Type type;
public HasBlobWrapper(IHasBlobUntyped data, Type type)
{
this.data = data;
this.type = type;
}
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get => data.Blob; set => data.Blob = value; }
public string Blob2 { get => data.Blob2; set => data.Blob2 = value; }
public Type Type { get => type; set => type = value; }
}
public static IHasBlob<B> HasTypedBlob<B>(this IHasBlobUntyped data)
{
return new HasBlobWrapper<B>(data);
}
public static IHasBlob HasTypedBlob(this IHasBlobUntyped data, Type blobType)
{
return new HasBlobWrapper(data, blobType);
}
public static B? GetBlob<B>(this IHasBlob<B> data, JsonSerializerSettings? settings = null)
{
if (data.Blob2 is not null)
return JObject.Parse(data.Blob2).ToObject<B>(JsonSerializer.CreateDefault(settings ?? DefaultSerializer));
#pragma warning disable CS0618 // Type or member is obsolete
if (data.Blob is not null && data.Blob.Length != 0)
return JObject.Parse(ZipUtils.Unzip(data.Blob)).ToObject<B>();
#pragma warning restore CS0618 // Type or member is obsolete
return default;
}
public static object? GetBlob(this IHasBlob data, JsonSerializerSettings? settings = null)
{
if (data.Blob2 is not null)
return JObject.Parse(data.Blob2).ToObject(data.Type, JsonSerializer.CreateDefault(settings ?? DefaultSerializer));
#pragma warning disable CS0618 // Type or member is obsolete
if (data.Blob is not null && data.Blob.Length != 0)
return JObject.Parse(ZipUtils.Unzip(data.Blob)).ToObject(data.Type);
#pragma warning restore CS0618 // Type or member is obsolete
return default;
}
public static T SetBlob<T, B>(this T data, B blob, JsonSerializerSettings? settings = null) where T : IHasBlob<B>
{
if (blob is null)
data.Blob2 = null;
else
data.Blob2 = JObject.FromObject(blob, JsonSerializer.CreateDefault(settings ?? DefaultSerializer)).ToString(Formatting.None);
#pragma warning disable CS0618 // Type or member is obsolete
data.Blob = new byte[0];
#pragma warning restore CS0618 // Type or member is obsolete
return data;
}
}
}

View File

@@ -1,13 +1,23 @@
using System.Reflection.Metadata;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using Newtonsoft.Json;
namespace BTCPayServer.Data namespace BTCPayServer.Data
{ {
public static class InvoiceDataExtensions public static class InvoiceDataExtensions
{ {
public static void SetBlob(this InvoiceData invoiceData, InvoiceEntity blob)
{
if (blob.Metadata is null)
blob.Metadata = new InvoiceMetadata();
invoiceData.HasTypedBlob<InvoiceEntity>().SetBlob(blob);
}
public static InvoiceEntity GetBlob(this InvoiceData invoiceData, BTCPayNetworkProvider networks) public static InvoiceEntity GetBlob(this InvoiceData invoiceData, BTCPayNetworkProvider networks)
{ {
#pragma warning disable CS0618 // Type or member is obsolete
var entity = InvoiceRepository.FromBytes<InvoiceEntity>(invoiceData.Blob); if (invoiceData.Blob is not null && invoiceData.Blob.Length != 0)
{
var entity = JsonConvert.DeserializeObject<InvoiceEntity>(ZipUtils.Unzip(invoiceData.Blob), InvoiceRepository.DefaultSerializerSettings);
entity.Networks = networks; entity.Networks = networks;
if (entity.Metadata is null) if (entity.Metadata is null)
{ {
@@ -22,6 +32,14 @@ namespace BTCPayServer.Data
} }
return entity; return entity;
} }
else
{
var entity = invoiceData.HasTypedBlob<InvoiceEntity>().GetBlob();
entity.Networks = networks;
return entity;
}
#pragma warning restore CS0618 // Type or member is obsolete
}
public static InvoiceState GetInvoiceState(this InvoiceData invoiceData) public static InvoiceState GetInvoiceState(this InvoiceData invoiceData)
{ {
return new InvoiceState(invoiceData.Status, invoiceData.ExceptionStatus); return new InvoiceState(invoiceData.Status, invoiceData.ExceptionStatus);

View File

@@ -1,4 +1,5 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using BTCPayServer.Payments;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@@ -6,8 +7,16 @@ namespace BTCPayServer.Data
{ {
public static class PaymentDataExtensions public static class PaymentDataExtensions
{ {
public static void SetBlob(this PaymentData paymentData, PaymentEntity entity)
{
paymentData.Type = entity.GetPaymentMethodId().ToStringNormalized();
paymentData.Blob2 = entity.Network.ToString(entity);
}
public static PaymentEntity GetBlob(this PaymentData paymentData, BTCPayNetworkProvider networks) public static PaymentEntity GetBlob(this PaymentData paymentData, BTCPayNetworkProvider networks)
{ {
#pragma warning disable CS0618 // Type or member is obsolete
if (paymentData.Blob is not null && paymentData.Blob.Length != 0)
{
var unziped = ZipUtils.Unzip(paymentData.Blob); var unziped = ZipUtils.Unzip(paymentData.Blob);
var cryptoCode = "BTC"; var cryptoCode = "BTC";
if (JObject.Parse(unziped).TryGetValue("cryptoCode", out var v) && v.Type == JTokenType.String) if (JObject.Parse(unziped).TryGetValue("cryptoCode", out var v) && v.Type == JTokenType.String)
@@ -26,5 +35,20 @@ namespace BTCPayServer.Data
paymentEntity.Accounted = paymentData.Accounted; paymentEntity.Accounted = paymentData.Accounted;
return paymentEntity; return paymentEntity;
} }
#pragma warning restore CS0618 // Type or member is obsolete
if (paymentData.Blob2 is not null)
{
if (!PaymentMethodId.TryParse(paymentData.Type, out var pmi))
return null;
var network = networks.GetNetwork<BTCPayNetworkBase>(pmi.CryptoCode);
if (network is null)
return null;
var entity = network.ToObject<PaymentEntity>(paymentData.Blob2);
entity.Network = network;
entity.Accounted = paymentData.Accounted;
return entity;
}
return null;
}
} }
} }

View File

@@ -9,13 +9,20 @@ namespace BTCPayServer.Data
{ {
public static PaymentRequestBaseData GetBlob(this PaymentRequestData paymentRequestData) public static PaymentRequestBaseData GetBlob(this PaymentRequestData paymentRequestData)
{ {
var result = paymentRequestData.Blob == null if (paymentRequestData.Blob2 is not null)
? new PaymentRequestBaseData() {
: ParseBlob(paymentRequestData.Blob); return paymentRequestData.HasTypedBlob<PaymentRequestBaseData>().GetBlob();
return result; }
#pragma warning disable CS0618 // Type or member is obsolete
else if (paymentRequestData.Blob is not null)
{
return ParseBlob(paymentRequestData.Blob);
}
#pragma warning restore CS0618 // Type or member is obsolete
return new PaymentRequestBaseData();
} }
private static PaymentRequestBaseData ParseBlob(byte[] blob) static PaymentRequestBaseData ParseBlob(byte[] blob)
{ {
var jobj = JObject.Parse(ZipUtils.Unzip(blob)); var jobj = JObject.Parse(ZipUtils.Unzip(blob));
// Fixup some legacy payment requests // Fixup some legacy payment requests
@@ -24,14 +31,9 @@ namespace BTCPayServer.Data
return jobj.ToObject<PaymentRequestBaseData>(); return jobj.ToObject<PaymentRequestBaseData>();
} }
public static bool SetBlob(this PaymentRequestData paymentRequestData, PaymentRequestBaseData blob) public static void SetBlob(this PaymentRequestData paymentRequestData, PaymentRequestBaseData blob)
{ {
var original = new Serializer(null).ToString(paymentRequestData.GetBlob()); paymentRequestData.HasTypedBlob<PaymentRequestBaseData>().SetBlob(blob);
var newBlob = new Serializer(null).ToString(blob);
if (original == newBlob)
return false;
paymentRequestData.Blob = ZipUtils.Zip(newBlob);
return true;
} }
} }
} }

View File

@@ -48,19 +48,19 @@ namespace BTCPayServer.Data
{ {
public static WebhookBlob GetBlob(this WebhookData webhook) public static WebhookBlob GetBlob(this WebhookData webhook)
{ {
return JsonConvert.DeserializeObject<WebhookBlob>(Encoding.UTF8.GetString(webhook.Blob)); return webhook.HasTypedBlob<WebhookBlob>().GetBlob();
} }
public static void SetBlob(this WebhookData webhook, WebhookBlob blob) public static void SetBlob(this WebhookData webhook, WebhookBlob blob)
{ {
webhook.Blob = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(blob)); webhook.HasTypedBlob<WebhookBlob>().SetBlob(blob);
} }
public static WebhookDeliveryBlob GetBlob(this WebhookDeliveryData webhook) public static WebhookDeliveryBlob GetBlob(this WebhookDeliveryData webhook)
{ {
return JsonConvert.DeserializeObject<WebhookDeliveryBlob>(ZipUtils.Unzip(webhook.Blob), HostedServices.WebhookSender.DefaultSerializerSettings); return webhook.HasTypedBlob<WebhookDeliveryBlob>().GetBlob(HostedServices.WebhookSender.DefaultSerializerSettings);
} }
public static void SetBlob(this WebhookDeliveryData webhook, WebhookDeliveryBlob blob) public static void SetBlob(this WebhookDeliveryData webhook, WebhookDeliveryBlob blob)
{ {
webhook.Blob = ZipUtils.Zip(JsonConvert.SerializeObject(blob, Formatting.None, HostedServices.WebhookSender.DefaultSerializerSettings)); webhook.HasTypedBlob<WebhookDeliveryBlob>().SetBlob(blob, HostedServices.WebhookSender.DefaultSerializerSettings);
} }
} }
} }

View File

@@ -17,27 +17,5 @@ namespace BTCPayServer
name = String.Empty; name = String.Empty;
return new MimeKit.MailboxAddress(name, user.Email); return new MimeKit.MailboxAddress(name, user.Email);
} }
public static UserBlob GetBlob(this ApplicationUser user)
{
var result = user.Blob == null
? new UserBlob()
: JObject.Parse(ZipUtils.Unzip(user.Blob)).ToObject<UserBlob>();
return result;
}
public static bool SetBlob(this ApplicationUser user, UserBlob blob)
{
var newBytes = InvoiceRepository.ToBytes(blob);
if (user.Blob != null && newBytes.SequenceEqual(user.Blob))
{
return false;
}
user.Blob = newBytes;
return true;
}
}
public class UserBlob
{
public bool ShowInvoiceStatusChangeHint { get; set; }
} }
} }

View File

@@ -9,23 +9,17 @@ namespace BTCPayServer.Fido2
{ {
public static Fido2CredentialBlob GetFido2Blob(this Fido2Credential credential) public static Fido2CredentialBlob GetFido2Blob(this Fido2Credential credential)
{ {
var result = credential.Blob == null return credential.HasTypedBlob<Fido2CredentialBlob>().GetBlob() ?? new Fido2CredentialBlob();
? new Fido2CredentialBlob()
: JObject.Parse(ZipUtils.Unzip(credential.Blob)).ToObject<Fido2CredentialBlob>();
return result;
} }
public static bool SetBlob(this Fido2Credential credential, Fido2CredentialBlob descriptor) public static void SetBlob(this Fido2Credential credential, Fido2CredentialBlob descriptor)
{ {
var original = new Serializer(null).ToString(credential.GetFido2Blob()); var current = credential.GetFido2Blob();
var newBlob = new Serializer(null).ToString(descriptor); var a = JObject.FromObject(current);
if (original == newBlob) var b = JObject.FromObject(descriptor);
return false; if (JObject.DeepEquals(a, b))
return;
credential.Type = Fido2Credential.CredentialType.FIDO2; credential.Type = Fido2Credential.CredentialType.FIDO2;
credential.Blob = ZipUtils.Zip(newBlob); credential.HasTypedBlob<Fido2CredentialBlob>().SetBlob(descriptor);
return true;
} }
} }
} }

View File

@@ -1,5 +1,5 @@
using BTCPayServer.Abstractions.Form; using BTCPayServer.Abstractions.Form;
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;

View File

@@ -9,7 +9,6 @@ using System.Threading.Tasks;
using BTCPayServer.Abstractions.Form; using BTCPayServer.Abstractions.Form;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;

View File

@@ -11,7 +11,6 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Forms.Models; using BTCPayServer.Forms.Models;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;

View File

@@ -318,7 +318,7 @@ namespace BTCPayServer.HostedServices
var sig = Encoders.Hex.EncodeData(hmac.ComputeHash(bytes)); var sig = Encoders.Hex.EncodeData(hmac.ComputeHash(bytes));
content.Headers.Add("BTCPay-Sig", $"sha256={sig}"); content.Headers.Add("BTCPay-Sig", $"sha256={sig}");
request.Content = content; request.Content = content;
var deliveryBlob = ctx.Delivery.Blob is null ? new WebhookDeliveryBlob() : ctx.Delivery.GetBlob(); var deliveryBlob = ctx.Delivery.GetBlob() ?? new WebhookDeliveryBlob();
deliveryBlob.Request = bytes; deliveryBlob.Request = bytes;
try try
{ {

View File

@@ -358,14 +358,14 @@ namespace BTCPayServer.Hosting
new LightningAddressData() new LightningAddressData()
{ {
StoreDataId = storeMap.Key, StoreDataId = storeMap.Key,
Username = storeitem, Username = storeitem
Blob = new LightningAddressDataBlob() }
.SetBlob(new LightningAddressDataBlob()
{ {
Max = val.Max, Max = val.Max,
Min = val.Min, Min = val.Min,
CurrencyCode = val.CurrencyCode CurrencyCode = val.CurrencyCode
}.SerializeBlob() }), ctx);
}, ctx);
} }
} }
} }

View File

@@ -4,16 +4,14 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using PayoutData = BTCPayServer.Data.PayoutData; using PayoutData = BTCPayServer.Data.PayoutData;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData; using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.PayoutProcessors; namespace BTCPayServer.PayoutProcessors;
@@ -79,9 +77,8 @@ public abstract class BaseAutomatedPayoutProcessor<T> : BaseAsyncService where T
await Task.Delay(blob.Interval, CancellationToken); await Task.Delay(blob.Interval, CancellationToken);
} }
public static T GetBlob(PayoutProcessorData payoutProcesserSettings)
public static T GetBlob(PayoutProcessorData data)
{ {
return InvoiceRepository.FromBytes<T>(data.Blob); return payoutProcesserSettings.HasTypedBlob<T>().GetBlob();
} }
} }

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;

View File

@@ -5,13 +5,11 @@ using System.Threading.Tasks;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Configuration; using BTCPayServer.Configuration;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Data.Payouts.LightningLike; using BTCPayServer.Data.Payouts.LightningLike;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Lightning; using BTCPayServer.Lightning;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.Payments.Lightning; using BTCPayServer.Payments.Lightning;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using LNURL; using LNURL;
@@ -19,7 +17,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using PayoutData = BTCPayServer.Data.PayoutData; using PayoutData = BTCPayServer.Data.PayoutData;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData; using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.PayoutProcessors.Lightning; namespace BTCPayServer.PayoutProcessors.Lightning;

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;

View File

@@ -6,10 +6,9 @@ using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models; using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.OnChain; using BTCPayServer.PayoutProcessors.OnChain;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -90,7 +89,7 @@ public class UILightningAutomatedPayoutProcessorsController : Controller
})) }))
.FirstOrDefault(); .FirstOrDefault();
activeProcessor ??= new PayoutProcessorData(); activeProcessor ??= new PayoutProcessorData();
activeProcessor.Blob = InvoiceRepository.ToBytes(automatedTransferBlob.ToBlob()); activeProcessor.HasTypedBlob<AutomatedPayoutBlob>().SetBlob(automatedTransferBlob.ToBlob());
activeProcessor.StoreId = storeId; activeProcessor.StoreId = storeId;
activeProcessor.PaymentMethod = new PaymentMethodId(cryptoCode, LightningPaymentType.Instance).ToString(); activeProcessor.PaymentMethod = new PaymentMethodId(cryptoCode, LightningPaymentType.Instance).ToString();
activeProcessor.Processor = _lightningAutomatedPayoutSenderFactory.Processor; activeProcessor.Processor = _lightningAutomatedPayoutSenderFactory.Processor;

View File

@@ -1,4 +1,4 @@
using BTCPayServer.PayoutProcessors.Settings; using BTCPayServer.Data;
namespace BTCPayServer.PayoutProcessors.OnChain; namespace BTCPayServer.PayoutProcessors.OnChain;

View File

@@ -5,11 +5,9 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Events; using BTCPayServer.Events;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services; using BTCPayServer.Services;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using BTCPayServer.Services.Wallets; using BTCPayServer.Services.Wallets;
@@ -19,7 +17,7 @@ using NBitcoin;
using NBXplorer; using NBXplorer;
using NBXplorer.DerivationStrategy; using NBXplorer.DerivationStrategy;
using PayoutData = BTCPayServer.Data.PayoutData; using PayoutData = BTCPayServer.Data.PayoutData;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData; using PayoutProcessorData = BTCPayServer.Data.PayoutProcessorData;
namespace BTCPayServer.PayoutProcessors.OnChain namespace BTCPayServer.PayoutProcessors.OnChain
{ {

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;

View File

@@ -6,9 +6,8 @@ using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models; using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.Settings;
using BTCPayServer.Services.Invoices; using BTCPayServer.Services.Invoices;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -103,7 +102,7 @@ public class UIOnChainAutomatedPayoutProcessorsController : Controller
})) }))
.FirstOrDefault(); .FirstOrDefault();
activeProcessor ??= new PayoutProcessorData(); activeProcessor ??= new PayoutProcessorData();
activeProcessor.Blob = InvoiceRepository.ToBytes(automatedTransferBlob.ToBlob()); activeProcessor.HasTypedBlob<OnChainAutomatedPayoutBlob>().SetBlob(automatedTransferBlob.ToBlob());
activeProcessor.StoreId = storeId; activeProcessor.StoreId = storeId;
activeProcessor.PaymentMethod = new PaymentMethodId(cryptoCode, BitcoinPaymentType.Instance).ToString(); activeProcessor.PaymentMethod = new PaymentMethodId(cryptoCode, BitcoinPaymentType.Instance).ToString();
activeProcessor.Processor = _onChainAutomatedPayoutSenderFactory.Processor; activeProcessor.Processor = _onChainAutomatedPayoutSenderFactory.Processor;

View File

@@ -4,7 +4,6 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.HostedServices; using BTCPayServer.HostedServices;
using BTCPayServer.Logging; using BTCPayServer.Logging;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;

View File

@@ -1,4 +1,4 @@
using BTCPayServer.Data.Data; using BTCPayServer.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using BTCPayServer.PayoutProcessors.Lightning; using BTCPayServer.PayoutProcessors.Lightning;
using BTCPayServer.PayoutProcessors.OnChain; using BTCPayServer.PayoutProcessors.OnChain;

View File

@@ -1,8 +0,0 @@
using System;
namespace BTCPayServer.PayoutProcessors.Settings;
public class AutomatedPayoutBlob
{
public TimeSpan Interval { get; set; } = TimeSpan.FromHours(1);
}

View File

@@ -6,7 +6,6 @@ using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Abstractions.Models; using BTCPayServer.Abstractions.Models;
using BTCPayServer.Client; using BTCPayServer.Client;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Data.Data;
using BTCPayServer.Payments; using BTCPayServer.Payments;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View File

@@ -68,7 +68,7 @@ namespace BTCPayServer.Security.Greenfield
claims.Add(new Claim(_identityOptions.CurrentValue.ClaimsIdentity.UserIdClaimType, key.UserId)); claims.Add(new Claim(_identityOptions.CurrentValue.ClaimsIdentity.UserIdClaimType, key.UserId));
claims.AddRange((await _userManager.GetRolesAsync(key.User)).Select(s => new Claim(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, s))); claims.AddRange((await _userManager.GetRolesAsync(key.User)).Select(s => new Claim(_identityOptions.CurrentValue.ClaimsIdentity.RoleClaimType, s)));
claims.AddRange(Permission.ToPermissions(key.GetBlob().Permissions).Select(permission => claims.AddRange(Permission.ToPermissions(key.GetBlob()?.Permissions ?? Array.Empty<string>()).Select(permission =>
new Claim(GreenfieldConstants.ClaimTypes.Permission, permission.ToString()))); new Claim(GreenfieldConstants.ClaimTypes.Permission, permission.ToString())));
return AuthenticateResult.Success(new AuthenticationTicket( return AuthenticateResult.Success(new AuthenticationTicket(
new ClaimsPrincipal(new ClaimsIdentity(claims, GreenfieldConstants.AuthenticationType)), new ClaimsPrincipal(new ClaimsIdentity(claims, GreenfieldConstants.AuthenticationType)),

View File

@@ -1274,7 +1274,6 @@ namespace BTCPayServer.Services.Invoices
if (string.IsNullOrEmpty(CryptoPaymentDataType)) if (string.IsNullOrEmpty(CryptoPaymentDataType))
{ {
paymentType = BitcoinPaymentType.Instance; paymentType = BitcoinPaymentType.Instance;
;
} }
else if (!PaymentTypes.TryParse(CryptoPaymentDataType, out paymentType)) else if (!PaymentTypes.TryParse(CryptoPaymentDataType, out paymentType))
{ {

View File

@@ -22,7 +22,7 @@ namespace BTCPayServer.Services.Invoices
{ {
public class InvoiceRepository public class InvoiceRepository
{ {
static JsonSerializerSettings DefaultSerializerSettings; internal static JsonSerializerSettings DefaultSerializerSettings;
static InvoiceRepository() static InvoiceRepository()
{ {
DefaultSerializerSettings = new JsonSerializerSettings(); DefaultSerializerSettings = new JsonSerializerSettings();
@@ -147,7 +147,7 @@ namespace BTCPayServer.Services.Invoices
var expiry = DateTimeOffset.Now + seconds; var expiry = DateTimeOffset.Now + seconds;
invoice.ExpirationTime = expiry; invoice.ExpirationTime = expiry;
invoice.MonitoringExpiration = expiry.AddHours(1); invoice.MonitoringExpiration = expiry.AddHours(1);
invoiceData.Blob = ToBytes(invoice, _btcPayNetworkProvider.DefaultNetwork); invoiceData.SetBlob(invoice);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
@@ -168,8 +168,7 @@ namespace BTCPayServer.Services.Invoices
var invoice = invoiceData.GetBlob(_btcPayNetworkProvider); var invoice = invoiceData.GetBlob(_btcPayNetworkProvider);
invoice.MonitoringExpiration = invoice.MonitoringExpiration.AddHours(1); invoice.MonitoringExpiration = invoice.MonitoringExpiration.AddHours(1);
invoiceData.Blob = ToBytes(invoice, null); invoiceData.SetBlob(invoice);
await ctx.SaveChangesAsync(); await ctx.SaveChangesAsync();
} }
@@ -190,7 +189,6 @@ namespace BTCPayServer.Services.Invoices
StoreDataId = storeId, StoreDataId = storeId,
Id = invoice.Id, Id = invoice.Id,
Created = invoice.InvoiceTime, Created = invoice.InvoiceTime,
Blob = ToBytes(invoice, null),
OrderId = invoice.Metadata.OrderId, OrderId = invoice.Metadata.OrderId,
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
Status = invoice.StatusString, Status = invoice.StatusString,
@@ -199,6 +197,7 @@ namespace BTCPayServer.Services.Invoices
CustomerEmail = invoice.RefundMail, CustomerEmail = invoice.RefundMail,
Archived = false Archived = false
}; };
invoiceData.SetBlob(invoice);
await context.Invoices.AddAsync(invoiceData); await context.Invoices.AddAsync(invoiceData);
@@ -247,7 +246,7 @@ namespace BTCPayServer.Services.Invoices
private InvoiceEntity Clone(InvoiceEntity invoice) private InvoiceEntity Clone(InvoiceEntity invoice)
{ {
var temp = new InvoiceData(); var temp = new InvoiceData();
temp.Blob = ToBytes(invoice); temp.SetBlob(invoice);
return temp.GetBlob(_btcPayNetworkProvider); return temp.GetBlob(_btcPayNetworkProvider);
} }
@@ -307,7 +306,7 @@ namespace BTCPayServer.Services.Invoices
} }
#pragma warning restore CS0618 #pragma warning restore CS0618
invoiceEntity.SetPaymentMethod(paymentMethod); invoiceEntity.SetPaymentMethod(paymentMethod);
invoice.Blob = ToBytes(invoiceEntity, network); invoice.SetBlob(invoiceEntity);
await context.AddressInvoices.AddAsync(new AddressInvoiceData() await context.AddressInvoices.AddAsync(new AddressInvoiceData()
{ {
@@ -341,7 +340,7 @@ namespace BTCPayServer.Services.Invoices
.Set(GetDestination(paymentMethod), paymentMethod.GetId())); .Set(GetDestination(paymentMethod), paymentMethod.GetId()));
} }
invoiceEntity.SetPaymentMethod(paymentMethod); invoiceEntity.SetPaymentMethod(paymentMethod);
invoice.Blob = ToBytes(invoiceEntity, network); invoice.SetBlob(invoiceEntity);
AddToTextSearch(context, invoice, paymentMethod.GetPaymentMethodDetails().GetPaymentDestination()); AddToTextSearch(context, invoice, paymentMethod.GetPaymentMethodDetails().GetPaymentDestination());
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
@@ -416,7 +415,7 @@ namespace BTCPayServer.Services.Invoices
var blob = invoiceData.GetBlob(_btcPayNetworkProvider); var blob = invoiceData.GetBlob(_btcPayNetworkProvider);
blob.Price = invoice.Price; blob.Price = invoice.Price;
AddToTextSearch(context, invoiceData, new[] { invoice.Price.ToString(CultureInfo.InvariantCulture) }); AddToTextSearch(context, invoiceData, new[] { invoice.Price.ToString(CultureInfo.InvariantCulture) });
invoiceData.Blob = ToBytes(blob, null); invoiceData.SetBlob(blob);
await context.SaveChangesAsync().ConfigureAwait(false); await context.SaveChangesAsync().ConfigureAwait(false);
} }
@@ -478,7 +477,7 @@ namespace BTCPayServer.Services.Invoices
} }
blob.Metadata = newMetadata; blob.Metadata = newMetadata;
invoiceData.Blob = ToBytes(blob); invoiceData.SetBlob(blob);
await context.SaveChangesAsync().ConfigureAwait(false); await context.SaveChangesAsync().ConfigureAwait(false);
return ToEntity(invoiceData); return ToEntity(invoiceData);
} }
@@ -770,22 +769,12 @@ namespace BTCPayServer.Services.Invoices
return status; return status;
} }
public static byte[] ToBytes<T>(T obj, BTCPayNetworkBase network = null)
{
return ZipUtils.Zip(ToJsonString(obj, network));
}
public static T FromBytes<T>(byte[] blob, BTCPayNetworkBase network = null) public static T FromBytes<T>(byte[] blob, BTCPayNetworkBase network = null)
{ {
return network == null return network == null
? JsonConvert.DeserializeObject<T>(ZipUtils.Unzip(blob), DefaultSerializerSettings) ? JsonConvert.DeserializeObject<T>(ZipUtils.Unzip(blob), DefaultSerializerSettings)
: network.ToObject<T>(ZipUtils.Unzip(blob)); : network.ToObject<T>(ZipUtils.Unzip(blob));
} }
public static string ToJsonString<T>(T data, BTCPayNetworkBase network)
{
return network == null ? JsonConvert.SerializeObject(data, DefaultSerializerSettings) : network.ToString(data);
}
} }
public class InvoiceQuery public class InvoiceQuery

View File

@@ -65,16 +65,15 @@ namespace BTCPayServer.Services.Invoices
bitcoinPaymentMethod.NextNetworkFee = bitcoinPaymentMethod.NetworkFeeRate.GetFee(100); // assume price for 100 bytes bitcoinPaymentMethod.NextNetworkFee = bitcoinPaymentMethod.NetworkFeeRate.GetFee(100); // assume price for 100 bytes
paymentMethod.SetPaymentMethodDetails(bitcoinPaymentMethod); paymentMethod.SetPaymentMethodDetails(bitcoinPaymentMethod);
invoiceEntity.SetPaymentMethod(paymentMethod); invoiceEntity.SetPaymentMethod(paymentMethod);
invoice.Blob = InvoiceRepository.ToBytes(invoiceEntity, network); invoice.SetBlob(invoiceEntity);
} }
PaymentData data = new PaymentData PaymentData data = new PaymentData
{ {
Id = paymentData.GetPaymentId(), Id = paymentData.GetPaymentId(),
Blob = InvoiceRepository.ToBytes(entity, entity.Network),
InvoiceDataId = invoiceId, InvoiceDataId = invoiceId,
Accounted = accounted Accounted = accounted
}; };
data.SetBlob(entity);
await context.Payments.AddAsync(data); await context.Payments.AddAsync(data);
InvoiceRepository.AddToTextSearch(context, invoice, paymentData.GetSearchTerms()); InvoiceRepository.AddToTextSearch(context, invoice, paymentData.GetSearchTerms());
@@ -123,7 +122,7 @@ namespace BTCPayServer.Services.Invoices
} }
dbPayment.Accounted = payment.Value.entity.Accounted; dbPayment.Accounted = payment.Value.entity.Accounted;
dbPayment.Blob = InvoiceRepository.ToBytes(payment.Value.entity, payment.Value.entity.Network); dbPayment.SetBlob(payment.Value.entity);
} }
await context.SaveChangesAsync().ConfigureAwait(false); await context.SaveChangesAsync().ConfigureAwait(false);
eventsToSend.ForEach(_eventAggregator.Publish); eventsToSend.ForEach(_eventAggregator.Publish);

View File

@@ -154,7 +154,7 @@ namespace BTCPayServer.Services.Notifications
var handler = GetHandler(data.NotificationType); var handler = GetHandler(data.NotificationType);
if (handler is null) if (handler is null)
return null; return null;
var notification = JsonConvert.DeserializeObject(ZipUtils.Unzip(data.Blob), handler.NotificationBlobType); var notification = data.HasTypedBlob(handler.NotificationBlobType).GetBlob();
var obj = new NotificationViewModel var obj = new NotificationViewModel
{ {
Id = data.Id, Id = data.Id,

View File

@@ -40,16 +40,15 @@ namespace BTCPayServer.Services.Notifications
{ {
foreach (var uid in users) foreach (var uid in users)
{ {
var obj = JsonConvert.SerializeObject(notification);
var data = new NotificationData var data = new NotificationData
{ {
Id = Guid.NewGuid().ToString(), Id = Guid.NewGuid().ToString(),
Created = DateTimeOffset.UtcNow, Created = DateTimeOffset.UtcNow,
ApplicationUserId = uid, ApplicationUserId = uid,
NotificationType = notification.NotificationType, NotificationType = notification.NotificationType,
Blob = ZipUtils.Zip(obj),
Seen = false Seen = false
}; };
data.HasTypedBlob<BaseNotification>().SetBlob(notification);
await db.Notifications.AddAsync(data); await db.Notifications.AddAsync(data);
} }
await db.SaveChangesAsync(); await db.SaveChangesAsync();

View File

@@ -1,6 +1,6 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.AspNetCore.Mvc.TagHelpers
@using BTCPayServer.Abstractions.Models @using BTCPayServer.Abstractions.Models
@model List<BTCPayServer.Data.Data.FormData> @model List<BTCPayServer.Data.FormData>
@{ @{
Layout = "../Shared/_NavLayout.cshtml"; Layout = "../Shared/_NavLayout.cshtml";
ViewData["NavPartialName"] = "../UIStores/_Nav"; ViewData["NavPartialName"] = "../UIStores/_Nav";

View File

@@ -1,7 +1,7 @@
@inject UserManager<ApplicationUser> _userManager @inject UserManager<ApplicationUser> _userManager
@* This is a temporary infobox to inform users about the state changes in 1.4.0. It should be removed eventually. *@ @* This is a temporary infobox to inform users about the state changes in 1.4.0. It should be removed eventually. *@
@if ((await _userManager.GetUserAsync(User)).GetBlob().ShowInvoiceStatusChangeHint) @if ((await _userManager.GetUserAsync(User)).GetBlob()?.ShowInvoiceStatusChangeHint is true)
{ {
<div class="alert alert-light alert-dismissible fade show mb-5" role="alert"> <div class="alert alert-light alert-dismissible fade show mb-5" role="alert">
<form method="post" asp-controller="UIManage" asp-action="DisableShowInvoiceStatusChangeHint" id="invoicestatuschangeform"> <form method="post" asp-controller="UIManage" asp-action="DisableShowInvoiceStatusChangeHint" id="invoicestatuschangeform">