diff --git a/ruby/lib/jam_ruby/constants/validation_messages.rb b/ruby/lib/jam_ruby/constants/validation_messages.rb index a3a51621a..da90d06cd 100644 --- a/ruby/lib/jam_ruby/constants/validation_messages.rb +++ b/ruby/lib/jam_ruby/constants/validation_messages.rb @@ -43,6 +43,11 @@ module ValidationMessages INVALID_FPFILE = "is not valid" VERIFY_EMAIL = "You need to verify your email." + CHINESE_CANT_BE_MIXED = "must be all Chinese or Japanese" + CHINESE_NAME_TOO_LONG = "must be 4 characters or less when Chinese or Japanese" + NO_SPECIAL_CHARACTERS = "must not have special characters" + INVALID_NAME = "not valid" + # recurly RECURLY_ERROR = "Error occurred during Recurly transaction." RECURLY_ACCOUNT_ERROR = "You don't have Recurly account yet." diff --git a/ruby/lib/jam_ruby/models/instrument.rb b/ruby/lib/jam_ruby/models/instrument.rb index e8b407135..16b907301 100644 --- a/ruby/lib/jam_ruby/models/instrument.rb +++ b/ruby/lib/jam_ruby/models/instrument.rb @@ -27,6 +27,7 @@ module JamRuby "tuba" => "tuba", "ukulele" => "ukelele", "upright bass" => "upright_bass", + "double bass" => "double_bass", "viola" => "viola", "violin" => "violin", "voice" => "voice" diff --git a/ruby/lib/jam_ruby/models/invited_user.rb b/ruby/lib/jam_ruby/models/invited_user.rb index 16be90d84..ae93bf76b 100644 --- a/ruby/lib/jam_ruby/models/invited_user.rb +++ b/ruby/lib/jam_ruby/models/invited_user.rb @@ -26,6 +26,7 @@ module JamRuby validate :valid_personalized_invitation # validate :not_accepted_twice validate :not_accepted_twice, :if => lambda { |iu| iu.email_required? } + validate :spammer validate :can_invite? after_save :track_user_progression @@ -102,6 +103,31 @@ module JamRuby errors.add(:accepted, "you can only accept an invitation once") if accepted_twice end + # the same account should not receive emails within the same day + def spammer + max_invites_ever_per_sender + max_invites_per_day_per_sender + max_invites_to_receiver_per_day + end + + def max_invites_ever_per_sender + if InvitedUser.where(:sender => self.sender).count > APP_CONFIG.max_invites_ever_per_sender + errors.add(:base, "max invites sent by this account") + end + end + + def max_invites_per_day_per_sender + if InvitedUser.where(:sender => self.sender).where("created_at > ?", Time.now - 1.days).count > APP_CONFIG.max_invites_per_day_per_sender + errors.add(:base, "maximum number of invites sent in past 24 hours") + end + end + + def max_invites_to_receiver_per_day + if InvitedUser.where(:email => self.email).where("created_at > ?", Time.now - 1.days).count > APP_CONFIG.max_invites_to_receiver_per_day - 1 + errors.add(:base, "someone has already sent to #{self.email} in past 24 hours") + end + end + def one_facebook_invite_per_user rel = InvitedUser.where(:invite_medium => FB_MEDIUM, :sender_id => self.sender_id) rel = rel.where(['id != ?',self.id]) if self.id diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index a3942e9dc..e76563b35 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -291,9 +291,11 @@ module JamRuby validate :validate_update_email validate :validate_avatar_info validate :email_case_insensitive_uniqueness + validate :validate_spammy_names validate :update_email_case_insensitive_uniqueness, :if => :updating_email validate :validate_mods validate :presence_gift_card, :if => :expecting_gift_card + validate :validate_special_chars_names, :on => :create scope :musicians, -> { where(:musician => true) } scope :fans, -> { where(:musician => false) } @@ -529,6 +531,56 @@ module JamRuby end end + + def validate_special_chars_names + if name.include?("www") + errors.add(:first_name, ValidationMessages::INVALID_NAME) + elsif name.include?("http") + errors.add(:first_name, ValidationMessages::INVALID_NAME) + end + + if !first_name.nil? && first_name =~ /[\\*\\.\\&\\:\\%]/ + errors.add(:first_name, ValidationMessages::NO_SPECIAL_CHARACTERS) + elsif !last_name.nil? && last_name =~ /[\*\.\\&]/ + errors.add(:last_name, ValidationMessages::NO_SPECIAL_CHARACTERS) + end + end + + def validate_spammy_names + + test = "" + test += first_name if !first_name.nil? + test += last_name if !last_name.nil? + + if test == "" + return + end + + some_chinese = test !~ /\p{Han}/ + + any_chinese = (test =~ /\p{Han}/) != nil + + all_chinese = (test =~ /\p{^Han}/) == nil + + any_non_chinese = (test =~ /\p{^Han}/) != nil + + if any_chinese + # must be ALL chinese + if !all_chinese + errors.add(:first_name, ValidationMessages::CHINESE_CANT_BE_MIXED) + errors.add(:last_name, ValidationMessages::CHINESE_CANT_BE_MIXED) + elsif !first_name.nil? && first_name.length > 4 + errors.add(:first_name, ValidationMessages::CHINESE_NAME_TOO_LONG) + elsif !last_name.nil? && last_name.length > 4 + errors.add(:last_name, ValidationMessages::CHINESE_NAME_TOO_LONG) + end + end + + + + + end + def validate_avatar_info if updating_avatar # we want to mak sure that original_fpfile and cropped_fpfile seems like real fpfile info objects (i.e, json objects from filepicker.io) diff --git a/ruby/spec/jam_ruby/models/invited_user_spec.rb b/ruby/spec/jam_ruby/models/invited_user_spec.rb index a00db8a20..a9a6777e4 100644 --- a/ruby/spec/jam_ruby/models/invited_user_spec.rb +++ b/ruby/spec/jam_ruby/models/invited_user_spec.rb @@ -6,6 +6,79 @@ describe InvitedUser do UserMailer.deliveries.clear end + describe 'spammer' do + + after {Timecop.return} + + + let(:user1) { FactoryGirl.create(:user) } + + it 'max_invites_ever_per_sender' do + + Timecop.travel(Date.new(2016, 3, 20)) + + APP_CONFIG.max_invites_ever_per_sender.times do + invited_user = FactoryGirl.create(:invited_user, :sender => user1) + end + + invited_user = FactoryGirl.build(:invited_user, :sender => user1) + invited_user.save + invited_user.should_not be_valid + + # but move time forward... + + Timecop.travel(Date.new(2016, 3, 22)) + + # this should never 'heal'; once you hit max, you are done for good + invited_user = FactoryGirl.build(:invited_user, :sender => user1) + invited_user.save + invited_user.should_not be_valid + end + + it 'max_invites_per_day_per_sender' do + + Timecop.travel(Date.new(2016, 3, 20)) + + APP_CONFIG.max_invites_per_day_per_sender.times do + invited_user = FactoryGirl.create(:invited_user, :sender => user1) + end + + invited_user = FactoryGirl.build(:invited_user, :sender => user1) + invited_user.save + invited_user.should_not be_valid + + # but move time forward... + + Timecop.travel(Date.new(2016, 3, 22)) + + # this should work because we moved forward by 2 days + invited_user = FactoryGirl.create(:invited_user, :sender => user1) + end + + + it 'max_invites_to_receiver_per_day' do + + Timecop.travel(Date.new(2016, 3, 20)) + + APP_CONFIG.max_invites_to_receiver_per_day.times do + invited_user = FactoryGirl.create(:invited_user, :email => 'seth@jamkazam.com') + end + + invited_user = FactoryGirl.build(:invited_user, :email => 'seth@jamkazam.com') + invited_user.save + invited_user.should_not be_valid + + # but move time forward... + + Timecop.travel(Date.new(2016, 3, 22)) + + # this should work because we moved forward by 2 days + invited_user = FactoryGirl.create(:invited_user, :email => 'seth@jamkazam.com') + end + + + end + it 'create an invitation from end-user' do # create an end user diff --git a/ruby/spec/jam_ruby/models/user_spec.rb b/ruby/spec/jam_ruby/models/user_spec.rb index 0b8729dd9..ae6f1a3ed 100644 --- a/ruby/spec/jam_ruby/models/user_spec.rb +++ b/ruby/spec/jam_ruby/models/user_spec.rb @@ -98,6 +98,69 @@ describe User do it { should be_admin } end + describe "namespam" do + + describe "no hostnames" do + before {@user.first_name = "bleh www.something.com"} + it { should_not be_valid } + end + + describe "first name can't be mixed chinese" do + before {@user.first_name = "注冊ww"} + it { should_not be_valid } + end + + describe "long chinese names" do + before {@user.first_name = "注冊注冊注冊"; @user.last_name = "注冊"} + it { should_not be_valid } + end + + describe "if chinese first name, must be chinese last name" do + before {@user.first_name = "注冊"; @user.last_name = "abc"} + it { should_not be_valid } + end + + describe "chinese names can be allchinese" do + before {@user.first_name = "注冊"; @user.last_name = "注冊"} + it { puts @user.errors.inspect; should be_valid } + end + + describe "no hostname-looking stuff - first name" do + before {@user.first_name = "www server com"} + it { should_not be_valid } + end + + describe "no hostname-looking stuff - last name" do + before {@user.first_name = "www server com"} + it { should_not be_valid } + end + + describe "no junk characters" do + before {@user.first_name = "name.come"} + it { should_not be_valid } + end + + describe "no junk characters - period" do + before {@user.first_name = "name.come"} + it { should_not be_valid } + end + + describe "no junk characters - percent" do + before {@user.first_name = "name%"} + it { should_not be_valid } + end + + describe "no junk characters - amp" do + before {@user.first_name = "name&"} + it { should_not be_valid } + end + + describe "no junk characters - asterisk" do + before {@user.first_name = "name*"} + it { should_not be_valid } + end + end + describe "when first name is not present" do before { @user.first_name = " " } diff --git a/ruby/spec/support/utilities.rb b/ruby/spec/support/utilities.rb index 9e17eb029..91858a0db 100644 --- a/ruby/spec/support/utilities.rb +++ b/ruby/spec/support/utilities.rb @@ -318,6 +318,18 @@ def app_config 1 end + def max_invites_ever_per_sender + 4 + end + + def max_invites_per_day_per_sender + 3 + end + + def max_invites_to_receiver_per_day + 1 + end + def check_bounced_emails false end diff --git a/web/app/assets/images/content/icon_instrument_double_bass24.png b/web/app/assets/images/content/icon_instrument_double_bass24.png new file mode 100644 index 000000000..c054f32ad Binary files /dev/null and b/web/app/assets/images/content/icon_instrument_double_bass24.png differ diff --git a/web/app/assets/images/content/icon_instrument_double_bass256.png b/web/app/assets/images/content/icon_instrument_double_bass256.png new file mode 100644 index 000000000..c5373a215 Binary files /dev/null and b/web/app/assets/images/content/icon_instrument_double_bass256.png differ diff --git a/web/app/assets/images/content/icon_instrument_double_bass45.png b/web/app/assets/images/content/icon_instrument_double_bass45.png new file mode 100644 index 000000000..7c2b8e1d1 Binary files /dev/null and b/web/app/assets/images/content/icon_instrument_double_bass45.png differ diff --git a/web/app/assets/javascripts/globals.js b/web/app/assets/javascripts/globals.js index e21d883e2..922953b86 100644 --- a/web/app/assets/javascripts/globals.js +++ b/web/app/assets/javascripts/globals.js @@ -231,7 +231,7 @@ "Electric Guitar": { "client_id": 50, "server_id": "electric guitar" }, "Keyboard": { "client_id": 60, "server_id": "keyboard" }, "Piano": { "client_id": 61, "server_id": "piano" }, - "Upright Bass": { "client_id": 62, "server_id": "double bass" }, + "Double Bass": { "client_id": 62, "server_id": "double bass" }, "Voice": { "client_id": 70, "server_id": "voice" }, "Flute": { "client_id": 80, "server_id": "flute" }, "Clarinet": { "client_id": 90, "server_id": "clarinet" }, diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index 304a28078..755a7ce1b 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -85,6 +85,7 @@ "tuba": "tuba", "ukulele": "ukulele", "upright bass": "upright_bass", + "double bass": "double_bass", "viola": "viola", "violin": "violin", "voice": "voice" diff --git a/web/app/controllers/api_live_streams_controller.rb b/web/app/controllers/api_live_streams_controller.rb index 225ea7cef..c979aa7aa 100644 --- a/web/app/controllers/api_live_streams_controller.rb +++ b/web/app/controllers/api_live_streams_controller.rb @@ -73,6 +73,15 @@ class ApiLiveStreamsController < ApiController end participants = params["participants"] + if !participants.nil? && participants.to_i < 2 + return + end + + duration_sec = params["duration_sec"] + if !duration_sec.nil? && duration_sec.to_i < 180 + return + end + body = "\n" body += "Participants: #{participants}\n\n" body += build_user_detail(current_user) @@ -108,7 +117,6 @@ class ApiLiveStreamsController < ApiController client_live_stream.save end - AdminMailer.ugly({to:'david@jamkazam.com', cc:'seth@jamkazam.com,peter@jamkazam.com', body: body, subject: subject}).deliver_now rescue => e AdminMailer.ugly({to:'david@jamkazam.com', cc:'seth@jamkazam.com,peter@jamkazam.com', body: params.to_s + "\n\n" + e.to_s, subject: 'Live Stream Started!'}).deliver_now @@ -117,7 +125,7 @@ class ApiLiveStreamsController < ApiController end def stream_started - email_stream_event("Live Stream Started!", false) + #email_stream_event("Live Stream Started!", false) diff --git a/web/app/views/users/_user_dropdown.html.erb b/web/app/views/users/_user_dropdown.html.erb index 55c761ac5..11f3935fc 100644 --- a/web/app/views/users/_user_dropdown.html.erb +++ b/web/app/views/users/_user_dropdown.html.erb @@ -61,7 +61,7 @@
  • <%= link_to "Download App", downloads_path, :rel => "external" %>
  • - <% if @nativeClient %> + <% if false #@nativeClient %>
  • <%= link_to "Test Network", '#' %>
  • <% end %>
  • <%= link_to "Get Help", 'https://forum.jamkazam.com/', :rel => "external" %>
  • diff --git a/web/config/application.rb b/web/config/application.rb index 14bca627d..a39ab2d23 100644 --- a/web/config/application.rb +++ b/web/config/application.rb @@ -385,6 +385,11 @@ if defined?(Bundler) config.jamtrack_landing_bubbles_enabled = true config.jamtrack_browser_bubbles_enabled = true + # spam for invited users + config.max_invites_ever_per_sender = 70 + config.max_invites_per_day_per_sender = 20 + config.max_invites_to_receiver_per_day = 1 + config.react.variant = :production config.react.addons = true diff --git a/web/spec/support/app_config.rb b/web/spec/support/app_config.rb index a9e69058c..7962415d1 100644 --- a/web/spec/support/app_config.rb +++ b/web/spec/support/app_config.rb @@ -168,6 +168,18 @@ def web_config def rating_dialog_min_num 1 end + + def max_invites_ever_per_sender + 3 + end + + def max_invites_per_day_per_sender + 4 + end + + def max_invites_to_receiver_per_day + 1 + end end klass.new end