dodgy_stalker 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/Gemfile +5 -0
- data/LICENSE +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/dodgy_stalker.gemspec +33 -0
- data/lib/dodgy_stalker/config.rb +9 -0
- data/lib/dodgy_stalker/data_store/blacklist.rb +9 -0
- data/lib/dodgy_stalker/data_store/common.rb +35 -0
- data/lib/dodgy_stalker/data_store/whitelist.rb +14 -0
- data/lib/dodgy_stalker/data_store/wordlist.rb +72 -0
- data/lib/dodgy_stalker/data_store.rb +10 -0
- data/lib/dodgy_stalker/engines/banned_words.rb +43 -0
- data/lib/dodgy_stalker/engines/blacklist.rb +55 -0
- data/lib/dodgy_stalker/engines/stop_forum_spam.rb +41 -0
- data/lib/dodgy_stalker/engines.rb +8 -0
- data/lib/dodgy_stalker/policy.rb +18 -0
- data/lib/dodgy_stalker/version.rb +3 -0
- data/lib/dodgy_stalker.rb +36 -0
- data/lib/generators/dodgy_stalker/migration_generator.rb +24 -0
- data/lib/generators/dodgy_stalker/templates/migration.rb +36 -0
- data/spec/datastores/blacklist_spec.rb +40 -0
- data/spec/datastores/whitelist_spec.rb +44 -0
- data/spec/datastores/wordlist_spec.rb +21 -0
- data/spec/engines/banned_words_spec.rb +61 -0
- data/spec/engines/blacklist_spec.rb +67 -0
- data/spec/engines/stop_form_spam_spec.rb +19 -0
- data/spec/migrations/001_create_dodgy_stalker_tables.rb +36 -0
- data/spec/policy_spec.rb +17 -0
- data/spec/spec_helper.rb +27 -0
- metadata +238 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 49d60a3dcc9fdc99c8ace0e7b52f5c154ff7e789
|
4
|
+
data.tar.gz: 9f0b6893003afbdbf4b7de4b9b0ea122a74935f7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 19eed3bc970fcd54a81bd745522d8d0e2fcd8552c51927d5a8f8d6a5df90a485abcf1ca66668f934dcb13974439947eb746a724493fcba0ae9a8c2dc0a823c13
|
7
|
+
data.tar.gz: 03d729e57525e13ee9616d5f63e51ea7463c9eb808e8ccb592d4957c937f6d380fb670676cd844304b9d42b4bb3b92c2bb82ca1af944332bd47bf2f0429b0cbf
|
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
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
|
18
|
+
# YARD artifacts
|
19
|
+
.yardoc
|
20
|
+
_yardoc
|
21
|
+
doc/
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Robert Ulejczyk
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 robuye
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# DodgyStalker
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'dodgy_stalker'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install dodgy_stalker
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dodgy_stalker/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dodgy_stalker"
|
8
|
+
spec.version = DodgyStalker::VERSION
|
9
|
+
spec.authors = ["robuye"]
|
10
|
+
spec.email = ["rulejczyk@gmail.com"]
|
11
|
+
spec.description = %q{Filters to detect spam, trolls and unwanted content}
|
12
|
+
spec.summary = %q{Filters to detect spam, trolls and unwanted content}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "rspec-expectations"
|
25
|
+
spec.add_development_dependency "rspec-mocks"
|
26
|
+
spec.add_development_dependency "pry"
|
27
|
+
spec.add_development_dependency "pg"
|
28
|
+
spec.add_development_dependency "database_cleaner"
|
29
|
+
|
30
|
+
spec.add_dependency "activerecord", "~> 4.0"
|
31
|
+
spec.add_dependency "typhoeus"
|
32
|
+
spec.add_dependency "addressable"
|
33
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module DodgyStalker
|
2
|
+
module DataStore
|
3
|
+
module Common
|
4
|
+
def on_list(attributes)
|
5
|
+
model.where(attributes_conditions(attributes))
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(attributes)
|
9
|
+
model.where(attributes).first_or_create
|
10
|
+
end
|
11
|
+
|
12
|
+
def remove(attr)
|
13
|
+
conditions = attributes.with_indifferent_access.except(:id, :created_at, :updated_at).merge(attr)
|
14
|
+
model.where(conditions).delete_all
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
#Build OR query from non-empty attributes
|
20
|
+
def attributes_conditions(attributes)
|
21
|
+
attributes.reject {|k,v| v.nil?}.
|
22
|
+
map {|attribute, value| arel_table[attribute].eq(value) }.
|
23
|
+
inject(:or)
|
24
|
+
end
|
25
|
+
|
26
|
+
def arel_table
|
27
|
+
model.arel_table
|
28
|
+
end
|
29
|
+
|
30
|
+
def model
|
31
|
+
self.class
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module DodgyStalker
|
2
|
+
module DataStore
|
3
|
+
class Whitelist < ActiveRecord::Base
|
4
|
+
self.table_name = 'whitelist'
|
5
|
+
|
6
|
+
include Common
|
7
|
+
|
8
|
+
def on_list(attr)
|
9
|
+
conditions = attributes.with_indifferent_access.except(:id, :created_at, :updated_at).merge(attr)
|
10
|
+
model.where(conditions)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module DodgyStalker
|
2
|
+
module DataStore
|
3
|
+
class Wordlist < ActiveRecord::Base
|
4
|
+
self.table_name = 'wordlist'
|
5
|
+
|
6
|
+
before_save :regexscape_word
|
7
|
+
|
8
|
+
DependentAttributes = [
|
9
|
+
[:ban, :hold, :notify],
|
10
|
+
[:blacklist_email]
|
11
|
+
]
|
12
|
+
|
13
|
+
#Turns off all dependent attributes, toggles the one passed
|
14
|
+
def toggle(attribute)
|
15
|
+
DependentAttributes.select {|array| array.include?(attribute.to_sym)}.each do |dependencies|
|
16
|
+
attributes_for_update = dependencies.each_with_object({}) {|a, memo| memo[a] = false}
|
17
|
+
update_attributes(attributes_for_update.merge({attribute.to_sym => !self.read_attribute(attribute)}))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def banned
|
22
|
+
@current = model.where(ban: true)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def banned?
|
27
|
+
!!ban
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_hold
|
31
|
+
@current = model.where(hold: true)
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_notify
|
36
|
+
@current = model.where(notify: true)
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def email
|
41
|
+
@current = model.where(blacklist_email: true)
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
def current
|
46
|
+
@current || model
|
47
|
+
end
|
48
|
+
|
49
|
+
def match(input, partials_match=false)
|
50
|
+
if partials_match
|
51
|
+
current.where(":input ~* regexp_word", input: input)
|
52
|
+
else
|
53
|
+
current.where(":input ~* ('#{word_separator}' || regexp_word || '#{word_separator}')", input: input)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def regexscape_word
|
60
|
+
self.regexp_word = Regexp.escape(word)
|
61
|
+
end
|
62
|
+
|
63
|
+
def word_separator
|
64
|
+
DodgyStalker.config.word_separator
|
65
|
+
end
|
66
|
+
|
67
|
+
def model
|
68
|
+
@model ||= self.class
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module DodgyStalker
|
2
|
+
module Engines
|
3
|
+
class BannedWords
|
4
|
+
def initialize(input)
|
5
|
+
@input = input
|
6
|
+
end
|
7
|
+
|
8
|
+
def banned
|
9
|
+
@banned ||= source.banned.match(input).map(&:word)
|
10
|
+
end
|
11
|
+
|
12
|
+
def on_hold
|
13
|
+
@hold ||= source.on_hold.match(input).map(&:word)
|
14
|
+
end
|
15
|
+
|
16
|
+
def notify
|
17
|
+
@notify ||= source.to_notify.match(input).map(&:word)
|
18
|
+
end
|
19
|
+
|
20
|
+
def blacklisted_email
|
21
|
+
@blacklisted_email ||= source.email.match(input, true).map(&:word)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_a(with_partials=false)
|
25
|
+
@to_a ||= source.match(input, with_partials).map(&:word)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_words(with_partials=false)
|
29
|
+
@to_words ||= source.match(input, with_partials)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def input
|
35
|
+
@input
|
36
|
+
end
|
37
|
+
|
38
|
+
def source
|
39
|
+
DataStore::Wordlist.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module DodgyStalker
|
2
|
+
module Engines
|
3
|
+
class Blacklist
|
4
|
+
def initialize(attributes)
|
5
|
+
@attributes = attributes
|
6
|
+
end
|
7
|
+
|
8
|
+
def banned_ip?(ip)
|
9
|
+
return false if ip.nil?
|
10
|
+
DataStore::Blacklist.where(ip_address: ip).exists?
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_blacklist?
|
14
|
+
return false if whitelist.on_list(attributes).exists?
|
15
|
+
|
16
|
+
Policy.new(fetched_results).validate
|
17
|
+
end
|
18
|
+
|
19
|
+
def blacklist!(opts={})
|
20
|
+
if (blacklist.add(attributes.merge(opts)) && whitelist.remove(attributes))
|
21
|
+
true
|
22
|
+
else
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#Remove attributes from blacklist and add to whitelist
|
28
|
+
def remove!
|
29
|
+
if (blacklist.remove(attributes) && whitelist.add(attributes))
|
30
|
+
true
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def fetched_results
|
39
|
+
@fetched_results ||= blacklist.on_list(attributes).to_a
|
40
|
+
end
|
41
|
+
|
42
|
+
def blacklist
|
43
|
+
DataStore::Blacklist.new
|
44
|
+
end
|
45
|
+
|
46
|
+
def whitelist
|
47
|
+
DataStore::Whitelist.new
|
48
|
+
end
|
49
|
+
|
50
|
+
def attributes
|
51
|
+
@attributes
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
module DodgyStalker
|
3
|
+
module Engines
|
4
|
+
class StopForumSpam
|
5
|
+
def initialize(attributes)
|
6
|
+
@attributes = attributes
|
7
|
+
end
|
8
|
+
|
9
|
+
def on_blacklist?
|
10
|
+
confidence_for(:username) > 0.75 || confidence_for(:email) > 0.75
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def confidence_for(key)
|
16
|
+
response[key.to_s]['confidence'].to_f
|
17
|
+
rescue #if anything goes wrong do not crash
|
18
|
+
0.0
|
19
|
+
end
|
20
|
+
|
21
|
+
def query_stopforumspam
|
22
|
+
Typhoeus.get(url)
|
23
|
+
end
|
24
|
+
|
25
|
+
def response
|
26
|
+
@response ||= JSON.parse(query_stopforumspam.body)
|
27
|
+
end
|
28
|
+
|
29
|
+
def url
|
30
|
+
base = 'http://www.stopforumspam.com/api'
|
31
|
+
uri = Addressable::URI.parse(base)
|
32
|
+
uri.query_values = attributes.merge({f: 'json'})
|
33
|
+
uri.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def attributes
|
37
|
+
@attributes.select {|k,v| [:username, :email].include?(k)}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module DodgyStalker
|
2
|
+
class Policy
|
3
|
+
def initialize(spamcheck_results)
|
4
|
+
@spamcheck_results = spamcheck_results
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate
|
8
|
+
#analyze results to determine the ranking
|
9
|
+
spamcheck_results.any?
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def spamcheck_results
|
15
|
+
@spamcheck_results
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "dodgy_stalker/version"
|
2
|
+
|
3
|
+
require "typhoeus"
|
4
|
+
require "json"
|
5
|
+
require "active_record"
|
6
|
+
|
7
|
+
require "dodgy_stalker/config"
|
8
|
+
require "dodgy_stalker/data_store"
|
9
|
+
require "dodgy_stalker/engines"
|
10
|
+
require "dodgy_stalker/policy"
|
11
|
+
|
12
|
+
module DodgyStalker
|
13
|
+
class << self
|
14
|
+
attr_writer :config
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.config
|
18
|
+
@config ||= Config.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.configure
|
22
|
+
yield(config)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.disable!
|
26
|
+
@disabled = true
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.enable!
|
30
|
+
@disabled = false
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.disabled
|
34
|
+
@disabled
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
module DodgyStalker
|
5
|
+
class MigrationGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.next_migration_number(dirname)
|
13
|
+
if ActiveRecord::Base.timestamped_migrations
|
14
|
+
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
15
|
+
else
|
16
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_migration_file
|
21
|
+
migration_template 'migration.rb', "db/migrate/create_dodgy_stalker_tables.rb"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class CreateDodgyStalkerTables < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table "wordlist", force: true do |t|
|
4
|
+
t.string "word"
|
5
|
+
t.boolean "ban"
|
6
|
+
t.boolean "notify"
|
7
|
+
t.boolean "hold"
|
8
|
+
t.string "regexp_word"
|
9
|
+
t.boolean "blacklist_email", default: false
|
10
|
+
t.datetime "created_at", null: false
|
11
|
+
t.datetime "updated_at", null: false
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table "whitelist", force: true do |t|
|
15
|
+
t.string "username"
|
16
|
+
t.string "email"
|
17
|
+
t.string "ip_address"
|
18
|
+
t.string "twitter_uid"
|
19
|
+
t.string "google_uid"
|
20
|
+
t.string "facebook_uid"
|
21
|
+
t.datetime "created_at", null: false
|
22
|
+
t.datetime "updated_at", null: false
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table "blacklist", force: true do |t|
|
26
|
+
t.string "username"
|
27
|
+
t.string "email"
|
28
|
+
t.string "ip_address"
|
29
|
+
t.string "twitter_uid"
|
30
|
+
t.string "google_uid"
|
31
|
+
t.string "facebook_uid"
|
32
|
+
t.datetime "created_at", null: false
|
33
|
+
t.datetime "updated_at", null: false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DodgyStalker::DataStore::Blacklist do
|
4
|
+
let(:list) { described_class.new }
|
5
|
+
let(:user) { double('User', username: 'Rob', email: 'email@domain.com') }
|
6
|
+
let(:attributes) { { email: user.email, username: user.username } }
|
7
|
+
|
8
|
+
describe "#on_list" do
|
9
|
+
it "returns matches for any attributes" do
|
10
|
+
list.add(username: user.username)
|
11
|
+
list.add(email: user.email)
|
12
|
+
list.on_list(attributes).should have(2).entries
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#add" do
|
17
|
+
it "adds new entry to blacklist" do
|
18
|
+
expect { list.add(attributes) }.to change { DodgyStalker::DataStore::Blacklist.count }.
|
19
|
+
from(0).to(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "does not add duplicates" do
|
23
|
+
list.add(attributes)
|
24
|
+
expect { list.add(attributes) }.to_not change { DodgyStalker::DataStore::Blacklist.count }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#remove" do
|
29
|
+
it "removes user from blacklist" do
|
30
|
+
list.add(attributes)
|
31
|
+
expect { list.remove(attributes) }.to change { DodgyStalker::DataStore::Blacklist.count }.
|
32
|
+
from(1).to(0)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "removes only exact matches" do
|
36
|
+
list.add(attributes.merge(facebook_uid: '123'))
|
37
|
+
expect { list.remove(attributes) }.to_not change { DodgyStalker::DataStore::Blacklist.count }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DodgyStalker::DataStore::Whitelist do
|
4
|
+
let(:list) { described_class.new }
|
5
|
+
let(:user) { double('User', email: 'rob@example.com', username: 'rob') }
|
6
|
+
let(:attributes) { { email: user.email, username: user.username } }
|
7
|
+
|
8
|
+
describe "#on_list" do
|
9
|
+
it "returns only exact matches" do
|
10
|
+
list.add(username: user.username)
|
11
|
+
list.add(email: user.email)
|
12
|
+
list.add(attributes)
|
13
|
+
|
14
|
+
list.on_list(attributes).should have(1).entry
|
15
|
+
|
16
|
+
list.on_list(username: user.username, email: 'mail@domain.com').should have(0).entries
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#add" do
|
21
|
+
it "adds new entry to whitelist" do
|
22
|
+
expect { list.add(attributes) }.to change { DodgyStalker::DataStore::Whitelist.count }.
|
23
|
+
from(0).to(1)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "does not add duplicates" do
|
27
|
+
list.add(attributes)
|
28
|
+
expect { list.add(attributes) }.to_not change { DodgyStalker::DataStore::Whitelist.count }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#remove" do
|
33
|
+
it "removes user from whitelist" do
|
34
|
+
list.add(attributes)
|
35
|
+
expect { list.remove(attributes) }.to change { DodgyStalker::DataStore::Whitelist.count }.
|
36
|
+
from(1).to(0)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "removes only exact matches" do
|
40
|
+
list.add(attributes.merge(facebook_uid: '123'))
|
41
|
+
expect { list.remove(attributes) }.to_not change { DodgyStalker::DataStore::Whitelist.count }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DodgyStalker::DataStore::Wordlist do
|
4
|
+
let(:wordlist) { described_class.new(word: 'word') }
|
5
|
+
|
6
|
+
describe "#toggle" do
|
7
|
+
context "attributes :ban, :hold, :notify" do
|
8
|
+
it "toggle one attribute, turn off others" do
|
9
|
+
wordlist.toggle('ban')
|
10
|
+
wordlist.ban.should be true
|
11
|
+
wordlist.hold.should be false
|
12
|
+
wordlist.notify.should be false
|
13
|
+
|
14
|
+
wordlist.toggle('hold')
|
15
|
+
wordlist.ban.should be false
|
16
|
+
wordlist.hold.should be true
|
17
|
+
wordlist.notify.should be false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DodgyStalker::Engines::BannedWords do
|
4
|
+
let(:engine) { described_class.new(input) }
|
5
|
+
let(:input) { "fuck! 'quoted' +plused+ ass underage viagra" }
|
6
|
+
let(:datastore) { DodgyStalker::DataStore::Wordlist }
|
7
|
+
|
8
|
+
describe "#banned" do
|
9
|
+
it "returns a list of banned words in input" do
|
10
|
+
datastore.create(word: 'fuck!', ban: true)
|
11
|
+
datastore.create(word: 'ass', ban: true)
|
12
|
+
engine.banned.should =~ ['fuck!', 'ass']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#blacklisted_email" do
|
17
|
+
it "returns a list of blacklisted emails" do
|
18
|
+
datastore.create(word: '@wp.pl', blacklist_email: true)
|
19
|
+
described_class.new('piotr@wp.pl').blacklisted_email.should =~ ['@wp.pl']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#on_hold" do
|
24
|
+
it "returns a list of hold words in input" do
|
25
|
+
datastore.create(word: 'viagra', hold: true)
|
26
|
+
engine.on_hold.should =~ ['viagra']
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#notify" do
|
31
|
+
it "returns a list of notify words in input" do
|
32
|
+
datastore.create(word: 'underage', notify: true)
|
33
|
+
engine.notify.should =~ ['underage']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#match" do
|
38
|
+
it "matches full words (no partials)" do
|
39
|
+
datastore.create(word: 'fuck', ban: true)
|
40
|
+
engine.banned.should be_empty
|
41
|
+
end
|
42
|
+
|
43
|
+
it "ignores quotes on matches" do
|
44
|
+
datastore.create(word: 'quoted', ban: true)
|
45
|
+
engine.banned.to_a.should have(1).word
|
46
|
+
end
|
47
|
+
|
48
|
+
it "allows to change word separator via config" do
|
49
|
+
old_separator = DodgyStalker::Config.new.word_separator
|
50
|
+
DodgyStalker.configure {|c| c.word_separator = %q{(^|\s|\A|\Z|$|\.|,|\+)} }
|
51
|
+
datastore.create(word: 'plused', ban: true)
|
52
|
+
engine.banned.to_a.should have(1).word
|
53
|
+
DodgyStalker.configure {|c| c.word_separator = old_separator }
|
54
|
+
end
|
55
|
+
|
56
|
+
it "matches with partials" do
|
57
|
+
datastore.create(word: 'fuck', ban: true)
|
58
|
+
engine.to_a(true).should have(1).element
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DodgyStalker::Engines::Blacklist do
|
4
|
+
let(:engine) { described_class.new(attributes) }
|
5
|
+
let(:user) { double('User', username: 'rob', email: 'rob@example.com') }
|
6
|
+
let(:attributes) { { email: user.email, username: user.username } }
|
7
|
+
|
8
|
+
describe "#on_blacklist?" do
|
9
|
+
context "when there is no whitelist entry" do
|
10
|
+
it "returns true when user is on blacklist" do
|
11
|
+
DodgyStalker::DataStore::Blacklist.new.add(attributes)
|
12
|
+
engine.on_blacklist?.should be true
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns false when user is not on blacklist" do
|
16
|
+
engine.on_blacklist?.should be false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns false when there is whitelist entry" do
|
21
|
+
DodgyStalker::DataStore::Whitelist.new.add(attributes)
|
22
|
+
DodgyStalker::DataStore::Blacklist.new.add(attributes)
|
23
|
+
engine.on_blacklist?.should be false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#blacklist!" do
|
28
|
+
it "adds user to blacklist" do
|
29
|
+
expect { engine.blacklist! }.to change { DodgyStalker::DataStore::Blacklist.count }.
|
30
|
+
from(0).to(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "removes user from whitelist" do
|
34
|
+
DodgyStalker::DataStore::Whitelist.new.add(attributes)
|
35
|
+
expect { engine.blacklist! }.to change { DodgyStalker::DataStore::Whitelist.count }.
|
36
|
+
from(1).to(0)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#banned_ip?" do
|
41
|
+
it "returns false if passed ip is nil" do
|
42
|
+
engine.banned_ip?(nil).should be false
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns false if IP is not on blacklist" do
|
46
|
+
engine.banned_ip?('0.0.0.0').should be false
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns true if IP is on blacklist" do
|
50
|
+
DodgyStalker::DataStore::Blacklist.new.add(ip_address: '1.2.3.4')
|
51
|
+
engine.banned_ip?('1.2.3.4').should be true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#remove!" do
|
56
|
+
it "removes the user from blacklist" do
|
57
|
+
DodgyStalker::DataStore::Blacklist.new.add(attributes)
|
58
|
+
expect { engine.remove! }.to change { DodgyStalker::DataStore::Blacklist.count }.
|
59
|
+
from(1).to(0)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "adds the user to whitelist" do
|
63
|
+
expect { engine.remove! }.to change { DodgyStalker::DataStore::Whitelist.count }.
|
64
|
+
from(0).to(1)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe DodgyStalker::Engines::StopForumSpam do
|
5
|
+
let(:engine) { described_class.new(attributes) }
|
6
|
+
let(:attributes) { { username: 'amilesqexaxdy5478', email: 'robyyy@egamok.tgory.pl' } }
|
7
|
+
|
8
|
+
context "when user is in sfs database" do
|
9
|
+
it "returns true confidence is above 0.75" do
|
10
|
+
engine.stub(:confidence_for).and_return(0.76)
|
11
|
+
engine.on_blacklist?.should be true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns false when confidence is below 0.75" do
|
15
|
+
engine.stub(:confidence_for).and_return(0.74)
|
16
|
+
engine.on_blacklist?.should be false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class CreateDodgyStalkerTables < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table "wordlist", force: true do |t|
|
4
|
+
t.string "word"
|
5
|
+
t.boolean "ban"
|
6
|
+
t.boolean "notify"
|
7
|
+
t.boolean "hold"
|
8
|
+
t.string "regexp_word"
|
9
|
+
t.boolean "blacklist_email", default: false
|
10
|
+
t.datetime "created_at", null: false
|
11
|
+
t.datetime "updated_at", null: false
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table "whitelist", force: true do |t|
|
15
|
+
t.string "username"
|
16
|
+
t.string "email"
|
17
|
+
t.string "ip_address"
|
18
|
+
t.string "twitter_uid"
|
19
|
+
t.string "google_uid"
|
20
|
+
t.string "facebook_uid"
|
21
|
+
t.datetime "created_at", null: false
|
22
|
+
t.datetime "updated_at", null: false
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table "blacklist", force: true do |t|
|
26
|
+
t.string "username"
|
27
|
+
t.string "email"
|
28
|
+
t.string "ip_address"
|
29
|
+
t.string "twitter_uid"
|
30
|
+
t.string "google_uid"
|
31
|
+
t.string "facebook_uid"
|
32
|
+
t.datetime "created_at", null: false
|
33
|
+
t.datetime "updated_at", null: false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/policy_spec.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DodgyStalker::Policy do
|
4
|
+
let(:spamcheck_results) { [double('Result'), double('Result')] }
|
5
|
+
let(:policy) { described_class.new(spamcheck_results) }
|
6
|
+
|
7
|
+
describe "#validate" do
|
8
|
+
it "returns true if there are any blacklist results" do
|
9
|
+
policy.validate.should be true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns false if there are no blacklist entries" do
|
13
|
+
policy.stub(:spamcheck_results).and_return([])
|
14
|
+
policy.validate.should be false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'database_cleaner'
|
3
|
+
require 'dodgy_stalker'
|
4
|
+
require 'pry'
|
5
|
+
|
6
|
+
DatabaseCleaner.strategy = :transaction
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.mock_with :rspec
|
9
|
+
config.order = "random"
|
10
|
+
config.before(:suite) { DatabaseCleaner.clean_with(:truncation) }
|
11
|
+
|
12
|
+
config.around do |example|
|
13
|
+
DatabaseCleaner.start
|
14
|
+
example.run
|
15
|
+
DatabaseCleaner.clean
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
ActiveRecord::Base.establish_connection(
|
20
|
+
adapter: 'postgresql',
|
21
|
+
database: 'dodgy_stalker',
|
22
|
+
username: 'rob',
|
23
|
+
host: 'localhost'
|
24
|
+
)
|
25
|
+
|
26
|
+
|
27
|
+
ActiveRecord::Migrator.migrate(File.expand_path('../migrations', __FILE__))
|
metadata
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dodgy_stalker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- robuye
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-expectations
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-mocks
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pg
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: database_cleaner
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: activerecord
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '4.0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '4.0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: typhoeus
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: addressable
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description: Filters to detect spam, trolls and unwanted content
|
168
|
+
email:
|
169
|
+
- rulejczyk@gmail.com
|
170
|
+
executables: []
|
171
|
+
extensions: []
|
172
|
+
extra_rdoc_files: []
|
173
|
+
files:
|
174
|
+
- ".gitignore"
|
175
|
+
- Gemfile
|
176
|
+
- LICENSE
|
177
|
+
- LICENSE.txt
|
178
|
+
- README.md
|
179
|
+
- Rakefile
|
180
|
+
- dodgy_stalker.gemspec
|
181
|
+
- lib/dodgy_stalker.rb
|
182
|
+
- lib/dodgy_stalker/config.rb
|
183
|
+
- lib/dodgy_stalker/data_store.rb
|
184
|
+
- lib/dodgy_stalker/data_store/blacklist.rb
|
185
|
+
- lib/dodgy_stalker/data_store/common.rb
|
186
|
+
- lib/dodgy_stalker/data_store/whitelist.rb
|
187
|
+
- lib/dodgy_stalker/data_store/wordlist.rb
|
188
|
+
- lib/dodgy_stalker/engines.rb
|
189
|
+
- lib/dodgy_stalker/engines/banned_words.rb
|
190
|
+
- lib/dodgy_stalker/engines/blacklist.rb
|
191
|
+
- lib/dodgy_stalker/engines/stop_forum_spam.rb
|
192
|
+
- lib/dodgy_stalker/policy.rb
|
193
|
+
- lib/dodgy_stalker/version.rb
|
194
|
+
- lib/generators/dodgy_stalker/migration_generator.rb
|
195
|
+
- lib/generators/dodgy_stalker/templates/migration.rb
|
196
|
+
- spec/datastores/blacklist_spec.rb
|
197
|
+
- spec/datastores/whitelist_spec.rb
|
198
|
+
- spec/datastores/wordlist_spec.rb
|
199
|
+
- spec/engines/banned_words_spec.rb
|
200
|
+
- spec/engines/blacklist_spec.rb
|
201
|
+
- spec/engines/stop_form_spam_spec.rb
|
202
|
+
- spec/migrations/001_create_dodgy_stalker_tables.rb
|
203
|
+
- spec/policy_spec.rb
|
204
|
+
- spec/spec_helper.rb
|
205
|
+
homepage: ''
|
206
|
+
licenses:
|
207
|
+
- MIT
|
208
|
+
metadata: {}
|
209
|
+
post_install_message:
|
210
|
+
rdoc_options: []
|
211
|
+
require_paths:
|
212
|
+
- lib
|
213
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
214
|
+
requirements:
|
215
|
+
- - ">="
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '0'
|
218
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
requirements: []
|
224
|
+
rubyforge_project:
|
225
|
+
rubygems_version: 2.2.2
|
226
|
+
signing_key:
|
227
|
+
specification_version: 4
|
228
|
+
summary: Filters to detect spam, trolls and unwanted content
|
229
|
+
test_files:
|
230
|
+
- spec/datastores/blacklist_spec.rb
|
231
|
+
- spec/datastores/whitelist_spec.rb
|
232
|
+
- spec/datastores/wordlist_spec.rb
|
233
|
+
- spec/engines/banned_words_spec.rb
|
234
|
+
- spec/engines/blacklist_spec.rb
|
235
|
+
- spec/engines/stop_form_spam_spec.rb
|
236
|
+
- spec/migrations/001_create_dodgy_stalker_tables.rb
|
237
|
+
- spec/policy_spec.rb
|
238
|
+
- spec/spec_helper.rb
|