@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require "digest"
+
require_relative "./usage_report"
class CustomerUsage
@@ -26,7 +28,7 @@ class CustomerUsage
)
end
- def incr_message_usage(amount=1)
+ def incr_message_usage(amount=1, body=nil)
today = Time.now.utc.to_date
EMPromise.all([
expire_message_usage,
@@ -34,8 +36,21 @@ class CustomerUsage
"jmp_customer_outbound_messages-#{@customer_id}",
amount,
today.strftime("%Y%m%d")
- )
- ])
+ ),
+ incr_body(amount, body)
+ ]).then { |result| { today: result[1], body: result[2] } }
+ end
+
+ def incr_body(amount, body)
+ # Short message like "hello" we can't block dupes
+ return 0 if body.to_s.length < 30
+
+ hash = Digest::SHA2.hexdigest(body[0..100])
+
+ EMPromise.all([
+ REDIS.incrby("jmp_outbound_body-#{hash}", amount),
+ REDIS.expire("jmp_outbound_body-#{hash}", 120)
+ ]).then(&:first)
end
def message_usage(range)
@@ -321,6 +321,12 @@ def billable_message(m)
b && !b.empty? || m.find("ns:x", ns: OOB.registered_ns).first
end
+def expired_guard(customer)
+ return unless !customer.plan_name || customer.active?
+
+ raise CustomerExpired, "Your account is expired, please top up"
+end
+
class OverLimit < StandardError
def initialize(customer, usage)
super("Please contact support")
@@ -333,7 +339,8 @@ class OverLimit < StandardError
BLATHER.join(CONFIG[:notify_admin], "sgx-jmp")
BLATHER.say(
CONFIG[:notify_admin], "#{@customer.customer_id} has used " \
- "#{@usage} messages today", :groupchat
+ "#{@usage[:today]} messages today (global #{@usage[:body]} this body)",
+ :groupchat
)
end
end
@@ -392,7 +399,6 @@ end
message do |m|
StatsD.increment("message")
- today = Time.now.utc.to_date
find_from_and_to_customer(m.from, m.to).then { |(customer, target_customer)|
if target_customer && customer.registered?
m.from = "#{customer.registered?.phone}@sgx-jmp"
@@ -401,17 +407,18 @@ message do |m|
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
+ expired_guard(customer)
EMPromise.all([
TrustLevelRepo.new.find(customer),
- customer.message_usage((today..today))
+ customer.incr_message_usage(1, m.body)
]).then { |(tl, usage)|
- raise OverLimit.new(customer, usage) unless tl.send_message?(usage)
+ next if tl.send_message?(usage[:today]) && usage[:body].to_i < 5
+
+ log.warn "OverLimit", m
+ raise OverLimit.new(customer, usage)
}.then do
- EMPromise.all([customer.incr_message_usage, customer.stanza_from(m)])
+ customer.stanza_from(m)
end
}.catch_only(OverLimit) { |e|
e.notify_admin