mongo_masker 1.0.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 +7 -0
- data/.dockerignore +1 -0
- data/.gitignore +53 -0
- data/Dockerfile +12 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +21 -0
- data/README.md +41 -0
- data/bin/mongo_masker +16 -0
- data/docker-compose.yml +20 -0
- data/lib/mongo_masker.rb +141 -0
- data/mongo_masker.gemspec +23 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f217269ec66fb6a591ab9892b713668ef49cd761030f0f1daf3fb8f806c928f5
|
4
|
+
data.tar.gz: c3720d536bd94c8adc2c2a5fbd07446ebb54e9a192d34e93b0be7fea36ee34f3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 16e4d2ca4b1b9ef37005beebe1bfb44431b8ba4bfdd93758c15f55178042da1f1ccee353cec9f70823ddc7928d6619b1c0c32a82a13f42ceb95824ef0e5c8e2a
|
7
|
+
data.tar.gz: cd977e2df4ecc121785d3c28158020883f895f0922b3973c21de401c54e0f6937f52d0655af6b26d3ccf6bc84d3641968b4a41972cbe22e98a30a20cb15da71e
|
data/.dockerignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/data/
|
data/.gitignore
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
# Used by dotenv library to load environment variables.
|
14
|
+
# .env
|
15
|
+
|
16
|
+
## Specific to RubyMotion:
|
17
|
+
.dat*
|
18
|
+
.repl_history
|
19
|
+
build/
|
20
|
+
*.bridgesupport
|
21
|
+
build-iPhoneOS/
|
22
|
+
build-iPhoneSimulator/
|
23
|
+
|
24
|
+
## Specific to RubyMotion (use of CocoaPods):
|
25
|
+
#
|
26
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
27
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
28
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
29
|
+
#
|
30
|
+
# vendor/Pods/
|
31
|
+
|
32
|
+
## Documentation cache and generated files:
|
33
|
+
/.yardoc/
|
34
|
+
/_yardoc/
|
35
|
+
/doc/
|
36
|
+
/rdoc/
|
37
|
+
|
38
|
+
## Environment normalization:
|
39
|
+
/.bundle/
|
40
|
+
/vendor/bundle
|
41
|
+
/lib/bundler/man/
|
42
|
+
|
43
|
+
# for a library or gem, you might want to ignore these files since the code is
|
44
|
+
# intended to run in multiple environments; otherwise, check them in:
|
45
|
+
# Gemfile.lock
|
46
|
+
# .ruby-version
|
47
|
+
# .ruby-gemset
|
48
|
+
|
49
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
50
|
+
.rvmrc
|
51
|
+
|
52
|
+
# import data
|
53
|
+
/data/
|
data/Dockerfile
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
bson (4.4.2)
|
5
|
+
ffaker (2.10.0)
|
6
|
+
irb (1.0.0)
|
7
|
+
mongo (2.7.0)
|
8
|
+
bson (>= 4.4.2, < 5.0.0)
|
9
|
+
thor (0.20.3)
|
10
|
+
|
11
|
+
PLATFORMS
|
12
|
+
ruby
|
13
|
+
|
14
|
+
DEPENDENCIES
|
15
|
+
ffaker
|
16
|
+
irb
|
17
|
+
mongo
|
18
|
+
thor
|
19
|
+
|
20
|
+
BUNDLED WITH
|
21
|
+
1.17.1
|
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Mongodb-data-masking
|
2
|
+
Masking your data in mongodb
|
3
|
+
|
4
|
+
# Usage
|
5
|
+
```
|
6
|
+
bundle
|
7
|
+
ruby masker.rb mask mask.yml
|
8
|
+
```
|
9
|
+
|
10
|
+
# Example mask.yml
|
11
|
+
```yaml
|
12
|
+
version: 1
|
13
|
+
db_url: mongodb://mongodb:27017/development
|
14
|
+
models:
|
15
|
+
- name: users
|
16
|
+
condition:
|
17
|
+
email:
|
18
|
+
"$not": !ruby/regexp '/@basicinc\.jp$/'
|
19
|
+
fields:
|
20
|
+
email: FFaker::Internet.safe_email
|
21
|
+
- name: users
|
22
|
+
fields:
|
23
|
+
reset_password_token: String.new
|
24
|
+
confirmation_token: String.new
|
25
|
+
- name: sitesconta
|
26
|
+
fields:
|
27
|
+
title: FFaker::NameJA.name
|
28
|
+
description: FFaker::LoremJA.sentence
|
29
|
+
domain: FFaker::Internet.domain_name
|
30
|
+
external_service: :external_services
|
31
|
+
- name: external_services
|
32
|
+
fields:
|
33
|
+
_type: "'ExternalService'"
|
34
|
+
facebook: nil
|
35
|
+
google: nil
|
36
|
+
- name: contacts
|
37
|
+
condition:
|
38
|
+
site_id:
|
39
|
+
"$ne": BSON::ObjectId('12312345346456456456sdff')
|
40
|
+
delete: true
|
41
|
+
```
|
data/bin/mongo_masker
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'mongo_masker'
|
4
|
+
require 'thor'
|
5
|
+
|
6
|
+
class MongoMasker::Cli < Thor
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
desc 'mask MASKER_FILE', 'Mask database'
|
10
|
+
def mask(masker_file)
|
11
|
+
masker = MongoMasker::Main.new(masker_file)
|
12
|
+
masker.mask
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
MongoMasker::Cli.start
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
version: '3'
|
2
|
+
services:
|
3
|
+
mongodb:
|
4
|
+
image: mongo:3.4.2
|
5
|
+
volumes:
|
6
|
+
- mongo-data:/data/db
|
7
|
+
- ./data:/tmp/data
|
8
|
+
|
9
|
+
app:
|
10
|
+
build: ./
|
11
|
+
links:
|
12
|
+
- mongodb
|
13
|
+
volumes:
|
14
|
+
- ./lib:/masking/lib
|
15
|
+
- ./bin:/masking/bin
|
16
|
+
stdin_open: true
|
17
|
+
tty: true
|
18
|
+
|
19
|
+
volumes:
|
20
|
+
mongo-data:
|
data/lib/mongo_masker.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'ffaker'
|
3
|
+
require 'mongo'
|
4
|
+
|
5
|
+
Mongo::Logger.logger.level = Logger::FATAL
|
6
|
+
|
7
|
+
module MongoMasker
|
8
|
+
class Main
|
9
|
+
def initialize(config = nil)
|
10
|
+
configure config unless config.nil?
|
11
|
+
@sequence = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def db
|
15
|
+
@db ||= Mongo::Client.new(@config['db_url'] || 'mongodb://mongodb:27017/development')
|
16
|
+
end
|
17
|
+
|
18
|
+
def mask(config = nil)
|
19
|
+
configure config unless config.nil?
|
20
|
+
raise 'Please provide mask' if @config.nil?
|
21
|
+
|
22
|
+
track_time do
|
23
|
+
@config['models'].each do |model|
|
24
|
+
mask_document model
|
25
|
+
end
|
26
|
+
puts 'Done!' unless @config['silent']
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def configure(config)
|
31
|
+
@config = config.is_a?(String) ? load_from_yaml(config) : config
|
32
|
+
end
|
33
|
+
|
34
|
+
def seq
|
35
|
+
@sequence += 1
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def track_time
|
41
|
+
start_at = Time.now
|
42
|
+
yield
|
43
|
+
finish_at = Time.now
|
44
|
+
puts "Elapsed time: #{format_time_diff(start_at, finish_at)}" unless @config['silent']
|
45
|
+
end
|
46
|
+
|
47
|
+
def format_time_diff(start_at, finish_at)
|
48
|
+
output = Time.at(finish_at - start_at).strftime '%H hours %M minutes %S seconds'
|
49
|
+
output.gsub(/^0+ hours /, '').gsub(/^0+ minutes /, '')
|
50
|
+
end
|
51
|
+
|
52
|
+
def mask_document(model)
|
53
|
+
scope = prepair_scope model
|
54
|
+
|
55
|
+
if model['delete']
|
56
|
+
delete_documents scope, model
|
57
|
+
else
|
58
|
+
mask_each_document scope, model
|
59
|
+
end
|
60
|
+
rescue StandardError => e
|
61
|
+
puts "\nCan't mask #{model['name']}" unless @config['silent']
|
62
|
+
raise e
|
63
|
+
ensure
|
64
|
+
puts '' unless @config['silent']
|
65
|
+
end
|
66
|
+
|
67
|
+
def delete_documents(scope, model)
|
68
|
+
puts "Deleting #{model['name']}"
|
69
|
+
scope.delete_many
|
70
|
+
end
|
71
|
+
|
72
|
+
def mask_each_document(scope, model)
|
73
|
+
total = scope.count()
|
74
|
+
|
75
|
+
scope.each_with_index do |document, index|
|
76
|
+
print "Masking #{model['name']} (#{index + 1}/#{total})\r" unless @config['silent']
|
77
|
+
mask = create_mask model['fields']
|
78
|
+
|
79
|
+
apply_mask(document, mask)
|
80
|
+
db[model['name']].find({_id: document['_id']}).update_one(document)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def prepair_scope(model)
|
85
|
+
scope = db[model['name']]
|
86
|
+
scope.find(parse_condition(model['condition']))
|
87
|
+
end
|
88
|
+
|
89
|
+
def parse_condition condition
|
90
|
+
if condition.is_a?(String) && condition.match?(/^BSON::ObjectId\('[A-Za-z0-9]+'\)$/)
|
91
|
+
return eval(condition)
|
92
|
+
end
|
93
|
+
|
94
|
+
if condition.is_a?(Hash)
|
95
|
+
condition.each do |op, value|
|
96
|
+
condition[op] = parse_condition value
|
97
|
+
end
|
98
|
+
return condition
|
99
|
+
end
|
100
|
+
|
101
|
+
if condition.is_a?(Array)
|
102
|
+
return condition.map do |value|
|
103
|
+
parse_condition value
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
condition
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_mask(fields)
|
111
|
+
mask = {}
|
112
|
+
fields.each do |field, value|
|
113
|
+
if value.is_a?(Symbol)
|
114
|
+
sub_mask = create_mask @config['models'].find{|model| model['name'] == value.to_s}['fields']
|
115
|
+
mask[field] = sub_mask
|
116
|
+
next
|
117
|
+
end
|
118
|
+
|
119
|
+
mask[field] = evalute_field_value(value)
|
120
|
+
end
|
121
|
+
mask
|
122
|
+
end
|
123
|
+
|
124
|
+
def apply_mask(document, mask)
|
125
|
+
mask = mask.reject do |field, _value|
|
126
|
+
document[field].nil?
|
127
|
+
end
|
128
|
+
document.update(mask)
|
129
|
+
end
|
130
|
+
|
131
|
+
def evalute_field_value(value)
|
132
|
+
eval(value)
|
133
|
+
rescue StandardError
|
134
|
+
raise "Can't eval `#{value}`"
|
135
|
+
end
|
136
|
+
|
137
|
+
def load_from_yaml(config_path)
|
138
|
+
YAML.load_file config_path
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'mongo_masker'
|
3
|
+
s.version = '1.0.0'
|
4
|
+
s.date = '2019-02-19'
|
5
|
+
s.summary = 'Mongo masker'
|
6
|
+
s.description = 'Masking production data mongodb for testing/development'
|
7
|
+
s.authors = ['Clicia Scarlet']
|
8
|
+
s.email = ['pnvduc@gmail.com']
|
9
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
10
|
+
s.bindir = 'bin'
|
11
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
12
|
+
s.require_paths = ['lib']
|
13
|
+
s.homepage = 'https://github.com/basicinc/Masker'
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.add_runtime_dependency 'thor'
|
17
|
+
s.add_runtime_dependency 'mongo'
|
18
|
+
s.add_runtime_dependency 'ffaker'
|
19
|
+
s.add_runtime_dependency 'irb'
|
20
|
+
|
21
|
+
s.add_development_dependency 'bundler'
|
22
|
+
s.add_development_dependency 'rake'
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mongo_masker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Clicia Scarlet
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mongo
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: ffaker
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
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: irb
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
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: bundler
|
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: rake
|
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
|
+
description: Masking production data mongodb for testing/development
|
98
|
+
email:
|
99
|
+
- pnvduc@gmail.com
|
100
|
+
executables:
|
101
|
+
- mongo_masker
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- ".dockerignore"
|
106
|
+
- ".gitignore"
|
107
|
+
- Dockerfile
|
108
|
+
- Gemfile
|
109
|
+
- Gemfile.lock
|
110
|
+
- README.md
|
111
|
+
- bin/mongo_masker
|
112
|
+
- docker-compose.yml
|
113
|
+
- lib/mongo_masker.rb
|
114
|
+
- mongo_masker.gemspec
|
115
|
+
homepage: https://github.com/basicinc/Masker
|
116
|
+
licenses:
|
117
|
+
- MIT
|
118
|
+
metadata: {}
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
requirements: []
|
134
|
+
rubyforge_project:
|
135
|
+
rubygems_version: 2.7.6
|
136
|
+
signing_key:
|
137
|
+
specification_version: 4
|
138
|
+
summary: Mongo masker
|
139
|
+
test_files: []
|