* VRFS-3260 - fraud check code and admin helpers complete
This commit is contained in:
parent
48f61552ce
commit
c96f0a7859
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue