Compare commits

...

444 Commits

Author SHA1 Message Date
c0a0420b69 add opensats and update strike logo 2023-07-26 20:15:08 +02:00
79e121c3af Disabling playing of the invoice sound for existing stores 2023-07-26 10:42:00 -05:00
8eabdab53a Preventing entering of negative tips and discounts in POS 2023-07-26 07:26:53 -05:00
957fb09ffc Reverting logic of how paid amount is displayed on the receipt 2023-07-26 07:26:32 -05:00
4bffe117a9 Do not show cheatmode in release, fix warnigns 2023-07-25 10:50:34 +09:00
05b01a13c8 Fix NRE error in PoS report 2023-07-24 23:20:17 +09:00
08e21c1a5d Fix report view 2023-07-24 23:13:11 +09:00
4d5245605d bump 2023-07-24 22:59:18 +09:00
453548d614 Checkout v2: Play sound when invoice is paid (#5113)
* Checkout v2: Play sound when invoice is paid

Closes #5085.

* Refactoring: Use low-level audio API to play the sound

Allows to play the sound regardless of browser permissions.

* Add audio file detection

* Use model state for file upload errors

* Add default sound and customizing option

* Fix mp3 detection

* Add sounds

* Update defaults

* Add nfcread and error sounds

* Improve label wording

* Replace sound

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-07-24 22:57:24 +09:00
95a0614ae1 Support accepting 0 amount bolt 11 invoices for payouts (#4014)
* Support accepting 0 amount bolt 11 invoices for payouts

* add test

* handle validation better

* fix case when we just want pp to provide amt

* Update BTCPayServer/HostedServices/PullPaymentHostedService.cs

* Update BTCPayServer/HostedServices/PullPaymentHostedService.cs

* Update BTCPayServer/Data/Payouts/LightningLike/UILightningLikePayoutController.cs

* Update UILightningLikePayoutController.cs

* fix null

* fix payments of payouts on cln

* add comment

* bump lightning lib

---------

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
2023-07-24 20:40:26 +09:00
36ea17a6b7 Introduce Payout metadata for api and plugins (#5182)
* Introduce Payout metadata for api and plugins

* fix controller

* fix metadata requirement

* save an object

* pr changes
2023-07-24 18:37:18 +09:00
dc986959fd Add reporting feature (#5155)
* Add reporting feature

* Remove nodatime

* Add summaries

* work...

* Add chart title

* Fix error

* Allow to set hour in the field

* UI updates

* Fix fake data

* ViewDefinitions can be dynamic

* Add items sold

* Sticky table headers

* Update JS and remove jQuery usages

* JS click fix

* Handle tag all invoices for app

* fix dup row in items report

* Can cancel invoice request

* Add tests

* Fake data for items sold

* Rename Items to Products, improve navigation F5

* Use bordered table for summaries

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-07-24 09:24:32 +09:00
845e2881fa POS Cart redesign (#5171)
* Move POS assets

* WIP

* Refactor into common Vue mixin

* Offcanvas updates

* Unifications across POS views

* POSData view fix

* Number and test fixes

* Update cart width

* Fix test

* More view unification

* Hide cart when emptied

* Validate cart

* Header improvement

* Increase remove icon size

* Animate add to cart action

* Offcanvas for mobile, sidebar for desktop

* ui+pos: updates icon size + badge + label

* Remove cart table headers

* Use same size for Cart and Shop headlines

* Update search placeholder

* Bump horizontal  input padding

* Increase sidebar width

* Bump badge font size

* Fix manipulating the quantity of line items

* Fix cart icon

* Update cart display

* updates empty button

* Rounded search input

* Remove cart button on desktop

* Fix dark accent color

* More accent fixes

* Fix plus/minus alignment

* Update BTCPayServer/Views/Shared/PointOfSale/Public/Cart.cshtml

* Apply suggestions from code review

---------

Co-authored-by: dstrukt <gfxdsign@gmail.com>
2023-07-22 21:15:41 +09:00
2e4be9310c Design system updates (#5186) 2023-07-21 09:27:37 +02:00
a2faa6fd59 Minor fixes (#5185) 2023-07-21 09:05:50 +02:00
0a78846e8d Stop using bitpay's CreateInvoice for non bitpay API usage (#5184) 2023-07-21 09:08:32 +09:00
4063a5aaee Quality of life improvements to payout processors (#5135)
* Quality of life improvements to payout processors

* Allows more fleixble intervals for payout processing from 10-60 mins to 1min-24hours(requested by users)
* Cancel ln payotus that expired (bolt11)
* Allow cancelling of ln payotus that have failed to be paid after x attempts
* Allow conifguring a threshold for when to process on-chain payouts (reduces fees)

# Conflicts:
#	BTCPayServer.Tests/SeleniumTests.cs

* Simplify the code

* switch to concurrent dictionary

* Allow ProcessNewPayoutsInstantly

* refactor plugin hook service to have events available and change processor hooks to actions with better args

* add procesor extended tests

* Update BTCPayServer.Tests/GreenfieldAPITests.cs

* fix concurrency issue

* Update BTCPayServer/PayoutProcessors/BaseAutomatedPayoutProcessor.cs

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-07-20 22:05:14 +09:00
b1c81b696f Generate unique order IDs for PoS and Crowdfund sales (#5127)
* Generate unique order IDs for PoS and Crowdfund sales

Part of #5054.

* Refactorings

* Updates

* Updates

* Refactoring

* Remove search by AdditionalSearchTerm

* Implement appid

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-07-20 16:03:39 +09:00
0017f236a7 Improve create first store view (#5181)
* Improve create first store view

Closes #5008.

* Fix tests
2023-07-19 22:21:16 +09:00
19d5e64063 Form invoice amount adjusters (#5158)
* Fix constant fields being editable on UI

* fix redirect to checkout if invoice is settled (redirect to receipt instead)

* enhance: make mirror field type able to map values

* Introduce invoice amount adjustment fields for form

* Integrate invoice amount adjustment fields for form on pos

* Support mirror in editor

* Indicate when special field names are used

* polsih mirror view and name suggestions for fields

* clarify

* hide hidden field from ui

* Minor adjustmentts

* Improve mirror field editing

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-07-19 18:54:51 +09:00
22435a2bf5 Refactor logic for calculating due amount of invoices (#5174)
* Refactor logic for calculating due amount of invoices

* Remove Money type from the accounting

* Fix tests

* Fix a corner case

* fix bug

* Rename PaymentCurrency to Currency

* Fix bug

* Rename PaymentCurrency -> Currency

* Payment objects should have access to the InvoiceEntity

* Set Currency USD in tests

* Simplify some code

* Remove useless code

* Simplify code, kukks comment
2023-07-19 18:47:32 +09:00
a7def63137 fix pos item topups lnurl (#5172)
fixes #5170
2023-07-17 13:08:41 +02:00
3703a170e7 try fix migration for pos yml 2023-07-13 14:59:18 +02:00
73fbfbd7cb Add support for Monero RPC authentication (#5157)
Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
2023-07-13 12:24:08 +02:00
acae3b8753 Refactoring 2023-07-13 12:17:41 +02:00
a618f901fc Support NFC on modal 2023-07-13 12:17:41 +02:00
6d4918f0ab Update ViewPullPayment.cshtml 2023-07-13 12:17:01 +02:00
7f2c4d2e7a add extension point for pull payment view 2023-07-13 12:17:01 +02:00
fd6d361e1a CheckoutV2: When WebSocket disconnects, we should continue polling via XHR (#5165)
* When WebSocket disconnects, we should continue polling via XHR

* Update BTCPayServer/wwwroot/checkout-v2/checkout.js

Co-authored-by: d11n <mail@dennisreimann.de>

---------

Co-authored-by: d11n <mail@dennisreimann.de>
2023-07-11 21:56:13 +02:00
b5f0924651 Serialize PosAppCartItem.value as decimal instead of string 2023-07-11 15:49:16 +09:00
1600dd4759 POS: Backwards-compatible price parsing (#5163)
* POS: Backwards-compatible price parsing

Fixes #5159 and a regression introduced in bbff9710bf2f4a66bd6f4cd9e8ee55618d0ca5e0: The price in posData needs to be parsed in a backwards-compatible manner, as the old format of price as an object exists in the invoice metadata.

* Test corner cases

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-07-11 15:32:01 +09:00
c777746b69 Custom Forms: Allow HTML in labels and help text (#5136)
* Custom Forms: Allow HTML in labels and help text

Fixes #5003.

* Vue: Sanitize labels and helper text input

* Form editor: Fix blur on input for select option values

---------

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
2023-07-11 13:02:02 +09:00
9f5466a41f Make sure CheckJsContent run as part of CI, and ignore end of line differences 2023-07-11 09:41:28 +09:00
4d1e4801bf Dark theme color fix 2023-07-10 11:33:39 +02:00
5e469ff9c0 Improve rates (#5166)
* Removes Chaincoin shitcoin which is so dead even its website is gone
* Add ExchangeRateHost and FreeCurrencyRates as new rate providers
* Add recommended rate providers for UGX and RSD
* Fix BTX rate by switching to graviex
* Fix BTC rate by switching to exmo
* Fix LCAD rate script
2023-07-10 17:31:48 +09:00
2f3eedea5b Invoice lists: Show icons for payment methods (#5137) 2023-07-08 17:33:13 +02:00
5c5d6dc1e2 Bumping LND to 0.16.4-beta 2023-07-08 08:22:42 -05:00
fbe31ce64f Support LNURL in pay button (#5107)
* Support LNURL in pay button

* UI updates

* Cleanups

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-07-06 10:12:31 +02:00
0b082138c8 Payment Requests: List view improvements (#5065)
* List invoice checkbox variant

* Remove custom css

* Improve payment requests list view

* Improve Payment Requests List View

* List invoice checkbox variant

* Remove custom css

* Improve payment requests list view

* Improve Payment Requests List View

* Update payment request (name link leads to view not edit)

* Refactoring

---------

Co-authored-by: d11n <mail@dennisreimann.de>
2023-07-06 10:02:23 +02:00
966e598f10 Apps: Add direct file upload in item editor (#5140) 2023-07-06 11:01:36 +09:00
e998340387 POS: Account for custom amount in cart view (#5151)
* Add failing test

* Account for custom amount

* Test fix
2023-07-05 17:23:15 +09:00
f6b27cc5f9 Compare domains in lowercase
Domains are case-insensitive, so this comparision should be too.

I encountered this issue with a Citadel user who accidentially named their domain an uppercase name (Pay.example.com), but browsers automatically converted it to pay.example.com
2023-07-03 08:49:16 +02:00
f3dbf1e139 Allow browser to access LND config (#5128) 2023-06-30 15:08:23 +09:00
627d84fc91 Update to Bootstrap v5.3 (#5132)
Based on btcpayserver/btcpayserver-design#63
2023-06-30 09:21:27 +09:00
8cde8c01df Add category feature to the PoS with Cart (#5078)
* Add grouping feature to the PoS with Cart

* Improve UI

* Rename groups to categories

* Make it easier to select categories of the items

* Refactor TemplateEditor, use TomSelect for categories

* Prevent Vue code insertion

* Prevent empty categories

* Add label ids

* Add test case

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-06-30 09:13:15 +09:00
983b8c1f54 Fix changelog 2023-06-27 21:32:05 +09:00
d666d8ea1a Changelog 1.10.3 (#5125)
* Changelog 1.10.3

* Apply suggestions from code review

Co-authored-by: d11n <mail@dennisreimann.de>

* Apply suggestions from code review

* Update changelog

---------

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
Co-authored-by: d11n <mail@dennisreimann.de>
2023-06-27 21:23:56 +09:00
3ed81c3a78 Greenfield: Fix missing default currency in stores API
Docs mention it should be present, but it wasn't. Fixes #5123.
2023-06-27 12:52:24 +02:00
4afec2e2b6 Fix: Using lnaddresses on Nostr should not result in lots of invoice being created 2023-06-27 12:50:24 +02:00
db83d238d5 Crowdfund: Fix JS errors in empty state (#5121)
An empty crfowdfund with the default perk had JS errors.
2023-06-27 09:42:18 +09:00
fdcf7b3b7a Bumping LND to 0.16.3-beta (#5124) 2023-06-27 09:06:31 +09:00
53aafcf86b Fix: The current preimage of a invoice's lightning payment method should be available via API (#5111) 2023-06-23 19:12:11 +09:00
aec84f6d67 Dashboard: Limit "Top Items" to five (#5110)
Feedback we got at BTCPrague: Do not show more than five items in the top list, because otherwise the list can get very long if there's a POS with many items.
2023-06-23 11:31:05 +02:00
01e9f82d24 Policies: Update wording to fit API keys and Roles (#5106)
* Policies: Update wording to fit API keys and Roles

Closes #5021.

* API keys: Improve spacing
2023-06-22 10:37:30 +02:00
2eff45e65c Ajaxify the wallet transaction list to avoid timeout (Fix #4987) (#5100)
* Ajaxify the wallet transaction list to avoid timeout (Fix #4987)

* Add cancellation to request to wallet transactions

* Fix tests

* Improve empty state

* Cleanups

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-06-22 16:09:53 +09:00
13203c3e2b Receipt improvements (#5077)
* Remove Order ID link

* Add separate print version for receipt

* Fix POS number handling and add keypad test

Fixes #5056.

* Add formatting function

* Remove OrderUrl for POS, bring back order link for receipt

* Update BTCPayServer/Plugins/PointOfSale/Controllers/UIPointOfSaleController.cs
2023-06-22 15:57:29 +09:00
82c5e0e43d Dashboard: Make invoice badges consistent with those on invoices list (#5108)
Closes #4969.
2023-06-22 15:47:12 +09:00
a1575f404b Invoices: Fix search box shrinking too small (#5105)
Fixes #5099.
2023-06-21 09:52:42 +02:00
e1509506dc Upgrade Bootstrap-Vue and fix tooltip positioning
Fixes #4956.
2023-06-21 08:31:13 +02:00
0c1d0d7b05 Fix: formResponse and formId missing from API's GetPaymentRequest route 2023-06-21 12:47:21 +09:00
ad70856af0 Fix: LN payments failed to be detected on litd (#5104) 2023-06-21 12:15:46 +09:00
8615f120ce Fix tests 2023-06-20 22:37:05 +09:00
0d0477d661 Lightning: Relax GetInfo constraint for LNDhub connections (#5083)
* Lightning: Relax GetInfo constraint for LNDhub connections

The LNDhub-compatible implementation by LNbits does not support the `GetInfo` call for all their funding sources — see lnbits/lnbits#1182. By catching that exception in combination with the `LndHubLightningClient`, we give people the ability to still use their LNbits-based LNDhub as a Lightning node.

Fixes #4482.

* Update approach to handling unsupported GetInfo calls
2023-06-20 17:28:16 +09:00
b31dc30878 Make file management UI more useful (#5081)
* Make file management UI more useful

* Simplify markup

* Move file info to top

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-06-20 08:58:28 +02:00
6e392f4cfb After changing PoS items in UpdatePoS ident the JSON template 2023-06-19 14:44:12 +09:00
cc3bdc331e Fix build 2023-06-16 23:19:47 +09:00
76faf77a1c Fix keypad view broken by previous commit 2023-06-16 23:18:47 +09:00
d8c0e5bf3a Add extension point to template editor (#5080) 2023-06-16 23:05:49 +09:00
28c4c320cc Checkout v2: Add return link in processing state (#5075)
* Checkout v2: Add return link in processing state

* Update copy text position
2023-06-16 23:05:08 +09:00
e81403ec3f Fix: Applying a discount in PoS with cart wasn't working (#5079) 2023-06-16 23:02:14 +09:00
f11424f73a Pull Payment: Support LNURL Withdraw with SATS denomination (#5041)
* Pull Payment: Support LNURL Withdraw with SATS denomination

* Refactor and add tests
2023-06-16 10:56:17 +09:00
fa8b977016 Remove id from create webhook endpoint; fix consistency. (#5045) 2023-06-16 10:53:41 +09:00
d181846339 Refund: Fix overpaid option (#5076)
Closes #5066.
2023-06-16 10:52:52 +09:00
1956919886 Do not crash when an invoice have an amount that is too big (#5070) 2023-06-16 10:47:58 +09:00
0f66498965 NFC: Do not start scanning if unsupported
Fixes #5067.
2023-06-14 09:14:09 +02:00
918cd152b1 Fix: Incorrect rounding in the receipt of PoS invoice (fix #5071) (#5072) 2023-06-13 20:34:21 +02:00
d3222df396 Fix build warnings (#5069)
Fixes these two:

```
/source/BTCPayServer/Hosting/MigrationStartupTask.cs(643,49): warning CS0168: The variable 'items' is declared but never used [/source/BTCPayServer/BTCPayServer.csproj]
/source/BTCPayServer/Hosting/MigrationStartupTask.cs(644,24): warning CS0168: The variable 'newTemplate' is declared but never used [/source/BTCPayServer/BTCPayServer.csproj]
```
2023-06-13 20:46:44 +09:00
a84ffd8c7e Crowdfund: Fix null pointer exception for topup type (missing price) (#5068)
Items with type topup have a price = null and hence not even the property set (ignored in JSON). This needs to be handled in the temlate, otherwise this exception occurs:

```
An unhandled exception was thrown by the application.
System.InvalidOperationException: Nullable object must have a value.
   at AspNetCoreGeneratedDocument.Views_Shared_Crowdfund_Public_ContributeForm.<>c__DisplayClass24_0.<<ExecuteAsync>b__0>d.MoveNext()
```
2023-06-13 20:46:27 +09:00
6d0f9120b8 prep for 1.10.2 2023-06-07 18:02:51 +02:00
aafb4a7f2a Fix stale invoice api for settle invoice
fixes #5049
2023-06-07 17:57:03 +02:00
ae432ff237 Fix: Crash on migation of old instances (Fix #5051) 2023-06-07 10:20:39 +02:00
cdc318c71a Pay Button: Fix circular reference when serializing JSON
When apps were set, the `GetAllApps` included the store data, which led to a circular reference when serializing the JSON. That data isn't necessary here, so we can just drop it before rendering.

Fixes #5038.
2023-06-05 12:35:06 +02:00
94d1cec8a9 Hide Sensitive Info: Fix script location
The script snippet needs to be located outside of the theme if-conditions, otherwise it only works if no custom theme is applied.
2023-06-05 12:34:54 +02:00
c0bc19ea59 Update Changelog 2023-06-02 18:21:57 +09:00
6f07714cd9 Language update 2023-06-02 18:18:10 +09:00
a9d2cac23c bump 1.10.1 2023-06-02 18:15:56 +09:00
693b46126b Bump Bitcoin core to 25.0 (#5032) 2023-06-02 16:41:35 +09:00
bbff9710bf fix cart + form combination bug fixes #5031 2023-06-02 09:34:55 +02:00
358e122775 Fix tests 2023-06-01 22:17:42 +09:00
3818468932 Pluginify on chain wallet setup (#4999)
* Pluginify on chain wallet setup

This PR fixes a few logical points in the wallet setup flow to allow more extensive plugin flexibility; It also fixes an issue when building plugins that requires an Altcoin config profile. Here is an example showcasing the Liquid+ plugin using this to enforce that it is a hot wallet (a requirement it has) and that import to RPC is always set, and a new option that is used to configure the wallet further https://i.imgur.com/pDPQ73v.gif

* Update BTCPayServer/Controllers/UIStoresController.Onchain.cs

* update nbx
2023-06-01 21:18:28 +09:00
3d2554fbe1 Make role name show uneditable when not creating 2023-05-31 15:49:34 +02:00
4309603317 Hide topup items from cart 2023-05-31 15:49:34 +02:00
f733c9ea77 Form Builder: Improve wording
Element -> Field. Something bas and I came across while reviewing the blog post.
2023-05-31 14:57:11 +02:00
775ee01171 fix store role deletion fixes #5027 2023-05-31 13:42:38 +02:00
33ec790137 Changelog 2023-05-31 11:50:10 +09:00
0c575c888c Remove payment requirement for marking expired invoices (#5006)
* Remove payment requirement for marking expired invoices

Allows to manually mark expired invoices, regardless of registered payments. See dennisreimann/btcpayserver-plugin-lnbank#34 for context, in which BTCPay Server sometimes did not register payments that were received to a LNbank wallet (this got fixed in btcpayserver/BTCPayServer.Lightning#129)

* Refactor conditions for better readability
2023-05-31 11:49:01 +09:00
24f7e51e3a Small adjustements 2023-05-31 11:27:03 +09:00
0a0cf97c55 Do not cleanup unreachable stores (#5025) 2023-05-31 11:22:37 +09:00
16b988d097 UI: Only display applicable refund options
Fixes #5019.
2023-05-30 12:51:51 +02:00
5edc0ff6ef UI: Fix visual bug with Hide Sensitive Info
Fixes #5011
2023-05-30 11:20:58 +02:00
375b96e508 UI: Center-align recovery phrase
Fixes #5007.
2023-05-30 11:19:16 +02:00
1e72b12074 UI: Store selector link distinguishes between owner and user
The `IsOwner` property went missing with #4940, so everyone landed on the invoices list when switching stores. This brings back the original behaviour of linking to the Dashboard, if the user has the permission to access it.

Fixes #5015.
2023-05-30 11:18:34 +02:00
4a6d52f78e Fix crowdfund perk support fixes #5013 2023-05-30 10:34:48 +02:00
35dd580e74 Fix cart view and provide better naming for default items fixes #5012 2023-05-30 10:05:31 +02:00
79836ef1de make free invoices from pos redirect to receipt and make receipt reload fast on such case 2023-05-30 10:04:23 +02:00
8cb06f9c6c fix user store reole setting fixes #5010 2023-05-30 09:37:14 +02:00
215a36e7a9 Fix: Some multi path payment on LND wouldn't be detected 2023-05-30 12:26:30 +09:00
247f6b86a5 Changelog 1.10.0 (#5004) 2023-05-29 16:24:27 +09:00
a9d42f1e6a Add What's New in v1.10.0 (#4992)
* Add What's New in v1.10.0

* Update BTCPayServer/Views/UIStores/Dashboard.cshtml

Co-authored-by: B <102448109+Bas02@users.noreply.github.com>

---------

Co-authored-by: B <102448109+Bas02@users.noreply.github.com>
2023-05-29 16:08:46 +09:00
4e03c2523a Prune webhook data from database 2023-05-29 09:02:47 +02:00
418b476725 Bug fix on StoreRoleId parsing 2023-05-27 12:51:48 +09:00
783e4ccb35 Store Custom Roles (#4940) 2023-05-26 23:49:32 +09:00
6b7fb55658 Fix: Payment not marked as settled even if the payment is successful with LNBank
Fix https://github.com/dennisreimann/btcpayserver-plugin-lnbank/issues/33
2023-05-25 21:09:13 +09:00
3d5361cd11 [Bug] If a altcoins is disabled from BTCPay and payout processor is used, it would crash at restart (#4997)
Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
2023-05-25 12:42:23 +02:00
2c4349c630 Test concurrent payment of lightning invoices 2023-05-25 18:41:17 +09:00
3589417b58 Form Editor: Minor wording adjustments (#4998) 2023-05-25 08:51:03 +02:00
55203e0b64 Dashboard: Fix SATS denomination display (#4994)
When the default currency of the store is SATS, the display was broken.
2023-05-25 10:08:00 +09:00
a918288e3b Fix codeql config to not scan vendor js, add it to solution 2023-05-23 10:38:59 +09:00
e183138d2c Remove vendor js from codeql scan 2023-05-23 10:07:08 +09:00
d3e42862ed Create codeql.yml (#4821)
Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
2023-05-23 09:23:24 +09:00
8860eec254 Switch Apps to json not YML (#4792) 2023-05-23 09:18:57 +09:00
97e7e60cea Add minrelayfee to payjoin request
fixes #4689
2023-05-22 14:56:08 +02:00
44aaf7acbb Form editor (#4968)
Co-authored-by: dstrukt <gfxdsign@gmail.com>
2023-05-22 13:30:28 +02:00
9b721fae27 Better handle postgres requests for wallet objects (#4985) 2023-05-20 23:26:16 +09:00
c3f412e3bb Bump tests to Bitcoin Core 24.1 (#4988) 2023-05-20 21:38:39 +09:00
ee738a29f0 Stop spamming logs with event aggregator logging 2023-05-19 15:24:20 +09:00
6c6544bf9b Improve invoice filtering UI (#4914)
* Improve invoice filtering UI

Closes #3664.

* UI updates

* Add app filter

* Add indicator for active filters

* updates text

* Improve selected filter display

* Apply suggestions from code review

---------

Co-authored-by: dstrukt <gfxdsign@gmail.com>
2023-05-19 10:42:09 +09:00
3d57b944ca Fix a bunch of minor bugs (#4983) 2023-05-19 08:41:21 +09:00
acf003b1b4 Do not generate new address when a new payment is detected (#4984)
* Do not generate new address when a new payment is detected

* Update BTCPayServer.Tests/UnitTest1.cs

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>

---------

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
2023-05-18 16:53:01 +09:00
52e108d32f Minor design system updates (#4973)
- Update Manage Plugins icon
- Add ESC to supporters sprite
- Update body-text-active variable
2023-05-17 10:19:26 +02:00
7b96f96025 bump clightning (#4970)
* bump clightning

* Remove Lightning Charge from our tests
2023-05-16 09:17:21 +09:00
8db5e7e043 Plugins: Allow payout processors to signal they cannot be removed through common UI 2023-05-15 09:49:13 +02:00
25fb5c1293 Checkout v2: Improve expired paid partial state (#4827)
Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
2023-05-11 10:38:40 +02:00
37f0498def adds payouts settings button (#3857)
Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-05-11 10:37:28 +02:00
02110f93d7 Hide sensitive info (#4966) 2023-05-11 10:35:51 +02:00
195dfc2c47 Refund updates (#4934) 2023-05-11 10:33:33 +02:00
541b6cf9eb Improve create first store case (#4951) 2023-05-10 11:18:29 +02:00
2c26b77afc Forms: Add multiline input (#4942) 2023-05-10 11:14:19 +02:00
99bcec5597 bump nbx 2023-05-09 22:06:23 +09:00
781190a65d Bump to 1.9.3 (#4955)
* Bump to 1.9.3

* Apply suggestions from code review

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

Co-authored-by: d11n <mail@dennisreimann.de>

* Update Changelog.md

Co-authored-by: d11n <mail@dennisreimann.de>

* Update Changelog.md

Co-authored-by: d11n <mail@dennisreimann.de>

---------

Co-authored-by: d11n <mail@dennisreimann.de>
2023-05-08 21:30:43 +09:00
3763480280 NFC: Handle HTTP-related exceptions (#4965) 2023-05-08 12:11:42 +02:00
6fad5ebedb Do not crash checkout when attempting lnurl checkout through non secure page (#4964)
Co-authored-by: d11n <mail@dennisreimann.de>
2023-05-08 12:09:48 +02:00
0690194aa1 Fix posdata with primitive array (#4954)
Co-authored-by: d11n <mail@dennisreimann.de>
2023-05-08 11:02:13 +02:00
03b94e2be3 Minor refactoring about DefaultPaymentMethod 2023-05-08 09:14:58 +09:00
18e34b3cbe Checkout v2: Improve truncation of displayed addresses (#4924) 2023-05-05 10:00:55 +02:00
a0bb3ace61 LN Settings: Show only node host name (#4927) 2023-05-05 09:59:33 +02:00
920ad67633 Rates: Fix advanced rules example formatting
Fixes #4920.
2023-05-05 09:58:42 +02:00
8b8f72129c Crowdfund: Fix redirect URL fallback
As the request for invoice creation is issued via web socket, the display URL ends up being the hob connection URL. This replaces it with the actual app URL and fixes #4930.
2023-05-05 09:57:44 +02:00
b9b11e722c Greenfield: Apply store default payment method on invoice creation
Fixes #4947.
2023-05-05 09:56:23 +02:00
eddd458744 Fix missing shopify link
fixes #4945
2023-05-05 09:51:45 +02:00
439ea20a89 Resolving weird Firefox form autocomplete behavior on our POS (#4950) 2023-05-04 18:49:35 +02:00
cec223c8e7 Fix missing closing div (#4944) 2023-05-03 10:55:20 +02:00
25cb188d00 Bumping LND to 0.16.2-beta 2023-04-29 09:10:07 -05:00
31007a8d96 Merge pull request #4929 from dennisreimann/esc
Supporters: Add ESC
2023-04-27 18:30:09 +02:00
a4fa8db69b Supporters: Add ESC 2023-04-27 18:28:29 +02:00
6193835ea1 Make LightningListener nullable, fix some NRE 2023-04-27 13:37:32 +09:00
0c78e9e4ac Bumping LND to 0.16.1-beta (#4921) 2023-04-27 13:17:57 +09:00
58c409e7fa Fix tests 2023-04-27 13:00:25 +09:00
9577eed524 Validate input in greenfield for payout processors (#4922) 2023-04-27 10:59:19 +09:00
76f32cd064 Fix payment request overriding user provided email 2023-04-26 14:06:42 +02:00
92d9c17095 Fix payment request merge conflict marker in UI 2023-04-26 14:06:23 +02:00
b0396df33f Update changelog 2023-04-26 18:27:06 +09:00
c17572c76f Clip configuration values for payout processors 2023-04-26 18:24:46 +09:00
5c91e072a6 Prevent payout processors from stalling restart 2023-04-26 18:09:56 +09:00
4991d0f965 Update Changelog and bump version 2023-04-26 17:57:25 +09:00
45b74e1ce5 Fix cart receipt + fix pos email form forwarding (#4917)
* Show correct array regardless of size

fixes #4890

* Email provided to pos form was not forwarded to form

fixes #4810

* Make invoice receipt url redirect to the invoice redirect url if receipt is not enabled

When setting up a default email rule upon invoice settlement, you would link to the receipt page naturally. However, if using the payment requests, receipts are disabled as the payment request itself is the receipt.  This commit makes the receipt url redirect to the invoice redirect url if available, and in the case of payment requests, it would mean the receipt url is the payment request url. fixes #4895

* Set the email address in the form when configured in the payment request

* fix pay request email copy

* fix payouts nav link

fixes #4788

* Update BTCPayServer/Views/UIPaymentRequest/EditPaymentRequest.cshtml

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>

---------

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
2023-04-26 16:45:35 +09:00
ccb4b9a9ba Merge pull request #4916 from dennisreimann/receipt-print
Receipt: Optimize print view
2023-04-26 15:41:41 +09:00
dd635071d6 Merge pull request #4909 from dennisreimann/fix-4889
POS: Fix choiceKey case
2023-04-26 15:16:54 +09:00
fe1448dfae Merge pull request #4911 from NicolasDorier/qiponbtq
Remove LNURLStandardInvoiceEnabled
2023-04-26 15:15:20 +09:00
56855bc54d Fix typo in PayJoinEndpointController.cs (#4918) 2023-04-25 22:29:06 +02:00
b51fa8df5a Fix indent 2023-04-25 21:03:12 +09:00
3aa979cb11 Test updates 2023-04-25 13:07:01 +02:00
c95f75bc6c Remove disable BOLT11 option 2023-04-25 12:21:27 +02:00
b13a636f89 Fix syntax error 2023-04-25 12:11:08 +02:00
8de55cef31 Unify checkout v1 behaviour with v2 2023-04-25 11:36:45 +02:00
cb781f42e3 POS: Fix choiceKey case
I came across this while debugging #4889. This does not actually fix it, but it fixes an inconsistence in the casing of the parameter name.

However, I think the original issue is a caching problem in the browser. I was able to reproduce it on first load, after reloading the page once more it works as intended. The weird thing is: even though the values are correct on first load (verified via debugger), the `choiceKey` for the first item is set incorrectly to an integer value.
2023-04-25 09:16:09 +02:00
b59292dc24 Receipt: Optimize print view
Fixes #4902
2023-04-25 07:30:15 +02:00
03b793d7e2 Fix tests 2023-04-25 10:28:36 +09:00
bee18d1cfb Can set LazyPaymentMethod at the invoice creation level 2023-04-25 08:38:42 +09:00
d8698181f4 Remove LNURLStandardInvoiceEnabled 2023-04-24 23:52:40 +09:00
47f5d97eaf Prevent an NRE in LNURL (#4908)
* Prevent an NRE in LNURL

In addition to f05a7f9f14e0a2f906c79951a15311085774db85. Fixes #4904.

* Revert "Prevent an NRE in LNURL"

This reverts commit 0b241d61ab45b79297211e04da0e05c2cb10dada.

* Fix NRE

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-04-24 21:50:31 +09:00
cb3c5e56fd Fix: Poll of Lightning Invoice status might fail on LND if LNURL is used (#4910) 2023-04-24 18:15:39 +09:00
39b76c08de Fix: Form in Payment Requests was not setting its values to the invoices metadata (#4907) 2023-04-24 18:04:46 +09:00
c3c8cc21ff Security Page Refactor (#4815)
* Update SECURITY.md

* typo

* project vs product

* Suggestion Update - Docker Deployment

Co-authored-by: d11n <mail@dennisreimann.de>

* Suggestion - Email highlight

Co-authored-by: d11n <mail@dennisreimann.de>

---------

Co-authored-by: d11n <mail@dennisreimann.de>
2023-04-24 15:04:56 +09:00
6dba1b6d8b Nullable on LanguageService 2023-04-20 09:44:24 +09:00
381fe70a79 Add UserAgent to IPN and webhook HTTP requests (Fix #4883) 2023-04-19 21:13:31 +09:00
feb927c2e4 Add missing param, fix response code. (#4891) 2023-04-19 13:07:36 +09:00
e77bd4c188 Swagger: FIx typos in pull payments docs (#4893)
Fixes #4892.
2023-04-19 13:06:51 +09:00
43436fc49e Remove BTCPayServer.Plugins.Test (#4875)
Remove the plugin, which is superseded with the plugin template and move the PluginPacker to the root of th solution (which matches its location in the file system).
2023-04-17 11:38:03 +09:00
d738f797ec bump 2023-04-17 11:11:00 +09:00
b5de97f785 Update changelog 2023-04-17 10:54:00 +09:00
b0c1b0895d Fix crash if auto detect language on checkout page, and the language couldn't be detected (Fix #4881) (#4888) 2023-04-17 10:53:45 +09:00
8e60932f81 Migrate reference to AppType in server settings (Fix #4882) 2023-04-17 10:34:41 +09:00
7d14cd74f2 LightningLikePaymentData: Null-check preimage (#4886)
Fixes #4884.
2023-04-17 00:08:40 +02:00
717f1610f5 Update changelog 2023-04-13 16:28:30 +09:00
f1abe6497f Fix wrong data mapping to store data instead of store user data. (#4874) 2023-04-13 16:27:40 +09:00
046129a57d Bumping LND to 0.16.0-beta (#4873) 2023-04-13 14:48:47 +09:00
90d300a490 Remove superflous category in API doc 2023-04-13 08:41:46 +09:00
a2d506c0db Checkout v2: Confetti for processing payments (#4872)
Let's not spoil the fun for those paying on-chain.
2023-04-13 08:40:21 +09:00
58748a24da What's New entry for v1.9 (#4871)
Copy is just a proposal from my side. Link check expected to fail, because the blog post isn't up yet.
2023-04-12 20:40:20 +09:00
639e8a4a1d Add links to invoice metadata in the docs (#4869) 2023-04-12 16:30:34 +09:00
48ebaf5c5a Do not put payRequest in the metadata (#4870) 2023-04-12 16:30:22 +09:00
1aaccb1e6b Do not show empty JObject in AddtionalData of views 2023-04-11 13:21:02 +09:00
f05a7f9f14 Prevent an NRE in LNURL 2023-04-11 13:08:14 +09:00
98ddb348b0 Update changelog 2023-04-10 20:21:13 +09:00
a4aa85ebab Fix: If connection to Lightning node was interrupted, payments would be missed (#4865) 2023-04-10 19:35:01 +09:00
516efe56f4 Refactor: Dot not make LNURLPaymentMethodDetails depends on BTCPayInvoiceId (#4864)
* Refactor: Dot not make LNURLPaymentMethodDetails depends on BTCPayInvoiceId

* Abstract PaymentProof

* fix bug

* Make the selenium container resolves the btcpay host name
2023-04-10 16:38:49 +09:00
a4d72d5bbc Fix tests 2023-04-10 15:06:59 +09:00
24b8ec16f1 Fix tests 2023-04-10 13:37:09 +09:00
ac25fef555 Remove warning 2023-04-10 12:01:11 +09:00
8302f082a2 Do not render the TruncateCenter if text null or empty 2023-04-10 11:17:29 +09:00
7546ef7a8e Dotnet reformat 2023-04-10 11:07:03 +09:00
f598c70a4f Add comment TODO for improving automatic translations efficiency. 2023-04-10 11:03:36 +09:00
422da21de5 Update Changelog 2023-04-07 17:52:48 +09:00
f530fb3241 Update changelog 2023-04-07 17:50:57 +09:00
5d39bb7466 Allow LN Address to customize invoice metadata, and various bug fixes on LNUrl (#4855)
* Allow LN Address to customize invoice metadata

solves https://github.com/OpenSats/website/issues/8

* Refactor GetLNUrl

* Fix lightningAddresssettings.Max being ignored

* Fix: The payRequest generated by the callback wasn't the same as the original

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-04-07 17:48:58 +09:00
041cba72b6 Made Fake Custodian config field non-required (#4861) 2023-04-07 15:59:44 +09:00
892b3e273f Improve Labeling further (#4849)
* If loading addresses into the send wallet page using bip21 or address,  (or clicking on "Send selected payouts"  from the payotus page), existing labels will be pre-populated.
*  Add the payout label to the address when the payoutis created instead of to the transaction when it is paid.
*  Add the label attachments when adding labels from an address to the transaction.
2023-04-07 15:58:41 +09:00
91faf5756d With core lightning, getting payment by paymenthash wouldn't return the successful payment if the first one failed. 2023-04-07 15:54:56 +09:00
e239390ebf Allow any bolt11 invoice for pullpayments/payouts (#4857)
closes #4830

If users want to deal with expired payout destinations, then they should be able to conifugre it that way. Some wallets simply do not allow customizing the bolt11 expiry and the defaults are much less than a day. I think we should merge #3857 if we introduce this as an automated payotu processor for lightning running every few minutes would work together with this and solve it.
2023-04-06 15:54:19 +09:00
b24764d679 bump 2023-04-05 23:38:39 +09:00
4d5a568fd7 Changelog 1.9 (#4852) 2023-04-05 23:37:01 +09:00
5ab55e71e0 Add cart items to receipt (#4851) 2023-04-05 15:42:23 +02:00
929d63ecf8 Fixed nav menu active states + Better Fake Custodian (#4854) 2023-04-05 15:11:46 +02:00
0ef7f3715f remove obsolete reference 2023-04-05 15:09:42 +02:00
2298f3901a Update langs (#4853) 2023-04-05 13:32:24 +09:00
3005f1937a Replace GetUriByAction by GetPathByAction 2023-04-05 10:58:56 +09:00
f48eec2e93 Fix: Redirecting to local absolute URL in wizard windows should work 2023-04-05 10:55:35 +09:00
754d304e54 Fix tx link in Recent Transactions 2023-04-05 08:53:34 +09:00
9b8d08a668 Make Checkout V2 the default (#4850)
* Make Checkout V2 the default

* Fix align
2023-04-05 08:35:50 +09:00
1b672a1ace Allow multi-step settings in custodian (#4838)
* Allow multi-step settings in custodian

* Fix CustodianAccount.Name not saved

* Reuse TradeQuantity for SimulateTrade

* TradeQuantityJsonConverter accepts numerics

* Fix build
2023-04-04 14:48:29 +09:00
60d6e98c67 Form System Flexibility improvements (#4774)
* Introduce very flexible form input system

* Refactorings after rebase

* Test fix

* Update BTCPayServer/Forms/FormDataService.cs

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-04-04 11:01:34 +09:00
11f05285a1 Invoice Details: Improve payments list and print view (#4817)
Closes #4729.

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
2023-04-04 10:59:14 +09:00
2bd1842da1 Improve pagination (#4828)
Based on the design repo updates by @benalleng in btcpayserver/btcpayserver-design#61. Closes #3835.
2023-04-04 10:54:04 +09:00
57544068e9 Store rule emails in HTML + Test rule emails (#4843)
* Store rule emails in HTML + Test rule emails

* Store rule emails in HTML + Test rule emails

* Update BTCPayServer/Controllers/UIStoresController.Email.cs

Thanks !

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>

* change in StoreEmails() to work properly with add commande

* CanSetupEmailServer() : Remove Bosy sendkeys that doesn't work with new HTML control

* Update test for new HTML control

* better command treatment

---------

Co-authored-by: nisaba <infos@nisaba.solutions>
Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
2023-04-04 10:52:42 +09:00
60cfea9f94 Add presets in the checkout appearance (#4756) 2023-04-04 10:45:40 +09:00
eece001376 Add labels for recent txs dashboard widget (#4831)
* Add labels for recent txs dashboard widget

It is not with the rich data for now, but a good start.

* Turn labels into links

* Add rich info to dashboard labels

* Use truncate-center component for recent transactions

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-03-30 19:54:11 +02:00
98d8ef8e1a Checkout Appearance: Move language settings into the general section (#4833)
The language settings work for both versions of the checkout, so let's make them available for both. Request by @petzsch.
2023-03-30 08:18:13 +02:00
0e43042217 Remove FakeCustodian as a separate project (#4839) 2023-03-30 12:38:30 +09:00
c8e6714207 Merge pull request #4784 from dennisreimann/unify-plugins-apps
Apps become plugins
2023-03-29 20:03:18 +02:00
824e779eb2 Hooks for Zaps (#4826) 2023-03-29 12:27:04 +02:00
83ea898780 Checkout: Update wording (#4829)
We make it "Payment Received" instead of "Payment Sent", because in other places we are also talking from the merchant perspective.
2023-03-29 17:24:49 +09:00
5af3233fd6 Add link to forms doc 2023-03-28 22:02:58 +09:00
08ff2f3173 Checkout: Fix language select width in modal (#4823) 2023-03-28 13:12:47 +02:00
22657b66d7 NFC finetuning (#4822) 2023-03-28 12:36:32 +02:00
8b6c7a6061 Pull Payments: FIx column order in list (#4818)
Date and name were swapped. Fixes #4814.
2023-03-28 19:10:50 +09:00
1f197f6688 Merge pull request #4819 from dennisreimann/nfc 2023-03-28 09:19:58 +02:00
1055e61bb4 NFC improvements
Two changes which fix #4807:

- Once permissions are granted we start scanning immediately, no need to ask for permissions or have the user click the button again
- We don't abort the scan, which gets rid of the cases in which the OS took over after the scan, because the user left the card on the device

Also adds feedback for the NFC states scanning and submitting.
2023-03-27 18:28:53 +02:00
7ad0aa82fc Apps become plugins
Unified navigation for apps that are now plugins. Part of #4744.
2023-03-27 16:43:44 +02:00
d3f5576570 Remove store integrations list page (#4816)
Co-authored-by: d11n <mail@dennisreimann.de>
2023-03-27 16:40:50 +02:00
45141d1391 Checkout v2: Payment processing state (#4778) 2023-03-27 12:12:11 +02:00
de9ac9fd43 Receipt: Add payment proof (#4782)
* Receipt: Add payment proof

Closes #4685.

* shice

* Add truncate-center component

* Improve view

* Hide button and link when printed

* Describe component

* Remove transaction ID from UI

* Remove modification to interface

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-03-27 14:07:12 +09:00
c53d5272d6 Wallet Transactions Export: Add BIP-329 support (#4799)
* Wallet Transactions Export: Add BIP-329 support

* Adjust wording

* Export one line per label

* Join labels, fix type

* Rewrite the ProcessBip329 function to be more performant

* Add nullable on all TransactionsExport

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-03-27 13:59:33 +09:00
18c78192ec Reconstruct issue template (#4803)
* reconstruct issue template

* provide a direct link for filing a tech question
2023-03-27 13:59:07 +09:00
632d67eef4 Fix casing in template example for forms 2023-03-27 12:54:12 +09:00
c23aa48688 Optimize invoice print view (#4783)
Closes #4729.
2023-03-26 20:44:05 +09:00
95f3e429b4 Wallet transactions: Add label manager (#4796)
* Wallet transactions: Add label manager

* Update BTCPayServer/Views/UIWallets/WalletTransactions.cshtml

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>

* Add rich label info

* Fixes

* support labels in wallet send

* add labels to tx info page

* Remove noscript parts

* Allow click on transaction label info

* update psbt info labelstyling

* revert red pixel fix as it broke all

---------

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
2023-03-26 20:42:38 +09:00
8635fcfe84 UI: Redesign Recovery Seed view (#4793)
* Improve recovery seed backup page

* Fix errors from Selenium tests (Sequence contains no elements)

* Revert previous commit

* Improve recovery seed backup page

* Recovery phrase UI update

* recovery seed UI format

* Improve word order

* One column version

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-03-24 16:09:53 +01:00
d861537d9a Merge pull request #4809 from dennisreimann/gf-ln-array-fix
Greenfield: Fix Lightning transaction list return types
2023-03-23 18:59:36 +01:00
631ee99f60 Greenfield: Fix Lightning transaction list return types
The LocalBTCPayServerClient deserializes the results as arrays (`LightningPaymentData[]` and `LightningInvoiceData[]`) — if they are `IEnumerable` the `GetFromActionResult` does not return the data but null.
2023-03-23 17:42:10 +01:00
ffa1441ccd Delete code detecting whether the running version of nbx fixed a bug
The reason to delete this is that any version of NBX with this bug
wouldn't be able to run nowadays because of another bug which would
prevent NBXplorer from synching (Array size too big)
2023-03-23 13:45:40 +09:00
2f3e947027 Merge pull request #4795 from Kukks/lnurl-disable-if-no-node 2023-03-22 09:02:52 +01:00
a62aecfdfe Merge pull request #4798 from dennisreimann/fix-4794 2023-03-22 09:02:35 +01:00
5f829c68f2 Merge pull request #4797 from dennisreimann/fix-4790 2023-03-22 09:02:10 +01:00
0290d74aeb POS: Fix escaped HTML entities in item title
Properly escapes and the sanitized values. Fixes #4794.
2023-03-21 15:31:54 +01:00
f6bc16007d Label tooltips: Use plain text instead of HTML
Fixes #4790.
2023-03-21 15:21:24 +01:00
ad5752f09b Reuse LightningTimeout constant 2023-03-21 14:22:10 +01:00
55565f1718 Do not provide lnurl method if ln node is dead
fixes #3541
2023-03-21 13:48:25 +01:00
5f96d17b8c Update lang 2023-03-20 19:30:56 +09:00
fd22406e0a Fix PullTransifexTranslationsCore 2023-03-20 19:21:35 +09:00
64fe542c1e Update lang 2023-03-20 19:20:46 +09:00
fae1dc8dbb Adapt cookie auth to work with same API permission system (#4595)
* Adapt cookie auth to work with same API permission system

* Handle unscoped store permission case

* Do not consider Unscoped as a valid policy

* Add tests

* Refactor permissions scopes

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-03-20 10:46:46 +09:00
6f2b673021 Custodian withdrawal support + Some refactoring and cleanup (#4085)
* Renamed "WithdrawAsync" to "WithdrawToStoreWalletAsync"

* WIP

* WIP withdrawal + Refactored Form saving to JObject

* WIP

* Form to fix bad values during withdrawing appears correctly

* WIP

* Lots of cleanup and refactoring + Password field and toggle password view

* Cleanup + Finishing touches on withdrawals

* Added "Destination" dummy text as this is always the destination.

* Fixed broken test

* Added support for withdrawing using qty as a percentage if it ends with "%". Needs more testing.

* Fixed broken build

* Fixed broken build (2)

* Update BTCPayServer/wwwroot/swagger/v1/swagger.template.custodians.json

Co-authored-by: d11n <mail@dennisreimann.de>

* Update BTCPayServer/wwwroot/swagger/v1/swagger.template.custodians.json

Co-authored-by: d11n <mail@dennisreimann.de>

* Improved unit tests

* Fixed swagger bug

* Test improvements

Make string conversion of quantity explicitely.

* Fix build warnings

* Swagger: Add missing operationId

* Made change Dennis requested

* Removed unused file

* Removed incorrect comment

* Extra contructor

* Renamed client methods

* Cleanup config before saving

* Fixed broken controller

* Refactor custodian

* Fix build

* Make decimal fields strings to match the rest of Greenfield

* Improve parsing of % quantities

---------

Co-authored-by: d11n <mail@dennisreimann.de>
Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-03-20 10:45:32 +09:00
b26679ca14 Prevent people from starting with --sqlitefile or --mysql (#4772) 2023-03-20 10:40:48 +09:00
04ba1430ca Refactor plugin apps (#4780)
* Refactor plugins

* Add missing names to view models

* Cleanups

* Replace SalesAppBaseType by two interfaces

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-03-20 10:39:26 +09:00
53f3758abc Replace text in copy buttons with icon (#4764)
Closes #4699.
2023-03-19 21:43:38 +01:00
c6742f5533 Language selector: Ensure correct font-size (#4761)
* Language selector: Ensure correct font-size

Fixes the cut-off text on iOS, because somehow iOS uses a larger font-size by default.

* Fix select background color

Webkit-based browsers displayed transparent in a weird way.
2023-03-19 08:44:23 +01:00
cb44591a47 Derivation scheme parsing incorporates fingerprint and key path (#4781) 2023-03-17 14:35:30 +01:00
e02abb509f Allow plugins to do something before and after automatic payouts (#4224) 2023-03-17 13:50:37 +01:00
eff6be9643 Remove mention of LNUrl-Withdraw when paying by NFC (#4779) 2023-03-17 12:24:27 +01:00
348dbd7107 Support Form Select option (#4726)
* Support Form Select option

* Add country select
2023-03-17 14:37:37 +09:00
f74ea14d8b Plugins can now build apps (#4608)
* Plugins can now build apps

* fix tests

* fixup

* pluginize existing apps

* Test fixes part 1

* Test fixes part 2

* Fix Crowdfund namespace

* Syntax

* More namespace fixes

* Markup

* Test fix

* upstream fixes

* Add plugin icon

* Fix nullable build warnings

* allow pre popualting app creation

* Fixes after merge

* Make link methods async

* Use AppData as parameter for ConfigureLink

* GetApps by AppType

* Use ConfigureLink on dashboard

* Rename method

* Add properties to indicate stats support

* Property updates

* Test fixes

* Clean up imports

* Fixes after merge

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-03-17 11:56:32 +09:00
a671632fde Dashboard: Fix app stats tiles (#4775)
* Dashboard: Fix app stats tiles

They broke with #4747, because they contain script blocks that are loaded asynchronuosly and need to get run once the chart data is added to the page.

* Refactor PoS dashboard component

* Collocate the component JS files in separate files

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-03-16 15:51:24 +09:00
e344622c9e Form quick fixes (#4759) 2023-03-15 10:23:33 +01:00
06d7483ca3 Remove obsolete cli argument 'plugin-remote' (#4773) 2023-03-15 09:06:06 +01:00
7fe041fc2c Changelog 1.8.4 2023-03-15 10:45:49 +09:00
3f18e5476a Error when indexing invoices with some field that are too long (Fix #4771) 2023-03-15 09:31:38 +09:00
2a31613fe8 Fix invoice paid after expiration icon 2023-03-14 14:54:01 +01:00
ded0c8a3bc Update price display (#4736)
* Update price display

As proposed by @dstrukt in #4364.

* Update format

* Unify price display across the app

* Add DisplayFormatter

* Replace DisplayFormatCurrency method

* Use symbol currency format for invoice

* Unify currency formats on backend pages

* Revert recent changes

* Do not show exchange rate and fiat order amount for crypto denominations

* Fix test and add test cases
2023-03-13 10:12:58 +09:00
f3d9e07c5e Checkout v2: Celebrate payment with confetti (#4727)
* Checkout v2: Celebrate payment with confetti

Have a colorful celebration for successful payments.

* Make it default and add test
2023-03-13 10:09:56 +09:00
eb3ba95114 Make CanUsePullPaymentsViaUI more robust (#4762)
Fixes this nasty flaky test failure:

```
Failed CanUsePullPaymentsViaUI [17 s]
  Error Message:
   Assert.Equal() Failure
           ↓ (pos 1)
Expected: payout
Actual:   pull-payment
           ↑ (pos 1)
  Stack Trace:
     at BTCPayServer.Tests.ChromeTests.CanUsePullPaymentsViaUI() in /source/BTCPayServer.Tests/SeleniumTests.cs:line 1622
```

Because there are actually two labels, the previous selector was dependent on the correct ordern, because it always chose the first one …
2023-03-13 10:02:07 +09:00
7951dcada6 make sure we have cors for all of greenfield (#4760)
fixes #4758
2023-03-10 15:20:11 +01:00
06951a39c6 fix API breaking changefor payout processors (#4757)
fixes #4752
2023-03-10 17:57:33 +09:00
abe29f21f0 Checkout v2: Option to display amount in Sats in BIP21 case (#4730) 2023-03-09 21:36:11 +01:00
f57eab3008 Store branding: Add complementing text and accent colors (#4746) 2023-03-09 21:34:15 +01:00
6d4b2348ac Update changelog 2023-03-08 21:56:40 +09:00
397ca6ef0c Checkout v2: Minor UI updates (#4734)
* Checkout v2: Minor copy change

* Allow copying of invoice ID and order ID on results page

* Add copy icons for payment details on results view

* Add missing powered by class to store footers
2023-03-08 21:39:03 +09:00
d6e5ee2851 UI: Decrease content padding top on small screens (#4749)
If the viewport height is less than 800px, decrease the content padding top for breakpoints L and on.
2023-03-08 21:37:25 +09:00
98d62e826b Do not through missing-permission error when no store on /api/v1/stores (Close #4735) (#4748) 2023-03-08 21:36:51 +09:00
7b5ce8f70c CSP: Remove unsafe-eval when vue isn't used (#4747)
* CSP: Remove unsafe-eval when vue isn't used

* Prevent XSS injection via VueJS
2023-03-08 17:57:36 +09:00
2010a9a458 bump 2023-03-07 10:29:18 +09:00
f787058c17 Fix: Impossible to create invoice after migration from Sqlite (Close #4743) 2023-03-07 10:27:04 +09:00
87ccae0d90 add missing docs of store payment method criteria 2023-03-05 14:40:18 +01:00
07d95c6ed7 bump clightning 2023-03-05 11:08:01 +09:00
514823f7d2 bump clightning 2023-03-04 21:39:49 +09:00
fb4feb24f3 Minor updates from design repo (#4733) 2023-03-04 09:36:30 +01:00
5caa0e0722 [Greenfield] Allow passing email instead of user id in API (#4732) 2023-03-03 21:24:27 +09:00
0406b420c8 Do not create if create API key is called on a non-existant user (Fix #4731) 2023-03-03 20:30:54 +09:00
9d72b9779e Update Changelog 2023-03-03 20:20:59 +09:00
fdc47e4a38 Avoid crash when some plugins are installed (#4725) 2023-03-03 20:18:09 +09:00
0566e964c0 Fix incorrect punctuation in translations 2023-03-03 17:32:46 +09:00
896fbf9a5c Lang update 2023-03-03 16:38:39 +09:00
126c8c101e Re-add language selector (#4723)
Fixed version
2023-03-02 16:34:15 +09:00
3cb7cc01e4 Update db-migration.md 2023-03-02 13:20:47 +09:00
2b3d15bf45 Update Changelog.md 2023-03-01 23:50:35 +09:00
4049bdadcb Changelog v1.8 (#4670)
* Changelog v1.8

* Update Changelog.md

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>

* Add fix

* Update changlelog

---------

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-03-01 23:41:43 +09:00
2042ba37d8 Update What's New (#4713)
Links to https://blog.btcpayserver.org/btcpay-server-1-8-0/ which doesn't exist yet, that's why the linkcheck is expected to fail.
2023-03-01 23:41:27 +09:00
41a4ba62b0 Remove lang popup in checkout v2 2023-03-01 17:10:54 +09:00
21558d25b1 Do not show product information if there are no product information 2023-03-01 16:19:10 +09:00
06622bfbfd Translate Checkout v2 (#4710) 2023-03-01 15:49:21 +09:00
16fd2e3938 Greenfield: Show detailed Lightning routing error (#4722)
The implementations have more detailed messages for LN routing errors, which e.g. allow me to detect self-payemnts in LNbank. We pass those from the LN lib, so if we have it, we should display it to provide a better insight on what's going on when a rout cannot be found.
2023-03-01 15:46:48 +09:00
040d7670ec Add currency code to payment request list (#4709)
https://github.com/btcpayserver/btcpayserver/discussions/4619
2023-03-01 15:46:13 +09:00
23761eacc1 Unset X-Frame-Options header correctly (#4721)
* Unset X-Frame-Options header correctly

According to the [spec](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) there are onlye the `DENY` and `SAMEORIGIN` options, `ALLOW-FROM` being deprecated. Hence we have to actively unset the header, as we made `DENY` the default.

This also unsets the X-Frame-Options header for the public form pages, which fixes #4666.

* Ignore anti forgery token in Forms

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-03-01 15:27:18 +09:00
5790bed766 Do not crash sqlite migration if the db is create but without tables 2023-03-01 15:04:32 +09:00
2f88da67e8 Fix build warnings and indentation (#4720) 2023-03-01 10:32:48 +09:00
21091cbf1a show all plugins regardless of version (#4717) 2023-02-28 12:16:33 +01:00
808949a884 Update langs 2023-02-26 21:07:23 +09:00
06334273dc Fix crashing on unserialize of old data 2023-02-26 11:18:54 +09:00
5399c04dff Fix crashing on unserialize of old data 2023-02-26 11:05:23 +09:00
cd051d4093 Update transaction label display (#4700)
* Update transaction label display

* Fix test
2023-02-26 11:01:46 +09:00
0ca6e8ccfb bump 2023-02-26 00:20:55 +09:00
bd075919f3 Improve publish docker script 2023-02-26 00:19:59 +09:00
c229425534 Remove JSON in strings from JObjects (#4703) 2023-02-25 23:34:49 +09:00
e89b1826ce add invoicemetadata as a tab (#4693)
* add invocie metadata as a tab

* Allow forms to add to posdata too in pos app

* Cleanup view

* Display additional information directly

* Update BTCPayServer/Views/Shared/PosData.cshtml

* Update BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-02-25 22:38:28 +09:00
4ef19e19cc Checkout v2 fixes (#4705)
* Prevent duplicate titles on invoice view

* Fix text display of escaped values

Fixes #4696.

* Fix payment details re-rendering

Closes #4683. Closes #4684.

* Cleanup
2023-02-25 22:28:02 +09:00
ff58301729 do not require docker for plugin restart
we now have a more graceful restart mechanism specifically for plugins and most installs can handle this mechanism
2023-02-24 13:52:46 +01:00
4ae05272c3 Greenfield: Admins can create/delete API keys of any user (#4680)
* Greenfield: Admins can create/delete API keys of any user

* Greenfield: Improve doc for scoped apikey (Close #4673)

* Fix permissions hierarchy

* Update BTCPayServer.Client/Permissions.cs

* Fix tests

---------

Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
2023-02-24 16:19:03 +09:00
d14dafc871 Apply branding to custom forms (#4697) 2023-02-23 14:35:29 +01:00
022a077726 Use new transifex API on PullTransifexTranslations 2023-02-23 20:59:16 +09:00
d5bd86b07a POS: Align Keypad centered vertically (#4690) 2023-02-23 10:30:16 +01:00
66e1eee010 POS improvements (#4668) 2023-02-23 09:52:37 +01:00
ddb125f458 Fix: HTML injection in payment request/posData/receiptData (Close #4678) (#4679)
Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-02-22 16:35:34 +01:00
e6a157a101 Merge pull request #4686 from dennisreimann/noscript-fix 2023-02-22 14:01:13 +01:00
0a437fba6a Do not show Vue components when there is no JavaScript enabled
Small fix, came across this while testing the noscript checkout version.
2023-02-22 13:34:51 +01:00
39f2e80dc1 Merge pull request #4677 from dennisreimann/fix-4663 2023-02-22 12:30:16 +01:00
13f9eb0d18 Cleanups and unified wording 2023-02-22 11:20:50 +01:00
575b829799 Fix LNURL-Withdraw payments
Fixes comparisons of `long` and `LightMoney`, which did not work, because the `amount` provided was in sats and Lightmoney compares to millisats.

Closes #4663.
2023-02-22 11:18:26 +01:00
02e50fadae Fix: Crash during migration on some SQLite instances (Close #4623) 2023-02-22 17:07:27 +09:00
a02f191034 Fix: Crash during migration on some SQLite instances (Close #4623) 2023-02-22 16:55:19 +09:00
d73d0f178f Checkout: Allow NFC/LNURL-W whenever LNURL is available (#4671)
* Checkout: Allow NFC/LNURL-W whenever LNURL is available

With what we have in master right now, we display NFC only for top-up invoices. With these changes, we display NFC in all cases, where LNURL is available.

Note that this hides LNURL from the list of selectable payment methods, it's only available to use the NFC — and explicitely selectable only for the edge case of top-up invoice + non-unified QR (as before).

Rationale: Now that we got NFC tightly integrated, it doesn't make sense to support the NFC experience only for top-up invoices. With this we bring back LNURL for regular invoices as well, but don't make it selectable and use it only for the NFC functionality.

* Fix LNURL condition

* Improve and test NFC/LNURL display condition

Restores what was fixed in #4660.

* Fix and test Lightning-only case

* Add cache busting for locales
2023-02-22 15:53:14 +09:00
d542a61f5a Fix missing walletchanged event and add storeremoved event (#4676) 2023-02-22 13:13:58 +09:00
e0486aaa24 Label Manager component (#4594)
* Label Manager component

closes #4464

* UI updates

* Test fix

* add test

* fix warnings

* fix select update bug

* add test

* fix test

* Increase payment box max-width

* add labels from address to tx on detection

* Exclude well known label from the dropdown

* Add test on transaction label attachement, tighten UpdateLabels method to only update address labels

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-02-22 11:47:02 +09:00
02bf76fb3c Merge pull request #4554 from Kukks/gf/pmcriteria 2023-02-21 16:03:29 +01:00
8a3ece4a70 add test 2023-02-21 15:31:11 +01:00
c553dc02a9 Greenfield: Expose Payment method criteria 2023-02-21 15:23:51 +01:00
ff71caa47e Upgrade Lightning lib (#4674)
To include the fix from btcpayserver/BTCPayServer.Lightning#122
2023-02-21 16:00:10 +09:00
2bd8227e20 Start using JSONB column instead of app side compressed data (#4574) 2023-02-21 15:06:34 +09:00
5c61de3ae9 Different icons for notifications (#4632)
* Different icons for notifications

Closes #2510.

* Fix version appendix for SVG use attributes

* Fix SVGUse TagHelper

* Update icons
2023-02-21 11:06:27 +09:00
cff46f2d59 UI: Remove highlight for valid fields (#4669) 2023-02-20 19:23:09 +01:00
bbbaacc350 Generic Forms (#4561)
* Custom Forms

* Update BTCPayServer.Data/Migrations/20230125085242_AddForms.cs

* Cleanups

* Explain public form

* Add store branding

* Add form name to POS form

* add tests

* fix migration

* Minor cleanups

* Code improvements

* Add form validation

Closes #4317.

* Adapt form validation for Bootstrap 5

* update logic for forms

* pr changes

* Minor code cleanup

* Remove unused parameters

* Refactor Form data handling to avoid O(n3) issues

* Rename Hidden to Constant

* Pre-populate FormView from the query string params

* Fix test

---------

Co-authored-by: d11n <mail@dennisreimann.de>
Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-02-20 19:35:54 +09:00
60f84d5e30 Display "Pay by LNURL" only when appropriate (#4660)
Closes #4657.
2023-02-20 08:49:10 +09:00
5218aa3c43 Fix missing style tag around embedded CSS (#4659) 2023-02-18 20:38:02 +09:00
4b2ea0c0c3 Fix: Should not crash with command line arg --help 2023-02-16 18:32:26 +09:00
9b865ef849 Fix build and run scripts (#4655) 2023-02-16 18:31:33 +09:00
9344113ae4 Version bump 2023-02-16 17:46:27 +09:00
4448ac9d2a Changelog 1.7.12 (#4653) 2023-02-16 17:45:51 +09:00
9aff143d40 UI: Fix standalone confirmation modal 2023-02-15 16:17:22 +01:00
fc14f418cb Fix: Setting the password of a new created user via API shouldn't be required (Close #4534) (#4647) 2023-02-15 17:11:39 +09:00
b99253ff47 Revert "Fix: Setting the password of a new created user via API shouldn't be required (Close #4534) (#4645)" (#4646)
This reverts commit 9cb844cbbbd4118442d85e6d7a3031f3e1e6ed5b.
2023-02-15 16:32:36 +09:00
9cb844cbbb Fix: Setting the password of a new created user via API shouldn't be required (Close #4534) (#4645) 2023-02-15 16:32:03 +09:00
285aedef2f Fix: If user get locked out, unlocking or deleting user fails (Fix #4641) (#4644)
This is due to the fact our UserService is a singleton, and it had a
reference on UserManager which is scoped.

UserManager is caching user entities at the scope level.
UserService then had a view completely unsynchronized with the database.
2023-02-15 16:00:52 +09:00
5121d64022 Fix: Migrating from SQLite was crashing in some conditions (Close #4623) 2023-02-15 15:59:45 +09:00
8b80910d70 Fix: Unable to Edit amount when cloning paid Payment Request (Close #4639) 2023-02-15 15:33:26 +09:00
a5ff655eed Fix: If user get locked out, unlocking or deleting user fails
This is due to the fact our UserService is a singleton, and it had a
reference on UserManager which is scoped.

UserManager is caching user entities at the scope level.
UserService then had a view completely unsynchronized with the database.
2023-02-15 14:28:34 +09:00
cc9c63c33e Add list count to user preferences cookie (#4637)
I think it's fair to assume that the user wants to set this as a preference and it fixes #4592.
2023-02-15 11:04:17 +09:00
87eef72289 fix typo in vaultbridge.ui.js (#4640)
targetting -> targeting
2023-02-14 19:20:03 +01:00
8e8ba3d052 Webhook: Add missing model validation (#4636)
Fixes #4628.
2023-02-14 22:37:35 +09:00
fea27b900c Harden file type inputs (#4635) 2023-02-14 17:03:12 +09:00
7ad91a76cd Checkout v2: FIx automatic redirect after paid (#4633) 2023-02-14 08:56:00 +09:00
a62b674722 bump 2023-02-13 23:40:32 +09:00
350f35b08d Add code comment 2023-02-13 23:39:55 +09:00
f405321abc Changelog 1.7.11 (#4631) 2023-02-13 23:35:33 +09:00
0d077f6ce5 Fix lnurl for pull paymentdescription + fix authorize redirect form issue (#4630)
fixes #4627
fixes #4624
2023-02-13 23:34:43 +09:00
dffa6accb0 Fix XSS: Stenghten CSP rules on static file uploads (#4629) 2023-02-13 23:04:15 +09:00
b5abcd5ae5 Merge pull request #4622 from dennisreimann/domain-mapping 2023-02-13 13:41:34 +01:00
72a9e676c1 Feature Descriptor (#3831) 2023-02-13 09:25:24 +01:00
3658b396d3 Update db-migration.md 2023-02-11 21:04:43 +09:00
537acab16d Update db-migration.md 2023-02-11 21:04:28 +09:00
8c6fe91c71 After successful migration from SQLite or MySql, there is an error after a restart 2023-02-11 21:01:36 +09:00
3c344331af Improve domain mapping constraint
- Fix potential double assignment to appId, leading to an [exception](https://pastebin.com/j8dhtcTE)
- Add port to redirect, which makes it work in dev env
2023-02-10 18:15:54 +01:00
d14ce2a37f POS: Improve Keypad view (#4596)
* UI updates

* Updates modes and calculation

* Unify tip buttons

* White caret

* Add top margin to calculation

* Add space between mode buttons and keypad

* Discount updates
2023-02-10 16:26:38 +01:00
33d272d4b0 Crowdfund: View updates (#4588)
* Crowdfund: View updates

Improve store branding and remove the card styles, because they had borders which seemed like visual clutter. Other than that I made some changes to the header section and cleaned up the markup and indentation.

* adds column spacing + details header

* Move the Featured Image input

* Center align the Last Updated

* Remove store header, update header section

* Bump description font size

* Improve perk display

* Improve details section

* Fix main image display

---------

Co-authored-by: dstrukt <gfxdsign@gmail.com>
2023-02-10 16:26:09 +01:00
57f5c15670 Merge pull request #4620 from btcpayserver/Kukks-patch-1 2023-02-10 09:45:30 +01:00
487faa69c6 Bump version 2023-02-10 09:40:03 +01:00
9148a1e564 fix #4570 2023-02-10 09:10:10 +01:00
4c3f5e1e1a fix #4618 2023-02-10 08:59:18 +01:00
b0bf0824dd Update db migration doc 2023-02-10 15:48:43 +09:00
dea5991e01 bump 2023-02-10 11:53:17 +09:00
739932a280 Changelog 2023-02-10 11:52:37 +09:00
1f8bc5b490 Add ability to migrate from MySQL and SQLite with EF (#4614) 2023-02-10 11:43:46 +09:00
753ffd401b BIP21 + LNURL fix (#4616)
In case of the unified invoice, the LNURL wasn't correct — with this change we are simply reusing th one that was issued on invoice creation instead of generating it anew on the fly.

Also fixes missing uppercasing for the QR code in case of non-unified QR.
And removes the `lightning:` scheme from the LNURL that's displayed to the user (unifies it with what we do for Onchain and Lightning)
2023-02-10 11:23:48 +09:00
0d1bab45a0 Fix MySQL migrations 2023-02-10 11:17:52 +09:00
17cc439de3 Merge pull request #4617 from dennisreimann/lnurl-cors
LNURL: Add missing CORS
2023-02-09 20:34:44 +01:00
5d03e300fb LNURL: Add missing CORS
In addition to #4587. Closes #4615.
2023-02-09 17:45:09 +01:00
a20408bed1 Fix crash for installations supporting zcash or monero (#4610) 2023-02-09 09:49:08 +09:00
ed0ccd6f13 Bump lightning lib, fix warnings 2023-02-08 21:29:20 +09:00
bb1138efb5 Catch exception when creating new invoice with GetLNURL 2023-02-08 20:45:05 +09:00
82b36aaca7 bump 2023-02-08 20:20:56 +09:00
688044429e Changelog 1.7.6 (#4606) 2023-02-08 20:14:51 +09:00
7bbfc8e6d4 Greenfield: Currency rate should be strings (#4607) 2023-02-08 19:18:37 +09:00
85513aa5c3 Make NFC built in (#4541)
* Make NFC built int

* support checkout v2

* uninstall old plugin

* fix lnurl in unified checkout

* fix tests

* fix tests

* fix old checkout unified qr

* clean up and make nfc submission more sturdy

* support topup invoices for lnurlw

* fix test

* Payment URI fixes

* Fix LNURL exclusion cases

* UI updates

* Adapt test

---------

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
2023-02-08 15:47:38 +09:00
67254cc30c Website is nullable. (#4604) 2023-02-07 12:04:13 +01:00
b055844973 Greenfield get app details (#4102)
* Add Greenfield API endpoints for retrieving app details

* add app items details

* Add GetPosApp and GetCrowdfundApp to LocalBTCPayServerClient

* Simplify POS app data items example

* Document app type enum

* make "RequiresRefundEmail" nullable

* remove "Template" and "PerksTemplate" fields
2023-02-07 17:01:53 +09:00
9ba03848f2 Small perf improvement when fetching exactly 1 payout by id 2023-02-07 16:53:44 +09:00
5b96ab89fd Fix Payout Mark Paid in UI (#4585)
fixes #4579
2023-02-07 16:51:20 +09:00
6a4d8f7404 Fix: Payjoin wasn't always properly choosing utxo for optimal change (#4600)
* Fix: Payjoin wasn't always properly choosing utxo for optimal change

* Update with timeout
2023-02-07 16:43:31 +09:00
219d03b8dd Fix: If PoS item code contains a /, LNUrl would not work (fix #4601) (#4602)
This is caused by a weird buggy behavior from ASP.NET Core concerning
path value decoding. (More information on
https://github.com/dotnet/aspnetcore/issues/14170#issuecomment-533342396)

This hasn't been fixed for a while, and the dotnet team keeps reporting
it over and over.
2023-02-06 18:17:17 +09:00
523654f2eb Upgrade Lightning lib (#4589)
Includes the updates from btcpayserver/BTCPayServer.Lightning#121.
2023-02-06 13:26:11 +09:00
b9b8cb9f63 Fix test 2023-02-06 12:38:18 +09:00
94f2cd4257 Server Theme: Allow to unset CustomThemeCssUri
It is necessary to have a way to unset the deprecated variable, to get access to the new way of uploading a theme file.
2023-02-04 17:24:19 +01:00
26248774c2 App domain redirect (#4391)
* Fix duplicates in GetAllApps with allowNoUser

* Use domain mapping as canonical reference and redirect to it

* Revert domain mapping to hostname instead of URL
2023-02-02 20:53:42 +09:00
99299ba06f bump nbx 2023-02-02 10:15:04 +01:00
6e42eaa26c fix plugin packer when relative path provided 2023-02-02 10:15:03 +01:00
ae7b621e3d Change Stores.DerivationStrategies to JSONB (#4573)
Gradually changing column from blobs to JSONB allow us to
later take advantages of more powerful queries on postgres.
2023-02-02 09:43:39 +09:00
f2ced20c42 Fix a bunch of open redirect (#4575) 2023-02-02 09:42:58 +09:00
e4f256d5cd Lightning Address: Fix availability check and refactor option view (#4584)
As @petzsch rightfully assumed in #4578, the check took only the last available LN payment method into account, which in this case was LN on LTC. We now pass the crypto code as well and I refactored the checks as well as the option view.

Fixes #4578.
2023-02-02 09:42:41 +09:00
ca1dac4cc3 Add missing CORS to ln address of BTCPay (Compatibility Beach Wallet) (#4587) 2023-02-02 09:40:31 +09:00
8fc2729fab Merge pull request #4580 from dennisreimann/disqus-csp
Fixes https://github.com/btcpayserver/btcpayserver/issues/4572
2023-02-01 13:12:11 +01:00
24c19efd52 Crowdfund: Add CSP rules for Disqus
Fixes #4572.
2023-01-31 22:13:45 +01:00
a3edd829a6 Add onchain wallet send ui extension 2023-01-31 16:49:41 +01:00
9ec475fa40 Fix PluginPacker crash 2023-01-31 23:24:20 +09:00
aad06c583e Greenfield: Add store rates api (#4550)
* Add store rates api

* Improve doc

---------

Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
2023-01-31 14:42:25 +09:00
f821e35cb0 Store branding: Unify public pages (#4568)
Closes #3842.
2023-01-30 09:23:49 +01:00
14313291d5 Make test less flaky by ordering GetApps query 2023-01-30 17:17:35 +09:00
b818352a04 Register rate providers in DI, so it can be accessed by plugins (#4551) 2023-01-30 09:46:12 +09:00
c0c34fbb41 Add GreenField endpoint for fetching all apps (#4462)
Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
2023-01-30 09:42:24 +09:00
b372dc21d6 handle non built in tag attachments better 2023-01-27 15:44:21 +01:00
3d576cd06b Fix XSS on uploaded files to the file storage (#4567) 2023-01-26 19:12:06 +09:00
438dcc4c6f Add Greenfield API endpoint for pull payment LNURL items (#4472)
* Add Greenfield API endpoint for pull payment LNURL items

close #4365

* Rename GetLNURLs to GetPullPaymentLNURL

* update "ln-url-not-supported" to "lnurl-not-supported"

* remove hardcoding of "BTC"

* update "PullPayments_LNURL" to "PullPayments_GetPullPaymentLNURL"

* update description of 400 status code response

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
2023-01-26 14:43:07 +09:00
de4ac2c830 Greenfield: Add payments list endpoint (#4407)
Based on btcpayserver/BTCPayServer.Lightning#109
2023-01-26 13:22:49 +09:00
f46443a5e3 Add additional permission for pull payments (#4539)
* Add additional permission for pull payments

* Apply suggestions from code review
2023-01-26 09:46:05 +09:00
69e90b7ff1 Point of Sale: Improve merchant view (#4560)
* Point of Sale: Improve merchant view

Closes #3843.

* Trim bottom section

* Display App Name and Display Title next to each other

* Update views
2023-01-26 09:27:31 +09:00
5089ec9826 Merge pull request #4527 from dennisreimann/branding-new 2023-01-25 15:11:08 +01:00
4df2f1f756 Store Branding: Add custom CSS option 2023-01-24 13:24:17 +01:00
828 changed files with 32364 additions and 29601 deletions

View File

@ -1,8 +1,14 @@
blank_issues_enabled: true
contact_links:
- name: 🚀 Discussions
url: https://github.com/btcpayserver/btcpayserver/discussions
about: Technical discussions, questions and feature requests
- name: 💡 Request a feature
url: https://github.com/btcpayserver/btcpayserver/discussions/categories/ideas-feature-requests
about: Submit a feature request or vote on ideas posted by others. Features with most upvotes become roadmap candidates
- name: 🧑‍💻 Ask a technical question
url: https://github.com/btcpayserver/btcpayserver/discussions/new?category=technical-support
about: If you're experiencing a technical problem post it to our community support forum
- name: 🔌 Report a problem with a plugin
url: https://github.com/btcpayserver/btcpayserver/discussions/new?category=plugins-integrations
about: Experiencing a problem with a third-party plugin? Post it here and we will tag their developers to assist
- name: 📝 Official Documentation
url: https://docs.btcpayserver.org
about: Check our documentation for answers to common questions

2
.github/codeql/codeql-config.yml vendored Normal file
View File

@ -0,0 +1,2 @@
paths-ignore:
- 'BTCPayServer/wwwroot/vendor/**/*.js'

80
.github/workflows/codeql.yml vendored Normal file
View File

@ -0,0 +1,80 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
# Allow running tests manually. Usefull if scan failure, or need to rescan before next scheduled date.
workflow_dispatch:
# We scan only on a schedule for now, can uncomment the following to scan on commit or PR merge later on if deemed appropriate.
# push:
# branches: [ "master" ]
# pull_request:
# branches: [ "master" ]
schedule:
# Scan every Monday 06:00 UTC.
- cron: '0 6 * * 1'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript', 'csharp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql/codeql-config.yml
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

View File

@ -1,21 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Pack Test Plugin" type="DotNetProject" factoryName=".NET Project" singleton="false">
<option name="EXE_PATH" value="$PROJECT_DIR$/BTCPayServer.PluginPacker/bin/Debug/netcoreapp3.1/BTCPayServer.PluginPacker.dll" />
<option name="PROGRAM_PARAMETERS" value="../../../../BTCPayServer.Plugins.Test\bin\Debug\netcoreapp3.1 BTCPayServer.Plugins.Test &quot;../../../../Packed Plugins&quot;" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/BTCPayServer.PluginPacker/bin/Debug/netcoreapp3.1" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/BTCPayServer.PluginPacker/BTCPayServer.PluginPacker.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value=".NETCoreApp,Version=v3.1" />
<method v="2">
<option name="Build" default="false" projectName="BTCPayServer.Plugins.Test" projectPath="C:\Git\btcpayserver\Plugins\BTCPayServer.Plugins.Test\BTCPayServer.Plugins.Test.csproj" />
<option name="Build" />
</method>
</configuration>
</component>

View File

@ -1,3 +1,5 @@
using System.IO;
namespace BTCPayServer.Configuration
{
public class DataDirectories
@ -7,5 +9,12 @@ namespace BTCPayServer.Configuration
public string TempStorageDir { get; set; }
public string StorageDir { get; set; }
public string TempDir { get; set; }
public string ToDatadirFullPath(string path)
{
if (Path.IsPathRooted(path))
return path;
return Path.Combine(DataDir, path);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Data.Common;
using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
@ -21,7 +22,6 @@ namespace BTCPayServer.Abstractions.Contracts
}
public abstract T CreateContext();
class CustomNpgsqlMigrationsSqlGenerator : NpgsqlMigrationsSqlGenerator
{
#pragma warning disable EF1001 // Internal EF Core API usage.

View File

@ -19,6 +19,8 @@ namespace BTCPayServer.Abstractions.Contracts
public class NotificationViewModel
{
public string Id { get; set; }
public string Identifier { get; set; }
public string Type { get; set; }
public DateTimeOffset Created { get; set; }
public string Body { get; set; }
public string ActionLink { get; set; }

View File

@ -1,3 +1,4 @@
using System;
using System.Threading.Tasks;
namespace BTCPayServer.Abstractions.Contracts
@ -6,5 +7,8 @@ namespace BTCPayServer.Abstractions.Contracts
{
Task ApplyAction(string hook, object args);
Task<object> ApplyFilter(string hook, object args);
event EventHandler<(string hook, object args)> ActionInvoked;
event EventHandler<(string hook, object args)> FilterInvoked;
}
}

View File

@ -5,4 +5,8 @@ public class AssetBalancesUnavailableException : CustodianApiException
public AssetBalancesUnavailableException(System.Exception e) : base(500, "asset-balances-unavailable", $"Cannot fetch the asset balances: {e.Message}", e)
{
}
public AssetBalancesUnavailableException(string errorMsg) : base(500, "asset-balances-unavailable", $"Cannot fetch the asset balances: {errorMsg}")
{
}
}

View File

@ -10,7 +10,7 @@ public class CustodianApiException : Exception
HttpStatus = httpStatus;
Code = code;
}
public CustodianApiException(int httpStatus, string code, string message) : this(httpStatus, code, message, null)
{
}

View File

@ -0,0 +1,28 @@
using System.Collections.Generic;
using BTCPayServer.Client.Models;
using BTCPayServer.JsonConverters;
namespace BTCPayServer.Abstractions.Custodians.Client;
public class SimulateWithdrawalResult
{
public string PaymentMethod { get; }
public string Asset { get; }
public decimal MinQty { get; }
public decimal MaxQty { get; }
public List<LedgerEntryData> LedgerEntries { get; }
// Fee can be NULL if unknown.
public decimal? Fee { get; }
public SimulateWithdrawalResult(string paymentMethod, string asset, List<LedgerEntryData> ledgerEntries,
decimal minQty, decimal maxQty)
{
PaymentMethod = paymentMethod;
Asset = asset;
LedgerEntries = ledgerEntries;
MinQty = minQty;
MaxQty = maxQty;
}
}

View File

@ -5,9 +5,14 @@ using Newtonsoft.Json.Linq;
namespace BTCPayServer.Abstractions.Custodians;
/// <summary>
/// Interface for custodians that can move funds to the store wallet.
/// </summary>
public interface ICanWithdraw
{
public Task<WithdrawResult> WithdrawAsync(string paymentMethod, decimal amount, JObject config, CancellationToken cancellationToken);
public Task<WithdrawResult> WithdrawToStoreWalletAsync(string paymentMethod, decimal amount, JObject config, CancellationToken cancellationToken);
public Task<SimulateWithdrawalResult> SimulateWithdrawalAsync(string paymentMethod, decimal qty, JObject config, CancellationToken cancellationToken);
public Task<WithdrawResult> GetWithdrawalInfoAsync(string paymentMethod, string withdrawalId, JObject config, CancellationToken cancellationToken);

View File

@ -1,3 +1,4 @@
#nullable enable
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@ -20,7 +21,6 @@ public interface ICustodian
*/
Task<Dictionary<string, decimal>> GetAssetBalancesAsync(JObject config, CancellationToken cancellationToken);
public Task<Form.Form> GetConfigForm(JObject config, string locale,
CancellationToken cancellationToken = default);
public Task<Form.Form> GetConfigForm(JObject config, CancellationToken cancellationToken = default);
}

View File

@ -7,6 +7,10 @@ namespace BTCPayServer.Abstractions.Extensions;
public static class GreenfieldExtensions
{
public static IActionResult UserNotFound(this ControllerBase ctrl)
{
return ctrl.CreateAPIError(404, "user-not-found", "The user was not found");
}
public static IActionResult CreateValidationError(this ControllerBase controller, ModelStateDictionary modelState)
{
return controller.UnprocessableEntity(modelState.ToGreenfieldValidationError());

View File

@ -12,7 +12,7 @@ public class Field
{
public static Field Create(string label, string name, string value, bool required, string helpText, string type = "text")
{
return new Field()
return new Field
{
Label = label,
Name = name,
@ -26,14 +26,14 @@ public class Field
// The name of the HTML5 node. Should be used as the key for the posted data.
public string Name;
public bool Hidden;
public bool Constant;
// HTML5 compatible type string like "text", "textarea", "email", "password", etc. Each type is a class and may contain more fields (i.e. "select" would have options).
// HTML5 compatible type string like "text", "textarea", "email", "password", etc.
public string Type;
public static Field CreateFieldset()
{
return new Field() { Type = "fieldset" };
return new Field { Type = "fieldset" };
}
// The value field is what is currently in the DB or what the user entered, but possibly not saved yet due to validation errors.
@ -55,7 +55,7 @@ public class Field
public List<Field> Fields { get; set; } = new();
// The field is considered "valid" if there are no validation errors
public List<string> ValidationErrors = new List<string>();
public List<string> ValidationErrors = new();
public virtual bool IsValid()
{

View File

@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json.Linq;
using Npgsql.Internal.TypeHandlers.GeometricHandlers;
namespace BTCPayServer.Abstractions.Form;
@ -20,6 +22,7 @@ public class Form
return JObject.FromObject(this, CamelCaseSerializerSettings.Serializer).ToString(Newtonsoft.Json.Formatting.Indented);
}
#nullable restore
// Messages to be shown at the top of the form indicating user feedback like "Saved successfully" or "Please change X because of Y." or a warning, etc...
public List<AlertMessage> TopMessages { get; set; } = new();
@ -29,129 +32,104 @@ public class Form
// Are all the fields valid in the form?
public bool IsValid()
{
if (TopMessages?.Any(t => t.Type == AlertMessage.AlertMessageType.Danger) is true)
return false;
return Fields.Select(f => f.IsValid()).All(o => o);
}
public Field GetFieldByName(string name)
public Field GetFieldByFullName(string fullName)
{
return GetFieldByName(name, Fields, null);
}
private static Field GetFieldByName(string name, List<Field> fields, string prefix)
{
prefix ??= string.Empty;
foreach (var field in fields)
foreach (var f in GetAllFields())
{
var currentPrefix = prefix;
if (!string.IsNullOrEmpty(field.Name))
{
currentPrefix = $"{prefix}{field.Name}";
if (currentPrefix.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
return field;
}
currentPrefix += "_";
}
var subFieldResult = GetFieldByName(name, field.Fields, currentPrefix);
if (subFieldResult is not null)
{
return subFieldResult;
}
if (f.FullName == fullName)
return f.Field;
}
return null;
}
public List<string> GetAllNames()
public IEnumerable<(string FullName, List<string> Path, Field Field)> GetAllFields()
{
return GetAllNames(Fields);
HashSet<string> nameReturned = new();
foreach (var f in GetAllFieldsCore(new List<string>(), Fields))
{
var fullName = string.Join('_', f.Path.Where(s => !string.IsNullOrEmpty(s)));
if (!nameReturned.Add(fullName))
continue;
yield return (fullName, f.Path, f.Field);
}
}
private static List<string> GetAllNames(List<Field> fields)
public bool ValidateFieldNames(out List<string> errors)
{
var names = new List<string>();
errors = new List<string>();
HashSet<string> nameReturned = new();
foreach (var f in GetAllFieldsCore(new List<string>(), Fields))
{
var fullName = string.Join('_', f.Path.Where(s => !string.IsNullOrEmpty(s)));
if (!nameReturned.Add(fullName))
{
errors.Add($"Form contains duplicate field names '{fullName}'");
}
}
return errors.Count == 0;
}
IEnumerable<(List<string> Path, Field Field)> GetAllFieldsCore(List<string> path, List<Field> fields)
{
foreach (var field in fields)
{
string prefix = string.Empty;
List<string> thisPath = new(path.Count + 1);
thisPath.AddRange(path);
if (!string.IsNullOrEmpty(field.Name))
{
names.Add(field.Name);
prefix = $"{field.Name}_";
thisPath.Add(field.Name);
yield return (thisPath, field);
}
if (field.Fields.Any())
foreach (var descendant in GetAllFieldsCore(thisPath, field.Fields))
{
names.AddRange(GetAllNames(field.Fields).Select(s => $"{prefix}{s}"));
}
}
return names;
}
public void ApplyValuesFromOtherForm(Form form)
{
foreach (var fieldset in Fields)
{
foreach (var field in fieldset.Fields)
{
field.Value = form
.GetFieldByName(
$"{(string.IsNullOrEmpty(fieldset.Name) ? string.Empty : fieldset.Name + "_")}{field.Name}")
?.Value;
descendant.Field.Constant = field.Constant || descendant.Field.Constant;
yield return descendant;
}
}
}
public void ApplyValuesFromForm(IFormCollection form)
public void ApplyValuesFromForm(IEnumerable<KeyValuePair<string, StringValues>> form)
{
var names = GetAllNames();
foreach (var name in names)
var values = form.GroupBy(f => f.Key, f => f.Value).ToDictionary(g => g.Key, g => g.First());
foreach (var f in GetAllFields())
{
var field = GetFieldByName(name);
if (field is null || !form.TryGetValue(name, out var val))
{
if (f.Field.Constant || !values.TryGetValue(f.FullName, out var val))
continue;
}
field.Value = val;
f.Field.Value = val;
}
}
public Dictionary<string, object> GetValues()
public void SetValues(JObject values)
{
return GetValues(Fields);
var fields = GetAllFields().ToDictionary(k => k.FullName, k => k.Field);
SetValues(fields, new List<string>(), values);
}
private static Dictionary<string, object> GetValues(List<Field> fields)
private void SetValues(Dictionary<string, Field> fields, List<string> path, JObject values)
{
var result = new Dictionary<string, object>();
foreach (Field field in fields)
foreach (var prop in values.Properties())
{
var name = field.Name ?? string.Empty;
if (field.Fields.Any())
List<string> propPath = new List<string>(path.Count + 1);
propPath.AddRange(path);
propPath.Add(prop.Name);
if (prop.Value.Type == JTokenType.Object)
{
var values = GetValues(fields);
values.Remove(string.Empty, out var keylessValue);
result.TryAdd(name, values);
if (keylessValue is not Dictionary<string, object> dict)
continue;
foreach (KeyValuePair<string, object> keyValuePair in dict)
{
result.TryAdd(keyValuePair.Key, keyValuePair.Value);
}
SetValues(fields, propPath, (JObject)prop.Value);
}
else
else if (prop.Value.Type == JTokenType.String)
{
result.TryAdd(name, field.Value);
var fullName = string.Join('_', propPath.Where(s => !string.IsNullOrEmpty(s)));
if (fields.TryGetValue(fullName, out var f) && !f.Constant)
f.Value = prop.Value.Value<string>();
}
}
return result;
}
}

View File

@ -114,6 +114,11 @@ namespace BTCPayServer.Security
_Policies.Add(policy);
}
public void UnsafeEval()
{
Add("script-src", "'unsafe-eval'");
}
public IEnumerable<ConsentSecurityPolicy> Rules => _Policies;
public bool HasRules => _Policies.Count != 0;

View File

@ -6,31 +6,33 @@ using Microsoft.Extensions.Logging;
namespace BTCPayServer.Abstractions.TagHelpers;
[HtmlTargetElement(Attributes = nameof(Permission))]
[HtmlTargetElement(Attributes = "[permission]")]
[HtmlTargetElement(Attributes = "[not-permission]" )]
public class PermissionTagHelper : TagHelper
{
private readonly IAuthorizationService _authorizationService;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<PermissionTagHelper> _logger;
public PermissionTagHelper(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor, ILogger<PermissionTagHelper> logger)
public PermissionTagHelper(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor)
{
_authorizationService = authorizationService;
_httpContextAccessor = httpContextAccessor;
_logger = logger;
}
public string Permission { get; set; }
public string NotPermission { get; set; }
public string PermissionResource { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (string.IsNullOrEmpty(Permission))
if (string.IsNullOrEmpty(Permission) && string.IsNullOrEmpty(NotPermission))
return;
if (_httpContextAccessor.HttpContext is null)
return;
var key = $"{Permission}_{PermissionResource}";
var expectedResult = !string.IsNullOrEmpty(Permission);
var key = $"{Permission??NotPermission}_{PermissionResource}";
if (!_httpContextAccessor.HttpContext.Items.TryGetValue(key, out var o) ||
o is not AuthorizationResult res)
{
@ -39,7 +41,7 @@ public class PermissionTagHelper : TagHelper
Permission);
_httpContextAccessor.HttpContext.Items.Add(key, res);
}
if (!res.Succeeded)
if (expectedResult != res.Succeeded)
{
output.SuppressOutput();
}

View File

@ -23,10 +23,19 @@ public class SVGUse : UrlResolutionTagHelper2
{
_fileVersionProvider = fileVersionProvider;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var attr = output.Attributes["href"].Value.ToString();
attr = _fileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, attr);
var symbolIndex = attr!.IndexOf("#", StringComparison.InvariantCulture);
var start = attr.IndexOf("~", StringComparison.InvariantCulture) + 1;
var length = (symbolIndex != -1 ? symbolIndex : attr.Length) - start;
var filePath = attr.Substring(start, length);
if (!string.IsNullOrEmpty(filePath))
{
var versioned = _fileVersionProvider.AddFileVersionToPath(ViewContext.HttpContext.Request.PathBase, filePath);
attr = attr.Replace(filePath, versioned);
}
output.Attributes.SetAttribute("href", attr);
base.Process(context, output);
}

View File

@ -12,6 +12,8 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/btcpayserver/btcpayserver</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<Configurations>Debug;Release;Altcoins-Debug;Altcoins-Release</Configurations>
<Platforms>AnyCPU</Platforms>
</PropertyGroup>
<PropertyGroup>
<Version Condition=" '$(Version)' == '' ">1.7.2</Version>

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
@ -22,6 +23,15 @@ namespace BTCPayServer.Client
return await HandleResponse<ApiKeyData>(response);
}
public virtual async Task<ApiKeyData> CreateAPIKey(string userId, CreateApiKeyRequest request, CancellationToken token = default)
{
if (request == null)
throw new ArgumentNullException(nameof(request));
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/{userId}/api-keys",
bodyPayload: request, method: HttpMethod.Post), token);
return await HandleResponse<ApiKeyData>(response);
}
public virtual async Task RevokeCurrentAPIKeyInfo(CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/api-keys/current", null, HttpMethod.Delete), token);
@ -35,5 +45,14 @@ namespace BTCPayServer.Client
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/api-keys/{apikey}", null, HttpMethod.Delete), token);
await HandleResponse(response);
}
public virtual async Task RevokeAPIKey(string userId, string apikey, CancellationToken token = default)
{
if (apikey == null)
throw new ArgumentNullException(nameof(apikey));
if (userId is null)
throw new ArgumentNullException(nameof(userId));
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/users/{userId}/api-keys/{apikey}", null, HttpMethod.Delete), token);
await HandleResponse(response);
}
}
}

View File

@ -52,6 +52,44 @@ namespace BTCPayServer.Client
return await HandleResponse<AppDataBase>(response);
}
public virtual async Task<AppDataBase[]> GetAllApps(string storeId, CancellationToken token = default)
{
if (storeId == null)
throw new ArgumentNullException(nameof(storeId));
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/apps",
method: HttpMethod.Get), token);
return await HandleResponse<AppDataBase[]>(response);
}
public virtual async Task<AppDataBase[]> GetAllApps(CancellationToken token = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/apps",
method: HttpMethod.Get), token);
return await HandleResponse<AppDataBase[]>(response);
}
public virtual async Task<PointOfSaleAppData> GetPosApp(string appId, CancellationToken token = default)
{
if (appId == null)
throw new ArgumentNullException(nameof(appId));
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/apps/pos/{appId}",
method: HttpMethod.Get), token);
return await HandleResponse<PointOfSaleAppData>(response);
}
public virtual async Task<CrowdfundAppData> GetCrowdfundApp(string appId, CancellationToken token = default)
{
if (appId == null)
throw new ArgumentNullException(nameof(appId));
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/apps/crowdfund/{appId}",
method: HttpMethod.Get), token);
return await HandleResponse<CrowdfundAppData>(response);
}
public virtual async Task DeleteApp(string appId, CancellationToken token = default)
{
if (appId == null)

View File

@ -50,7 +50,7 @@ namespace BTCPayServer.Client
await HandleResponse(response);
}
public virtual async Task<DepositAddressData> GetDepositAddress(string storeId, string accountId, string paymentMethod, CancellationToken token = default)
public virtual async Task<DepositAddressData> GetCustodianAccountDepositAddress(string storeId, string accountId, string paymentMethod, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/addresses/{paymentMethod}"), token);
return await HandleResponse<DepositAddressData>(response);
@ -58,7 +58,6 @@ namespace BTCPayServer.Client
public virtual async Task<MarketTradeResponseData> MarketTradeCustodianAccountAsset(string storeId, string accountId, TradeRequestData request, CancellationToken token = default)
{
//var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/users", null, request, HttpMethod.Post), token);
//return await HandleResponse<ApplicationUserData>(response);
var internalRequest = CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/trades/market", null,
@ -67,13 +66,13 @@ namespace BTCPayServer.Client
return await HandleResponse<MarketTradeResponseData>(response);
}
public virtual async Task<MarketTradeResponseData> GetTradeInfo(string storeId, string accountId, string tradeId, CancellationToken token = default)
public virtual async Task<MarketTradeResponseData> GetCustodianAccountTradeInfo(string storeId, string accountId, string tradeId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/trades/{tradeId}", method: HttpMethod.Get), token);
return await HandleResponse<MarketTradeResponseData>(response);
}
public virtual async Task<TradeQuoteResponseData> GetTradeQuote(string storeId, string accountId, string fromAsset, string toAsset, CancellationToken token = default)
public virtual async Task<TradeQuoteResponseData> GetCustodianAccountTradeQuote(string storeId, string accountId, string fromAsset, string toAsset, CancellationToken token = default)
{
var queryPayload = new Dictionary<string, object>();
queryPayload.Add("fromAsset", fromAsset);
@ -82,13 +81,19 @@ namespace BTCPayServer.Client
return await HandleResponse<TradeQuoteResponseData>(response);
}
public virtual async Task<WithdrawalResponseData> CreateWithdrawal(string storeId, string accountId, WithdrawRequestData request, CancellationToken token = default)
public virtual async Task<WithdrawalResponseData> CreateCustodianAccountWithdrawal(string storeId, string accountId, WithdrawRequestData request, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/withdrawals", bodyPayload: request, method: HttpMethod.Post), token);
return await HandleResponse<WithdrawalResponseData>(response);
}
public virtual async Task<WithdrawalResponseData> GetWithdrawalInfo(string storeId, string accountId, string paymentMethod, string withdrawalId, CancellationToken token = default)
public virtual async Task<WithdrawalSimulationResponseData> SimulateCustodianAccountWithdrawal(string storeId, string accountId, WithdrawRequestData request, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/withdrawals/simulation", bodyPayload: request, method: HttpMethod.Post), token);
return await HandleResponse<WithdrawalSimulationResponseData>(response);
}
public virtual async Task<WithdrawalResponseData> GetCustodianAccountWithdrawalInfo(string storeId, string accountId, string paymentMethod, string withdrawalId, CancellationToken token = default)
{
var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/custodian-accounts/{accountId}/withdrawals/{paymentMethod}/{withdrawalId}", method: HttpMethod.Get), token);
return await HandleResponse<WithdrawalResponseData>(response);

View File

@ -114,6 +114,24 @@ namespace BTCPayServer.Client
return await HandleResponse<LightningInvoiceData[]>(response);
}
public virtual async Task<LightningPaymentData[]> GetLightningPayments(string cryptoCode,
bool? includePending = null, long? offsetIndex = null, CancellationToken token = default)
{
var queryPayload = new Dictionary<string, object>();
if (includePending is bool v)
{
queryPayload.Add("includePending", v.ToString());
}
if (offsetIndex is > 0)
{
queryPayload.Add("offsetIndex", offsetIndex);
}
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/server/lightning/{cryptoCode}/payments", queryPayload), token);
return await HandleResponse<LightningPaymentData[]>(response);
}
public virtual async Task<LightningInvoiceData> CreateLightningInvoice(string cryptoCode, CreateLightningInvoiceRequest request,
CancellationToken token = default)
{

View File

@ -116,6 +116,24 @@ namespace BTCPayServer.Client
return await HandleResponse<LightningInvoiceData[]>(response);
}
public virtual async Task<LightningPaymentData[]> GetLightningPayments(string storeId, string cryptoCode,
bool? includePending = null, long? offsetIndex = null, CancellationToken token = default)
{
var queryPayload = new Dictionary<string, object>();
if (includePending is bool v)
{
queryPayload.Add("includePending", v.ToString());
}
if (offsetIndex is > 0)
{
queryPayload.Add("offsetIndex", offsetIndex);
}
var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/lightning/{cryptoCode}/payments", queryPayload), token);
return await HandleResponse<LightningPaymentData[]>(response);
}
public virtual async Task<LightningInvoiceData> CreateLightningInvoice(string storeId, string cryptoCode,
CreateLightningInvoiceRequest request, CancellationToken token = default)
{

View File

@ -97,5 +97,15 @@ namespace BTCPayServer.Client
method: HttpMethod.Post, bodyPayload: request), cancellationToken);
await HandleResponse(response);
}
public virtual async Task<PullPaymentLNURL> GetPullPaymentLNURL(string pullPaymentId,
CancellationToken cancellationToken = default)
{
var response = await _httpClient.SendAsync(
CreateHttpRequest(
$"/api/v1/pull-payments/{pullPaymentId}/lnurl",
method: HttpMethod.Get), cancellationToken);
return await HandleResponse<PullPaymentLNURL>(response);
}
}
}

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using BTCPayServer.Client.Models;
@ -11,5 +12,11 @@ namespace BTCPayServer.Client
var response = await _httpClient.SendAsync(CreateHttpRequest("api/v1/server/info"), token);
return await HandleResponse<ServerInfoData>(response);
}
public virtual async Task<List<RoleData>> GetServerRoles(CancellationToken token = default)
{
using var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/server/roles"), token);
return await HandleResponse<List<RoleData>>(response);
}
}
}

View File

@ -37,7 +37,7 @@ namespace BTCPayServer.Client
return await HandleResponse<StoreRateConfiguration>(response);
}
public virtual async Task<List<StoreRatePreviewResult>> PreviewUpdateStoreRateConfiguration(string storeId,
public virtual async Task<List<StoreRateResult>> PreviewUpdateStoreRateConfiguration(string storeId,
StoreRateConfiguration request,
string[] currencyPair,
CancellationToken token = default)
@ -47,7 +47,18 @@ namespace BTCPayServer.Client
queryPayload: new Dictionary<string, object>() { { "currencyPair", currencyPair } },
method: HttpMethod.Post),
token);
return await HandleResponse<List<StoreRatePreviewResult>>(response);
return await HandleResponse<List<StoreRateResult>>(response);
}
public virtual async Task<List<StoreRateResult>> GetStoreRates(string storeId, string[] currencyPair,
CancellationToken token = default)
{
using var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/rates",
queryPayload: new Dictionary<string, object>() { { "currencyPair", currencyPair } },
method: HttpMethod.Get),
token);
return await HandleResponse<List<StoreRateResult>>(response);
}
}
}

View File

@ -9,6 +9,13 @@ namespace BTCPayServer.Client
{
public partial class BTCPayServerClient
{
public virtual async Task<List<RoleData>> GetStoreRoles(string storeId,
CancellationToken token = default)
{
using var response = await _httpClient.SendAsync(CreateHttpRequest($"api/v1/stores/{storeId}/roles"), token);
return await HandleResponse<List<RoleData>>(response);
}
public virtual async Task<IEnumerable<StoreUserData>> GetStoreUsers(string storeId,
CancellationToken token = default)
{

View File

@ -51,7 +51,8 @@ namespace BTCPayServer.Client
{
if (message.StatusCode == System.Net.HttpStatusCode.UnprocessableEntity)
{
var err = JsonConvert.DeserializeObject<Models.GreenfieldValidationError[]>(await message.Content.ReadAsStringAsync());
var aa = await message.Content.ReadAsStringAsync();
var err = JsonConvert.DeserializeObject<Models.GreenfieldValidationError[]>(aa);
throw new GreenfieldValidationException(err);
}
if (message.StatusCode == System.Net.HttpStatusCode.Forbidden)

View File

@ -30,9 +30,9 @@ namespace BTCPayServer.JsonConverters
case JTokenType.Integer:
case JTokenType.String:
if (objectType == typeof(decimal) || objectType == typeof(decimal?))
return decimal.Parse(token.ToString(), CultureInfo.InvariantCulture);
return decimal.Parse(token.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture);
if (objectType == typeof(double) || objectType == typeof(double?))
return double.Parse(token.ToString(), CultureInfo.InvariantCulture);
return double.Parse(token.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture);
throw new JsonSerializationException("Unexpected object type: " + objectType);
case JTokenType.Null when objectType == typeof(decimal?) || objectType == typeof(double?):
return null;

View File

@ -0,0 +1,36 @@
using System;
using System.Globalization;
using BTCPayServer.Client.Models;
using BTCPayServer.Lightning;
using NBitcoin.JsonConverters;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client.JsonConverters
{
public class TradeQuantityJsonConverter : JsonConverter<TradeQuantity>
{
public override TradeQuantity ReadJson(JsonReader reader, Type objectType, TradeQuantity existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
switch (token.Type)
{
case JTokenType.Float:
case JTokenType.Integer:
case JTokenType.String:
if (TradeQuantity.TryParse(token.ToString(), out var q))
return q;
break;
case JTokenType.Null:
return null;
}
throw new JsonObjectException("Invalid TradeQuantity, expected string. Expected: \"1.50\" or \"50%\"", reader);
}
public override void WriteJson(JsonWriter writer, TradeQuantity value, JsonSerializer serializer)
{
if (value is not null)
writer.WriteValue(value.ToString());
}
}
}

View File

@ -1,8 +1,11 @@
#nullable enable
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client.Models;
public class CreatePayoutThroughStoreRequest : CreatePayoutRequest
{
public string? PullPaymentId { get; set; }
public bool? Approved { get; set; }
public JObject? Metadata { get; set; }
}

View File

@ -86,6 +86,7 @@ namespace BTCPayServer.Client.Models
public bool? RequiresRefundEmail { get; set; } = null;
public string DefaultLanguage { get; set; }
public CheckoutType? CheckoutType { get; set; }
public bool? LazyPaymentMethods { get; set; }
}
}
public class InvoiceData : InvoiceDataBase

View File

@ -3,7 +3,6 @@ namespace BTCPayServer.Client.Models
public class LNURLPayPaymentMethodBaseData
{
public bool UseBech32Scheme { get; set; }
public bool EnableForStandardInvoices { get; set; }
public bool LUD12Enabled { get; set; }
public LNURLPayPaymentMethodBaseData()

View File

@ -16,12 +16,11 @@ namespace BTCPayServer.Client.Models
{
}
public LNURLPayPaymentMethodData(string cryptoCode, bool enabled, bool useBech32Scheme, bool enableForStandardInvoices)
public LNURLPayPaymentMethodData(string cryptoCode, bool enabled, bool useBech32Scheme)
{
Enabled = enabled;
CryptoCode = cryptoCode;
UseBech32Scheme = useBech32Scheme;
EnableForStandardInvoices = enableForStandardInvoices;
}
}
}

View File

@ -1,3 +1,4 @@
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
@ -6,6 +7,7 @@ namespace BTCPayServer.Client.Models;
public class LedgerEntryData
{
public string Asset { get; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Qty { get; }
[JsonConverter(typeof(StringEnumConverter))]

View File

@ -3,8 +3,8 @@ namespace BTCPayServer.Client.Models;
public class LightningAddressData
{
public string Username { get; set; }
public string? CurrencyCode { get; set; }
public string CurrencyCode { get; set; }
public decimal? Min { get; set; }
public decimal? Max { get; set; }
}

View File

@ -10,4 +10,9 @@ public class LightningAutomatedPayoutSettings
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
public TimeSpan IntervalSeconds { get; set; }
public int? CancelPayoutAfterFailures { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public bool ProcessNewPayoutsInstantly { get; set; }
}

View File

@ -16,7 +16,7 @@ namespace BTCPayServer.Client.Models
[JsonProperty("BOLT11")]
public string BOLT11 { get; set; }
public string PaymentHash { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
@ -24,7 +24,7 @@ namespace BTCPayServer.Client.Models
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset? PaidAt { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset ExpiresAt { get; set; }

View File

@ -4,7 +4,6 @@ namespace BTCPayServer.Client.Models
{
public string ConnectionString { get; set; }
public bool DisableBOLT11PaymentOption { get; set; }
public LightningNetworkPaymentMethodBaseData()
{

View File

@ -16,13 +16,12 @@ namespace BTCPayServer.Client.Models
{
}
public LightningNetworkPaymentMethodData(string cryptoCode, string connectionString, bool enabled, string paymentMethod, bool disableBOLT11PaymentOption)
public LightningNetworkPaymentMethodData(string cryptoCode, string connectionString, bool enabled, string paymentMethod)
{
Enabled = enabled;
CryptoCode = cryptoCode;
ConnectionString = connectionString;
PaymentMethod = paymentMethod;
DisableBOLT11PaymentOption = disableBOLT11PaymentOption;
}
public string PaymentMethod { get; set; }

View File

@ -6,6 +6,8 @@ namespace BTCPayServer.Client.Models
public class NotificationData
{
public string Id { get; set; }
public string Identifier { get; set; }
public string Type { get; set; }
public string Body { get; set; }
public bool Seen { get; set; }
public Uri Link { get; set; }

View File

@ -12,4 +12,8 @@ public class OnChainAutomatedPayoutSettings
public TimeSpan IntervalSeconds { get; set; }
public int? FeeBlockTarget { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public decimal Threshold { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public bool ProcessNewPayoutsInstantly { get; set; }
}

View File

@ -0,0 +1,13 @@
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models;
public class PaymentMethodCriteriaData
{
public string PaymentMethod { get; set; }
public string CurrencyCode { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
public bool Above { get; set; }
}

View File

@ -31,5 +31,6 @@ namespace BTCPayServer.Client.Models
public PayoutState State { get; set; }
public int Revision { get; set; }
public JObject PaymentProof { get; set; }
public JObject Metadata { get; set; }
}
}

View File

@ -15,11 +15,53 @@ namespace BTCPayServer.Client.Models
public class PointOfSaleAppData : AppDataBase
{
// We can add POS specific things here later
public string Title { get; set; }
public string DefaultView { get; set; }
public bool ShowCustomAmount { get; set; }
public bool ShowDiscount { get; set; }
public bool EnableTips { get; set; }
public string Currency { get; set; }
public object Items { get; set; }
public string FixedAmountPayButtonText { get; set; }
public string CustomAmountPayButtonText { get; set; }
public string TipText { get; set; }
public string CustomCSSLink { get; set; }
public string NotificationUrl { get; set; }
public string RedirectUrl { get; set; }
public string Description { get; set; }
public string EmbeddedCSS { get; set; }
public bool? RedirectAutomatically { get; set; }
public bool? RequiresRefundEmail { get; set; }
}
public class CrowdfundAppData : AppDataBase
{
// We can add Crowdfund specific things here later
public string Title { get; set; }
public bool Enabled { get; set; }
public bool EnforceTargetAmount { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset? StartDate { get; set; }
public string TargetCurrency { get; set; }
public string Description { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset? EndDate { get; set; }
public decimal? TargetAmount { get; set; }
public string CustomCSSLink { get; set; }
public string MainImageUrl { get; set; }
public string EmbeddedCSS { get; set; }
public string NotificationUrl { get; set; }
public string Tagline { get; set; }
public object Perks { get; set; }
public bool DisqusEnabled { get; set; }
public string DisqusShortname { get; set; }
public bool SoundsEnabled { get; set; }
public bool AnimationsEnabled { get; set; }
public int ResetEveryAmount { get; set; }
public string ResetEvery { get; set; }
public bool DisplayPerksValue { get; set; }
public bool DisplayPerksRanking { get; set; }
public bool SortPerksByPopularity { get; set; }
public string[] Sounds { get; set; }
public string[] AnimationColors { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace BTCPayServer.Client.Models
{
public class PullPaymentLNURL
{
public string LNURLBech32 { get; set; }
public string LNURLUri { get; set; }
}
}

View File

@ -9,6 +9,7 @@ namespace BTCPayServer.Client.Models
{
RateThen,
CurrentRate,
OverpaidAmount,
Fiat,
Custom
}
@ -18,8 +19,13 @@ namespace BTCPayServer.Client.Models
public string? Name { get; set; } = null;
public string? PaymentMethod { get; set; }
public string? Description { get; set; } = null;
[JsonConverter(typeof(StringEnumConverter))]
public RefundVariant? RefundVariant { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal SubtractPercentage { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal? CustomAmount { get; set; }
public string? CustomCurrency { get; set; }

View File

@ -16,6 +16,8 @@ namespace BTCPayServer.Client.Models
public string Website { get; set; }
public string SupportUrl { get; set; }
[JsonConverter(typeof(TimeSpanJsonConverter.Seconds))]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public TimeSpan InvoiceExpiration { get; set; } = TimeSpan.FromMinutes(15);
@ -63,6 +65,9 @@ namespace BTCPayServer.Client.Models
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public NetworkFeeMode NetworkFeeMode { get; set; } = NetworkFeeMode.Never;
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public List<PaymentMethodCriteriaData> PaymentMethodCriteria { get; set; }
public bool PayJoinEnabled { get; set; }
public InvoiceData.ReceiptOptions Receipt { get; set; }

View File

@ -1,3 +1,5 @@
using System.Collections.Generic;
namespace BTCPayServer.Client.Models
{
public class StoreData : StoreBaseData
@ -17,4 +19,12 @@ namespace BTCPayServer.Client.Models
public string Role { get; set; }
}
public class RoleData
{
public string Id { get; set; }
public List<string> Permissions { get; set; }
public string Role { get; set; }
public bool IsServerRole { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using System.Collections.Generic;
namespace BTCPayServer.Client.Models;
public class StoreRatePreviewResult
{
public string CurrencyPair { get; set; }
public decimal? Rate { get; set; }
public List<string> Errors { get; set; }
}

View File

@ -1,7 +1,13 @@
using System.Collections.Generic;
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models;
public class StoreRateResult
{
public string CurrencyPair { get; set; }
public decimal Rate { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal? Rate { get; set; }
public List<string> Errors { get; set; }
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client.Models;
public class StoreReportRequest
{
public string ViewName { get; set; }
public TimePeriod TimePeriod { get; set; }
}
public class StoreReportResponse
{
public class Field
{
public Field()
{
}
public Field(string name, string type)
{
Name = name;
Type = type;
}
public string Name { get; set; }
public string Type { get; set; }
}
public IList<Field> Fields { get; set; } = new List<Field>();
public List<JArray> Data { get; set; }
public DateTimeOffset From { get; set; }
public DateTimeOffset To { get; set; }
public List<ChartDefinition> Charts { get; set; }
public int GetIndex(string fieldName)
{
return Fields.ToList().FindIndex(f => f.Name == fieldName);
}
}
public class ChartDefinition
{
public string Name { get; set; }
public List<string> Groups { get; set; } = new List<string>();
public List<string> Totals { get; set; } = new List<string>();
public bool HasGrandTotal { get; set; }
public List<string> Aggregates { get; set; } = new List<string>();
public List<string> Filters { get; set; } = new List<string>();
}
public class TimePeriod
{
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset? From { get; set; }
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset? To { get; set; }
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BTCPayServer.Client.Models
{
public class StoreReportsResponse
{
public string ViewName { get; set; }
public StoreReportResponse.Field[] Fields
{
get;
set;
}
}
}

View File

@ -1,8 +1,13 @@
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models;
public class TradeQuoteResponseData
{
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Bid { get; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Ask { get; }
public string ToAsset { get; }
public string FromAsset { get; }

View File

@ -1,8 +1,11 @@
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models;
public class TradeRequestData
{
public string FromAsset { set; get; }
public string ToAsset { set; get; }
public string Qty { set; get; }
[JsonConverter(typeof(JsonConverters.TradeQuantityJsonConverter))]
public TradeQuantity Qty { set; get; }
}

View File

@ -51,6 +51,10 @@ namespace BTCPayServer.Client.Models
public DateTimeOffset Timestamp { get; set; }
[JsonExtensionData]
public IDictionary<string, JToken> AdditionalData { get; set; }
public bool IsPruned()
{
return DeliveryId is null;
}
public T ReadAs<T>()
{
var str = JsonConvert.SerializeObject(this, DefaultSerializerSettings);

View File

@ -1,13 +1,85 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net.Http.Headers;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models;
public class WithdrawRequestData
{
public string PaymentMethod { set; get; }
public decimal Qty { set; get; }
[JsonConverter(typeof(JsonConverters.TradeQuantityJsonConverter))]
public TradeQuantity Qty { set; get; }
public WithdrawRequestData(string paymentMethod, decimal qty)
public WithdrawRequestData()
{
}
public WithdrawRequestData(string paymentMethod, TradeQuantity qty)
{
PaymentMethod = paymentMethod;
Qty = qty;
}
}
#nullable enable
public record TradeQuantity
{
public TradeQuantity(decimal value, ValueType type)
{
Type = type;
Value = value;
}
public enum ValueType
{
Exact,
Percent
}
public ValueType Type { get; }
public decimal Value { get; set; }
public override string ToString()
{
if (Type == ValueType.Exact)
return Value.ToString(CultureInfo.InvariantCulture);
else
return Value.ToString(CultureInfo.InvariantCulture) + "%";
}
public static TradeQuantity Parse(string str)
{
if (!TryParse(str, out var r))
throw new FormatException("Invalid TradeQuantity");
return r;
}
public static bool TryParse(string str, [MaybeNullWhen(false)] out TradeQuantity quantity)
{
if (str is null)
throw new ArgumentNullException(nameof(str));
quantity = null;
str = str.Trim();
str = str.Replace(" ", "");
if (str.Length == 0)
return false;
if (str[^1] == '%')
{
if (!decimal.TryParse(str[..^1], NumberStyles.Any, CultureInfo.InvariantCulture, out var r))
return false;
if (r < 0.0m)
return false;
quantity = new TradeQuantity(r, TradeQuantity.ValueType.Percent);
}
else
{
if (!decimal.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out var r))
return false;
if (r < 0.0m)
return false;
quantity = new TradeQuantity(r, TradeQuantity.ValueType.Exact);
}
return true;
}
}

View File

@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace BTCPayServer.Client.Models;
public abstract class WithdrawalBaseResponseData
{
public string Asset { get; }
public string PaymentMethod { get; }
public List<LedgerEntryData> LedgerEntries { get; }
public string AccountId { get; }
public string CustodianCode { get; }
public WithdrawalBaseResponseData(string paymentMethod, string asset, List<LedgerEntryData> ledgerEntries, string accountId,
string custodianCode)
{
PaymentMethod = paymentMethod;
Asset = asset;
LedgerEntries = ledgerEntries;
AccountId = accountId;
CustodianCode = custodianCode;
}
}

View File

@ -5,18 +5,13 @@ using Newtonsoft.Json.Converters;
namespace BTCPayServer.Client.Models;
public class WithdrawalResponseData
public class WithdrawalResponseData : WithdrawalBaseResponseData
{
public string Asset { get; }
public string PaymentMethod { get; }
public List<LedgerEntryData> LedgerEntries { get; }
public string WithdrawalId { get; }
public string AccountId { get; }
public string CustodianCode { get; }
[JsonConverter(typeof(StringEnumConverter))]
public WithdrawalStatus Status { get; }
public string WithdrawalId { get; }
public DateTimeOffset CreatedTime { get; }
public string TransactionId { get; }
@ -24,14 +19,10 @@ public class WithdrawalResponseData
public string TargetAddress { get; }
public WithdrawalResponseData(string paymentMethod, string asset, List<LedgerEntryData> ledgerEntries, string withdrawalId, string accountId,
string custodianCode, WithdrawalStatus status, DateTimeOffset createdTime, string targetAddress, string transactionId)
string custodianCode, WithdrawalStatus status, DateTimeOffset createdTime, string targetAddress, string transactionId) : base(paymentMethod, asset, ledgerEntries, accountId,
custodianCode)
{
PaymentMethod = paymentMethod;
Asset = asset;
LedgerEntries = ledgerEntries;
WithdrawalId = withdrawalId;
AccountId = accountId;
CustodianCode = custodianCode;
TargetAddress = targetAddress;
TransactionId = transactionId;
Status = status;

View File

@ -0,0 +1,21 @@
using System.Collections.Generic;
using BTCPayServer.JsonConverters;
using Newtonsoft.Json;
namespace BTCPayServer.Client.Models;
public class WithdrawalSimulationResponseData : WithdrawalBaseResponseData
{
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal? MinQty { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal? MaxQty { get; set; }
public WithdrawalSimulationResponseData(string paymentMethod, string asset, string accountId,
string custodianCode, List<LedgerEntryData> ledgerEntries, decimal? minQty, decimal? maxQty) : base(paymentMethod,
asset, ledgerEntries, accountId, custodianCode)
{
MinQty = minQty;
MaxQty = maxQty;
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Linq.Expressions;
namespace BTCPayServer.Client
{
@ -28,8 +30,11 @@ namespace BTCPayServer.Client
public const string CanViewNotificationsForUser = "btcpay.user.canviewnotificationsforuser";
public const string CanViewUsers = "btcpay.server.canviewusers";
public const string CanCreateUser = "btcpay.server.cancreateuser";
public const string CanManageUsers = "btcpay.server.canmanageusers";
public const string CanDeleteUser = "btcpay.user.candeleteuser";
public const string CanManagePullPayments = "btcpay.store.canmanagepullpayments";
public const string CanCreatePullPayments = "btcpay.store.cancreatepullpayments";
public const string CanCreateNonApprovedPullPayments = "btcpay.store.cancreatenonapprovedpullpayments";
public const string CanViewCustodianAccounts = "btcpay.store.canviewcustodianaccounts";
public const string CanManageCustodianAccounts = "btcpay.store.canmanagecustodianaccounts";
public const string CanDepositToCustodianAccounts = "btcpay.store.candeposittocustodianaccount";
@ -64,11 +69,14 @@ namespace BTCPayServer.Client
yield return CanViewLightningInvoiceInStore;
yield return CanCreateLightningInvoiceInStore;
yield return CanManagePullPayments;
yield return CanCreatePullPayments;
yield return CanCreateNonApprovedPullPayments;
yield return CanViewCustodianAccounts;
yield return CanManageCustodianAccounts;
yield return CanDepositToCustodianAccounts;
yield return CanWithdrawFromCustodianAccounts;
yield return CanTradeCustodianAccount;
yield return CanManageUsers;
}
}
public static bool IsValidPolicy(string policy)
@ -92,9 +100,45 @@ namespace BTCPayServer.Client
{
return policy.StartsWith("btcpay.plugin", StringComparison.OrdinalIgnoreCase);
}
public static bool IsUserPolicy(string policy)
{
return policy.StartsWith("btcpay.user", StringComparison.OrdinalIgnoreCase);
}
}
public class PermissionSet
{
public PermissionSet() : this(Array.Empty<Permission>())
{
}
public PermissionSet(Permission[] permissions)
{
Permissions = permissions;
}
public Permission[] Permissions { get; }
public bool Contains(Permission requestedPermission)
{
return Permissions.Any(p => p.Contains(requestedPermission));
}
public bool Contains(string permission, string store)
{
if (permission is null)
throw new ArgumentNullException(nameof(permission));
if (store is null)
throw new ArgumentNullException(nameof(store));
return Contains(Permission.Create(permission, store));
}
}
public class Permission
{
static Permission()
{
PolicyMap = Init();
}
public static Permission Create(string policy, string scope = null)
{
if (TryCreatePermission(policy, scope, out var r))
@ -110,7 +154,7 @@ namespace BTCPayServer.Client
policy = policy.Trim().ToLowerInvariant();
if (!Policies.IsValidPolicy(policy))
return false;
if (scope != null && !Policies.IsStorePolicy(policy))
if (!string.IsNullOrEmpty(scope) && !Policies.IsStorePolicy(policy))
return false;
permission = new Permission(policy, scope);
return true;
@ -163,7 +207,7 @@ namespace BTCPayServer.Client
}
if (!Policies.IsStorePolicy(subpermission.Policy))
return true;
return Scope == null || subpermission.Scope == this.Scope;
return Scope == null || subpermission.Scope == Scope;
}
public static IEnumerable<Permission> ToPermissions(string[] permissions)
@ -179,37 +223,80 @@ namespace BTCPayServer.Client
private bool ContainsPolicy(string subpolicy)
{
if (this.Policy == Policies.Unrestricted)
return ContainsPolicy(Policy, subpolicy);
}
private static bool ContainsPolicy(string policy, string subpolicy)
{
if (policy == Policies.Unrestricted)
return true;
if (this.Policy == subpolicy)
if (policy == subpolicy)
return true;
switch (subpolicy)
if (!PolicyMap.TryGetValue(policy, out var subPolicies))
return false;
return subPolicies.Contains(subpolicy) || subPolicies.Any(s => ContainsPolicy(s, subpolicy));
}
public static ReadOnlyDictionary<string, HashSet<string>> PolicyMap { get; private set; }
private static ReadOnlyDictionary<string, HashSet<string>> Init()
{
var policyMap = new Dictionary<string, HashSet<string>>();
PolicyHasChild(policyMap, Policies.CanModifyStoreSettings,
Policies.CanManageCustodianAccounts,
Policies.CanManagePullPayments,
Policies.CanModifyInvoices,
Policies.CanViewStoreSettings,
Policies.CanModifyStoreWebhooks,
Policies.CanModifyPaymentRequests,
Policies.CanUseLightningNodeInStore);
PolicyHasChild(policyMap,Policies.CanManageUsers, Policies.CanCreateUser);
PolicyHasChild(policyMap,Policies.CanManagePullPayments, Policies.CanCreatePullPayments);
PolicyHasChild(policyMap,Policies.CanCreatePullPayments, Policies.CanCreateNonApprovedPullPayments);
PolicyHasChild(policyMap,Policies.CanModifyPaymentRequests, Policies.CanViewPaymentRequests);
PolicyHasChild(policyMap,Policies.CanModifyProfile, Policies.CanViewProfile);
PolicyHasChild(policyMap,Policies.CanUseLightningNodeInStore, Policies.CanViewLightningInvoiceInStore, Policies.CanCreateLightningInvoiceInStore);
PolicyHasChild(policyMap,Policies.CanManageNotificationsForUser, Policies.CanViewNotificationsForUser);
PolicyHasChild(policyMap,Policies.CanModifyServerSettings,
Policies.CanUseInternalLightningNode,
Policies.CanManageUsers);
PolicyHasChild(policyMap, Policies.CanUseInternalLightningNode, Policies.CanCreateLightningInvoiceInternalNode, Policies.CanViewLightningInvoiceInternalNode);
PolicyHasChild(policyMap, Policies.CanManageCustodianAccounts, Policies.CanViewCustodianAccounts);
PolicyHasChild(policyMap, Policies.CanModifyInvoices, Policies.CanViewInvoices, Policies.CanCreateInvoice, Policies.CanCreateLightningInvoiceInStore);
PolicyHasChild(policyMap, Policies.CanViewStoreSettings, Policies.CanViewInvoices, Policies.CanViewPaymentRequests);
var missingPolicies = Policies.AllPolicies.ToHashSet();
//recurse through the tree to see which policies are not included in the tree
foreach (var policy in policyMap)
{
case Policies.CanViewInvoices when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanViewInvoices when this.Policy == Policies.CanModifyInvoices:
case Policies.CanModifyStoreWebhooks when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanViewInvoices when this.Policy == Policies.CanViewStoreSettings:
case Policies.CanViewStoreSettings when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanCreateInvoice when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanModifyInvoices when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanViewProfile when this.Policy == Policies.CanModifyProfile:
case Policies.CanModifyPaymentRequests when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanViewPaymentRequests when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanManagePullPayments when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanViewPaymentRequests when this.Policy == Policies.CanViewStoreSettings:
case Policies.CanViewPaymentRequests when this.Policy == Policies.CanModifyPaymentRequests:
case Policies.CanCreateLightningInvoiceInternalNode when this.Policy == Policies.CanUseInternalLightningNode:
case Policies.CanViewLightningInvoiceInternalNode when this.Policy == Policies.CanUseInternalLightningNode:
case Policies.CanCreateLightningInvoiceInStore when this.Policy == Policies.CanUseLightningNodeInStore:
case Policies.CanViewLightningInvoiceInStore when this.Policy == Policies.CanUseLightningNodeInStore:
case Policies.CanViewNotificationsForUser when this.Policy == Policies.CanManageNotificationsForUser:
case Policies.CanUseInternalLightningNode when this.Policy == Policies.CanModifyServerSettings:
case Policies.CanViewCustodianAccounts when this.Policy == Policies.CanManageCustodianAccounts:
case Policies.CanViewCustodianAccounts when this.Policy == Policies.CanModifyStoreSettings:
case Policies.CanManageCustodianAccounts when this.Policy == Policies.CanModifyStoreSettings:
return true;
default:
return false;
missingPolicies.Remove(policy.Key);
foreach (var subPolicy in policy.Value)
{
missingPolicies.Remove(subPolicy);
}
}
foreach (var missingPolicy in missingPolicies)
{
policyMap.Add(missingPolicy, new HashSet<string>());
}
return new ReadOnlyDictionary<string, HashSet<string>>(policyMap);
}
private static void PolicyHasChild(Dictionary<string, HashSet<string>>policyMap, string policy, params string[] subPolicies)
{
if (policyMap.TryGetValue(policy, out var existingSubPolicies))
{
foreach (string subPolicy in subPolicies)
{
existingSubPolicies.Add(subPolicy);
}
}
else
{
policyMap.Add(policy, subPolicies.ToHashSet());
}
}
@ -218,23 +305,17 @@ namespace BTCPayServer.Client
public override string ToString()
{
if (Scope != null)
{
return $"{Policy}:{Scope}";
}
return Policy;
return Scope != null ? $"{Policy}:{Scope}" : Policy;
}
public override bool Equals(object obj)
{
Permission item = obj as Permission;
if (item == null)
return false;
return ToString().Equals(item.ToString());
return item != null && ToString().Equals(item.ToString());
}
public static bool operator ==(Permission a, Permission b)
{
if (System.Object.ReferenceEquals(a, b))
if (ReferenceEquals(a, b))
return true;
if (((object)a == null) || ((object)b == null))
return false;

View File

@ -16,7 +16,7 @@ namespace BTCPayServer
DefaultRateRules = new[]
{
"BTG_X = BTG_BTC * BTC_X",
"BTG_BTC = bitfinex(BTG_BTC)",
"BTG_BTC = exmo(BTG_BTC)",
},
CryptoImagePath = "imlegacy/btg.svg",
LightningImagePath = "imlegacy/btg-lightning.svg",

View File

@ -17,7 +17,7 @@ namespace BTCPayServer
DefaultRateRules = new[]
{
"BTX_X = BTX_BTC * BTC_X",
"BTX_BTC = hitbtc(BTX_BTC)"
"BTX_BTC = graviex(BTX_BTC)"
},
CryptoImagePath = "imlegacy/bitcore.svg",
LightningImagePath = "imlegacy/bitcore-lightning.svg",

View File

@ -1,32 +0,0 @@
using NBitcoin;
namespace BTCPayServer
{
public partial class BTCPayNetworkProvider
{
public void InitChaincoin()
{
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("CHC");
Add(new BTCPayNetwork()
{
CryptoCode = nbxplorerNetwork.CryptoCode,
DisplayName = "Chaincoin",
BlockExplorerLink = NetworkType == ChainName.Mainnet
? "https://explorer.chaincoin.org/Explorer/Transaction/{0}"
: "https://test.explorer.chaincoin.org/Explorer/Transaction/tx/{0}",
NBXplorerNetwork = nbxplorerNetwork,
DefaultRateRules = new[]
{
"CHC_X = CHC_BTC * BTC_X",
"CHC_BTC = txbit(CHC_X)"
},
CryptoImagePath = "imlegacy/chaincoin.png",
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
//https://github.com/satoshilabs/slips/blob/master/slip-0044.md
CoinType = NetworkType == ChainName.Mainnet ? new KeyPath("711'")
: new KeyPath("1'")
});
}
}
}

View File

@ -63,6 +63,7 @@ namespace BTCPayServer
"LCAD_CAD = 1",
"LCAD_X = CAD_BTC * BTC_X",
"LCAD_BTC = bylls(CAD_BTC)",
"CAD_BTC = LCAD_BTC"
},
AssetId = new uint256("0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a"),
DisplayName = "Liquid CAD",

View File

@ -1,4 +1,5 @@
#if ALTCOINS
using System;
using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Common;
@ -34,12 +35,12 @@ namespace BTCPayServer
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId));
}
public override PaymentUrlBuilder GenerateBIP21(string cryptoInfoAddress, Money cryptoInfoDue)
public override PaymentUrlBuilder GenerateBIP21(string cryptoInfoAddress, decimal? cryptoInfoDue)
{
//precision 0: 10 = 0.00000010
//precision 2: 10 = 0.00001000
//precision 8: 10 = 10
var money = cryptoInfoDue is null ? null : new Money(cryptoInfoDue.ToDecimal(MoneyUnit.BTC) / decimal.Parse("1".PadRight(1 + 8 - Divisibility, '0')), MoneyUnit.BTC);
var money = cryptoInfoDue / (decimal)Math.Pow(10, 8 - Divisibility);
var builder = base.GenerateBIP21(cryptoInfoAddress, money);
builder.QueryParams.Add("assetid", AssetId.ToString());
return builder;

View File

@ -45,10 +45,10 @@ namespace BTCPayServer.Services.Altcoins.Monero.RPC
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.Default.GetBytes($"{_username}:{_password}")));
var rawResult = await _httpClient.SendAsync(httpRequest, cts);
var rawJson = await rawResult.Content.ReadAsStringAsync();
HttpResponseMessage rawResult = await _httpClient.SendAsync(httpRequest, cts);
rawResult.EnsureSuccessStatusCode();
var rawJson = await rawResult.Content.ReadAsStringAsync();
JsonRpcResult<TResponse> response;
try
{

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using BTCPayServer.Common;
@ -87,13 +88,13 @@ namespace BTCPayServer
});
}
public virtual PaymentUrlBuilder GenerateBIP21(string cryptoInfoAddress, Money cryptoInfoDue)
public virtual PaymentUrlBuilder GenerateBIP21(string cryptoInfoAddress, decimal? cryptoInfoDue)
{
var builder = new PaymentUrlBuilder(this.NBitcoinNetwork.UriScheme);
builder.Host = cryptoInfoAddress;
if (cryptoInfoDue != null && cryptoInfoDue != Money.Zero)
if (cryptoInfoDue is not null && cryptoInfoDue.Value != 0.0m)
{
builder.QueryParams.Add("amount", cryptoInfoDue.ToString(false, true));
builder.QueryParams.Add("amount", cryptoInfoDue.Value.ToString(CultureInfo.InvariantCulture));
}
return builder;
}

View File

@ -56,7 +56,6 @@ namespace BTCPayServer
InitViacoin();
InitMonero();
InitZcash();
InitChaincoin();
// InitArgoneum();//their rate source is down 9/15/20.
// InitMonetaryUnit(); Not supported from Bittrex from 11/23/2022, dead shitcoin

View File

@ -4,7 +4,7 @@
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="NBXplorer.Client" Version="4.2.3" />
<PackageReference Include="NBXplorer.Client" Version="4.2.5" />
<PackageReference Include="NicolasDorier.StandardConfiguration" Version="2.0.1" />
</ItemGroup>
<ItemGroup Condition="'$(Altcoins)' != 'true'">

View File

@ -1,6 +1,6 @@
using System;
using System.Linq;
using BTCPayServer.Data.Data;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
@ -30,7 +30,12 @@ namespace BTCPayServer.Data
{
_designTime = designTime;
}
#nullable enable
public async Task<string?> GetMigrationState()
{
return (await Settings.FromSqlRaw("SELECT \"Id\", \"Value\" FROM \"Settings\" WHERE \"Id\"='MigrationData'").AsNoTracking().FirstOrDefaultAsync())?.Value;
}
#nullable restore
public DbSet<AddressInvoiceData> AddressInvoices { get; set; }
public DbSet<APIKeyData> ApiKeys { get; set; }
public DbSet<AppData> Apps { get; set; }
@ -59,6 +64,7 @@ namespace BTCPayServer.Data
public DbSet<U2FDevice> U2FDevices { get; set; }
public DbSet<Fido2Credential> Fido2Credentials { get; set; }
public DbSet<UserStore> UserStore { get; set; }
public DbSet<StoreRole> StoreRoles { get; set; }
[Obsolete]
public DbSet<WalletData> Wallets { get; set; }
public DbSet<WalletObjectData> WalletObjects { get; set; }
@ -69,6 +75,7 @@ namespace BTCPayServer.Data
public DbSet<WebhookData> Webhooks { get; set; }
public DbSet<LightningAddressData> LightningAddresses { get; set; }
public DbSet<PayoutProcessorData> PayoutProcessors { get; set; }
public DbSet<FormData> Forms { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
@ -83,23 +90,23 @@ namespace BTCPayServer.Data
// some of the data models don't have OnModelCreating for now, commenting them
ApplicationUser.OnModelCreating(builder);
ApplicationUser.OnModelCreating(builder, Database);
AddressInvoiceData.OnModelCreating(builder);
APIKeyData.OnModelCreating(builder);
APIKeyData.OnModelCreating(builder, Database);
AppData.OnModelCreating(builder);
CustodianAccountData.OnModelCreating(builder);
CustodianAccountData.OnModelCreating(builder, Database);
//StoredFile.OnModelCreating(builder);
InvoiceEventData.OnModelCreating(builder);
InvoiceSearchData.OnModelCreating(builder);
InvoiceWebhookDeliveryData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder);
NotificationData.OnModelCreating(builder);
InvoiceData.OnModelCreating(builder, Database);
NotificationData.OnModelCreating(builder, Database);
//OffchainTransactionData.OnModelCreating(builder);
BTCPayServer.Data.PairedSINData.OnModelCreating(builder);
PairingCodeData.OnModelCreating(builder);
//PayjoinLock.OnModelCreating(builder);
PaymentRequestData.OnModelCreating(builder);
PaymentData.OnModelCreating(builder);
PaymentRequestData.OnModelCreating(builder, Database);
PaymentData.OnModelCreating(builder, Database);
PayoutData.OnModelCreating(builder);
PendingInvoiceData.OnModelCreating(builder);
//PlannedTransaction.OnModelCreating(builder);
@ -110,7 +117,7 @@ namespace BTCPayServer.Data
StoreWebhookData.OnModelCreating(builder);
StoreData.OnModelCreating(builder, Database);
U2FDevice.OnModelCreating(builder);
Fido2Credential.OnModelCreating(builder);
Fido2Credential.OnModelCreating(builder, Database);
BTCPayServer.Data.UserStore.OnModelCreating(builder);
//WalletData.OnModelCreating(builder);
WalletObjectData.OnModelCreating(builder, Database);
@ -118,10 +125,12 @@ namespace BTCPayServer.Data
#pragma warning disable CS0612 // Type or member is obsolete
WalletTransactionData.OnModelCreating(builder);
#pragma warning restore CS0612 // Type or member is obsolete
WebhookDeliveryData.OnModelCreating(builder);
LightningAddressData.OnModelCreating(builder);
PayoutProcessorData.OnModelCreating(builder);
//WebhookData.OnModelCreating(builder);
WebhookDeliveryData.OnModelCreating(builder, Database);
LightningAddressData.OnModelCreating(builder, Database);
PayoutProcessorData.OnModelCreating(builder, Database);
WebhookData.OnModelCreating(builder, Database);
FormData.OnModelCreating(builder, Database);
StoreRole.OnModelCreating(builder, Database);
if (Database.IsSqlite() && !_designTime)

View File

@ -1,3 +1,6 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;

View File

@ -1,9 +1,11 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class APIKeyData
public class APIKeyData : IHasBlob<APIKeyBlob>
{
[MaxLength(50)]
public string Id { get; set; }
@ -16,13 +18,15 @@ namespace BTCPayServer.Data
public APIKeyType Type { get; set; } = APIKeyType.Legacy;
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public StoreData StoreData { get; set; }
public ApplicationUser User { get; set; }
public string Label { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<APIKeyData>()
.HasOne(o => o.StoreData)
@ -36,6 +40,13 @@ namespace BTCPayServer.Data
builder.Entity<APIKeyData>()
.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 Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data
{
// 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 List<StoredFile> StoredFiles { get; set; }
@ -20,15 +22,28 @@ namespace BTCPayServer.Data
public List<UserStore> UserStores { get; set; }
public List<Fido2Credential> Fido2Credentials { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { 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>()
.HasMany<IdentityUserRole<string>>(user => user.UserRoles)
.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 Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data;
public class CustodianAccountData
public class CustodianAccountData : IHasBlob<JObject>
{
[Required]
[MaxLength(50)]
@ -24,19 +26,29 @@ public class CustodianAccountData
public string Name { get; set; }
[JsonIgnore]
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
[JsonIgnore]
public string Blob2 { get; set; }
[JsonIgnore]
public StoreData StoreData { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<CustodianAccountData>()
.HasOne(o => o.StoreData)
.WithMany(i => i.CustodianAccounts)
.HasForeignKey(i => i.StoreId).OnDelete(DeleteBehavior.Cascade);
builder.Entity<APIKeyData>()
builder.Entity<CustodianAccountData>()
.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.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class Fido2Credential
public class Fido2Credential : IHasBlobUntyped
{
public string Name { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
@ -14,6 +15,7 @@ namespace BTCPayServer.Data
public string ApplicationUserId { get; set; }
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public CredentialType Type { get; set; }
public enum CredentialType
{
@ -22,12 +24,18 @@ namespace BTCPayServer.Data
[Display(Name = "Lightning node (LNURL Auth)")]
LNURLAuth
}
public static void OnModelCreating(ModelBuilder builder)
public static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<Fido2Credential>()
.HasOne(o => o.ApplicationUser)
.WithMany(i => i.Fido2Credentials)
.HasForeignKey(i => i.ApplicationUserId).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<Fido2Credential>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
public ApplicationUser ApplicationUser { get; set; }

View File

@ -2,11 +2,30 @@ using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data.Data;
namespace BTCPayServer.Data;
public class FormData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
public string Name { get; set; }
public string StoreId { get; set; }
public StoreData Store { get; set; }
public string Config { get; set; }
public bool Public { get; set; }
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<FormData>()
.HasOne(o => o.Store)
.WithMany(o => o.Forms).OnDelete(DeleteBehavior.Cascade);
builder.Entity<FormData>().HasIndex(o => o.StoreId);
if (databaseFacade.IsNpgsql())
{
builder.Entity<FormData>()
.Property(o => o.Config)
.HasColumnType("JSONB");
}
}
}

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

View File

@ -1,17 +1,24 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Data;
public class LightningAddressData
public class LightningAddressData : IHasBlob<LightningAddressDataBlob>
{
public string Username { get; set; }
public string StoreDataId { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public StoreData Store { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<LightningAddressData>()
.HasOne(o => o.Store)
@ -20,6 +27,12 @@ public class LightningAddressData
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<LightningAddressData>().HasKey(o => o.Username);
if (databaseFacade.IsNpgsql())
{
builder.Entity<LightningAddressData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
@ -28,4 +41,9 @@ public class LightningAddressDataBlob
public string CurrencyCode { get; set; }
public decimal? Min { get; set; }
public decimal? Max { get; set; }
public JObject InvoiceMetadata { get; set; }
[JsonExtensionData] public Dictionary<string, JToken> AdditionalData { get; set; }
}

View File

@ -1,10 +1,12 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
namespace BTCPayServer.Data
{
public class NotificationData
public class NotificationData : IHasBlobUntyped
{
[MaxLength(36)]
public string Id { get; set; }
@ -17,15 +19,23 @@ namespace BTCPayServer.Data
[Required]
public string NotificationType { get; set; }
public bool Seen { get; set; }
[Obsolete("Use Blob2 instead")]
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>()
.HasOne(o => o.ApplicationUser)
.WithMany(n => n.Notifications)
.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.Infrastructure;
namespace BTCPayServer.Data
{
public class PaymentData
public class PaymentData : IHasBlobUntyped
{
public string Id { get; set; }
public string InvoiceDataId { get; set; }
public InvoiceData InvoiceData { get; set; }
[Obsolete("Use Blob2 instead")]
public byte[] Blob { get; set; }
public string Blob2 { get; set; }
public string Type { get; set; }
public bool Accounted { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<PaymentData>()
.HasOne(o => o.InvoiceData)
.WithMany(i => i.Payments).OnDelete(DeleteBehavior.Cascade);
builder.Entity<PaymentData>()
.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 Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace BTCPayServer.Data
{
public class PaymentRequestData
public class PaymentRequestData : IHasBlobUntyped
{
public string Id { get; set; }
public DateTimeOffset Created { get; set; }
@ -14,10 +15,12 @@ namespace BTCPayServer.Data
public Client.Models.PaymentRequestData.PaymentRequestStatus Status { get; set; }
[Obsolete("Use Blob2 instead")]
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>()
.HasOne(o => o.StoreData)
@ -28,6 +31,13 @@ namespace BTCPayServer.Data
.HasDefaultValue(new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero));
builder.Entity<PaymentRequestData>()
.HasIndex(o => o.Status);
if (databaseFacade.IsNpgsql())
{
builder.Entity<PaymentRequestData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
}
}

View File

@ -1,9 +1,16 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
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 bool ProcessNewPayoutsInstantly { get; set; }
}
public class PayoutProcessorData : IHasBlobUntyped
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
@ -12,14 +19,22 @@ public class PayoutProcessorData
public string PaymentMethod { get; set; }
public string Processor { get; set; }
[Obsolete("Use Blob2 instead")]
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>()
.HasOne(o => o.Store)
.WithMany(data => data.PayoutProcessors).OnDelete(DeleteBehavior.Cascade);
if (databaseFacade.IsNpgsql())
{
builder.Entity<PayoutProcessorData>()
.Property(o => o.Blob2)
.HasColumnType("JSONB");
}
}
public override string ToString()

View File

@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
using BTCPayServer.Client.Models;
using BTCPayServer.Data.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using PayoutProcessorData = BTCPayServer.Data.Data.PayoutProcessorData;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace BTCPayServer.Data
{
@ -25,7 +24,6 @@ namespace BTCPayServer.Data
[Obsolete("Use GetDerivationStrategies instead")]
public string DerivationStrategy { get; set; }
[Obsolete("Use GetDerivationStrategies instead")]
public string DerivationStrategies { get; set; }
public string StoreName { get; set; }
@ -36,8 +34,6 @@ namespace BTCPayServer.Data
public byte[] StoreCertificate { get; set; }
[NotMapped] public string Role { get; set; }
public string StoreBlob { get; set; }
[Obsolete("Use GetDefaultPaymentId instead")]
@ -50,6 +46,8 @@ namespace BTCPayServer.Data
public IEnumerable<PayoutData> Payouts { get; set; }
public IEnumerable<CustodianAccountData> CustodianAccounts { get; set; }
public IEnumerable<StoreSettingData> Settings { get; set; }
public IEnumerable<FormData> Forms { get; set; }
public IEnumerable<StoreRole> StoreRoles { get; set; }
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
@ -58,6 +56,20 @@ namespace BTCPayServer.Data
builder.Entity<StoreData>()
.Property(o => o.StoreBlob)
.HasColumnType("JSONB");
builder.Entity<StoreData>()
.Property(o => o.DerivationStrategies)
.HasColumnType("JSONB");
}
else if (databaseFacade.IsMySql())
{
builder.Entity<StoreData>()
.Property(o => o.StoreBlob)
.HasConversion(new ValueConverter<string, byte[]>
(
convertToProviderExpression: (str) => Encoding.UTF8.GetBytes(str),
convertFromProviderExpression: (bytes) => Encoding.UTF8.GetString(bytes)
));
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Newtonsoft.Json;
namespace BTCPayServer.Data;
public class StoreRole
{
public string Id { get; set; }
public string StoreDataId { get; set; }
public string Role { get; set; }
public List<string> Permissions { get; set; }
public List<UserStore> Users { get; set; }
public StoreData StoreData { get; set; }
internal static void OnModelCreating(ModelBuilder builder, DatabaseFacade databaseFacade)
{
builder.Entity<StoreRole>(entity =>
{
entity.HasOne(e => e.StoreData)
.WithMany(s => s.StoreRoles)
.HasForeignKey(e => e.StoreDataId)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired(false);
entity.HasIndex(entity => new {entity.StoreDataId, entity.Role}).IsUnique();
});
if (!databaseFacade.IsNpgsql())
{
builder.Entity<StoreRole>()
.Property(o => o.Permissions)
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<List<string>>(v)?? new List<string>(),
new ValueComparer<List<string>>(
(c1, c2) => c1 ==c2 || c1 != null && c2 != null && c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
c => c.ToList()));
}
}
}

View File

@ -1,3 +1,4 @@
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace BTCPayServer.Data
@ -9,7 +10,10 @@ namespace BTCPayServer.Data
public string StoreDataId { get; set; }
public StoreData StoreData { get; set; }
public string Role { get; set; }
[Column("Role")]
public string StoreRoleId { get; set; }
public StoreRole StoreRole { get; set; }
internal static void OnModelCreating(ModelBuilder builder)
@ -32,6 +36,10 @@ namespace BTCPayServer.Data
.HasOne(pt => pt.StoreData)
.WithMany(t => t.UserStores)
.HasForeignKey(pt => pt.StoreDataId);
builder.Entity<UserStore>().HasOne(e => e.StoreRole)
.WithMany(role => role.Users)
.HasForeignKey(e => e.StoreRoleId);
}
}
}

View File

@ -12,6 +12,13 @@ namespace BTCPayServer.Data
{
public class Types
{
public static readonly HashSet<string> AllTypes;
static Types()
{
AllTypes = typeof(Types).GetFields()
.Where(f => f.FieldType == typeof(string))
.Select(f => (string)f.GetValue(null)).ToHashSet(StringComparer.OrdinalIgnoreCase);
}
public const string Label = "label";
public const string Tx = "tx";
public const string Payjoin = "payjoin";

View File

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

View File

@ -1,4 +1,4 @@
// <auto-generated />
// <auto-generated />
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
@ -17,20 +17,21 @@ namespace BTCPayServer.Migrations
{
protected override void Up(MigrationBuilder migrationBuilder)
{
int? maxLength = this.IsMySql(migrationBuilder.ActiveProvider) ? (int?)255 : null;
migrationBuilder.AddColumn<string>(
name: "StoreDataId",
table: "Payouts",
type: "TEXT",
nullable: true);
nullable: true,
maxLength: maxLength);
migrationBuilder.CreateTable(
name: "PayoutProcessors",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false),
StoreId = table.Column<string>(type: "TEXT", nullable: true),
PaymentMethod = table.Column<string>(type: "TEXT", nullable: true),
Processor = table.Column<string>(type: "TEXT", nullable: true),
Id = table.Column<string>(nullable: false, maxLength: maxLength),
StoreId = table.Column<string>(nullable: true, maxLength: maxLength),
PaymentMethod = table.Column<string>(nullable: true),
Processor = table.Column<string>(nullable: true),
Blob = table.Column<byte[]>(nullable: true)
},
constraints: table =>

View File

@ -1,4 +1,4 @@
// <auto-generated />
// <auto-generated />
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
@ -17,12 +17,13 @@ namespace BTCPayServer.Migrations
{
protected override void Up(MigrationBuilder migrationBuilder)
{
int? maxLength = this.IsMySql(migrationBuilder.ActiveProvider) ? (int?)255 : null;
migrationBuilder.CreateTable(
name: "LightningAddresses",
columns: table => new
{
Username = table.Column<string>(type: "TEXT", nullable: false),
StoreDataId = table.Column<string>(type: "TEXT", nullable: false),
Username = table.Column<string>(nullable: false, maxLength: maxLength),
StoreDataId = table.Column<string>(nullable: false, maxLength: maxLength),
Blob = table.Column<byte[]>( nullable: true)
},
constraints: table =>

View File

@ -14,12 +14,13 @@ namespace BTCPayServer.Migrations
{
protected override void Up(MigrationBuilder migrationBuilder)
{
int? maxlength = migrationBuilder.IsMySql() ? 255 : null;
migrationBuilder.CreateTable(
name: "StoreSettings",
columns: table => new
{
Name = table.Column<string>(type: "TEXT", nullable: false),
StoreId = table.Column<string>(type: "TEXT", nullable: false),
Name = table.Column<string>(nullable: false, maxLength: maxlength),
StoreId = table.Column<string>(nullable: false, maxLength: maxlength),
Value = table.Column<string>(type: migrationBuilder.IsNpgsql() ? "JSONB" : "TEXT", nullable: true)
},
constraints: table =>

View File

@ -17,13 +17,15 @@ namespace BTCPayServer.Migrations
{
protected override void Up(MigrationBuilder migrationBuilder)
{
int? maxlength = migrationBuilder.IsMySql() ? 255 : null;
migrationBuilder.CreateTable(
name: "WalletObjects",
columns: table => new
{
WalletId = table.Column<string>(type: "TEXT", nullable: false),
Type = table.Column<string>(type: "TEXT", nullable: false),
Id = table.Column<string>(type: "TEXT", nullable: false),
WalletId = table.Column<string>(nullable: false, maxLength: maxlength),
Type = table.Column<string>(nullable: false, maxLength: maxlength),
Id = table.Column<string>(nullable: false, maxLength: maxlength),
Data = table.Column<string>(type: migrationBuilder.IsNpgsql() ? "JSONB" : "TEXT", nullable: true)
},
constraints: table =>
@ -35,15 +37,17 @@ namespace BTCPayServer.Migrations
table: "WalletObjects",
columns: new[] { "Type", "Id" });
maxlength = migrationBuilder.IsMySql() ? 100 : null;
migrationBuilder.CreateTable(
name: "WalletObjectLinks",
columns: table => new
{
WalletId = table.Column<string>(type: "TEXT", nullable: false),
AType = table.Column<string>(type: "TEXT", nullable: false),
AId = table.Column<string>(type: "TEXT", nullable: false),
BType = table.Column<string>(type: "TEXT", nullable: false),
BId = table.Column<string>(type: "TEXT", nullable: false),
WalletId = table.Column<string>(nullable: false, maxLength: maxlength),
AType = table.Column<string>(nullable: false, maxLength: maxlength),
AId = table.Column<string>(nullable: false, maxLength: maxlength),
BType = table.Column<string>(nullable: false, maxLength: maxlength),
BId = table.Column<string>(nullable: false, maxLength: maxlength),
Data = table.Column<string>(type: migrationBuilder.IsNpgsql() ? "JSONB" : "TEXT", nullable: true)
},
constraints: table =>

View File

@ -0,0 +1,30 @@
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20230123062447_migrateoldratesource")]
public partial class migrateoldratesource : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder.IsNpgsql())
{
migrationBuilder.Sql("UPDATE \"Stores\" SET \"StoreBlob\"=jsonb_set(\"StoreBlob\", \'{preferredExchange}\', \'{\"oasis_trade\": \"oasisdev\", \"gdax\":\"coinbasepro\", \"coinaverage\":\"coingecko\"}\'::jsonb->(\"StoreBlob\"->>\'preferredExchange\')) WHERE \"StoreBlob\"->>\'preferredExchange\' = ANY (ARRAY[\'oasis_trade\', \'gdax\', \'coinaverage\']);");
}
}
protected override void Down(MigrationBuilder migrationBuilder)
{
// Not supported
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20230125085242_AddForms")]
public partial class AddForms : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
int? maxlength = migrationBuilder.IsMySql() ? 255 : null;
migrationBuilder.CreateTable(
name: "Forms",
columns: table => new
{
Id = table.Column<string>(type: "TEXT", nullable: false, maxLength: maxlength),
Name = table.Column<string>(type: "TEXT", nullable: true, maxLength: maxlength),
StoreId = table.Column<string>(type: "TEXT", nullable: true, maxLength: maxlength),
Config = table.Column<string>(type: migrationBuilder.IsNpgsql() ? "JSONB" : "TEXT", nullable: true),
Public = table.Column<bool>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Forms", x => x.Id);
table.ForeignKey(
name: "FK_Forms_Stores_StoreId",
column: x => x.StoreId,
principalTable: "Stores",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Forms_StoreId",
table: "Forms",
column: "StoreId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Forms");
}
}
}

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

@ -0,0 +1,30 @@
using System;
using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace BTCPayServer.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20230130062447_jsonb2")]
public partial class jsonb2 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder.IsNpgsql())
{
migrationBuilder.Sql("ALTER TABLE \"Stores\" ALTER COLUMN \"DerivationStrategies\" TYPE JSONB USING \"DerivationStrategies\"::JSONB");
}
}
protected override void Down(MigrationBuilder migrationBuilder)
{
// Not supported
}
}
}

Some files were not shown because too many files have changed in this diff Show More