-
-
Couldn't load subscription status.
- Fork 371
[feat] Add stripe payments #3184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
101 commits
Select commit
Hold shift + click to select a range
3f131a7
feat: add `webhook` path
motorina0 154f10a
feat: basic functionality for `stripe`
motorina0 09a4344
feat: add fiat providers
motorina0 e7c59a7
feat: add pay with stripe button
motorina0 bc161ba
feat: select payment provider
motorina0 16c6845
feat: create checkout session
motorina0 6b57bc7
refactor: extract `amount_cents`
motorina0 84fb36a
feat: show stripe payment request
motorina0 4490673
feat: check payment with stripe
motorina0 7ea1417
fix: lint
motorina0 b796274
fix: error message
motorina0 1c8b097
refactor: simplify logic
motorina0 c5f3c48
feat: extra checks for paid incoming invoice
motorina0 6e884c7
chore: code clean-up
motorina0 b59c604
fix: notify for successful invoices
motorina0 6b4dda9
fix: the previous fix
motorina0 ddb38e6
fix: rever tasks logic
motorina0 f7d197b
feat: notify listeners when fiat payment is successfull
motorina0 31c9348
fix: var name
motorina0 a013b5f
feat: handle `stripe` notifications
motorina0 77fe046
chore: add todo
motorina0 d41df01
refactor: more generic fiat providers
motorina0 70cb58a
refactor: rename classes
motorina0 fe608c1
feat: check if stripe is enabled
motorina0 c610018
feat: add fiat providers tab
motorina0 9d9079f
feat: stripe placeholder settings
motorina0 74ff39b
feat: settings UI for `stripe`
motorina0 a777944
refactor: rename vars
motorina0 0ffcec6
feat: prepare to test connection
motorina0 0d6ce01
feat: extra properties
motorina0 966b106
feat: polish settings UI
motorina0 baff1fa
feat: add check buttons
motorina0 85adc51
feat: useful label
motorina0 37a8fbe
feat: check fit provider
motorina0 23d2dac
feat: check stale connection
motorina0 84deb9c
feat: add faucet wallet setting an UI
motorina0 d9c1e59
feat: only show enabled fiat providers
motorina0 8239da5
refactor: extract `_api_payments_create_fiat_invoice `
motorina0 7004611
refactor: simplify signature
motorina0 6dfc72d
refactor: extract functions to services
motorina0 ada2485
feat: use `get_fiat_provider()`
motorina0 6f2d12e
refactor: rename base classes
motorina0 bb9ca5b
refactor: simplify stale connection check
motorina0 f88409b
feat: better webhook secplainer
motorina0 e3c44b7
refactor: param order
motorina0 62f42bd
feat: check fiat payment limits
motorina0 c6cdf7e
fix: preserve payment fee
motorina0 3db2862
fix: default value for `fiat_provider`
motorina0 27f67f0
refactor: use FiatStatu
motorina0 f12482d
feat: add `handle_fiat_payment_confirmation`
motorina0 0919f80
fix: credit fiat fee wallet
motorina0 e761abb
chore: better error message
motorina0 c7a1556
feat: disable webhook URL input
motorina0 aa22787
feat: deduct from faucet wallet
motorina0 a703847
doc: extra description for fiat wallet
motorina0 dafd8d8
refactor: small changes
motorina0 dbce21b
test: add basic tests
motorina0 226c33e
test: add basic tests
motorina0 60d04b1
test: bypass weird github rule?
motorina0 39084df
test: limits validation
motorina0 597bb77
refactor: reorder tests
motorina0 2c1eb7f
test: fiat provider create invoice failed
motorina0 ebc7122
test: service_fee_fiat
motorina0 1e8f383
test: failed invoice exits
motorina0 3316c87
refactor: file rename
motorina0 9e687cc
test: add more assertions
motorina0 0a05032
test: fiat status update
motorina0 4757a4a
chore: clean-up
motorina0 ead4d42
refactor: rename webhook to callback
motorina0 76ffd75
test: allowed users
motorina0 23b33ed
chore: code format
motorina0 3db0657
test: api for fiat_provider
motorina0 7789ce1
test: add tests for faucet
motorina0 e8194e1
fet: better explanation for the webhook
motorina0 e236110
feat: check stripe signature
motorina0 36ca14d
refactor: rename test file
motorina0 c2221ad
test: check stripe signature (100% github copilot)
motorina0 1504561
refactor: introduce the `fiat_` prefix
motorina0 70debe6
refactor: clean-up
motorina0 8c2d48b
test: extra logging
motorina0 0da2bc4
refactor: less indent
motorina0 55afeff
chore: extra log
motorina0 3f7c333
test: small diferentiators
motorina0 400a081
fix: ids
motorina0 53cc75c
chore: extra logs
motorina0 eca59ca
fix: faucet payment
motorina0 d87bc28
chore: code clean-up
motorina0 ab36735
chore: extra log
motorina0 04e6a2d
test: enable stripe for api test
motorina0 f21c8b7
chore: code clean-up
motorina0 040d16b
chore: make bundle
motorina0 cc4f7f6
refactor: move `UnsupportedError`
motorina0 b9bb46c
refactor: rename `FiatWallet` to `FiatProvider`
motorina0 54f5353
chore: code clean-up
motorina0 82514ce
refactor: extract `normalize_endpoint` to `helpers`
motorina0 87e018f
refactor: rename function
motorina0 9a0899e
fix: typo
motorina0 28ad815
chore: make bundle
motorina0 8f3b8ce
refactor: rename package
motorina0 cdc8ff2
refactor: rename var
motorina0 188fb3a
feat: dense fiat provider list
motorina0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| import hashlib | ||
| import hmac | ||
| import time | ||
| from typing import Optional | ||
|
|
||
| from loguru import logger | ||
|
|
||
| from lnbits.core.crud.payments import get_standalone_payment | ||
| from lnbits.core.models.misc import SimpleStatus | ||
| from lnbits.fiat import get_fiat_provider | ||
|
|
||
|
|
||
| async def handle_stripe_event(event: dict): | ||
| event_id = event.get("id") | ||
| event_object = event.get("data", {}).get("object", {}) | ||
| object_type = event_object.get("object") | ||
| payment_hash = event_object.get("metadata", {}).get("payment_hash") | ||
| logger.debug( | ||
| f"Handling Stripe event: '{event_id}'. Type: '{object_type}'." | ||
| f" Payment hash: '{payment_hash}'." | ||
| ) | ||
| if not payment_hash: | ||
| logger.warning("Stripe event does not contain a payment hash.") | ||
| return | ||
|
|
||
| payment = await get_standalone_payment(payment_hash) | ||
motorina0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if not payment: | ||
| logger.warning(f"No payment found for hash: '{payment_hash}'.") | ||
| return | ||
| await payment.check_fiat_status() | ||
|
|
||
|
|
||
| def check_stripe_signature( | ||
| payload: bytes, | ||
| sig_header: Optional[str], | ||
| secret: Optional[str], | ||
| tolerance_seconds=300, | ||
| ): | ||
| if not sig_header: | ||
| logger.warning("Stripe-Signature header is missing.") | ||
| raise ValueError("Stripe-Signature header is missing.") | ||
|
|
||
| if not secret: | ||
| logger.warning("Stripe webhook signing secret is not set.") | ||
| raise ValueError("Stripe webhook cannot be verified.") | ||
|
|
||
| # Split the Stripe-Signature header | ||
| items = dict(i.split("=") for i in sig_header.split(",")) | ||
| timestamp = int(items["t"]) | ||
| signature = items["v1"] | ||
|
|
||
| # Check timestamp tolerance | ||
| if abs(time.time() - timestamp) > tolerance_seconds: | ||
| logger.warning("Timestamp outside tolerance.") | ||
| logger.debug( | ||
| f"Current time: {time.time()}, " | ||
| f"Timestamp: {timestamp}, " | ||
| f"Tolerance: {tolerance_seconds} seconds" | ||
| ) | ||
|
|
||
| raise ValueError("Timestamp outside tolerance." f"Timestamp: {timestamp}") | ||
|
|
||
| signed_payload = f"{timestamp}.{payload.decode()}" | ||
|
|
||
| # Compute HMAC SHA256 using the webhook secret | ||
| computed_signature = hmac.new( | ||
| key=secret.encode(), msg=signed_payload.encode(), digestmod=hashlib.sha256 | ||
| ).hexdigest() | ||
|
|
||
| # Compare signatures using constant time comparison | ||
| if hmac.compare_digest(computed_signature, signature) is not True: | ||
| logger.warning("Stripe signature verification failed.") | ||
| raise ValueError("Stripe signature verification failed.") | ||
|
|
||
|
|
||
| async def test_connection(provider: str) -> SimpleStatus: | ||
| """ | ||
| Test the connection to Stripe by checking if the API key is valid. | ||
| This function should be called when setting up or testing the Stripe integration. | ||
| """ | ||
| fiat_provider = await get_fiat_provider(provider) | ||
| status = await fiat_provider.status() | ||
| if status.error_message: | ||
| return SimpleStatus( | ||
| success=False, | ||
| message=f"Cconnection test failed: {status.error_message}", | ||
| ) | ||
|
|
||
| return SimpleStatus( | ||
| success=True, | ||
| message="Connection test successful." f" Balance: {status.balance}.", | ||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does is_internal also check if its fiat?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fiat payments are always internal payments, but I wanted to have an explicit prefix for it