safetynet 0.0.1 → 0.1.0
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 +4 -4
- data/README.md +69 -10
- data/Rakefile +31 -1
- data/lib/rails/generators/safetynet/safetynet_generator.rb +46 -0
- data/lib/rails/generators/safetynet/templates/db/migrate/1_create_safetynet_histories.rb +16 -0
- data/lib/rails/generators/safetynet/templates/initializer.rb +4 -0
- data/lib/safetynet/engine.rb +5 -0
- data/lib/safetynet/version.rb +1 -1
- data/lib/safetynet.rb +15 -10
- data/lib/tasks/safetynet_tasks.rake +4 -0
- metadata +64 -6
- data/.gitignore +0 -22
- data/Gemfile +0 -4
- data/safetynet.gemspec +0 -23
- /data/{LICENSE.txt → LICENSE.TXT} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c82ab26e4311dd4cee67b3512af96ce1a3cd871d
|
4
|
+
data.tar.gz: f7d833205366907799b196294574314e756a7694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3413d6714950b1ea54811c4caae76bbb47c4ac0a2f14306f2e7700ede475fb99e9bfbf9510d8138c7df349208db86a745d121a71d67524c636d87c1ca7d10774
|
7
|
+
data.tar.gz: ae9511d5345b41d51991862041bf39e420e479f38167b64428a7481bb6f0f3efe5e121e3bce988e8ef7be65de1f0bc5ce50d95feba68826b899d1836f42d3a50
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# Safetynet
|
2
2
|
|
3
|
-
|
3
|
+
Stop communication problems before they happen
|
4
4
|
|
5
|
-
|
5
|
+
Safetynet keeps track of email communications by user/email and ActionMailer message. If the same message is sent to the same user multiple times within the allowed timeframe, it will be blocked from delivery and notify system admins. The messages are filterable in a way similar to controller filters, and the checking method can be called by itself outside the normal hooks for additional throttling (i.e. SMS sending, push notifications, etc.).
|
6
|
+
|
7
|
+
## Rails Installation
|
6
8
|
|
7
9
|
Add this line to your application's Gemfile:
|
8
10
|
|
@@ -11,19 +13,76 @@ Add this line to your application's Gemfile:
|
|
11
13
|
And then execute:
|
12
14
|
|
13
15
|
$ bundle
|
16
|
+
$ rails generate safetynet
|
17
|
+
$ rake db:migrate
|
18
|
+
|
19
|
+
The generator creates two files:
|
14
20
|
|
15
|
-
|
21
|
+
1. a file under `config/initializers/safetynet.rb` configuring Safetynet with project-specific settings.
|
22
|
+
2. a migration file to create the safetynet_histories table
|
16
23
|
|
17
|
-
$ gem install safetynet
|
18
24
|
|
19
25
|
## Usage
|
20
26
|
|
21
|
-
|
27
|
+
###Applied to a mailer
|
28
|
+
|
29
|
+
Add the safetynet method to an ActionMailer::Base class with the following structure:
|
30
|
+
|
31
|
+
safetynet({
|
32
|
+
channel,
|
33
|
+
filters,
|
34
|
+
options: {
|
35
|
+
email: {
|
36
|
+
limit: 1,
|
37
|
+
timeframe: 30.minutes
|
38
|
+
}
|
39
|
+
}
|
40
|
+
})
|
41
|
+
|
42
|
+
And a description of each:
|
43
|
+
|
44
|
+
|Field|Type|Description|
|
45
|
+
|:-|:-|:-|
|
46
|
+
|**channel** |Symbol |The category of methods to watch (email/sms/etc.) -- see options below|
|
47
|
+
|**filters** |Hash |Hash of method names to watch (email only) that fits after_action requirements|
|
48
|
+
|**options** |Hash |Contains a hash for each channel and includes the next 2 fields|
|
49
|
+
|**limit** |Integer |Maximum # of methods for this channel (default: 1)|
|
50
|
+
|**timeframe** |Integer |Minimum allowed timeframe between last successful method call (default: 30.minutes)|
|
51
|
+
|
52
|
+
|
53
|
+
**Note:** Defaults to configured channel, method, and Safetynet configuration limit & timeframe for the channel
|
54
|
+
|
55
|
+
####Example:
|
56
|
+
|
57
|
+
class UserMailer < ActionMailer::Base
|
58
|
+
include Safetynet
|
59
|
+
safetynet :email, {except: [:user_registration_email, :forgot_password_email]}
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
###Standalone usage on a class
|
65
|
+
|
66
|
+
|
67
|
+
####Example:
|
68
|
+
|
69
|
+
class User < ActiveRecord::Base
|
70
|
+
include Safetynet
|
71
|
+
safetynet :sms
|
72
|
+
|
73
|
+
def send_sms
|
74
|
+
if permit_delivery?(self)
|
75
|
+
...
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
22
80
|
|
23
81
|
## Contributing
|
24
82
|
|
25
|
-
1.
|
26
|
-
2.
|
27
|
-
3.
|
28
|
-
4.
|
29
|
-
5.
|
83
|
+
1. Create an issue
|
84
|
+
2. Fork it ( https://github.com/arktisklada/safetynet/fork )
|
85
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
86
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
87
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
88
|
+
6. Create a new Pull Request
|
data/Rakefile
CHANGED
@@ -1,2 +1,32 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
2
6
|
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Safetynet'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
Rake::TestTask.new(:test) do |t|
|
25
|
+
t.libs << 'lib'
|
26
|
+
t.libs << 'test'
|
27
|
+
t.pattern = 'test/**/*_test.rb'
|
28
|
+
t.verbose = false
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task default: :test
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
class SafetynetGenerator < Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
desc "Creates the Safetynet initializer file at config/initializers/safetynet.rb and a migration"
|
8
|
+
|
9
|
+
|
10
|
+
def self.next_migration_number(path)
|
11
|
+
unless @prev_migration_nr
|
12
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
13
|
+
else
|
14
|
+
@prev_migration_nr += 1
|
15
|
+
end
|
16
|
+
@prev_migration_nr.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def install
|
20
|
+
generate_initializer
|
21
|
+
generate_migration
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def generate_initializer
|
28
|
+
template 'initializer.rb', 'config/initializers/safetynet.rb'
|
29
|
+
end
|
30
|
+
|
31
|
+
def configuration_output
|
32
|
+
output = <<-eos
|
33
|
+
Rails.configuration.safetynet = {
|
34
|
+
email: {
|
35
|
+
limit: Rails.env.development? ? 1000 : 1,
|
36
|
+
timeframe: 1.hour
|
37
|
+
}
|
38
|
+
}
|
39
|
+
eos
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate_migration
|
43
|
+
puts SafetynetGenerator.source_root
|
44
|
+
migration_template 'db/migrate/1_create_safetynet_histories.rb', 'db/migrate/create_safetynet_histories.rb'
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateSafetynetHistories < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :safetynet_histories do |t|
|
4
|
+
t.string :address
|
5
|
+
t.string :channel
|
6
|
+
t.string :method
|
7
|
+
t.datetime :created_at
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :safetynet_histories, [:address, :channel, :method, :created_at], name: 'safetynet_histories_idx'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :safetynet_histories
|
15
|
+
end
|
16
|
+
end
|
data/lib/safetynet/version.rb
CHANGED
data/lib/safetynet.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
require
|
1
|
+
require 'safetynet/version'
|
2
2
|
require 'active_support/concern'
|
3
|
+
require 'active_support/core_ext/numeric/time'
|
3
4
|
|
4
5
|
module Safetynet
|
5
6
|
extend ActiveSupport::Concern
|
6
7
|
|
8
|
+
|
7
9
|
# Saves a record for the current method
|
8
|
-
def safe_safetynet_delivery(
|
10
|
+
def safe_safetynet_delivery(address, channel, method)
|
9
11
|
options = self.class.safetynet_options
|
10
|
-
log =
|
11
|
-
|
12
|
+
log = Safetynet::History.new({
|
13
|
+
address: address,
|
12
14
|
method: method,
|
13
|
-
channel: channel.to_s
|
15
|
+
channel: channel.to_s,
|
16
|
+
created_at: Time.now
|
14
17
|
})
|
15
18
|
log.save
|
16
19
|
end
|
@@ -37,7 +40,7 @@ module Safetynet
|
|
37
40
|
# end
|
38
41
|
# end
|
39
42
|
def permit_delivery?(address, channel=nil, method=nil, limit=nil, timeframe=nil)
|
40
|
-
# Skip check if
|
43
|
+
# Skip check if address is whitelisted
|
41
44
|
return true if is_whitelisted?(address)
|
42
45
|
|
43
46
|
options = self.class.safetynet_options
|
@@ -50,7 +53,7 @@ module Safetynet
|
|
50
53
|
# Query the model to determine if delivery is permitted
|
51
54
|
permit_delivery = true
|
52
55
|
if limit != false
|
53
|
-
count_query =
|
56
|
+
count_query = Safetynet::History.where({
|
54
57
|
address: address,
|
55
58
|
channel: channel,
|
56
59
|
method: method
|
@@ -102,9 +105,9 @@ module Safetynet
|
|
102
105
|
permit_delivery
|
103
106
|
end
|
104
107
|
|
105
|
-
#
|
106
|
-
def is_whitelisted?(
|
107
|
-
!!(self.class.safetynet_options[:whitelist].match(
|
108
|
+
# Permits all whitelisted addresses by regex
|
109
|
+
def is_whitelisted?(address)
|
110
|
+
!!(self.class.safetynet_options[:whitelist].match(address))
|
108
111
|
end
|
109
112
|
|
110
113
|
module ClassMethods
|
@@ -147,3 +150,5 @@ module Safetynet
|
|
147
150
|
end
|
148
151
|
end
|
149
152
|
end
|
153
|
+
|
154
|
+
ActiveRecord::Base.send :include, Safetynet
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safetynet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- arktisklada
|
@@ -10,6 +10,34 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2015-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sqlite3
|
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'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: bundler
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +66,34 @@ dependencies:
|
|
38
66
|
- - ">="
|
39
67
|
- !ruby/object:Gem::Version
|
40
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-rails
|
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: rspec
|
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'
|
41
97
|
description: 'Safetynet keeps track of email communications by user/email and ActionMailer
|
42
98
|
message. If the same message is sent to the same user multiple times within the
|
43
99
|
allowed timeframe, it will be blocked from delivery and notify system admins. The
|
@@ -50,15 +106,17 @@ executables: []
|
|
50
106
|
extensions: []
|
51
107
|
extra_rdoc_files: []
|
52
108
|
files:
|
53
|
-
-
|
54
|
-
- Gemfile
|
55
|
-
- LICENSE.txt
|
109
|
+
- LICENSE.TXT
|
56
110
|
- README.md
|
57
111
|
- Rakefile
|
112
|
+
- lib/rails/generators/safetynet/safetynet_generator.rb
|
113
|
+
- lib/rails/generators/safetynet/templates/db/migrate/1_create_safetynet_histories.rb
|
114
|
+
- lib/rails/generators/safetynet/templates/initializer.rb
|
58
115
|
- lib/safetynet.rb
|
116
|
+
- lib/safetynet/engine.rb
|
59
117
|
- lib/safetynet/version.rb
|
60
|
-
-
|
61
|
-
homepage:
|
118
|
+
- lib/tasks/safetynet_tasks.rake
|
119
|
+
homepage: https://github.com/arktisklada/safetynet
|
62
120
|
licenses:
|
63
121
|
- MIT
|
64
122
|
metadata: {}
|
data/.gitignore
DELETED
@@ -1,22 +0,0 @@
|
|
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
|
-
*.bundle
|
19
|
-
*.so
|
20
|
-
*.o
|
21
|
-
*.a
|
22
|
-
mkmf.log
|
data/Gemfile
DELETED
data/safetynet.gemspec
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'safetynet/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "safetynet"
|
8
|
-
spec.version = Safetynet::VERSION
|
9
|
-
spec.authors = ["arktisklada"]
|
10
|
-
spec.email = ["mail@enorganik.com"]
|
11
|
-
spec.summary = %q{Stop communication problems before they happen}
|
12
|
-
spec.description = %q{Safetynet keeps track of email communications by user/email and ActionMailer message. If the same message is sent to the same user multiple times within the allowed timeframe, it will be blocked from delivery and notify system admins. The messages are filterable in a way similar to controller filters, and the checking method can be called by itself outside the normal hooks for additional throttling (i.e. SMS sending, push notifications, etc.). }
|
13
|
-
spec.homepage = ""
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
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.6"
|
22
|
-
spec.add_development_dependency "rake"
|
23
|
-
end
|
File without changes
|