diff --git a/sgx-bwmsgsv2.rb b/sgx-bwmsgsv2.rb index 7ce14ea9cef818e1d3622d4a2606ccd017df5c4e..5c922ab008a10d4ba0b5560f8cea08eb44912e79 100755 --- a/sgx-bwmsgsv2.rb +++ b/sgx-bwmsgsv2.rb @@ -46,6 +46,49 @@ require_relative 'lib/registration_repo' Sentry.init +BADWORD_LIST = [ + "marijuana", + "psilocybin", + "cannabis", + "cocaine", + "heroin", + "meth", + "methamphetamine", + "methamphetamines", + "cigarette", + "tobacco", + "cbd", + "thc", + "morphine", + "incall", + "in-call", + "outcall", + "out-call", + "shrooms", + "lsd", + "kratom", + "mdma", + "addy", + "xanz", + "cialis", + "viagra", + "bbfs", + "fentanyl", + "opium", + "golden teacher", + "bbbj", + "canna", + "fuck", + "xanax", + "zarareturns", + "zarareturns.com", + "plantation", +].freeze + +BADWORDS = Regexp.union( + BADWORD_LIST.map { |w| /\b#{Regexp.escape(w)}\b/ } +) + # List of supported MIME types from Bandwidth - https://support.bandwidth.com/hc/en-us/articles/360014128994-What-MMS-file-types-are-supported- MMS_MIME_TYPES = [ "application/json", @@ -390,6 +433,14 @@ module SGXbwmsgsv2 ) end + if body.downcase.match?(BADWORDS) + return EMPromise.reject([ + :wait, + 'recipient-unavailable', + 'Single message blocked by carrier content policy, see https://blog.jmp.chat/b/sms-censorship for details' + ]) + end + segment_size = body.ascii_only? ? 160 : 70 if !murl && ENV["MMS_PATH"] && body.length > segment_size*3 file = Multibases.pack( diff --git a/test/property/test_badwords.rb b/test/property/test_badwords.rb new file mode 100644 index 0000000000000000000000000000000000000000..be9cf6542d26d90dd85315498311d22ec28a24a9 --- /dev/null +++ b/test/property/test_badwords.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require "test_helper" +require_relative "../../sgx-bwmsgsv2" +require "rantly/minitest_extensions" +require_relative "rantly_extensions/data_extensions" + +class BadwordsPropertyTest < Minitest::Test + BW_MESSAGES_URL = + "https://messaging.bandwidth.com/api/v2/users/account/messages" + + def setup + reset_stanzas! + reset_redis! + end + + def test_message_containing_badword_is_rejected + property_of { + bad_word = choose(*BADWORD_LIST) + cased = choose(bad_word.downcase, bad_word.upcase, bad_word.capitalize) + + prefix = array(range(0, 4)) { sized(range(3, 8)) { string(:alnum) } } + suffix = array(range(0, 4)) { sized(range(3, 8)) { string(:alnum) } } + body = (prefix + [cased] + suffix).join(" ") + + dest = nanpa_phone + [body, dest] + }.check { |body, dest| + reset_stanzas! + reset_redis! + + stub_request(:post, BW_MESSAGES_URL).to_return( + status: 201, + body: JSON.dump(id: "bw-msg-stub") + ) + + m = Blather::Stanza::Message.new("#{dest}@component", body) + m.from = "test@example.com" + process_stanza(m) + + assert_equal 1, written.length, + "Expected exactly one error stanza for body: #{body.inspect}" + + stanza = Blather::XMPPNode.parse(written.first.to_xml) + assert stanza.error?, + "Expected error stanza for body: #{body.inspect}" + + error = stanza.find_first("error") + assert_equal "wait", error["type"], + "Expected error type 'wait' for body: #{body.inspect}" + assert_equal "recipient-unavailable", xmpp_error_name(error), + "Expected 'recipient-unavailable' for body: #{body.inspect}" + } + end + em :test_message_containing_badword_is_rejected + + def test_message_without_badwords_is_not_rejected_as_unavailable + property_of { + words = array(range(1, 6)) { sized(range(3, 10)) { string(:alnum) } } + guard(words.none? { |w| BADWORD_LIST.include?(w.downcase) }) + body = words.join(" ") + + dest = nanpa_phone + [body, dest] + }.check { |body, dest| + reset_stanzas! + reset_redis! + + stub_request(:post, BW_MESSAGES_URL).to_return( + status: 201, + body: JSON.dump(id: "bw-msg-stub") + ) + + m = Blather::Stanza::Message.new("#{dest}@component", body) + m.from = "test@example.com" + process_stanza(m) + + written.each do |response| + stanza = Blather::XMPPNode.parse(response.to_xml) + next unless stanza.error? + + error = stanza.find_first("error") + msg = "Clean message rejected as " \ + "recipient-unavailable: #{body.inspect}" + refute_equal "recipient-unavailable", + xmpp_error_name(error), msg + end + } + end + em :test_message_without_badwords_is_not_rejected_as_unavailable +end