* VRFS-3260 - fraud check code and admin helpers complete

This commit is contained in:
Seth Call 2015-05-20 09:24:17 -05:00
parent 48f61552ce
commit c96f0a7859
22 changed files with 471 additions and 65 deletions

View File

@ -0,0 +1,69 @@
ActiveAdmin.register JamRuby::FraudAlert, :as => 'Fraud Alerts' do
menu :label => 'Fraud Alerts', :parent => 'JamTracks'
config.sort_order = 'created_at desc'
config.batch_actions = false
scope("Not Whitelisted", default:true) { |scope|
scope.joins('INNER JOIN "machine_fingerprints" ON "machine_fingerprints"."id" = "fraud_alerts"."machine_fingerprint_id" LEFT OUTER JOIN "fingerprint_whitelists" ON "fingerprint_whitelists"."fingerprint" = "machine_fingerprints"."fingerprint"').where('fingerprint_whitelists IS NULL')}
index do
default_actions
column :machine_fingerprint
column :user
column :created_at
column :resolved
column "" do |alert|
link_to 'Matching MAC', "fraud_alerts/#{alert.id}/same_fingerprints"
end
column "" do |alert|
link_to 'Matching MAC and IP Address', "fraud_alerts/#{alert.id}/same_fingerprints_and_ip"
end
column "" do |alert|
link_to 'Matching IP Address', "fraud_alerts/#{alert.id}/same_ip"
end
column "" do |alert|
link_to 'Resolve', "fraud_alerts/#{alert.id}/resolve"
end
column "" do |alert|
link_to 'Whitelist Similar', "fraud_alerts/#{alert.id}/whitelist"
end
end
member_action :same_fingerprints, :method => :get do
alert = FraudAlert.find(params[:id])
redirect_to admin_machine_fingerprints_path("q[fingerprint_equals]" => alert.machine_fingerprint.fingerprint, commit: 'Filter', order: 'created_at_desc')
end
member_action :same_fingerprints_and_ip, :method => :get do
alert = FraudAlert.find(params[:id])
redirect_to admin_machine_fingerprints_path("q[fingerprint_equals]" => alert.machine_fingerprint.fingerprint, "q[remote_ip_equals]" => alert.machine_fingerprint.remote_ip, commit: 'Filter', order: 'created_at_desc')
end
member_action :resolve, :method => :get do
alert = FraudAlert.find(params[:id])
alert.resolved = true
alert.save!
redirect_to admin_fraud_alerts_path, notice: "That fraud alert has been marked as resolved"
end
member_action :whitelist, :method => :get do
alert = FraudAlert.find(params[:id])
wl = FingerprintWhitelist.new
wl.fingerprint = alert.machine_fingerprint.fingerprint
success = wl.save
redirect_to admin_fraud_alerts_path, notice: success ? "Added #{alert.machine_fingerprint.fingerprint} to whitelist" : "Could not add #{alert.machine_fingerprint.fingerprint} to whiteliste"
end
end

View File

@ -0,0 +1,8 @@
ActiveAdmin.register JamRuby::MachineExtra, :as => 'Machine Extra' do
menu :label => 'Machine Extra', :parent => 'JamTracks'
config.sort_order = 'created_at desc'
config.batch_actions = false
end

View File

@ -0,0 +1,22 @@
ActiveAdmin.register JamRuby::MachineFingerprint, :as => 'Machine Fingerprints' do
menu :label => 'Machine Fingerprints', :parent => 'JamTracks'
config.sort_order = 'created_at desc'
config.batch_actions = false
index do
column :user
column 'Hash' do |fp|
fp.fingerprint
end
column :remote_ip
column 'Detail' do |fp|
detail = fp.detail
if detail
detail.to_s
end
end
column :created_at
end
end

View File

@ -0,0 +1,13 @@
ActiveAdmin.register JamRuby::MusicSessionComment, :as => 'Ratings' do
config.per_page = 150
config.clear_action_items!
config.sort_order = 'created_at_desc'
menu :parent => 'Sessions', :label => 'Ratings'
index do
column :comment
column :user
column :created_at
end
end

View File

@ -0,0 +1,8 @@
ActiveAdmin.register JamRuby::SessionInfoComment, :as => 'Comments' do
config.per_page = 50
config.clear_action_items!
config.sort_order = 'created_at_desc'
menu :parent => 'Sessions', :label => 'Comments'
end

View File

@ -283,4 +283,5 @@ payment_history.sql
jam_track_right_private_key.sql
first_downloaded_jamtrack_at.sql
signing.sql
optimized_redeemption.sql
optimized_redeemption.sql
optimized_redemption_warn_mode.sql

View File

@ -0,0 +1,42 @@
DROP TABLE machine_fingerprints;
CREATE TABLE machine_fingerprints (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id VARCHAR(64) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
fingerprint VARCHAR(20000) NOT NULL,
when_taken VARCHAR NOT NULL,
print_type VARCHAR NOT NULL,
remote_ip VARCHAR(1000) NOT NULL,
jam_track_right_id BIGINT REFERENCES jam_track_rights(id) ON DELETE SET NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE machine_extras (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
machine_fingerprint_id VARCHAR(64) NOT NULL REFERENCES machine_fingerprints(id) ON DELETE CASCADE,
mac_address VARCHAR(100),
mac_name VARCHAR(255),
upstate BOOLEAN,
ipaddr_0 VARCHAR(200),
ipaddr_1 VARCHAR(200),
ipaddr_2 VARCHAR(200),
ipaddr_3 VARCHAR(200),
ipaddr_4 VARCHAR(200),
ipaddr_5 VARCHAR(200),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE fraud_alerts (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
machine_fingerprint_id VARCHAR(64) NOT NULL REFERENCES machine_fingerprints(id) ON DELETE CASCADE,
user_id VARCHAR(64) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
resolved BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE fingerprint_whitelists (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
fingerprint VARCHAR(20000) UNIQUE NOT NULL
);
CREATE INDEX machine_fingerprints_index1 ON machine_fingerprints USING btree (fingerprint, user_id, remote_ip, created_at);

View File

@ -104,6 +104,9 @@ require "jam_ruby/models/user"
require "jam_ruby/models/anonymous_user"
require "jam_ruby/models/signup_hint"
require "jam_ruby/models/machine_fingerprint"
require "jam_ruby/models/machine_extra"
require "jam_ruby/models/fraud_alert"
require "jam_ruby/models/fingerprint_whitelist"
require "jam_ruby/models/rsvp_request"
require "jam_ruby/models/rsvp_slot"
require "jam_ruby/models/rsvp_request_rsvp_slot"

View File

@ -0,0 +1,17 @@
module JamRuby
class FingerprintWhitelist < ActiveRecord::Base
@@log = Logging.logger[FingerprintWhitelist]
validates :fingerprint, presence: true, uniqueness: true
has_many :machine_fingerprint, class_name: 'JamRuby::MachineFingerprint', foreign_key: :fingerprint
def admin_url
APP_CONFIG.admin_root_url + "/admin/fingerprint_whitelists/" + id
end
def to_s
"#{fingerprint}"
end
end
end

View File

@ -0,0 +1,26 @@
module JamRuby
class FraudAlert < ActiveRecord::Base
@@log = Logging.logger[MachineExtra]
belongs_to :machine_fingerprint, :class_name => "JamRuby::MachineFingerprint"
belongs_to :user, :class_name => "JamRuby::User"
def self.create(machine_fingerprint, user)
fraud = FraudAlert.new
fraud.machine_fingerprint = machine_fingerprint
fraud.user = user
fraud.save
unless fraud.save
@@log.error("unable to create fraud: #{fraud.errors.inspect}")
end
fraud
end
def admin_url
APP_CONFIG.admin_root_url + "/admin/fraud_alerts/" + id
end
end
end

View File

@ -229,8 +229,8 @@ module JamRuby
return "no fingerprint specified"
end
all_fingerprint = fingerprint[:all]
running_fingerprint = fingerprint[:running]
all_fingerprint = fingerprint.delete(:all)
running_fingerprint = fingerprint.delete(:running)
if all_fingerprint.blank?
return "no all fingerprint specified"
@ -240,6 +240,9 @@ module JamRuby
return "no running fingerprint specified"
end
all_fingerprint_extra = fingerprint[all_fingerprint]
running_fingerprint_extra = fingerprint[running_fingerprint]
if redeemed && !redeemed_and_fingerprinted
# if this is a free JamTrack, we need to check for fraud or accidental misuse
@ -250,41 +253,80 @@ module JamRuby
return "already redeemed another"
end
# can we find a jam track that belongs to someone else with the same fingerprint
match = MachineFingerprint.find_by_fingerprint(all_fingerprint)
if FingerprintWhitelist.select('id').find_by_fingerprint(all_fingerprint)
# we can short circuit out of the rest of the check, since this is a known bad fingerprint
@@log.debug("ignoring 'all' hash found in whitelist")
else
# can we find a jam track that belongs to someone else with the same fingerprint
conflict = MachineFingerprint.select('count(id) as count').where('user_id != ?', current_user.id).where(fingerprint: all_fingerprint).where(remote_ip: remote_ip).where('created_at > ?', APP_CONFIG.expire_fingerprint_days.days.ago).first
conflict_count = conflict['count'].to_i
if match && match.user != current_user
AdminMailer.alerts(subject: "'All' fingerprint collision by #{current_user.name}",
body: "MachineFingerprint #{match.inspect}\n\nCurrent User: #{current_user.admin_url}").deliver
if conflict_count >= APP_CONFIG.found_conflict_count
mf = MachineFingerprint.create(all_fingerprint, current_user, MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT, MachineFingerprint::PRINT_TYPE_ACTIVE, remote_ip, all_fingerprint_extra, self)
# record the alert
fraud = FraudAlert.create(mf, current_user) if mf.valid?
fraud_admin_url = fraud.admin_url if fraud
AdminMailer.alerts(subject: "'All' fingerprint collision by #{current_user.name}",
body: "Current User: #{current_user.admin_url}\n\n Fraud Alert: #{fraud_admin_url}").deliver
# try to record the other fingerprint
mf = MachineFingerprint.create(running_fingerprint, current_user, MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT, MachineFingerprint::PRINT_TYPE_ACTIVE, remote_ip, running_fingerprint_extra, self)
if APP_CONFIG.error_on_fraud
return "other user has 'all' fingerprint"
else
self.redeemed_and_fingerprinted = true
save!
return nil
end
# try to record the other fingerprint
MachineFingerprint.create(running_fingerprint, current_user, MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT, MachineFingerprint::PRINT_TYPE_ACTIVE, remote_ip, self)
if APP_CONFIG.error_on_fraud
return "other user has 'all' fingerprint"
end
end
if all_fingerprint != running_fingerprint
match = MachineFingerprint.find_by_fingerprint(running_fingerprint)
if match && match.user != current_user
AdminMailer.alerts(subject: "'Running' fingerprint collision by #{current_user.name}",
body: "MachineFingerprint #{match.inspect}\n\nCurrent User: #{current_user.admin_url}").deliver
# try to record the other fingerprint
MachineFingerprint.create(all_fingerprint, current_user, MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT, MachineFingerprint::PRINT_TYPE_ALL, remote_ip, self)
if APP_CONFIG.error_on_fraud
return "other user has 'running' fingerprint"
if all_fingerprint != running_fingerprint
if FingerprintWhitelist.select('id').find_by_fingerprint(running_fingerprint)
# we can short circuit out of the rest of the check, since this is a known bad fingerprint
@@log.debug("ignoring 'running' hash found in whitelist")
else
conflict = MachineFingerprint.select('count(id) as count').where('user_id != ?', current_user.id).where(fingerprint: running_fingerprint).where(remote_ip: remote_ip).where('created_at > ?', APP_CONFIG.expire_fingerprint_days.days.ago).first
conflict_count = conflict['count'].to_i
if conflict_count >= APP_CONFIG.found_conflict_count
mf = MachineFingerprint.create(running_fingerprint, current_user, MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT, MachineFingerprint::PRINT_TYPE_ACTIVE, remote_ip, running_fingerprint_extra, self)
# record the alert
fraud = FraudAlert.create(mf, current_user) if mf.valid?
fraud_admin_url = fraud.admin_url if fraud
AdminMailer.alerts(subject: "'Running' fingerprint collision by #{current_user.name}",
body: "Current User: #{current_user.admin_url}\n\nFraud Alert: #{fraud_admin_url}").deliver\
# try to record the other fingerprint
mf = MachineFingerprint.create(all_fingerprint, current_user, MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT, MachineFingerprint::PRINT_TYPE_ALL, remote_ip, all_fingerprint_extra, self)
if APP_CONFIG.error_on_fraud
return "other user has 'running' fingerprint"
else
self.redeemed_and_fingerprinted = true
save!
return nil
end
end
end
end
# we made it past all checks; let's slap on the redeemed_fingerprint
self.redeemed_and_fingerprinted = true
MachineFingerprint.create(all_fingerprint, current_user, MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD, MachineFingerprint::PRINT_TYPE_ALL, remote_ip, self)
MachineFingerprint.create(all_fingerprint, current_user, MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD, MachineFingerprint::PRINT_TYPE_ALL, remote_ip, all_fingerprint_extra, self)
if all_fingerprint != running_fingerprint
MachineFingerprint.create(running_fingerprint, current_user, MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD, MachineFingerprint::PRINT_TYPE_ACTIVE, remote_ip, self)
MachineFingerprint.create(running_fingerprint, current_user, MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD, MachineFingerprint::PRINT_TYPE_ACTIVE, remote_ip, running_fingerprint_extra, self)
end
save!
@ -297,11 +339,12 @@ module JamRuby
def self.stats
stats = {}
result = JamTrackRight.select('count(id) as total, count(CASE WHEN signing_44 THEN 1 ELSE NULL END) + count(CASE WHEN signing_48 THEN 1 ELSE NULL END) as signing_count, count(CASE WHEN redeemed THEN 1 ELSE NULL END) as redeem_count').where(is_test_purchase: false).first
result = JamTrackRight.select('count(id) as total, count(CASE WHEN signing_44 THEN 1 ELSE NULL END) + count(CASE WHEN signing_48 THEN 1 ELSE NULL END) as signing_count, count(CASE WHEN redeemed THEN 1 ELSE NULL END) as redeem_count, count(CASE WHEN redeemed_and_fingerprinted THEN 1 ELSE NULL END) as redeemed_and_dl_count').where(is_test_purchase: false).first
stats['count'] = result['total'].to_i
stats['signing_count'] = result['signing_count'].to_i
stats['redeemed_count'] = result['redeem_count'].to_i
stats['redeemed_and_dl_count'] = result['redeem_and_dl_count'].to_i
stats['purchased_count'] = stats['count'] - stats['redeemed_count']
stats
end

View File

@ -0,0 +1,35 @@
module JamRuby
class MachineExtra < ActiveRecord::Base
@@log = Logging.logger[MachineExtra]
belongs_to :machine_fingerprint, :class_name => "JamRuby::MachineFingerprint"
def self.create(machine_fingerprint, data)
me = MachineExtra.new
me.machine_fingerprint = machine_fingerprint
me.mac_address = data[:mac]
me.mac_name = data[:name]
me.upstate = data[:upstate]
me.ipaddr_0 = data[:ipaddr_0]
me.ipaddr_1 = data[:ipaddr_1]
me.ipaddr_2 = data[:ipaddr_2]
me.ipaddr_3 = data[:ipaddr_3]
me.ipaddr_4 = data[:ipaddr_4]
me.ipaddr_5 = data[:ipaddr_5]
me.save
unless me.save
@@log.error("unable to create machine extra: #{me.errors.inspect}")
end
end
def admin_url
APP_CONFIG.admin_root_url + "/admin/machine_extras/" + id
end
def to_s
"#{mac_address} #{mac_name} #{upstate ? 'UP' : 'DOWN'} #{ipaddr_0} #{ipaddr_1} #{ipaddr_2} #{ipaddr_3} #{ipaddr_4} #{ipaddr_5}"
end
end
end

View File

@ -5,6 +5,8 @@ module JamRuby
belongs_to :user, :class_name => "JamRuby::User"
belongs_to :jam_track_right, :class_name => "JamRuby::JamTrackRight"
has_one :detail, :class_name => "JamRuby::MachineExtra"
belongs_to :fingerprint_whitelist, class_name: 'JamRuby::FingerprintWhitelist', foreign_key: :fingerprint
TAKEN_ON_SUCCESSFUL_DOWNLOAD = 'dl'
TAKEN_ON_FRAUD_CONFLICT = 'fc'
@ -15,11 +17,11 @@ module JamRuby
validates :user, presence:true
validates :when_taken, :inclusion => {:in => [TAKEN_ON_SUCCESSFUL_DOWNLOAD, TAKEN_ON_FRAUD_CONFLICT]}
validates :fingerprint, presence: true, uniqueness:true
validates :fingerprint, presence: true
validates :print_type, presence: true, :inclusion => {:in =>[PRINT_TYPE_ALL, PRINT_TYPE_ACTIVE]}
validates :remote_ip, presence: true
def self.create(fingerprint, user, when_taken, print_type, remote_ip, jam_track_right = nil)
def self.create(fingerprint, user, when_taken, print_type, remote_ip, extra, jam_track_right = nil)
mf = MachineFingerprint.new
mf.fingerprint = fingerprint
mf.user = user
@ -27,9 +29,21 @@ module JamRuby
mf.print_type = print_type
mf.remote_ip = remote_ip
mf.jam_track_right = jam_track_right
unless mf.save
if mf.save
MachineExtra.create(mf, extra) if extra
else
@@log.error("unable to create machine fingerprint: #{mf.errors.inspect}")
end
mf
end
def admin_url
APP_CONFIG.admin_root_url + "/admin/machine_fingerprints/" + id
end
def to_s
"#{fingerprint} #{remote_ip} #{user} #{detail}"
end
end
end

View File

@ -168,7 +168,8 @@ describe JamTrackRight do
JamTrackRight.stats.should eq('count' => 1,
'signing_count' => 0,
'redeemed_count' => 0,
'purchased_count' => 1)
'purchased_count' => 1,
'redeemed_and_dl_count' => 0)
end
it "two" do
@ -178,7 +179,8 @@ describe JamTrackRight do
JamTrackRight.stats.should eq('count' => 2,
'signing_count' => 0,
'redeemed_count' => 0,
'purchased_count' => 2)
'purchased_count' => 2,
'redeemed_and_dl_count' => 0)
right1.signing_44 = true
right1.save!
@ -188,7 +190,8 @@ describe JamTrackRight do
JamTrackRight.stats.should eq('count' => 2,
'signing_count' => 2,
'redeemed_count' => 0,
'purchased_count' => 2)
'purchased_count' => 2,
'redeemed_and_dl_count' => 0)
right1.redeemed = true
right1.save!
@ -196,7 +199,8 @@ describe JamTrackRight do
JamTrackRight.stats.should eq('count' => 2,
'signing_count' => 2,
'redeemed_count' => 1,
'purchased_count' => 1)
'purchased_count' => 1,
'redeemed_and_dl_count' => 0)
right2.is_test_purchase = true
right2.save!
@ -204,7 +208,8 @@ describe JamTrackRight do
JamTrackRight.stats.should eq('count' => 1,
'signing_count' => 1,
'redeemed_count' => 1,
'purchased_count' => 0)
'purchased_count' => 0,
'redeemed_and_dl_count' => 0)
end
end
@ -213,7 +218,9 @@ describe JamTrackRight do
let(:other) {FactoryGirl.create(:user)}
let(:first_fingerprint) { {all: 'all', running: 'running' } }
let(:new_fingerprint) { {all: 'all_2', running: 'running' } }
let(:full_fingerprint) { {all: :all_3, running: :running_3, all_3: { mac: "72:00:02:4C:1E:61", name: "en2", upstate: true }, running_3: { mac: "72:00:02:4C:1E:62", name: "en3", upstate: false } } }
let(:remote_ip) {'1.1.1.1'}
let(:remote_ip2) {'2.2.2.2'}
let(:jam_track_right) { FactoryGirl.create(:jam_track_right, user: user, redeemed: true, redeemed_and_fingerprinted: false) }
let(:jam_track_right_purchased) { FactoryGirl.create(:jam_track_right, user: user, redeemed: false, redeemed_and_fingerprinted: false) }
let(:jam_track_right_other) { FactoryGirl.create(:jam_track_right, user: other, redeemed: true, redeemed_and_fingerprinted: false) }
@ -233,16 +240,16 @@ describe JamTrackRight do
jam_track_right.redeemed_and_fingerprinted.should be_true
mf = MachineFingerprint.find_by_fingerprint(first_fingerprint[:all])
mf = MachineFingerprint.find_by_fingerprint('all')
mf.user.should eq(user)
mf.fingerprint.should eq(first_fingerprint[:all])
mf.fingerprint.should eq('all')
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD)
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ALL)
mf.jam_track_right.should eq(jam_track_right)
mf = MachineFingerprint.find_by_fingerprint(first_fingerprint[:running])
mf = MachineFingerprint.find_by_fingerprint('running')
mf.user.should eq(user)
mf.fingerprint.should eq(first_fingerprint[:running])
mf.fingerprint.should eq('running')
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD)
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ACTIVE)
mf.jam_track_right.should eq(jam_track_right)
@ -274,40 +281,80 @@ describe JamTrackRight do
end
it "protects against re-using fingerprint across users (conflicts on all fp)" do
first_fingerprint2 = first_fingerprint.clone
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
MachineFingerprint.count.should eq(2)
first_fingerprint[:running] = 'running_2'
jam_track_right_other.guard_against_fraud(other, first_fingerprint, remote_ip).should eq("other user has 'all' fingerprint")
first_fingerprint2[:running] = 'running_2'
jam_track_right_other.guard_against_fraud(other, first_fingerprint2, remote_ip).should eq("other user has 'all' fingerprint")
mf = MachineFingerprint.find_by_fingerprint(first_fingerprint[:running])
mf.user.should eq(other)
mf.fingerprint.should eq(first_fingerprint[:running])
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT)
mf = MachineFingerprint.find_by_fingerprint('running')
mf.user.should eq(user)
mf.fingerprint.should eq('running')
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD)
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ACTIVE)
mf.jam_track_right.should eq(jam_track_right_other)
MachineFingerprint.count.should eq(3)
mf.jam_track_right.should eq(jam_track_right)
MachineFingerprint.count.should eq(4)
end
it "protects against re-using fingerprint across users (conflicts on running fp)" do
first_fingerprint2 = first_fingerprint.clone
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
MachineFingerprint.count.should eq(2)
first_fingerprint[:all] = 'all_2'
jam_track_right_other.guard_against_fraud(other, first_fingerprint, remote_ip).should eq("other user has 'running' fingerprint")
first_fingerprint2[:all] = 'all_2'
jam_track_right_other.guard_against_fraud(other, first_fingerprint2, remote_ip).should eq("other user has 'running' fingerprint")
mf = MachineFingerprint.find_by_fingerprint(first_fingerprint[:all])
mf.user.should eq(other)
mf.fingerprint.should eq(first_fingerprint[:all])
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT)
mf = MachineFingerprint.find_by_fingerprint('all')
mf.user.should eq(user)
mf.fingerprint.should eq('all')
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD)
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ALL)
mf.jam_track_right.should eq(jam_track_right_other)
MachineFingerprint.count.should eq(3)
mf.jam_track_right.should eq(jam_track_right)
MachineFingerprint.count.should eq(4)
FraudAlert.count.should eq(1)
fraud = FraudAlert.first
fraud.user.should eq(other)
fraud.machine_fingerprint.should eq(MachineFingerprint.where(fingerprint:'running').where(user_id:other.id).first)
end
it "ignores whitelisted fingerprint" do
whitelist = FingerprintWhitelist.new
whitelist.fingerprint = first_fingerprint[:running]
whitelist.save!
first_fingerprint2 = first_fingerprint.clone
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
MachineFingerprint.count.should eq(2)
first_fingerprint2[:all] = 'all_2'
jam_track_right_other.guard_against_fraud(other, first_fingerprint2, remote_ip).should be_nil
FraudAlert.count.should eq(0)
end
it "does not conflict if same mac, but different IP address" do
first_fingerprint2 = first_fingerprint.clone
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
MachineFingerprint.count.should eq(2)
first_fingerprint2[:all] = 'all_2'
jam_track_right_other.guard_against_fraud(other, first_fingerprint2, remote_ip2).should eq(nil)
mf = MachineFingerprint.find_by_fingerprint('all')
mf.user.should eq(user)
mf.fingerprint.should eq('all')
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD)
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ALL)
mf.jam_track_right.should eq(jam_track_right)
MachineFingerprint.count.should eq(4)
FraudAlert.count.should eq(0)
end
# if you try to buy a regular jamtrack with a fingerprint belonging to another user? so what. you paid for it
it "allows re-use of fingerprint if jamtrack is a normal purchase" do
first_fingerprint2 = first_fingerprint.clone
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
MachineFingerprint.count.should eq(2)
jam_track_right_other_purchased.guard_against_fraud(other, first_fingerprint, remote_ip).should be_nil
jam_track_right_other_purchased.guard_against_fraud(other, first_fingerprint2, remote_ip).should be_nil
MachineFingerprint.count.should eq(2)
end
@ -319,13 +366,22 @@ describe JamTrackRight do
it "let's you download a free jamtrack if you have a second but undownloaded free one" do
right1 = FactoryGirl.create(:jam_track_right, user: user, redeemed: true, redeemed_and_fingerprinted: false)
first_fingerprint2 = first_fingerprint.clone
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
MachineFingerprint.count.should eq(2)
right1.guard_against_fraud(user, first_fingerprint, remote_ip).should eq('already redeemed another')
right1.guard_against_fraud(user, first_fingerprint2, remote_ip).should eq('already redeemed another')
MachineFingerprint.count.should eq(2)
end
it "creates metadata" do
right1 = FactoryGirl.create(:jam_track_right, user: user, redeemed: true, redeemed_and_fingerprinted: false)
jam_track_right.guard_against_fraud(user, full_fingerprint, remote_ip).should be_nil
MachineFingerprint.count.should eq(2)
MachineExtra.count.should eq(2)
end
end
end

View File

@ -198,6 +198,14 @@ def app_config
true
end
def expire_fingerprint_days
14
end
def found_conflict_count
1
end
private
def audiomixer_workspace_path

View File

@ -1478,12 +1478,13 @@
function enqueueJamTrack(options) {
var jamTrackId = options['id'];
delete options['id']
return $.ajax({
type: "POST",
url: '/api/jamtracks/enqueue/' + jamTrackId + '?' + $.param(options),
url: '/api/jamtracks/enqueue/' + jamTrackId,
dataType: "json",
contentType: 'applications/json'
data: options
});
}

View File

@ -196,9 +196,14 @@ class UsersController < ApplicationController
render :layout => "web"
end
# DO NOT USE CURRENT_USER IN THIS ROUTINE. IT'S CACHED FOR THE WHOLE SITE
# DO NOT USE CURRENT_USER IN THIS ROUTINE UNLESS REDIRECTING. IT'S CACHED FOR THE WHOLE SITE
def home
if current_user
redirect_to "/client#/home"
return
end
@no_user_dropdown = false
@promo_buzz = PromoBuzz.active
@ -209,7 +214,6 @@ class UsersController < ApplicationController
end
gon.signed_in = !current_user.nil?
render :layout => "web"
end

View File

@ -341,7 +341,9 @@ if defined?(Bundler)
config.remove_whitespace_credit_card = false
config.estimate_taxes = true
config.ad_sense_enabled = false
config.guard_against_fraud = false
config.guard_against_fraud = true
config.error_on_fraud = false
config.expire_fingerprint_days = 14
config.found_conflict_count = 1
end
end

View File

@ -15,6 +15,8 @@ describe ApiJamTracksController do
end
before(:each) do
FingerprintWhitelist.destroy_all
FraudAlert.destroy_all
MachineFingerprint.destroy_all
JamTrackRight.destroy_all
JamTrack.destroy_all
@ -299,6 +301,9 @@ describe ApiJamTracksController do
describe "guard fraud" do
after(:each) do
ENV['RAILS_TEST_IP_ADDRESS'] = nil
end
it "stops second user from downloading using same machine" do
right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
@ -306,6 +311,7 @@ describe ApiJamTracksController do
right.save!
get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
response.status.should == 202
MachineFingerprint.count.should eq(2)
user2 = FactoryGirl.create(:user)
@ -315,8 +321,10 @@ describe ApiJamTracksController do
right.redeemed = true
right.save!
get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
response.status.should == 403
JSON.parse(response.body)['message'].should eq("other user has 'all' fingerprint")
response.status.should == 202
# no error for the user... but we should have a FraudAlert
FraudAlert.count.should eq(1)
end
it "stops second user from enqueuing using same machine" do
@ -336,9 +344,10 @@ describe ApiJamTracksController do
right.save!
right.signing_queued_at.should be_nil
post :enqueue, {:format=>'json', :id=>right.jam_track.id, fingerprint: {all: 'all', running: 'running'} }
response.status.should == 200
get :download, :id=>@jam_track.id, sample_rate: 48, all_fp: 'all', running_fp: 'running'
response.status.should == 403
JSON.parse(response.body)['message'].should eq("other user has 'all' fingerprint")
response.status.should == 202
FraudAlert.count.should eq(1)
end
end
end

View File

@ -94,6 +94,14 @@ def web_config
def secret_token
'ced345e01611593c1b783bae98e4e56dbaee787747e92a141565f7c61d0ab2c6f98f7396fb4b178258301e2713816e158461af58c14b695901692f91e72b6200'
end
def expire_fingerprint_days
14
end
def found_conflict_count
1
end
end
klass.new
end

View File

@ -0,0 +1,17 @@
module ActionDispatch
class Request
def remote_ip_with_mocking
test_ip = ENV['RAILS_TEST_IP_ADDRESS']
unless test_ip.nil? or test_ip.empty?
return test_ip
else
return remote_ip_without_mocking
end
end
alias_method_chain :remote_ip, :mocking
end
end

View File

@ -225,7 +225,7 @@ def should_be_at_root(options={signed_in:nil})
find('h1', text: 'Live music platform & social network for musicians')
end
when Capybara::RackTest::Driver
signed_in = false # actually, the user may be signed in, but, we only redirect to /client in javascript, so RackTest won't do that
signed_in = !cookie_jar['remember_token'].nil?
if signed_in
find('h2', text: 'create session')
else