pg_rls 0.0.1.alpha → 0.0.1.beta
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/.rubocop.yml +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +10 -0
- data/README.md +12 -3
- data/Rakefile +9 -0
- data/lib/generators/pg_rls/active_record/active_record_generator.rb +61 -0
- data/lib/generators/pg_rls/active_record/templates/abstract_base_class.rb.tt +9 -0
- data/lib/generators/pg_rls/active_record/templates/init_migration.rb.tt +25 -0
- data/lib/generators/pg_rls/active_record/templates/init_model.rb.tt +29 -0
- data/lib/generators/pg_rls/active_record/templates/migration.rb.tt +17 -0
- data/lib/generators/pg_rls/active_record/templates/model.rb.tt +24 -0
- data/lib/generators/pg_rls/base.rb +36 -0
- data/lib/generators/pg_rls/install_generator.rb +75 -0
- data/lib/generators/pg_rls/pg_rls_generator.rb +12 -0
- data/lib/generators/pg_rls.rb +19 -0
- data/lib/generators/templates/README +19 -0
- data/lib/generators/templates/pg_rls.rb.tt +7 -0
- data/lib/pg_rls/multi_tenancy.rb +20 -0
- data/lib/pg_rls/schema/down_statements.rb +4 -4
- data/lib/pg_rls/schema/up_statements.rb +2 -2
- data/lib/pg_rls/secure_connection.rb +24 -0
- data/lib/pg_rls/{tenant/tenant.rb → tenant.rb} +4 -3
- data/lib/pg_rls/version.rb +1 -1
- data/lib/pg_rls.rb +10 -3
- metadata +32 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eff1edae4e2b864b6d1c50dbe73330ddd3092314fc0f0654ce631dd3f2381e73
|
|
4
|
+
data.tar.gz: f61c086a2319def269009a8acd4bb712457913cb23703d4f592486c1adc76161
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 88eaa010df64b8ba78630841f3ac886c44dca7929e43016e2dcbe6b4000a06ad41d0606e94fe7457eb3c46fe0e3c341d2208bf6b5fd64553fcd9eedbaee59c7a
|
|
7
|
+
data.tar.gz: 70aef5056d562fb96a2189d580f3b3cc31b1efb4ef71433969f8896268cdf0286bc5450b9b855166e48580d12aed451d0771c672611c3a934f7f046be2ea8dc9
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -2,6 +2,7 @@ PATH
|
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
4
|
pg_rls (0.0.1.alpha)
|
|
5
|
+
bundler (>= 2.2.10)
|
|
5
6
|
|
|
6
7
|
GEM
|
|
7
8
|
remote: https://rubygems.org/
|
|
@@ -136,6 +137,14 @@ GEM
|
|
|
136
137
|
rspec-mocks (3.10.2)
|
|
137
138
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
138
139
|
rspec-support (~> 3.10.0)
|
|
140
|
+
rspec-rails (5.0.2)
|
|
141
|
+
actionpack (>= 5.2)
|
|
142
|
+
activesupport (>= 5.2)
|
|
143
|
+
railties (>= 5.2)
|
|
144
|
+
rspec-core (~> 3.10)
|
|
145
|
+
rspec-expectations (~> 3.10)
|
|
146
|
+
rspec-mocks (~> 3.10)
|
|
147
|
+
rspec-support (~> 3.10)
|
|
139
148
|
rspec-support (3.10.2)
|
|
140
149
|
rubocop (1.22.1)
|
|
141
150
|
parallel (~> 1.10)
|
|
@@ -173,6 +182,7 @@ DEPENDENCIES
|
|
|
173
182
|
rails (~> 6.1.4, >= 6.1.4.1)
|
|
174
183
|
rake
|
|
175
184
|
rspec
|
|
185
|
+
rspec-rails
|
|
176
186
|
rubocop
|
|
177
187
|
|
|
178
188
|
RUBY VERSION
|
data/README.md
CHANGED
|
@@ -22,8 +22,17 @@ Or install it yourself as:
|
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
RUN `rails generate pg_rls:install company`
|
|
26
26
|
|
|
27
|
+
You can change company to anything you'd like like for example `tenant`
|
|
28
|
+
this will generate the model and inject all the required code
|
|
29
|
+
|
|
30
|
+
for any new model that required to be under rls you can generate it by writing
|
|
31
|
+
|
|
32
|
+
`rails generate pg_rls user`
|
|
33
|
+
and it will generate all the necesary information for you
|
|
34
|
+
|
|
35
|
+
enjoy the gem :)
|
|
27
36
|
## Development
|
|
28
37
|
|
|
29
38
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
@@ -32,7 +41,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
|
32
41
|
|
|
33
42
|
## Contributing
|
|
34
43
|
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
|
44
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/dandush03/pg_rls. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/dandush03/pg_rls/blob/master/CODE_OF_CONDUCT.md).
|
|
36
45
|
|
|
37
46
|
## License
|
|
38
47
|
|
|
@@ -40,4 +49,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
40
49
|
|
|
41
50
|
## Code of Conduct
|
|
42
51
|
|
|
43
|
-
Everyone interacting in the PgRls project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
|
52
|
+
Everyone interacting in the PgRls project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/dandush03/pg_rls/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
|
@@ -10,3 +10,12 @@ require 'rubocop/rake_task'
|
|
|
10
10
|
RuboCop::RakeTask.new
|
|
11
11
|
|
|
12
12
|
task default: %i[spec rubocop]
|
|
13
|
+
|
|
14
|
+
desc 'Generate documentation for PgRls.'
|
|
15
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
17
|
+
rdoc.title = 'PgRls'
|
|
18
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
|
19
|
+
rdoc.rdoc_files.include('README.md')
|
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
21
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators/active_record/model/model_generator'
|
|
4
|
+
require File.join(File.dirname(__FILE__), '../base')
|
|
5
|
+
|
|
6
|
+
module PgRls
|
|
7
|
+
module Generators
|
|
8
|
+
# Active Record Generator
|
|
9
|
+
class ActiveRecordGenerator < ::ActiveRecord::Generators::ModelGenerator
|
|
10
|
+
include ::PgRls::Base
|
|
11
|
+
|
|
12
|
+
source_root File.expand_path('./templates', __dir__)
|
|
13
|
+
|
|
14
|
+
hook_for :test_framework
|
|
15
|
+
|
|
16
|
+
def create_migration_file
|
|
17
|
+
migration_template migration_template_path, "#{migration_path}/#{file_sub_name}_#{table_name}.rb",
|
|
18
|
+
migration_version: migration_version
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_model_file
|
|
22
|
+
generate_abstract_class if database && !parent
|
|
23
|
+
template model_template_path, File.join('app/models', class_path, "#{file_name}.rb")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def migration_template_path
|
|
27
|
+
return 'init_migration.rb.tt' if installation_in_progress?
|
|
28
|
+
|
|
29
|
+
'migration.rb.tt'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def model_template_path
|
|
33
|
+
return 'init_model.rb.tt' if installation_in_progress?
|
|
34
|
+
|
|
35
|
+
'model.rb.tt'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def file_sub_name
|
|
39
|
+
return 'pg_rls_tenant_create' if installation_in_progress?
|
|
40
|
+
|
|
41
|
+
'pg_rls_create'
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def installation_in_progress?
|
|
45
|
+
shell.base.class.name.include?('Install')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def migration_version
|
|
49
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def migration_path
|
|
53
|
+
db_migrate_path
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
protected
|
|
57
|
+
|
|
58
|
+
def migration_action() = 'add'
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class PgRlsTenantCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def up
|
|
5
|
+
create_rls_tenant_table :<%= table_name %>, id: :uuid do |t|
|
|
6
|
+
t.string :name
|
|
7
|
+
t.string :logo
|
|
8
|
+
|
|
9
|
+
t.string :identification
|
|
10
|
+
t.string :subdomain
|
|
11
|
+
t.string :domain
|
|
12
|
+
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
add_index :companies, :name, unique: true
|
|
17
|
+
add_index :companies, :identification, unique: true
|
|
18
|
+
add_index :companies, :domain, unique: true
|
|
19
|
+
add_index :companies, :subdomain, unique: true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def down
|
|
23
|
+
drop_rls_tenant_table :companies
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
<% module_namespacing do -%>
|
|
4
|
+
class <%= class_name %> < <%= parent_class_name.classify %>
|
|
5
|
+
def self.current
|
|
6
|
+
find_by_tenant_id(connection.execute("SELECT current_setting('rls.tenant_id')").getvalue(0, 0))
|
|
7
|
+
rescue ActiveRecord::StatementInvalid
|
|
8
|
+
'no tenant is selected'
|
|
9
|
+
end
|
|
10
|
+
<% attributes.select(&:reference?).each do |attribute| -%>
|
|
11
|
+
belongs_to :<%= attribute.name %><%= ", polymorphic: true" if attribute.polymorphic? %>
|
|
12
|
+
<% end -%>
|
|
13
|
+
<% attributes.select(&:rich_text?).each do |attribute| -%>
|
|
14
|
+
has_rich_text :<%= attribute.name %>
|
|
15
|
+
<% end -%>
|
|
16
|
+
<% attributes.select(&:attachment?).each do |attribute| -%>
|
|
17
|
+
has_one_attached :<%= attribute.name %>
|
|
18
|
+
<% end -%>
|
|
19
|
+
<% attributes.select(&:attachments?).each do |attribute| -%>
|
|
20
|
+
has_many_attached :<%= attribute.name %>
|
|
21
|
+
<% end -%>
|
|
22
|
+
<% attributes.select(&:token?).each do |attribute| -%>
|
|
23
|
+
has_secure_token<% if attribute.name != "token" %> :<%= attribute.name %><% end %>
|
|
24
|
+
<% end -%>
|
|
25
|
+
<% if attributes.any?(&:password_digest?) -%>
|
|
26
|
+
has_secure_password
|
|
27
|
+
<% end -%>
|
|
28
|
+
end
|
|
29
|
+
<% end -%>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class PgRlsCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def up
|
|
5
|
+
create_rls_table :<%= table_name %><%= primary_key_type %> do |t|
|
|
6
|
+
<% attributes.each do |attribute| -%>
|
|
7
|
+
t.<%= attribute.type %> :<%= attribute.name %>
|
|
8
|
+
<% end -%>
|
|
9
|
+
|
|
10
|
+
t.timestamps null: false
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def down
|
|
15
|
+
drop_rls_table :<%= table_name %>
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
<% module_namespacing do -%>
|
|
4
|
+
class <%= class_name %> < <%= parent_class_name.classify %>
|
|
5
|
+
<% attributes.select(&:reference?).each do |attribute| -%>
|
|
6
|
+
belongs_to :<%= attribute.name %><%= ", polymorphic: true" if attribute.polymorphic? %>
|
|
7
|
+
<% end -%>
|
|
8
|
+
<% attributes.select(&:rich_text?).each do |attribute| -%>
|
|
9
|
+
has_rich_text :<%= attribute.name %>
|
|
10
|
+
<% end -%>
|
|
11
|
+
<% attributes.select(&:attachment?).each do |attribute| -%>
|
|
12
|
+
has_one_attached :<%= attribute.name %>
|
|
13
|
+
<% end -%>
|
|
14
|
+
<% attributes.select(&:attachments?).each do |attribute| -%>
|
|
15
|
+
has_many_attached :<%= attribute.name %>
|
|
16
|
+
<% end -%>
|
|
17
|
+
<% attributes.select(&:token?).each do |attribute| -%>
|
|
18
|
+
has_secure_token<% if attribute.name != "token" %> :<%= attribute.name %><% end %>
|
|
19
|
+
<% end -%>
|
|
20
|
+
<% if attributes.any?(&:password_digest?) -%>
|
|
21
|
+
has_secure_password
|
|
22
|
+
<% end -%>
|
|
23
|
+
end
|
|
24
|
+
<% end -%>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgRls
|
|
4
|
+
# Main Definition for Generator
|
|
5
|
+
module Base
|
|
6
|
+
protected
|
|
7
|
+
|
|
8
|
+
def nested_parent_name
|
|
9
|
+
@class_path.join('/')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def nested_parent_id
|
|
13
|
+
"#{nested_parent_name}_id"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def nested_parent_class_name
|
|
17
|
+
nested_parent_name.classify
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def plural_nested_parent_name
|
|
21
|
+
nested_parent_name.pluralize
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def class_path
|
|
25
|
+
[]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def regular_class_path
|
|
29
|
+
[]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def controller_class_path
|
|
33
|
+
[]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators/base'
|
|
4
|
+
require 'securerandom'
|
|
5
|
+
|
|
6
|
+
module PgRls
|
|
7
|
+
module Generators
|
|
8
|
+
MissingORMError = Class.new(Thor::Error)
|
|
9
|
+
# Installer Generator
|
|
10
|
+
class InstallGenerator < Rails::Generators::Base
|
|
11
|
+
APPLICATION_RECORD_LINE = 'class ApplicationRecord < ActiveRecord::Base'
|
|
12
|
+
APPLICATION_RECORD_PATH = 'app/models/application_record.rb'
|
|
13
|
+
APPLICATION_CONTROLLER_LINE = 'class ApplicationController < ActionController::Base'
|
|
14
|
+
APPLICATION_CONTROLLER_PATH = 'app/controllers/application_controller.rb'
|
|
15
|
+
source_root File.expand_path('../templates', __dir__)
|
|
16
|
+
|
|
17
|
+
desc 'Creates a PgRls initializer and copy locale files to your application.'
|
|
18
|
+
|
|
19
|
+
def orm_error_message
|
|
20
|
+
<<-ERROR.strip_heredoc
|
|
21
|
+
An ORM must be set to install PgRls in your application.
|
|
22
|
+
Be sure to have an ORM like Active Record or loaded in your
|
|
23
|
+
app or configure your own at `config/application.rb`.
|
|
24
|
+
config.generators do |g|
|
|
25
|
+
g.orm :your_orm_gem
|
|
26
|
+
end
|
|
27
|
+
ERROR
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def copy_initializer
|
|
31
|
+
raise MissingORMError, orm_error_message unless options[:orm]
|
|
32
|
+
|
|
33
|
+
template 'pg_rls.rb.tt', 'config/initializers/pg_rls.rb'
|
|
34
|
+
|
|
35
|
+
inject_include_to_application_record
|
|
36
|
+
inject_include_to_application_controller
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def inject_include_to_application_record
|
|
40
|
+
return if aplication_record_already_included?
|
|
41
|
+
|
|
42
|
+
gsub_file(APPLICATION_RECORD_PATH, /(#{Regexp.escape(APPLICATION_RECORD_LINE)})/mi) do |match|
|
|
43
|
+
"#{match}\n include PgRls::SecureConnection\n"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def inject_include_to_application_controller
|
|
48
|
+
return if aplication_controller_already_included?
|
|
49
|
+
|
|
50
|
+
gsub_file(APPLICATION_CONTROLLER_PATH, /(#{Regexp.escape(APPLICATION_CONTROLLER_LINE)})/mi) do |match|
|
|
51
|
+
"#{match}\n include PgRls::MultiTenancy\n"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def aplication_controller_already_included?
|
|
56
|
+
File.readlines(APPLICATION_CONTROLLER_PATH).grep(/include PgRls::MultiTenancy/).any?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def aplication_record_already_included?
|
|
60
|
+
File.readlines(APPLICATION_RECORD_PATH).grep(/include PgRls::SecureConnection/).any?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def initialize_error_text
|
|
64
|
+
<<-ERROR.strip_heredoc
|
|
65
|
+
ERROR
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def show_readme
|
|
69
|
+
readme 'README' if behavior == :invoke
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
hook_for :orm, required: true
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative File.join(File.dirname(__FILE__), 'active_record/active_record_generator')
|
|
4
|
+
|
|
5
|
+
module PgRls
|
|
6
|
+
module Generators
|
|
7
|
+
class PgRlsGenerator < ::Rails::Generators::NamedBase
|
|
8
|
+
# override ModelGenerator
|
|
9
|
+
hook_for :orm, required: true
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators/named_base'
|
|
4
|
+
require 'rails/generators/active_model'
|
|
5
|
+
require 'rails/generators/active_record/migration'
|
|
6
|
+
require 'active_record'
|
|
7
|
+
|
|
8
|
+
module PgRls
|
|
9
|
+
module Generators # :nodoc:
|
|
10
|
+
class PgRlsGenerator < Rails::Generators::NamedBase # :nodoc:
|
|
11
|
+
include PgRls::Generators::Migration
|
|
12
|
+
|
|
13
|
+
# Set the current directory as base for the inherited generators.
|
|
14
|
+
def self.base_root
|
|
15
|
+
__dir__
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
README
|
|
2
|
+
===============================================================================
|
|
3
|
+
WARNING!!
|
|
4
|
+
|
|
5
|
+
Once you remove a tenant all of his data would be removed as well
|
|
6
|
+
|
|
7
|
+
PgRls::SecureConnection was included to your ApplicationRecord do not remove it
|
|
8
|
+
|
|
9
|
+
===============================================================================
|
|
10
|
+
|
|
11
|
+
to generate secure model run
|
|
12
|
+
|
|
13
|
+
rails g pg_rls model_name
|
|
14
|
+
|
|
15
|
+
or
|
|
16
|
+
|
|
17
|
+
rails generate pg_rls model_name
|
|
18
|
+
|
|
19
|
+
===============================================================================
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgRls
|
|
4
|
+
# Ensure Connection is with App_use
|
|
5
|
+
module MultiTenancy
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.class_eval do
|
|
8
|
+
before_action :switch_tenant
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def switch_tenant
|
|
15
|
+
Tenant.switch request.subdomain
|
|
16
|
+
rescue NoMethodError
|
|
17
|
+
redirect_to '/'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -4,8 +4,8 @@ module PgRls
|
|
|
4
4
|
module Schema
|
|
5
5
|
# Down Schema Statements
|
|
6
6
|
module DownStatements
|
|
7
|
-
def drop_rls_user
|
|
8
|
-
ActiveRecord::Migration.execute "DROP USER #{
|
|
7
|
+
def drop_rls_user
|
|
8
|
+
ActiveRecord::Migration.execute "DROP USER #{PgRls::SECURE_USERNAME};"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def drop_rls_blocking_function
|
|
@@ -37,9 +37,9 @@ module PgRls
|
|
|
37
37
|
SQL
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
def drop_rls_policy(table_name
|
|
40
|
+
def drop_rls_policy(table_name)
|
|
41
41
|
ActiveRecord::Migration.execute <<-SQL
|
|
42
|
-
DROP POLICY #{table_name}_#{
|
|
42
|
+
DROP POLICY #{table_name}_#{PgRls::SECURE_USERNAME} ON #{table_name};
|
|
43
43
|
ALTER TABLE #{table_name} DISABLE ROW LEVEL SECURITY;
|
|
44
44
|
SQL
|
|
45
45
|
end
|
|
@@ -4,7 +4,7 @@ module PgRls
|
|
|
4
4
|
module Schema
|
|
5
5
|
# Up Schema Statements
|
|
6
6
|
module UpStatements
|
|
7
|
-
def create_rls_user(name:
|
|
7
|
+
def create_rls_user(name: PgRls::SECURE_USERNAME, password: 'password')
|
|
8
8
|
PgRls.execute <<-SQL
|
|
9
9
|
DROP ROLE IF EXISTS #{name};
|
|
10
10
|
CREATE USER #{name} WITH PASSWORD '#{password}';
|
|
@@ -71,7 +71,7 @@ module PgRls
|
|
|
71
71
|
SQL
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def create_rls_policy(table_name, user =
|
|
74
|
+
def create_rls_policy(table_name, user = PgRls::SECURE_USERNAME)
|
|
75
75
|
ActiveRecord::Migration.execute <<-SQL
|
|
76
76
|
ALTER TABLE #{table_name} ENABLE ROW LEVEL SECURITY;
|
|
77
77
|
CREATE POLICY #{table_name}_#{user}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PgRls
|
|
4
|
+
# Ensure Connection is with App_use
|
|
5
|
+
module SecureConnection
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.class_eval do
|
|
8
|
+
after_initialize :establish_secure_connection
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def establish_secure_connection
|
|
15
|
+
return if secure_connection_established?
|
|
16
|
+
|
|
17
|
+
PgRls.establish_new_connection
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def secure_connection_established?
|
|
21
|
+
PgRls.current_connection_username == PgRls::SECURE_USERNAME
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -6,10 +6,11 @@ module PgRls
|
|
|
6
6
|
class << self
|
|
7
7
|
SET_COMPANY_ID_SQL = 'SET rls.tenant_id = %s'
|
|
8
8
|
def switch(resource)
|
|
9
|
-
connection_adapter = PgRls.
|
|
9
|
+
connection_adapter = PgRls.connection_class
|
|
10
10
|
tenant = tenant_by_subdomain_uuid_or_tenant_id(resource)
|
|
11
|
-
connection_adapter.connection.execute(format(
|
|
12
|
-
|
|
11
|
+
connection_adapter.connection.execute(format(SET_COMPANY_ID_SQL,
|
|
12
|
+
connection_adapter.connection.quote(tenant.tenant_id)))
|
|
13
|
+
"RLS changed to '#{tenant}'"
|
|
13
14
|
rescue StandardError => e
|
|
14
15
|
puts 'connection was not made'
|
|
15
16
|
puts e
|
data/lib/pg_rls/version.rb
CHANGED
data/lib/pg_rls.rb
CHANGED
|
@@ -4,11 +4,14 @@ require 'active_record'
|
|
|
4
4
|
require 'forwardable'
|
|
5
5
|
require_relative 'pg_rls/version'
|
|
6
6
|
require_relative 'pg_rls/schema/statements'
|
|
7
|
-
require_relative 'pg_rls/tenant
|
|
7
|
+
require_relative 'pg_rls/tenant'
|
|
8
|
+
require_relative 'pg_rls/secure_connection'
|
|
9
|
+
require_relative 'pg_rls/multi_tenancy'
|
|
8
10
|
|
|
9
11
|
# PostgreSQL Row Level Security
|
|
10
12
|
module PgRls
|
|
11
13
|
class Error < StandardError; end
|
|
14
|
+
SECURE_USERNAME = 'app_user'
|
|
12
15
|
|
|
13
16
|
class << self
|
|
14
17
|
extend Forwardable
|
|
@@ -38,17 +41,21 @@ module PgRls
|
|
|
38
41
|
|
|
39
42
|
def establish_new_connection
|
|
40
43
|
connection_class.establish_connection(
|
|
41
|
-
|
|
44
|
+
**database_configuration
|
|
42
45
|
)
|
|
43
46
|
end
|
|
44
47
|
|
|
48
|
+
def current_connection_username
|
|
49
|
+
PgRls.connection_class.connection_db_config.configuration_hash[:username]
|
|
50
|
+
end
|
|
51
|
+
|
|
45
52
|
def execute(query)
|
|
46
53
|
@execute = ActiveRecord::Migration.execute(query)
|
|
47
54
|
end
|
|
48
55
|
|
|
49
56
|
def database_configuration
|
|
50
57
|
@database_configuration ||= database_connection_file[Rails.env].tap do |config|
|
|
51
|
-
config['username'] =
|
|
58
|
+
config['username'] = PgRls::SECURE_USERNAME
|
|
52
59
|
end
|
|
53
60
|
end
|
|
54
61
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pg_rls
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.1.
|
|
4
|
+
version: 0.0.1.beta
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Laloush
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-10-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2021-10-10 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: 2.2.10
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 2.2.10
|
|
13
27
|
description: Write a longer description or delete this line.
|
|
14
28
|
email:
|
|
15
29
|
- daniel.laloush@influitive.com
|
|
@@ -28,11 +42,25 @@ files:
|
|
|
28
42
|
- Rakefile
|
|
29
43
|
- bin/console
|
|
30
44
|
- bin/setup
|
|
45
|
+
- lib/generators/pg_rls.rb
|
|
46
|
+
- lib/generators/pg_rls/active_record/active_record_generator.rb
|
|
47
|
+
- lib/generators/pg_rls/active_record/templates/abstract_base_class.rb.tt
|
|
48
|
+
- lib/generators/pg_rls/active_record/templates/init_migration.rb.tt
|
|
49
|
+
- lib/generators/pg_rls/active_record/templates/init_model.rb.tt
|
|
50
|
+
- lib/generators/pg_rls/active_record/templates/migration.rb.tt
|
|
51
|
+
- lib/generators/pg_rls/active_record/templates/model.rb.tt
|
|
52
|
+
- lib/generators/pg_rls/base.rb
|
|
53
|
+
- lib/generators/pg_rls/install_generator.rb
|
|
54
|
+
- lib/generators/pg_rls/pg_rls_generator.rb
|
|
55
|
+
- lib/generators/templates/README
|
|
56
|
+
- lib/generators/templates/pg_rls.rb.tt
|
|
31
57
|
- lib/pg_rls.rb
|
|
58
|
+
- lib/pg_rls/multi_tenancy.rb
|
|
32
59
|
- lib/pg_rls/schema/down_statements.rb
|
|
33
60
|
- lib/pg_rls/schema/statements.rb
|
|
34
61
|
- lib/pg_rls/schema/up_statements.rb
|
|
35
|
-
- lib/pg_rls/
|
|
62
|
+
- lib/pg_rls/secure_connection.rb
|
|
63
|
+
- lib/pg_rls/tenant.rb
|
|
36
64
|
- lib/pg_rls/version.rb
|
|
37
65
|
homepage: https://github.com/Dandush03/pg_rls
|
|
38
66
|
licenses:
|