From 5ae7727f7a45f5374ccf46158d5275741a1e90da Mon Sep 17 00:00:00 2001 From: Changaco Date: Tue, 31 Oct 2023 12:25:30 +0100 Subject: [PATCH 1/5] refresh elsewhere accounts more often https://hackerone.com/reports/2230520 --- liberapay/main.py | 4 ++-- liberapay/models/account_elsewhere.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/liberapay/main.py b/liberapay/main.py index 9937777c3..3dfd10984 100644 --- a/liberapay/main.py +++ b/liberapay/main.py @@ -173,8 +173,8 @@ def default_body_parser(body_bytes, headers): cron(intervals.get('dequeue_emails', 60), Participant.dequeue_emails, True) cron(intervals.get('send_newsletters', 60), Participant.send_newsletters, True) cron(intervals.get('send_account_disabled_notifications', 600), send_account_disabled_notifications, True) - cron(intervals.get('refetch_elsewhere_data', 120), refetch_elsewhere_data, True) - cron(intervals.get('refetch_repos', 60), refetch_repos, True) + cron(intervals.get('refetch_elsewhere_data', 30), refetch_elsewhere_data, True) + cron(intervals.get('refetch_repos', 20), refetch_repos, True) cron(Weekly(weekday=3, hour=2), create_payday_issue, True) cron(intervals.get('clean_up_counters', 3600), website.db.clean_up_counters, True) cron(Daily(hour=1), clean_up_emails, True) diff --git a/liberapay/models/account_elsewhere.py b/liberapay/models/account_elsewhere.py index e3ddd0e3c..e7ab12e12 100644 --- a/liberapay/models/account_elsewhere.py +++ b/liberapay/models/account_elsewhere.py @@ -392,7 +392,7 @@ def refetch_elsewhere_data(): SELECT e, p FROM elsewhere e JOIN participants p ON p.id = e.participant - WHERE e.info_fetched_at < now() - interval '90 days' + WHERE e.info_fetched_at < now() - interval '30 days' AND (e.missing_since IS NULL OR e.missing_since > (current_timestamp - interval '30 days')) AND (e.last_fetch_attempt IS NULL OR e.last_fetch_attempt < (current_timestamp - interval '3 days')) AND (p.status = 'active' OR p.receiving > 0) From 22eb01b9ca3e56ee866cc284587f14b06704755b Mon Sep 17 00:00:00 2001 From: Changaco Date: Tue, 31 Oct 2023 12:26:05 +0100 Subject: [PATCH 2/5] rate-limit adding payment instruments, per account --- liberapay/constants.py | 1 + liberapay/models/exchange_route.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/liberapay/constants.py b/liberapay/constants.py index f2a757192..c1629f27d 100644 --- a/liberapay/constants.py +++ b/liberapay/constants.py @@ -301,6 +301,7 @@ def generate_value(self, currency): RATE_LIMITS = { 'add_email.source': (5, 60*60*24), # 5 per day 'add_email.target': (2, 60*60*24), # 2 per day + 'add_payment_instrument': (20, 60*60*24*7), # 20 per week 'admin.http-unsafe': (10, 60*60*24), # 10 per day 'change_currency': (4, 60*60*24*7), # 4 per week 'change_password': (7, 60*60*24*7), # 7 per week diff --git a/liberapay/models/exchange_route.py b/liberapay/models/exchange_route.py index 02120b1de..af92d8533 100644 --- a/liberapay/models/exchange_route.py +++ b/liberapay/models/exchange_route.py @@ -6,7 +6,7 @@ import stripe from ..constants import CARD_BRANDS -from ..exceptions import InvalidId +from ..exceptions import InvalidId, TooManyAttempts class ExchangeRoute(Model): @@ -70,6 +70,7 @@ def from_address(cls, participant, network, address): def insert(cls, participant, network, address, status, one_off=False, remote_user_id=None, country=None, currency=None): p_id = participant.id + cls.db.hit_rate_limit('add_payment_instrument', str(p_id), TooManyAttempts) r = cls.db.one(""" INSERT INTO exchange_routes AS r (participant, network, address, status, From bd363a1de9252f5d1f6623caa6d8b8495e038fd4 Mon Sep 17 00:00:00 2001 From: Changaco Date: Thu, 4 Jan 2024 09:05:22 +0100 Subject: [PATCH 3/5] fix handling of some payin transfers The old code mistakenly executes transfers from suspended payers to LiberapayOrg. --- liberapay/payin/stripe.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/liberapay/payin/stripe.py b/liberapay/payin/stripe.py index 5aec168ea..f592c73ec 100644 --- a/liberapay/payin/stripe.py +++ b/liberapay/payin/stripe.py @@ -460,22 +460,24 @@ def settle_charge_and_transfers( payer = db.Participant.from_id(payin.payer) undeliverable_amount = amount_settled.zero() for i, pt in enumerate(payin_transfers): - if payer.is_suspended and pt.status not in ('failed', 'succeeded'): - pt = update_payin_transfer( - db, pt.id, None, 'suspended', None, - update_donor=(update_donor and i == last), - ) - elif pt.destination_id == 'acct_1ChyayFk4eGpfLOC': - pt = update_payin_transfer( - db, pt.id, None, charge.status, error, - update_donor=(update_donor and i == last), - ) - elif pt.remote_id is None and pt.status in ('pre', 'pending'): - pt = execute_transfer( - db, pt, pt.destination_id, charge.id, - update_donor=(update_donor and i == last), - ) - elif payin.refunded_amount and pt.remote_id: + if payer.is_suspended: + if pt.status not in ('failed', 'succeeded'): + pt = update_payin_transfer( + db, pt.id, None, 'suspended', None, + update_donor=(update_donor and i == last), + ) + elif pt.remote_id is None: + if pt.destination_id == 'acct_1ChyayFk4eGpfLOC': + pt = update_payin_transfer( + db, pt.id, None, charge.status, error, + update_donor=(update_donor and i == last), + ) + elif pt.status in ('pre', 'pending'): + pt = execute_transfer( + db, pt, pt.destination_id, charge.id, + update_donor=(update_donor and i == last), + ) + else: pt = sync_transfer( db, pt, update_donor=(update_donor and i == last), From e1314db81ffc4b8ee65a8c30192c831c2030bbfc Mon Sep 17 00:00:00 2001 From: Changaco Date: Fri, 5 Jan 2024 18:44:54 +0100 Subject: [PATCH 4/5] show removed payment instruments to admins --- www/%username/routes/index.spt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/www/%username/routes/index.spt b/www/%username/routes/index.spt index d43d476ce..3a0569315 100644 --- a/www/%username/routes/index.spt +++ b/www/%username/routes/index.spt @@ -47,9 +47,9 @@ routes = website.db.all(""" FROM exchange_routes r WHERE r.participant = %s AND r.network IN ('stripe-card', 'stripe-sdd') - AND r.status IN ('chargeable', 'pending') + AND ( r.status IN ('chargeable', 'pending') OR %s ) ORDER BY r.ctime DESC -""", (participant.id,)) +""", (participant.id, user.is_acting_as('admin'))) today = utcnow().date() @@ -96,7 +96,7 @@ title = _("Payment Instruments")
% for route, last_payin in routes -
+
{{ fontawesome('credit-card', _("Credit/Debit Card")) if route.network == 'stripe-card' else fontawesome('bank', _("Bank Account")) if route.network == 'stripe-sdd' else @@ -124,6 +124,8 @@ title = _("Payment Instruments") % endif % if route.status == 'pending'   {{ _("pending") }} + % elif route.status != 'chargeable' +   {{ route.status }} % endif
{{ _("Added on {date}", date=route.ctime.date()) }} % set mandate_url = route.get_mandate_url() @@ -175,6 +177,7 @@ title = _("Payment Instruments")
{{ _("This payment instrument hasn't been used yet.") }} % endif
+ % if route.status in ('chargeable', 'pending') % if not route.is_default @@ -191,6 +194,7 @@ title = _("Payment Instruments") % endif % endif + % endif
% endfor From b720bb30cda125df76c7c3cc9bc55bc54759a503 Mon Sep 17 00:00:00 2001 From: Changaco Date: Fri, 5 Jan 2024 18:50:05 +0100 Subject: [PATCH 5/5] add links to Stripe dashboard for admins in ledgers --- liberapay/utils/history.py | 2 +- www/%username/ledger/index.spt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/liberapay/utils/history.py b/liberapay/utils/history.py index c76dcb7a8..d002af015 100644 --- a/liberapay/utils/history.py +++ b/liberapay/utils/history.py @@ -460,7 +460,7 @@ def iter_payin_events(db, participant, period_start, period_end, minimize=False) params = locals() payins = db.all(""" SELECT pi.id, pi.ctime, pi.amount, pi.status, pi.error, pi.amount_settled, pi.fee - , pi.refunded_amount, pi.off_session, r.network AS payin_method + , pi.refunded_amount, pi.off_session, pi.remote_id, r.network AS payin_method FROM payins pi JOIN exchange_routes r ON r.id = pi.route WHERE pi.payer = %(id)s diff --git a/www/%username/ledger/index.spt b/www/%username/ledger/index.spt index 7465d74fa..7bc474de4 100644 --- a/www/%username/ledger/index.spt +++ b/www/%username/ledger/index.spt @@ -57,7 +57,7 @@ if participant.join_time: years = list(range(current_year, max(participant.join_time.year, 2018) - 1, -1)) [---] text/html -% from "templates/macros/icons.html" import glyphicon +% from "templates/macros/icons.html" import fontawesome, glyphicon % from "templates/macros/payment-methods.html" import payment_method_icon with context % extends "templates/layouts/settings.html" @@ -184,7 +184,7 @@ if participant.join_time: {{ locale.format_money(event['fee']) if event['fee'] else '' }} {{ payment_method_icon(event['payin_method']) }} % if show_id - {{ event['id'] }} + {{ event['id'] }}{% if event['remote_id'] %} {{ fontawesome('external-link-square') }}{% endif %} % endif % elif event['kind'] == 'payin_transfer'