Require tokens in header or params (not cookies) - #210
Andrew Kane
committed Aug 23, 2016
commit b3b7b2865cb482bdd426211c895346b7ac431ac6
Showing 2
changed files with
90 additions
and 19 deletions
ahoy/tracker.rb b/lib/ahoy/tracker.rb
+77
-15
| @@ | @@ -12,6 +12,8 @@ module Ahoy |
| def track(name, properties = {}, options = {}) | |
| if exclude? | |
| debug "Event excluded" | |
| + | elsif missing_params? |
| + | debug "Missing required parameters" |
| else | |
| options = options.dup | |
| @@ | @@ -28,6 +30,8 @@ module Ahoy |
| def track_visit(options = {}) | |
| if exclude? | |
| debug "Visit excluded" | |
| + | elsif missing_params? |
| + | debug "Missing required parameters" |
| else | |
| if options[:defer] | |
| set_cookie("ahoy_track", true, nil, false) | |
| @@ | @@ -60,15 +64,19 @@ module Ahoy |
| end | |
| def visit_id | |
| - | @visit_id ||= ensure_uuid(existing_visit_id || visit_token_helper) |
| + | @visit_id ||= ensure_uuid(visit_token_helper) |
| end | |
| def visitor_id | |
| - | @visitor_id ||= ensure_uuid(existing_visitor_id || visitor_token_helper) |
| + | @visitor_id ||= ensure_uuid(visitor_token_helper) |
| end | |
| def new_visit? | |
| - | !existing_visit_id |
| + | !existing_visit_token |
| + | end |
| + | |
| + | def new_visitor? |
| + | !existing_visitor_token |
| end | |
| def set_visit_cookie | |
| @@ | @@ -76,7 +84,7 @@ module Ahoy |
| end | |
| def set_visitor_cookie | |
| - | unless existing_visitor_id |
| + | if new_visitor? |
| set_cookie("ahoy_visitor", visitor_id, Ahoy.visitor_duration) | |
| end | |
| end | |
| @@ | @@ -87,7 +95,7 @@ module Ahoy |
| # TODO better name | |
| def visit_properties | |
| - | @visit_properties ||= Ahoy::VisitProperties.new(request, @options.slice(:api)) |
| + | @visit_properties ||= Ahoy::VisitProperties.new(request, api: api?) |
| end | |
| def visit_token | |
| @@ | @@ -100,12 +108,16 @@ module Ahoy |
| protected | |
| - | def visit_token_helper |
| - | @visit_token_helper ||= existing_visit_id || (@options[:api] && request.params["visit_token"]) || (Ahoy.api_only ? nil : generate_id) |
| + | def api? |
| + | @options[:api] |
| end | |
| - | def visitor_token_helper |
| - | @visitor_token_helper ||= existing_visitor_id || (@options[:api] && request.params["visitor_token"]) || (Ahoy.api_only ? nil : generate_id) |
| + | def missing_params? |
| + | if api? && Ahoy.protect_from_forgery |
| + | !(existing_visit_token && existing_visitor_token) |
| + | else |
| + | false |
| + | end |
| end | |
| def set_cookie(name, value, duration = nil, use_domain = true) | |
| @@ | @@ -119,7 +131,7 @@ module Ahoy |
| end | |
| def trusted_time(time) | |
| - | if !time || (@options[:api] && !(1.minute.ago..Time.now).cover?(time)) |
| + | if !time || (api? && !(1.minute.ago..Time.now).cover?(time)) |
| Time.zone.now | |
| else | |
| time | |
| @@ | @@ -145,12 +157,62 @@ module Ahoy |
| @store.generate_id | |
| end | |
| - | def existing_visit_id |
| - | @existing_visit_id ||= request && (request.headers["Ahoy-Visit"] || request.cookies["ahoy_visit"]) |
| + | def visit_token_helper |
| + | @visit_token_helper ||= begin |
| + | token = existing_visit_token |
| + | token ||= generate_id unless api? |
| + | token |
| + | end |
| + | end |
| + | |
| + | def visitor_token_helper |
| + | @visitor_token_helper ||= begin |
| + | token = existing_visitor_token |
| + | token ||= generate_id unless api? |
| + | token |
| + | end |
| + | end |
| + | |
| + | def existing_visit_token |
| + | @existing_visit_token ||= begin |
| + | token = visit_header |
| + | token ||= visit_cookie unless api? && Ahoy.protect_from_forgery |
| + | token ||= visit_param if api? |
| + | token |
| + | end |
| + | end |
| + | |
| + | def existing_visitor_token |
| + | @existing_visitor_token ||= begin |
| + | token = visitor_header |
| + | token ||= visitor_cookie unless api? && Ahoy.protect_from_forgery |
| + | token ||= visitor_param if api? |
| + | token |
| + | end |
| + | end |
| + | |
| + | def visit_cookie |
| + | @visit_cookie ||= request && request.cookies["ahoy_visit"] |
| + | end |
| + | |
| + | def visitor_cookie |
| + | @visitor_cookie ||= request && request.cookies["ahoy_visitor"] |
| + | end |
| + | |
| + | def visit_header |
| + | @visit_header ||= request && request.headers["Ahoy-Visit"] |
| + | end |
| + | |
| + | def visitor_header |
| + | @visitor_header ||= request && request.headers["Ahoy-Visitor"] |
| + | end |
| + | |
| + | def visit_param |
| + | @visit_param ||= request && request.params["visit_token"] |
| end | |
| - | def existing_visitor_id |
| - | @existing_visitor_id ||= request && (request.headers["Ahoy-Visitor"] || request.cookies["ahoy_visitor"]) |
| + | def visitor_param |
| + | @visitor_param ||= request && request.params["visitor_token"] |
| end | |
| def ensure_uuid(id) | |
| @@ | @@ -158,7 +220,7 @@ module Ahoy |
| end | |
| def ensure_token(token) | |
| - | token.to_s.gsub(/[^a-z0-9\-]/i, "").first(64) |
| + | token.to_s.gsub(/[^a-z0-9\-]/i, "").first(64) if token |
| end | |
| def debug(message) | |
vendor/assets/javascripts/ahoy.js
+13
-4
| @@ | @@ -158,9 +158,20 @@ |
| } | |
| } | |
| + | function eventData(event) { |
| + | var data = { |
| + | events: [event], |
| + | visit_token: event.visit_token, |
| + | visitor_token: event.visitor_token |
| + | }; |
| + | delete event.visit_token; |
| + | delete event.visitor_token; |
| + | return data; |
| + | } |
| + | |
| function trackEvent(event) { | |
| ready( function () { | |
| - | sendRequest(eventsUrl(), {events: [event]}, function() { |
| + | sendRequest(eventsUrl(), eventData(event), function() { |
| // remove from queue | |
| for (var i = 0; i < eventQueue.length; i++) { | |
| if (eventQueue[i].id == event.id) { | |
| @@ | @@ -175,9 +186,7 @@ |
| function trackEventNow(event) { | |
| ready( function () { | |
| - | var data = { |
| - | events: [event] |
| - | } |
| + | var data = eventData(event); |
| var param = csrfParam(); | |
| var token = csrfToken(); | |
| if (param && token) data[param] = token; | |