class Match::Encryption::OpenSSL

Attributes

force_legacy_encryption[RW]
keychain_name[RW]
working_directory[RW]

Public Class Methods

configure(params) click to toggle source
# File match/lib/match/encryption/openssl.rb, line 19
def self.configure(params)
  return self.new(
    keychain_name: params[:keychain_name],
    working_directory: params[:working_directory],
    force_legacy_encryption: params[:force_legacy_encryption]
  )
end
new(keychain_name: nil, working_directory: nil, force_legacy_encryption: false) click to toggle source

@param keychain_name: The identifier used to store the passphrase in the Keychain @param working_directory: The path to where the certificates are stored @param force_legacy_encryption: Force use of legacy EncryptionV1 algorithm

# File match/lib/match/encryption/openssl.rb, line 30
def initialize(keychain_name: nil, working_directory: nil, force_legacy_encryption: false)
  self.keychain_name = keychain_name
  self.working_directory = working_directory
  self.force_legacy_encryption = force_legacy_encryption
end

Public Instance Methods

clear_password() click to toggle source

removes the password from the keychain again

# File match/lib/match/encryption/openssl.rb, line 74
def clear_password
  Security::InternetPassword.delete(server: server_name(self.keychain_name))
end
decrypt_files() click to toggle source
# File match/lib/match/encryption/openssl.rb, line 48
def decrypt_files
  files = []
  password = fetch_password!
  iterate(self.working_directory) do |current|
    files << current
    begin
      decrypt_specific_file(path: current, password: password)
    rescue => ex
      UI.verbose(ex.to_s)
      UI.error("Couldn't decrypt the repo, please make sure you enter the right password!")
      UI.user_error!("Invalid password passed via 'MATCH_PASSWORD'") if ENV["MATCH_PASSWORD"]
      clear_password
      self.decrypt_files # Call itself
      return
    end
    UI.success("🔓  Decrypted '#{File.basename(current)}'") if FastlaneCore::Globals.verbose?
  end
  UI.success("🔓  Successfully decrypted certificates repo")
  return files
end
encrypt_files(password: nil) click to toggle source
# File match/lib/match/encryption/openssl.rb, line 36
def encrypt_files(password: nil)
  files = []
  password ||= fetch_password!
  iterate(self.working_directory) do |current|
    files << current
    encrypt_specific_file(path: current, password: password, version: force_legacy_encryption ? 1 : 2)
    UI.success("🔒  Encrypted '#{File.basename(current)}'") if FastlaneCore::Globals.verbose?
  end
  UI.success("🔒  Successfully encrypted certificates repo")
  return files
end
store_password(password) click to toggle source
# File match/lib/match/encryption/openssl.rb, line 69
def store_password(password)
  Security::InternetPassword.add(server_name(self.keychain_name), "", password)
end

Private Instance Methods

decrypt_specific_file(path: nil, password: nil) click to toggle source
# File match/lib/match/encryption/openssl.rb, line 128
def decrypt_specific_file(path: nil, password: nil)
  e = MatchFileEncryption.new
  e.decrypt(file_path: path, password: password)
rescue => error
  UI.error(error.to_s)
  UI.crash!("Error decrypting '#{path}'")
end
encrypt_specific_file(path: nil, password: nil, version: nil) click to toggle source
# File match/lib/match/encryption/openssl.rb, line 117
def encrypt_specific_file(path: nil, password: nil, version: nil)
  UI.user_error!("No password supplied") if password.to_s.strip.length == 0
  e = MatchFileEncryption.new
  e.encrypt(file_path: path, password: password, version: version)
rescue FastlaneCore::Interface::FastlaneError
  raise
rescue => error
  UI.error(error.to_s)
  UI.crash!("Error encrypting '#{path}'")
end
fetch_password!() click to toggle source

Access the MATCH_PASSWORD, either from ENV variable, Keychain or user input

# File match/lib/match/encryption/openssl.rb, line 93
def fetch_password!
  password = ENV["MATCH_PASSWORD"]
  unless password
    item = Security::InternetPassword.find(server: server_name(self.keychain_name))
    password = item.password if item
  end

  unless password
    if !UI.interactive?
      UI.error("Neither the MATCH_PASSWORD environment variable nor the local keychain contained a password.")
      UI.error("Bailing out instead of asking for a password, since this is non-interactive mode.")
      UI.user_error!("Try setting the MATCH_PASSWORD environment variable, or temporarily enable interactive mode to store a password.")
    else
      UI.important("Enter the passphrase that should be used to encrypt/decrypt your certificates")
      UI.important("This passphrase is specific per repository and will be stored in your local keychain")
      UI.important("Make sure to remember the password, as you'll need it when you run match on a different machine")
      password = FastlaneCore::Helper.ask_password(message: "Passphrase for Match storage: ", confirm: true)
      store_password(password)
    end
  end

  return password
end
iterate(source_path) { |path| ... } click to toggle source
# File match/lib/match/encryption/openssl.rb, line 80
def iterate(source_path)
  Dir[File.join(source_path, "**", "*.{cer,p12,mobileprovision,provisionprofile}")].each do |path|
    next if File.directory?(path)
    yield(path)
  end
end
server_name(keychain_name) click to toggle source

server name used for accessing the macOS keychain

# File match/lib/match/encryption/openssl.rb, line 88
def server_name(keychain_name)
  ["match", keychain_name].join("_")
end