sniffles 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
1
  --color
2
- --format progress
2
+ --format documentation
data/Guardfile CHANGED
@@ -1,4 +1,4 @@
1
- guard 'rspec', :version => 2 do
1
+ guard 'rspec', :cli => '--color --format=documentation', :version => 2 do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
3
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
4
  watch('spec/spec_helper.rb') { "spec" }
@@ -0,0 +1,19 @@
1
+ module Sniffles
2
+ module HTML
3
+ def parse(html)
4
+ @doc = Nokogiri::HTML(html)
5
+ end
6
+
7
+ def text_at(pattern)
8
+ if (nodes = @doc.search(pattern)).any?
9
+ nodes.text
10
+ else
11
+ false
12
+ end
13
+ end
14
+
15
+ def text_match?(pattern, text)
16
+ (@doc.search(pattern).text == text)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ module Sniffles
2
+ module Sniffers
3
+ class GoogleAnalytics
4
+ include Text
5
+
6
+ attr_accessor :doc
7
+ attr_reader :output
8
+
9
+ def initialize(response_body)
10
+ @output = {}
11
+ parse(response_body) && process_document
12
+ end
13
+
14
+ def process_document
15
+ @output[:found] = google_analytics?
16
+ parse_google_analytics_ua
17
+ end
18
+
19
+ private
20
+ def google_analytics?
21
+ match?(/\.google\-analytics\.com|urchinTracker/i)
22
+ end
23
+
24
+ def parse_google_analytics_ua
25
+ @output[:ua] = capture(/[\"|\'](UA\-[\d]+\-[\d])[\"|\']/)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ module Sniffles
2
+ module Sniffers
3
+ class Mixpanel
4
+ include Text
5
+
6
+ attr_accessor :doc
7
+ attr_reader :output
8
+
9
+ def initialize(response_body)
10
+ @output = {}
11
+ parse(response_body) && process_document
12
+ end
13
+
14
+ def process_document
15
+ @output[:found] = mixpanel?
16
+ end
17
+
18
+ private
19
+ def mixpanel?
20
+ match?(/api\.mixpanel\.com\S+mixpanel\.js/)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module Sniffles
2
+ module Sniffers
3
+ class Quantcast
4
+ include Text
5
+
6
+ attr_accessor :doc
7
+ attr_reader :output
8
+
9
+ def initialize(response_body)
10
+ @output = {}
11
+ parse(response_body) && process_document
12
+ end
13
+
14
+ def process_document
15
+ @output[:found] = quantcast?
16
+ end
17
+
18
+ private
19
+ def quantcast?
20
+ match?(/\.quantserve\.com\/quant\.js/)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ module Sniffles
2
+ module Sniffers
3
+ class Wordpress
4
+ include HTML
5
+ attr_accessor :doc
6
+ attr_reader :name, :group, :output, :response
7
+
8
+ def initialize(response_body)
9
+ @output = {}
10
+ parse(response_body) && process_document
11
+ end
12
+
13
+ def process_document
14
+ @output[:found] = wordpress?
15
+ parse_version
16
+ parse_feed
17
+ parse_theme
18
+ parse_pingback
19
+ end
20
+
21
+ private
22
+ def wordpress?
23
+ @doc.xpath('//link[contains(@href,"wp-content")]').any?
24
+ end
25
+
26
+ def parse_feed
27
+ @output[:feed] = text_at("//link[@rel='alternate' and @type='application/rss+xml']/@href")
28
+ end
29
+
30
+ def parse_theme
31
+ theme_uri = text_at("//link[@rel='stylesheet' and contains(@href,'wp-content/themes/')][1]/@href")
32
+ @output[:theme] = (theme_uri ? clean_theme_uri(theme_uri)[1] : false)
33
+ end
34
+
35
+ def parse_version
36
+ version_meta_tag = text_at("//meta[@name='generator']/@content")
37
+ @output[:version] = (version_meta_tag ? extract_version(version_meta_tag)[1] : version_meta_tag)
38
+ end
39
+
40
+ def parse_pingback
41
+ @output[:pingback] = text_at("//link[@rel='pingback']/@href")
42
+ end
43
+
44
+ def clean_theme_uri(uri)
45
+ /wp-content\/themes\/([^\/]*)\//i.match uri
46
+ end
47
+
48
+ def extract_version(string)
49
+ /([\d]+\.[\d]+[\.]?[\d]?)/.match string
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,24 @@
1
+ module Sniffles
2
+ module Sniffers
3
+ class Jquery
4
+ include Text
5
+
6
+ attr_accessor :doc
7
+ attr_reader :output
8
+
9
+ def initialize(response_body)
10
+ @output = {}
11
+ parse(response_body) && process_document
12
+ end
13
+
14
+ def process_document
15
+ @output[:found] = jquery?
16
+ end
17
+
18
+ private
19
+ def jquery?
20
+ match?(/jQuery/)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ module Sniffles
2
+ module Sniffers
3
+ def self.use(response_body, name)
4
+ file = Dir.glob("lib/sniffles/sniffers/**/#{name.to_s}.rb").first
5
+ class_name = get_sniffer_class(name.to_s)
6
+ require File.expand_path(File.dirname(__FILE__) + "/../../#{file}")
7
+ eval("Sniffers::#{class_name}.new(response_body).output")
8
+ end
9
+
10
+ def self.list_all(group = "**")
11
+ Dir.glob("lib/sniffles/sniffers/#{group}/*.rb").collect do |sniffer|
12
+ sniffer.match(/sniffers\/[a-z]+\/(.*)\.rb$/)[1].to_sym
13
+ end
14
+ end
15
+
16
+ def self.list_groups
17
+ Dir.glob("lib/sniffles/sniffers/**").collect { |group| group.match(/sniffers\/(.*)$/)[1].to_sym }
18
+ end
19
+
20
+ def self.list_all_by_group
21
+ output = {}
22
+ list_groups.each { |group| output[group] = list_all(group).to_a }
23
+ output
24
+ end
25
+
26
+ def self.get_sniffer_class(name)
27
+ name.gsub(/\/(.?)/) { "::#{ $1.upcase }" }.gsub(/(?:^|[_-])(.)/) { $1.upcase }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ module Sniffles
2
+ module Text
3
+ def parse(text)
4
+ @doc = text
5
+ end
6
+
7
+ def match?(pattern)
8
+ !!(pattern.match(@doc))
9
+ end
10
+
11
+ def capture(pattern)
12
+ (captures = pattern.match(@doc)) ? captures[1] : false
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Sniffles
2
+ module Utils
3
+ def self.absolute_uri(host, path)
4
+ URI.parse(host).merge(URI.parse(path)).to_s
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module Sniffles
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/sniffles.rb CHANGED
@@ -1,33 +1,46 @@
1
1
  require 'nokogiri'
2
2
 
3
- require "sniffles/version"
3
+ require 'sniffles/version'
4
+ require 'sniffles/sniffers'
5
+ require 'sniffles/utils'
6
+ require 'sniffles/html'
7
+ require 'sniffles/text'
4
8
 
5
- module Sniffles
6
- def self.sniff(html)
7
- doc = Nokogiri::HTML::parse(html)
8
-
9
+ module Sniffles
10
+ def self.sniff(response_body, *sniffers_or_groups)
9
11
  output = {}
10
- output[:wordpress] = true if wordpress?(doc)
11
- output[:jquery] = true if jquery?(html)
12
- output[:quantcast] = true if quantcast?(html)
13
- output[:mixpanel] = true if mixpanel?(html)
14
12
 
13
+ if sniffers_or_groups.empty?
14
+ list_all.each do |sniffer|
15
+ output[sniffer] = Sniffers.use(response_body, sniffer)
16
+ end
17
+ else
18
+ sniffers_or_groups.each do |sniffer_or_group|
19
+ if list_all.include?(sniffer_or_group)
20
+ output[sniffer_or_group] = Sniffers.use(response_body, sniffer_or_group)
21
+ elsif list_groups.include?(sniffer_or_group)
22
+ list_all_by_group[sniffer_or_group].each do |sniffer|
23
+ output[sniffer] = Sniffers.use(response_body, sniffer)
24
+ end
25
+ else
26
+ raise UnknownSniffer, "#{sniffer_or_group} not found!"
27
+ end
28
+ end
29
+ end
15
30
  output
16
31
  end
17
32
 
18
- def self.wordpress?(doc)
19
- !doc.xpath('.//link[contains(@href,"wp-content")]').empty?
33
+ def self.list_all
34
+ Sniffers.list_all
20
35
  end
21
-
22
- def self.jquery?(html)
23
- !!(html =~ /jQuery/)
36
+
37
+ def self.list_groups
38
+ Sniffers.list_groups
24
39
  end
25
40
 
26
- def self.quantcast?(html)
27
- !!(html =~ /\.quantserve\.com\/quant\.js/)
28
- end
29
-
30
- def self.mixpanel?(html)
31
- !!(html =~ /api.mixpanel.com\S+mixpanel.js/)
41
+ def self.list_all_by_group
42
+ Sniffers.list_all_by_group
32
43
  end
44
+
45
+ class UnknownSniffer < Exception;end
33
46
  end