viking 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in viking.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Risk Danger Olson, James Herdman & Pierre-Louis Gottfrois
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,55 @@
1
+ # Viking
2
+
3
+ This is a fork of [Vikinggem](https://rubygems.org/gems/vikinggem). Bug fix and
4
+ new feature for this gem should be place here.
5
+
6
+ Viking brings you easy access to the [Akismet](http://akismet.com/), and [Defensio](http://www.defensio.com/) spam protection services, but without the need for you to use Rails. VikingGem is Ruby web framework agnostic.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'viking'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install viking
21
+
22
+ ## Usage
23
+
24
+ Viking.connect('akismet', api_key: '1234', blog: 'http://foo.com')
25
+
26
+ Spam or ham ?
27
+
28
+ Viking::Akismet.check_comment(options)
29
+
30
+ ## History
31
+
32
+ ### 1.0.0 2013-03-04
33
+
34
+ * Recreated new gem using current standards
35
+ * Fix some bugs
36
+
37
+ ### 0.0.3 2008-04-25
38
+
39
+ * Made contents of script/ executable
40
+
41
+ ### 0.0.2 2008-04-22
42
+
43
+ * Changed Manifest to include spec_helper.rb and website
44
+
45
+ ### 0.0.1 2008-04-22
46
+
47
+ * Initial release
48
+
49
+ ## Contributing
50
+
51
+ 1. Fork it
52
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
53
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
54
+ 4. Push to the branch (`git push origin my-new-feature`)
55
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,15 @@
1
+ require 'cgi'
2
+
3
+ class Object
4
+ unless method_defined?(:to_param)
5
+ def to_param
6
+ to_s
7
+ end
8
+ end
9
+
10
+ unless method_defined?(:to_query)
11
+ def to_query(key)
12
+ [CGI.escape(key.to_s), CGI.escape(to_param.to_s)].join('=')
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,35 @@
1
+ class Hash
2
+ unless method_defined?(:symbolize_keys)
3
+ def symbolize_keys
4
+ inject({}) do |options, (key, value)|
5
+ options[(key.to_sym rescue key) || key] = value
6
+ options
7
+ end
8
+ end
9
+ end
10
+
11
+ unless method_defined?(:dasherize_keys)
12
+ def dasherize_keys
13
+ inject({}) do |options, (key, value)|
14
+ options[key.to_s.gsub(/_/, '-')] = value
15
+ options
16
+ end
17
+ end
18
+ end
19
+
20
+ unless method_defined?(:to_query) && method(:to_query).arity == -1
21
+ def to_query(namespace=nil)
22
+ collect do |key, value|
23
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
24
+ end.sort * '&'
25
+ end
26
+ end
27
+ end
28
+
29
+ class Array
30
+ unless method_defined?(:to_query) && method(:to_query).arity == -1
31
+ def to_query(key)
32
+ collect { |value| value.to_query("#{key}[]") } * '&'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,80 @@
1
+ require "core_ext/object"
2
+ require "core_ext/transformations"
3
+ require "viking/version"
4
+
5
+ # = Description
6
+ # Provides a simple interface to polymorphically access to the spam protection
7
+ # service of your choice.
8
+ #
9
+ # = Usage
10
+ # I find it useful to first initialize Viking in a separate file during
11
+ # framework initialization. Rails initializers, for instance, work great for
12
+ # this. An example of such an initializer would be as follows:
13
+ #
14
+ # Viking.default_engie = 'defensio'
15
+ # Viking.connect_options = { :api_key => '1234abc' }
16
+ #
17
+ # From this point out, Viking should have everything it needs to access the
18
+ # service of your choice. Merely call methods on your service of choice as
19
+ # documented. For instance:
20
+ #
21
+ # Viking.mark_as_spam(:signaturs => "1234abc")
22
+ module Viking
23
+ class Error < StandardError; end
24
+
25
+ autoload :Akismet, 'viking/akismet'
26
+ autoload :Defensio, 'viking/defensio'
27
+
28
+ class << self
29
+
30
+ attr_accessor :logger
31
+ attr_accessor :default_engine
32
+ attr_accessor :connect_options
33
+ attr_writer :default_instance
34
+
35
+ def default_instance
36
+ @default_instance ||= connect(self.default_engine, self.connect_options)
37
+ end
38
+
39
+ def enabled?
40
+ !self.default_instance.nil?
41
+ end
42
+
43
+ def connect(engine, options)
44
+ unless engine.nil? || engine.empty?
45
+ Viking.const_get(engine.to_s.capitalize).new(options)
46
+ end
47
+ end
48
+
49
+ def verified?
50
+ self.default_instance.verified?
51
+ end
52
+
53
+ def check_article(options = {})
54
+ self.default_instance.check_article(options)
55
+ end
56
+
57
+ def check_comment(options = {})
58
+ self.default_instance.check_comment(options)
59
+ end
60
+
61
+ def mark_as_spam(options = {})
62
+ self.default_instance.mark_as_spam(options)
63
+ end
64
+
65
+ def mark_as_ham(options = {})
66
+ self.default_instance.mark_as_ham(options)
67
+ end
68
+
69
+ def stats
70
+ self.default_instance.stats
71
+ end
72
+
73
+ def mark_as_spam_or_ham(is_spam, options = {})
74
+ self.default_instance.mark_as_spam_or_ham(is_spam, options)
75
+ end
76
+
77
+ end
78
+ end
79
+
80
+ require "viking/base"
@@ -0,0 +1,203 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'set'
4
+
5
+ # Akismet
6
+ #
7
+ # Author:: David Czarnecki
8
+ # Copyright:: Copyright (c) 2005 - David Czarnecki
9
+ # License:: BSD
10
+ #
11
+ # Rewritten to be more agnostic
12
+ module Viking
13
+ class Akismet < Base
14
+
15
+ class << self
16
+
17
+ attr_accessor :valid_responses
18
+ attr_accessor :normal_responses
19
+ attr_accessor :standard_headers
20
+ attr_accessor :host
21
+ attr_accessor :port
22
+
23
+ end
24
+
25
+ self.host = 'rest.akismet.com'
26
+ self.port = 80
27
+ self.valid_responses = Set.new(['false', ''])
28
+ self.normal_responses = valid_responses.dup << 'true'
29
+ self.standard_headers = {
30
+ 'User-Agent' => "Viking (Ruby Gem) v#{Viking::VERSION}",
31
+ 'Content-Type' => 'application/x-www-form-urlencoded'
32
+ }
33
+
34
+ # Create a new instance of the Akismet class
35
+ #
36
+ # ==== Arguments
37
+ # Arguments are provided in the form of a Hash with the following keys
38
+ # (as Symbols) available:
39
+ #
40
+ # +api_key+:: your Akismet API key
41
+ # +blog+:: the blog associated with your api key
42
+ #
43
+ # The following keys are available and are entirely optional. They are
44
+ # available incase communication with Akismet's servers requires a
45
+ # proxy port and/or host:
46
+ #
47
+ # * +proxy_port+
48
+ # * +proxy_host+
49
+ def initialize(options)
50
+ super
51
+ self.verified_key = false
52
+ end
53
+
54
+ # Returns +true+ if the API key has been verified, +false+ otherwise
55
+ def verified?
56
+ (@verified_key ||= verify_api_key) != :false
57
+ end
58
+
59
+ # This is basically the core of everything. This call takes a number of
60
+ # arguments and characteristics about the submitted content and then
61
+ # returns a thumbs up or thumbs down. Almost everything is optional, but
62
+ # performance can drop dramatically if you exclude certain elements.
63
+ #
64
+ # ==== Arguments
65
+ # +options+ <Hash>:: describes the comment being verified
66
+ #
67
+ # The following keys are available for the +options+ hash:
68
+ #
69
+ # +user_ip+ (*required*)::
70
+ # IP address of the comment submitter.
71
+ # +user_agent+ (*required*)::
72
+ # user agent information.
73
+ # +referrer+ (<i>note spelling</i>)::
74
+ # the content of the HTTP_REFERER header should be sent here.
75
+ # +permalink+::
76
+ # permanent location of the entry the comment was submitted to
77
+ # +comment_type+::
78
+ # may be blank, comment, trackback, pingback, or a made up value like
79
+ # "registration".
80
+ # +comment_author+::
81
+ # submitted name with the comment
82
+ # +comment_author_email+::
83
+ # submitted email address
84
+ # +comment_author_url+::
85
+ # commenter URL
86
+ # +comment_content+::
87
+ # the content that was submitted
88
+ # Other server enviroment variables::
89
+ # In PHP there is an array of enviroment variables called <tt>_SERVER</tt>
90
+ # which contains information about the web server itself as well as a
91
+ # key/value for every HTTP header sent with the request. This data is
92
+ # highly useful to Akismet as how the submited content interacts with
93
+ # the server can be very telling, so please include as much information
94
+ # as possible.
95
+ def check_comment(options = {})
96
+ return false if invalid_options?
97
+ message = call_akismet('comment-check', options)
98
+ { :spam => !self.class.valid_responses.include?(message), :message => message }
99
+ end
100
+
101
+ # This call is for submitting comments that weren't marked as spam but
102
+ # should have been (i.e. false negatives). It takes identical arguments as
103
+ # +check_comment+.
104
+ def mark_as_spam(options = {})
105
+ return false if invalid_options?
106
+ { :message => call_akismet('submit-spam', options) }
107
+ end
108
+
109
+ # This call is intended for the marking of false positives, things that
110
+ # were incorrectly marked as spam. It takes identical arguments as
111
+ # +check_comment+ and +mark_as_spam+.
112
+ def mark_as_ham(options = {})
113
+ return false if invalid_options?
114
+ { :message => call_akismet('submit-ham', options) }
115
+ end
116
+
117
+ # Returns the URL for an Akismet request
118
+ #
119
+ # ==== Arguments
120
+ # +action+ <~to_s>:: a valid Akismet function name
121
+ #
122
+ # ==== Returns
123
+ # String
124
+ def self.url(action)
125
+ "/1.1/#{action}"
126
+ end
127
+
128
+ protected
129
+
130
+ # Internal call to Akismet. Prepares the data for posting to the Akismet
131
+ # service.
132
+ #
133
+ # ==== Arguments
134
+ # +akismet_function+ <String>::
135
+ # the Akismet function that should be called
136
+ #
137
+ # The following keys are available to configure a given call to Akismet:
138
+ #
139
+ # +user_ip+ (*required*)::
140
+ # IP address of the comment submitter.
141
+ # +user_agent+ (*required*)::
142
+ # user agent information.
143
+ # +referrer+ (<i>note spelling</i>)::
144
+ # the content of the HTTP_REFERER header should be sent here.
145
+ # +permalink+::
146
+ # the permanent location of the entry the comment was submitted to.
147
+ # +comment_type+::
148
+ # may be blank, comment, trackback, pingback, or a made up value like
149
+ # "registration".
150
+ # +comment_author+::
151
+ # submitted name with the comment
152
+ # +comment_author_email+::
153
+ # submitted email address
154
+ # +comment_author_url+::
155
+ # commenter URL
156
+ # +comment_content+::
157
+ # the content that was submitted
158
+ # Other server enviroment variables::
159
+ # In PHP there is an array of enviroment variables called <tt>_SERVER</tt>
160
+ # which contains information about the web server itself as well as a
161
+ # key/value for every HTTP header sent with the request. This data is
162
+ # highly useful to Akismet as how the submited content interacts with
163
+ # the server can be very telling, so please include as much information
164
+ # as possible.
165
+ def call_akismet(akismet_function, options = {})
166
+ http_post(
167
+ Net::HTTP.new([self.options[:api_key], self.class.host].join('.'), options[:proxy_host], options[:proxy_port]),
168
+ akismet_function,
169
+ options.update(:blog => self.options[:blog]).to_query
170
+ )
171
+ end
172
+
173
+ # Call to check and verify your API key. You may then call the
174
+ # <tt>verified?</tt> method to see if your key has been validated
175
+ def verify_api_key
176
+ return :false if invalid_options?
177
+ value = http_post(
178
+ Net::HTTP.new(self.class.host, self.class.port, options[:proxy_host], options[:proxy_port]),
179
+ 'verify-key',
180
+ {
181
+ :key => self.options[:api_key],
182
+ :blog => self.options[:blog]
183
+ }.to_query
184
+ )
185
+ self.verified_key = (value == 'valid') ? true : :false
186
+ end
187
+
188
+ def http_post(http, action, data)
189
+ resp = http.post(self.url(action), data, self.class.standard_headers)
190
+ log_request(self.url(action), data, resp)
191
+ resp.body
192
+ end
193
+
194
+ def url(action)
195
+ "/1.1/#{action}"
196
+ end
197
+
198
+ private
199
+
200
+ attr_accessor :verified_key
201
+
202
+ end
203
+ end
@@ -0,0 +1,74 @@
1
+ module Viking
2
+ class Base
3
+
4
+ attr_accessor :options
5
+
6
+ def initialize(options = {})
7
+ self.options = options
8
+ end
9
+
10
+ def verified?
11
+ end
12
+
13
+ def check_article(options = {})
14
+ end
15
+
16
+ def check_comment(options = {})
17
+ end
18
+
19
+ def mark_as_spam(options = {})
20
+ end
21
+
22
+ def mark_as_ham(options = {})
23
+ end
24
+
25
+ # Automatically determines whether to mark as spam or ham depending on a
26
+ # boolean switch, +is_spam+. The post will be marked as spam when
27
+ # +is_spam+ is +true+. The post will be marked as ham if +is_spam+ is
28
+ # +false+.
29
+ #
30
+ # ==== Arguments
31
+ # +is_spam+ <Boolean>::
32
+ # determines whether to mark a post as spam or ham -- spam when true,
33
+ # ham when false
34
+ #
35
+ # +options+ <Hash>::
36
+ # any options either +mark_as_spam+ or +mark_as_ham+ accepts
37
+ def mark_as_spam_or_ham(is_spam, options = {})
38
+ is_spam ? mark_as_spam(options) : mark_as_ham(options)
39
+ end
40
+
41
+ def stats
42
+ end
43
+
44
+ def logger
45
+ Viking.logger
46
+ end
47
+
48
+ def self.logger
49
+ Viking.logger
50
+ end
51
+
52
+ # Checks to ensure that the minimum number of +options+ have been provided
53
+ # to make a call to the spam protection service.
54
+ #
55
+ # Required options include:
56
+ # * +api_key+
57
+ # * +blog+
58
+ #
59
+ # See the module for your desired spam protection service for details on
60
+ # the format of these options.
61
+ def invalid_options?
62
+ self.options[:api_key].nil? || self.options[:blog].nil?
63
+ end
64
+
65
+ protected
66
+
67
+ def log_request(url, data, response)
68
+ return unless logger
69
+ logger.info("[#{self.class.name}] POST '%s' with %s" % [url, data])
70
+ logger.debug(">> #{response.body.inspect}")
71
+ end
72
+
73
+ end
74
+ end