From 9daaf10db0564b879282b13859f168c88919360e Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 26 Apr 2022 19:00:55 -0500 Subject: [PATCH 1/4] Refactor message limits, change to 500/day --- sgx_jmp.rb | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 5cc1d1da03d39d9f53a8be967e623f80c9797053..2025184bcea69dcf1efc13d9100286060b035a11 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -311,13 +311,21 @@ def billable_message(m) (m.body && !m.body.empty?) || m.find("ns:x", ns: OOB.registered_ns).first end -def notify_admin_of_usage(customer, usage, today) - ExpiringLock.new("jmp_usage_notify-#{customer.customer_id}").with do - BLATHER.join(CONFIG[:notify_admin], "sgx-jmp") - BLATHER.say( - CONFIG[:notify_admin], "#{customer.customer_id} has used " \ - "#{usage} messages since #{today - 30}", :groupchat - ) +class OverLimit < StandardError + def initialize(customer, usage) + super("Please contact support") + @customer = customer + @usage = usage + end + + def notify_admin + ExpiringLock.new("jmp_usage_notify-#{@customer.customer_id}").with do + BLATHER.join(CONFIG[:notify_admin], "sgx-jmp") + BLATHER.say( + CONFIG[:notify_admin], "#{@customer.customer_id} has used " \ + "#{@usage} messages today", :groupchat + ) + end end end @@ -329,19 +337,19 @@ message do |m| CustomerRepo .new(set_user: sentry_hub.current_scope.method(:set_user)) .find_by_jid(m.from.stripped).then { |customer| - EMPromise.all([ - (customer.incr_message_usage if billable_message(m)), - customer.message_usage((today..(today - 30))).then do |usage| - if usage < 4500 - customer.stanza_from(m) - else - BLATHER << m.as_error( - "policy-violation", :wait, "Please contact support" - ) - end - notify_admin_of_usage(customer, usage, today) if usage > 900 - end - ]) + next customer.stanza_from(m) unless billable_message(m) + + customer.message_usage((today..today)).then { |usage| + raise OverLimit.new(customer, usage) if usage > 500 + }.then do + EMPromise.all([ + customer.incr_message_usage, + customer.stanza_from(m) + ]) + end + }.catch_only(OverLimit) { |e| + e.notify_admin + BLATHER << m.as_error("policy-violation", :wait, e.message) }.catch_only(CustomerRepo::NotFound) { |e| BLATHER << m.as_error("forbidden", :auth, e.message) }.catch { |e| panic(e, sentry_hub) } From 94cef4ee6c1dbc487600a2ccee57f54bd6733414 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 26 Apr 2022 19:05:39 -0500 Subject: [PATCH 2/4] Use TrustLevel to determine daily quota --- lib/trust_level.rb | 16 ++++++++++++++++ sgx_jmp.rb | 7 +++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/trust_level.rb b/lib/trust_level.rb index 285850ff77dd2e9722f4f669be469a5cdeaeafc0..c70edeb92de07261af31ee26a308c5f477705f46 100644 --- a/lib/trust_level.rb +++ b/lib/trust_level.rb @@ -27,6 +27,10 @@ module TrustLevel def support_call?(*) false end + + def send_message?(*) + false + end end class Basement @@ -37,6 +41,10 @@ module TrustLevel def support_call?(rate, concurrency) rate <= 0.02 && concurrency < 1 end + + def send_message?(messages_today) + messages_today < 200 + end end class Paragon @@ -47,6 +55,10 @@ module TrustLevel def support_call?(_, concurrency) concurrency < 10 end + + def send_message?(messages_today) + messages_today < 700 + end end class Customer @@ -70,5 +82,9 @@ module TrustLevel def support_call?(rate, concurrency) rate <= @max_rate && concurrency < 4 end + + def send_message?(messages_today) + messages_today < 500 + end end end diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 2025184bcea69dcf1efc13d9100286060b035a11..3f5766ada233f4a2c8e4b7aa53405e23e7bc3ad0 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -339,8 +339,11 @@ message do |m| .find_by_jid(m.from.stripped).then { |customer| next customer.stanza_from(m) unless billable_message(m) - customer.message_usage((today..today)).then { |usage| - raise OverLimit.new(customer, usage) if usage > 500 + EMPromise.all([ + TrustLevelRepo.new.find(customer), + customer.message_usage((today..today)) + ]).then { |(tl, usage)| + raise OverLimit.new(customer, usage) unless tl.send_message?(usage) }.then do EMPromise.all([ customer.incr_message_usage, From 0925ae72ced0b5a9b2aae40c697b472aee97ced1 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 26 Apr 2022 19:22:20 -0500 Subject: [PATCH 3/4] Contacting support is not billable --- config-schema.dhall | 1 + config.dhall.sample | 1 + sgx_jmp.rb | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config-schema.dhall b/config-schema.dhall index 1e6f5eda9b7a7e1fcc9d441b3180cfb6015467bc..9878775bd435b06752207207e1176e513164036f 100644 --- a/config-schema.dhall +++ b/config-schema.dhall @@ -39,6 +39,7 @@ , sgx : Text , sip : { app : Text, realm : Text } , sip_host : Text +, unbilled_targets : List Text , upstream_domain : Text , web : < Inet : { interface : Text, port : Natural } | Unix : Text > , web_register : { from : Text, to : Text } diff --git a/config.dhall.sample b/config.dhall.sample index 61b0e87b7696af2d85c995a912f0ed2ac43293dc..cedfc1b832cd67146a310fd26ab5f160795415cf 100644 --- a/config.dhall.sample +++ b/config.dhall.sample @@ -76,6 +76,7 @@ in payable = "", notify_from = "+15551234567@example.net", admins = ["test\\40example.com@example.net"], + unbilled_targets = ["+14169938000"], upstream_domain = "example.net", approved_domains = toMap { `example.com` = Some "customer_id" } } diff --git a/sgx_jmp.rb b/sgx_jmp.rb index 3f5766ada233f4a2c8e4b7aa53405e23e7bc3ad0..b48dddaec11d8c50d694e0786ccfe2bc8d46a867 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -307,8 +307,11 @@ end # Especially if we have the component join MUC for notifications message(type: :groupchat) { true } +UNBILLED_TARGETS = Set.new(CONFIG[:unbilled_targets]) def billable_message(m) - (m.body && !m.body.empty?) || m.find("ns:x", ns: OOB.registered_ns).first + b = m.body + !UNBILLED_TARGETS.member?(m.to.node) && \ + (b && !b.empty? || m.find("ns:x", ns: OOB.registered_ns).first) end class OverLimit < StandardError From 5dfee341471ad8e315649bab239551478088a7b4 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 26 Apr 2022 19:26:04 -0500 Subject: [PATCH 4/4] Block outgoing messages when expired --- sgx_jmp.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sgx_jmp.rb b/sgx_jmp.rb index b48dddaec11d8c50d694e0786ccfe2bc8d46a867..be6cbf60462a24ba756f7f997875fc962500dc15 100644 --- a/sgx_jmp.rb +++ b/sgx_jmp.rb @@ -332,16 +332,21 @@ class OverLimit < StandardError end end +class CustomerExpired < StandardError; end + message do |m| StatsD.increment("message") sentry_hub = new_sentry_hub(m, name: "message") today = Time.now.utc.to_date - CustomerRepo - .new(set_user: sentry_hub.current_scope.method(:set_user)) + CustomerRepo.new(set_user: sentry_hub.current_scope.method(:set_user)) .find_by_jid(m.from.stripped).then { |customer| next customer.stanza_from(m) unless billable_message(m) + if customer.plan_name && !customer.active? + raise CustomerExpired, "Your account is expired, please top up" + end + EMPromise.all([ TrustLevelRepo.new.find(customer), customer.message_usage((today..today)) @@ -349,14 +354,13 @@ message do |m| raise OverLimit.new(customer, usage) unless tl.send_message?(usage) }.then do EMPromise.all([ - customer.incr_message_usage, - customer.stanza_from(m) + customer.incr_message_usage, customer.stanza_from(m) ]) end }.catch_only(OverLimit) { |e| e.notify_admin BLATHER << m.as_error("policy-violation", :wait, e.message) - }.catch_only(CustomerRepo::NotFound) { |e| + }.catch_only(CustomerRepo::NotFound, CustomerExpired) { |e| BLATHER << m.as_error("forbidden", :auth, e.message) }.catch { |e| panic(e, sentry_hub) } end