module Sidekiq::EncryptedArgs

Constants

SALT

Hard coded password salt used sent to the encryptor. Do no change.

VERSION

Public Class Methods

configure!(secret: nil) click to toggle source

Add the client and server middleware to the Sidekiq middleware chains. If you need to ensure the order of where the middleware is added, you can forgo this method and add it yourself.

This method prepends client middleware and appends server middleware.

@param [String] secret optionally set the secret here. See {.secret=}

# File lib/sidekiq/encrypted_args.rb, line 41
def configure!(secret: nil)
  self.secret = secret unless secret.nil?

  Sidekiq.configure_client do |config|
    config.client_middleware do |chain|
      chain.prepend Sidekiq::EncryptedArgs::ClientMiddleware
    end
  end

  Sidekiq.configure_server do |config|
    config.server_middleware do |chain|
      chain.add Sidekiq::EncryptedArgs::ServerMiddleware
    end
    config.client_middleware do |chain|
      chain.prepend Sidekiq::EncryptedArgs::ClientMiddleware
    end
  end
end
decrypt(encrypted_data) click to toggle source

Decrypt data

@param [String] encrypted_data Data that was previously encrypted. If the value passed in is an unencrypted string, then the string itself will be returned.

@return [Object]

# File lib/sidekiq/encrypted_args.rb, line 82
def decrypt(encrypted_data)
  return encrypted_data unless SecretKeys::Encryptor.encrypted?(encrypted_data)
  json = decrypt_string(encrypted_data)
  JSON.parse(json)
end
encrypt(data) click to toggle source

Encrypt a value.

@param [#to_json, Object] data Data to encrypt. You can pass any JSON compatible data types or structures.

@return [String]

# File lib/sidekiq/encrypted_args.rb, line 65
def encrypt(data)
  return nil if data.nil?
  json = (data.respond_to?(:to_json) ? data.to_json : JSON.generate(data))
  encrypted = encrypt_string(json)
  if encrypted == json
    data
  else
    encrypted
  end
end
encrypted_args_option(worker_class, job) click to toggle source

Private helper method to get the encrypted args option from an options hash. The value of this option can be `true` or an array indicating if each positional argument should be encrypted, or a hash with keys for the argument position and true as the value.

@private

# File lib/sidekiq/encrypted_args.rb, line 93
def encrypted_args_option(worker_class, job)
  option = job["encrypted_args"]
  return nil if option.nil?
  return [] if option == false

  indexes = []
  if option == true
    job["args"].size.times { |i| indexes << i }
  elsif option.is_a?(Hash)
    deprecation_warning("hash")
    indexes = replace_argument_positions(worker_class, option)
  else
    array_type = nil
    deprecation_message = nil
    Array(option).each_with_index do |val, position|
      current_type = nil
      if val.is_a?(Integer)
        indexes << val
        current_type = :integer
      elsif val.is_a?(Symbol) || val.is_a?(String)
        worker_class = constantize(worker_class) if worker_class.is_a?(String)
        position = perform_method_parameter_index(worker_class, val)
        indexes << position if position
        current_type = :symbol
      else
        deprecation_message = "boolean array"
        indexes << position if val
      end
      if array_type && current_type
        deprecation_message = "array of mixed types"
      else
        array_type ||= current_type
      end
    end
    deprecation_warning(deprecation_message) if deprecation_message
  end
  indexes
end
secret=(value) click to toggle source

Set the secret key used for encrypting arguments. If this is not set, the value will be loaded from the `SIDEKIQ_ENCRYPTED_ARGS_SECRET` environment variable. If that value is not set, arguments will not be encrypted.

You can set multiple secrets by passing an array if you need to roll your secrets. The left most value in the array will be used as the encryption secret, but all the values will be tried when decrypting. That way if you have scheduled jobs that were encrypted with a different secret, you can still make it available when decrypting the arguments when the job gets run. If you are using the environment variable, separate the keys with spaces.

@param [String] value One or more secrets to use for encrypting arguments. @return [void]

# File lib/sidekiq/encrypted_args.rb, line 30
def secret=(value)
  @encryptors = make_encryptors(value)
end

Private Class Methods

constantize(class_name) click to toggle source

@param [String] class_name name of a class @return [Class] class that was referenced by name

# File lib/sidekiq/encrypted_args.rb, line 173
def constantize(class_name)
  names = class_name.split("::")
  # Clear leading :: for root namespace since we're already calling from object
  names.shift if names.empty? || names.first.empty?
  # Map reduce to the constant. Use inherit=false to not accidentally search
  # parent modules
  names.inject(Object) { |constant, name| constant.const_get(name, false) }
end
decrypt_string(value) click to toggle source
# File lib/sidekiq/encrypted_args.rb, line 144
def decrypt_string(value)
  return value if encryptors == [nil]
  encryptors.each do |encryptor|
    begin
      return encryptor.decrypt(value) if encryptor
    rescue OpenSSL::Cipher::CipherError
      # Not the right key, try the next one
    end
  end
  raise InvalidSecretError
end
deprecation_warning(message) click to toggle source
# File lib/sidekiq/encrypted_args.rb, line 167
def deprecation_warning(message)
  warn("Sidekiq::EncryptedArgs: setting encrypted_args to #{message} is deprecated; support will be removed in version 1.2.")
end
encrypt_string(value) click to toggle source
# File lib/sidekiq/encrypted_args.rb, line 138
def encrypt_string(value)
  encryptor = encryptors.first
  return value if encryptor.nil?
  encryptor.encrypt(value)
end
encryptors() click to toggle source
# File lib/sidekiq/encrypted_args.rb, line 156
def encryptors
  if !defined?(@encryptors) || @encryptors.empty?
    @encryptors = make_encryptors(ENV["SIDEKIQ_ENCRYPTED_ARGS_SECRET"].to_s.split)
  end
  @encryptors
end
make_encryptors(secrets) click to toggle source
# File lib/sidekiq/encrypted_args.rb, line 163
def make_encryptors(secrets)
  Array(secrets).map { |val| val.nil? ? nil : SecretKeys::Encryptor.from_password(val, SALT) }
end
perform_method_parameter_index(worker_class, parameter) click to toggle source
# File lib/sidekiq/encrypted_args.rb, line 196
def perform_method_parameter_index(worker_class, parameter)
  if worker_class
    parameter = parameter.to_sym
    worker_class.instance_method(:perform).parameters.find_index { |_, name| name == parameter }
  end
end
replace_argument_positions(worker_class, encrypt_option_hash) click to toggle source
# File lib/sidekiq/encrypted_args.rb, line 182
def replace_argument_positions(worker_class, encrypt_option_hash)
  encrypted_indexes = []
  encrypt_option_hash.each do |key, value|
    next unless value
    if key.is_a?(Symbol) || key.is_a?(String)
      position = perform_method_parameter_index(worker_class, key)
      encrypted_indexes << position if position
    elsif key.is_a?(Integer)
      encrypted_indexes << key
    end
  end
  encrypted_indexes
end