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 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
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dodgy_stalker.gemspec
4
+ gem 'addressable'
5
+ gemspec
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,9 @@
1
+ module DodgyStalker
2
+ class Config
3
+ attr_accessor :word_separator
4
+
5
+ def word_separator
6
+ @word_separator ||= %q{(^|\s|\A|\Z|$|\.|,|''|"|`)}
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module DodgyStalker
2
+ module DataStore
3
+ class Blacklist < ActiveRecord::Base
4
+ self.table_name = 'blacklist'
5
+
6
+ include Common
7
+ end
8
+ end
9
+ 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,10 @@
1
+ module DodgyStalker
2
+ module DataStore
3
+ end
4
+ end
5
+
6
+ require "dodgy_stalker/data_store/common"
7
+ require "dodgy_stalker/data_store/blacklist"
8
+ require "dodgy_stalker/data_store/whitelist"
9
+ require "dodgy_stalker/data_store/wordlist"
10
+
@@ -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,8 @@
1
+ module DodgyStalker
2
+ module Engines
3
+ end
4
+ end
5
+
6
+ require 'dodgy_stalker/engines/banned_words'
7
+ require 'dodgy_stalker/engines/blacklist'
8
+ require 'dodgy_stalker/engines/stop_forum_spam'
@@ -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,3 @@
1
+ module DodgyStalker
2
+ VERSION = "0.0.1"
3
+ 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
@@ -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
@@ -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