diff --git a/lib/posgra/cli/app.rb b/lib/posgra/cli/app.rb index 34be271..2164476 100644 --- a/lib/posgra/cli/app.rb +++ b/lib/posgra/cli/app.rb @@ -1,6 +1,6 @@ class Posgra::CLI::App < Thor class_option :host, :default => ENV['POSGRA_DB_HOST'] || 'localhost', :aliases => '-h' - class_option :port, :type => :numeric, :default => ENV['POSGRA_DB_PORT'] || 5432, :aliases => '-p' + class_option :port, :type => :numeric, :default => ENV['POSGRA_DB_PORT'].to_i || 5432, :aliases => '-p' class_option :dbname, :default => ENV['POSGRA_DB_DATABASE'] || 'postgres', :aliases => '-d' class_option :user, :default => ENV['POSGRA_DB_USER'], :aliases => '-U' class_option :password, :default => ENV['POSGRA_DB_PASSWORD'], :aliases => '-P' diff --git a/lib/posgra/cli/database.rb b/lib/posgra/cli/database.rb index c6dcd78..6935495 100644 --- a/lib/posgra/cli/database.rb +++ b/lib/posgra/cli/database.rb @@ -12,7 +12,7 @@ class Posgra::CLI::Database < Thor desc 'apply FILE', 'Apply database grants' option :'dry-run', :type => :boolean, :default => false def apply(file) - check_fileanem(file) + check_filename(file) updated = client.apply_databases(file) unless updated @@ -23,7 +23,7 @@ def apply(file) desc 'export [FILE]', 'Export database grants' option :split, :type => :boolean, :default => false def export(file = nil) - check_fileanem(file) + check_filename(file) dsl = client.export_databases if options[:split] diff --git a/lib/posgra/cli/grant.rb b/lib/posgra/cli/grant.rb index c7ab94e..56f699b 100644 --- a/lib/posgra/cli/grant.rb +++ b/lib/posgra/cli/grant.rb @@ -14,7 +14,7 @@ class Posgra::CLI::Grant < Thor desc 'apply FILE', 'Apply grants' option :'dry-run', :type => :boolean, :default => false def apply(file) - check_fileanem(file) + check_filename(file) updated = client.apply_grants(file) unless updated @@ -25,7 +25,7 @@ def apply(file) desc 'export [FILE]', 'Export grants' option :split, :type => :boolean, :default => false def export(file = nil) - check_fileanem(file) + check_filename(file) dsl = client.export_grants if options[:split] diff --git a/lib/posgra/cli/helper.rb b/lib/posgra/cli/helper.rb index 64c197a..9cdefd4 100644 --- a/lib/posgra/cli/helper.rb +++ b/lib/posgra/cli/helper.rb @@ -8,7 +8,7 @@ module Posgra::CLI::Helper :exclude_object, ] - def check_fileanem(file) + def check_filename(file) if file =~ /\A-.+/ raise "Invalid failname: #{file}" end diff --git a/lib/posgra/cli/role.rb b/lib/posgra/cli/role.rb index 7b748e2..ea4999c 100644 --- a/lib/posgra/cli/role.rb +++ b/lib/posgra/cli/role.rb @@ -9,7 +9,7 @@ class Posgra::CLI::Role < Thor desc 'apply FILE', 'Apply roles' option :'dry-run', :type => :boolean, :default => false def apply(file) - check_fileanem(file) + check_filename(file) updated = client.apply_roles(file) unless updated @@ -19,7 +19,7 @@ def apply(file) desc 'export [FILE]', 'Export roles' def export(file = nil) - check_fileanem(file) + check_filename(file) dsl = client.export_roles if file.nil? or file == '-' diff --git a/lib/posgra/driver.rb b/lib/posgra/driver.rb index 6a46391..51bce2c 100644 --- a/lib/posgra/driver.rb +++ b/lib/posgra/driver.rb @@ -41,7 +41,7 @@ def create_user(user) updated = false password = @identifier.identify(user) - sql = "CREATE USER #{@client.escape_identifier(user)} PASSWORD #{@client.escape_literal(password)}" + sql = "CREATE USER #{escape(user)} PASSWORD #{@client.escape_literal(password)}" log(:info, sql, :color => :cyan) unless @options[:dry_run] @@ -55,7 +55,7 @@ def create_user(user) def drop_user(user) updated = false - sql = "DROP USER #{@client.escape_identifier(user)}" + sql = "DROP USER #{escape(user)}" log(:info, sql, :color => :red) unless @options[:dry_run] @@ -69,12 +69,13 @@ def drop_user(user) def create_group(group) updated = false - sql = "CREATE GROUP #{@client.escape_identifier(group)}" + sql = "CREATE GROUP #{escape(group, true)}" log(:info, sql, :color => :cyan) unless @options[:dry_run] exec(sql) updated = true + @groups = describe_groups.keys end updated @@ -83,7 +84,7 @@ def create_group(group) def add_user_to_group(user, group) updated = false - sql = "ALTER GROUP #{@client.escape_identifier(group)} ADD USER #{@client.escape_identifier(user)}" + sql = "ALTER GROUP #{escape(group, true)} ADD USER #{escape(user)}" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -97,7 +98,7 @@ def add_user_to_group(user, group) def drop_user_from_group(user, group) updated = false - sql = "ALTER GROUP #{@client.escape_identifier(group)} DROP USER #{@client.escape_identifier(user)}" + sql = "ALTER GROUP #{escape(group, true)} DROP USER #{escape(user)}" log(:info, sql, :color => :cyan) unless @options[:dry_run] @@ -111,12 +112,13 @@ def drop_user_from_group(user, group) def drop_group(group) updated = false - sql = "DROP GROUP #{@client.escape_identifier(group)}" + sql = "DROP GROUP #{escape(group, true)}" log(:info, sql, :color => :red) unless @options[:dry_run] exec(sql) updated = true + @groups = describe_groups.keys end updated @@ -135,7 +137,7 @@ def revoke_all_on_schema(role, schema) def revoke_all_on_object(role, schema, object) updated = false - sql = "REVOKE ALL ON #{@client.escape_identifier(schema)}.#{@client.escape_identifier(object)} FROM #{@client.escape_identifier(role)}" + sql = "REVOKE ALL ON #{escape(schema)}.#{escape(object)} FROM #{escape(role)}" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -147,7 +149,7 @@ def revoke_all_on_object(role, schema, object) end def revoke_all_on_database(role, database) - sql = "REVOKE ALL ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}" + sql = "REVOKE ALL ON DATABASE #{escape(database)} FROM #{escape(role)}" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -161,7 +163,7 @@ def revoke_all_on_database(role, database) def grant(role, priv, options, schema, object) updated = false - sql = "GRANT #{priv} ON #{@client.escape_identifier(schema)}.#{@client.escape_identifier(object)} TO #{@client.escape_identifier(role)}" + sql = "GRANT #{priv} ON #{escape(schema)}.#{escape(object)} TO #{escape(role)}" if options['is_grantable'] sql << ' WITH GRANT OPTION' @@ -183,7 +185,7 @@ def update_grant_options(role, priv, options, schema, object) if options.fetch('is_grantable') updated = grant_grant_option(role, priv, schema, object) else - updated = roveke_grant_option(role, priv, schema, object) + updated = revoke_grant_option(role, priv, schema, object) end updated @@ -192,7 +194,7 @@ def update_grant_options(role, priv, options, schema, object) def grant_grant_option(role, priv, schema, object) updated = false - sql = "GRANT #{priv} ON #{@client.escape_identifier(schema)}.#{@client.escape_identifier(object)} TO #{@client.escape_identifier(role)} WITH GRANT OPTION" + sql = "GRANT #{priv} ON #{escape(schema)}.#{escape(object)} TO #{escape(role)} WITH GRANT OPTION" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -203,10 +205,10 @@ def grant_grant_option(role, priv, schema, object) updated end - def roveke_grant_option(role, priv, schema, object) + def revoke_grant_option(role, priv, schema, object) updated = false - sql = "REVOKE GRANT OPTION FOR #{priv} ON #{@client.escape_identifier(schema)}.#{@client.escape_identifier(object)} FROM #{@client.escape_identifier(role)}" + sql = "REVOKE GRANT OPTION FOR #{priv} ON #{escape(schema)}.#{escape(object)} FROM #{escape(role)}" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -220,7 +222,7 @@ def roveke_grant_option(role, priv, schema, object) def revoke(role, priv, schema, object) updated = false - sql = "REVOKE #{priv} ON #{@client.escape_identifier(schema)}.#{@client.escape_identifier(object)} FROM #{@client.escape_identifier(role)}" + sql = "REVOKE #{priv} ON #{escape(schema)}.#{escape(object)} FROM #{escape(role)}" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -234,7 +236,7 @@ def revoke(role, priv, schema, object) def database_grant(role, priv, options, database) updated = false - sql = "GRANT #{priv} ON DATABASE #{@client.escape_identifier(database)} TO #{@client.escape_identifier(role)}" + sql = "GRANT #{priv} ON DATABASE #{escape(database)} TO #{escape(role)}" if options['is_grantable'] sql << ' WITH GRANT OPTION' @@ -256,7 +258,7 @@ def update_database_grant_options(role, priv, options, database) if options.fetch('is_grantable') updated = grant_database_grant_option(role, priv, database) else - updated = roveke_database_grant_option(role, priv, database) + updated = revoke_database_grant_option(role, priv, database) end updated @@ -265,7 +267,7 @@ def update_database_grant_options(role, priv, options, database) def grant_database_grant_option(role, priv, database) updated = false - sql = "GRANT #{priv} ON DATABASE #{@client.escape_identifier(database)} TO #{@client.escape_identifier(role)} WITH GRANT OPTION" + sql = "GRANT #{priv} ON DATABASE #{escape(database)} TO #{escape(role)} WITH GRANT OPTION" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -276,10 +278,10 @@ def grant_database_grant_option(role, priv, database) updated end - def roveke_database_grant_option(role, priv, database) + def revoke_database_grant_option(role, priv, database) updated = false - sql = "REVOKE GRANT OPTION FOR #{priv} ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}" + sql = "REVOKE GRANT OPTION FOR #{priv} ON DATABASE #{escape(database)} FROM #{escape(role)}" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -293,7 +295,7 @@ def roveke_database_grant_option(role, priv, database) def database_revoke(role, priv, database) updated = false - sql = "REVOKE #{priv} ON DATABASE #{@client.escape_identifier(database)} FROM #{@client.escape_identifier(role)}" + sql = "REVOKE #{priv} ON DATABASE #{escape(database)} FROM #{escape(role)}" log(:info, sql, :color => :green) unless @options[:dry_run] @@ -440,6 +442,16 @@ def describe_databases private + def escape(src, skip_group_command=false) + @groups ||= describe_groups.keys + if @groups.include?(src) && !skip_group_command + group_name = @client.escape_identifier(src.gsub('group:', '')) + "GROUP #{group_name}" + else + @client.escape_identifier(src) + end + end + def parse_aclitems(aclitems, owner, relkind) aclitems_fmt = DEFAULT_ACL_BY_KIND.fetch(relkind, DEFAULT_ACL) aclitems ||= aclitems_fmt % [owner, owner] diff --git a/lib/posgra/identifier/auto.rb b/lib/posgra/identifier/auto.rb index 37dfc4a..21e6626 100644 --- a/lib/posgra/identifier/auto.rb +++ b/lib/posgra/identifier/auto.rb @@ -1,17 +1,30 @@ +require 'csv' + class Posgra::Identifier::Auto def initialize(output, options = {}) @output = output @options = options + @accounts = {} + read_accounts end def identify(user) - password = mkpasswd((@options[:password_length] || 8).to_i) + password_length = [@options[:password_length].to_i, 8].max + password = @accounts.fetch(user, mkpasswd(password_length)) puts_password(user, password) password end private + def read_accounts + return unless File.file?(@output) + + CSV.foreach(@output, {encoding: "UTF-8", headers: false}) do |row| + @accounts[row[0]] = row[1] + end + end + def mkpasswd(len) sources = [ (1..9).to_a, @@ -30,6 +43,7 @@ def mkpasswd(len) end def puts_password(user, password) + @accounts[user] = password open_output do |f| f.puts("#{user},#{password}") end