module Calabash::Cucumber::KeychainHelpers

KeychainHelpers provide a helpers to access the iOS keychain.

### Simulator Note

When running on the simulator, the keychain is not sandboxed between applications like it is on a real device. These methods will return keychain records from all applications on the simulator, which may result in strange behavior if you aren’t expecting it.

@see goo.gl/JrFJMM Details about why some operations report

`FAILURE` and what can be done on the client side mitigate.

@see github.com/soffes/sskeychain SSKeychain

Public Instance Methods

_keychain_get(options={}) click to toggle source

@!visibility private Sends appropriately-configured ‘GET` request to the `keychain` server endpoint. Do not call this function directly; use one of the helper functions provided.

@see keychain_accounts @see keychain_account_for_service @return [Array<Hash>] contents of the iOS keychain @param [Hash] options @raise [RuntimeError] if http request does not report success

# File lib/calabash-cucumber/keychain_helpers.rb, line 31
def _keychain_get(options={})
  raw = http({:method => :get, :raw => true, :path => 'keychain'}, options)

  begin
    res = JSON.parse(raw)
  rescue TypeError, JSON::ParserError => _
    raise "Could not parse response '#{res}'; the app might have crashed or the server responded with invalid JSON."
  end

  if res['outcome'] != 'SUCCESS'
    raise "get keychain with options '#{options}' failed because: '#{res['reason']}'\n'#{res['details']}'"
  end

  res['results']
end
_keychain_post(options={}) click to toggle source

@!visibility private Sends appropriately-configured ‘POST` request to the `keychain` server endpoint. Do not call this function directly; use one of the helper functions provided.

@see keychain_clear @see keychain_clear_accounts_for_service @see keychain_delete_password @see keychain_set_password

@return [nil] @raise [RuntimeError] if http request does not report success

# File lib/calabash-cucumber/keychain_helpers.rb, line 112
def _keychain_post(options={})
  raw = http({:method => :post, :path => 'keychain'}, options)
  begin
    res = JSON.parse(raw)
  rescue TypeError, JSON::ParserError => _
    raise "Could not parse response '#{res}'; the app might have crashed or the server responded with invalid JSON."
  end
  if res['outcome'] != 'SUCCESS'
    raise "post keychain with options '#{options}' failed because: #{res['reason']}\n#{res['details']}"
  end
  res['results']
end
keychain_accounts() click to toggle source

Asks the keychain for all of the account records.

The hash keys are defined by the ‘SSKeychain` library.

@see github.com/soffes/sskeychain SSKeychain

The following keys are the most commonly useful:

“‘ svce #=> the service acct #=> the account (often a username) cdat #=> the creation date mdat #=> the last-modified date “`

@raise [RuntimeError] if http request does not report success @return [Array<Hash>] of all account records saved in the iOS keychain.

# File lib/calabash-cucumber/keychain_helpers.rb, line 64
def keychain_accounts
  _keychain_get
end
keychain_accounts_for_service(service) click to toggle source

Returns an list of all account records saved in the iOS keychain filtered by ‘service`.

@see keychain_accounts

@param [String] service the service whose accounts you are requesting @return [Array<Hash>] a list all account records filtered by ‘service`. @raise [RuntimeError] if http request does not report success

# File lib/calabash-cucumber/keychain_helpers.rb, line 76
def keychain_accounts_for_service(service)
  _keychain_get({:service => service})
end
keychain_clear() click to toggle source

On the iOS Simulator this clears all keychain entries for all applications.

On a physical device, this will clear all entries for the target application.

@return [nil]

@raise [RuntimeError] if http request does not report success

# File lib/calabash-cucumber/keychain_helpers.rb, line 134
def keychain_clear
  _keychain_post
end
keychain_clear_accounts_for_service(service) click to toggle source

Clear all entries in the keychain restricted to a single ‘service`.

@param [String] service filters which accounts should be cleared. @return [nil]

@raise [RuntimeError] if http request does not report success

# File lib/calabash-cucumber/keychain_helpers.rb, line 144
def keychain_clear_accounts_for_service(service)
  _keychain_post({:service => service})
end
keychain_delete_password(service, account) click to toggle source

Delete a single keychain record for the given ‘service` and `account` pair.

@param [String] service filters which accounts should be cleared. @param [String] account filters which account to clear

@raise [RuntimeError] if http request does not report success

# File lib/calabash-cucumber/keychain_helpers.rb, line 155
def keychain_delete_password(service, account)
  _keychain_post(:service => service, :account => account)
end
keychain_password(service, account) click to toggle source

Ask the keychain for an account password.

@note

**IMPORTANT**
On the XTC, the password cannot returned as plain text.
When using this keychain_password in your steps you can condition on
the XTC environment using `xamarin_test_cloud?`

@see Calabash::Cucumber::EnvironmentHelpers#xamarin_test_cloud?

@raise [RuntimeError] if http request does not report success @raise [RuntimeError] if ‘service` and `account` pair does not contain

a password

@return [String,Array<Hash>] password stored in keychain for ‘service`

and `account`.  *NB* on the XTC this returns an Array with one Hash.
# File lib/calabash-cucumber/keychain_helpers.rb, line 96
def keychain_password(service, account)
  _keychain_get({:service => service, :account => account}).first
end
keychain_set_password(service, account, password) click to toggle source

Set the password for a given service and account pair.

@param [String] service which service to update @param [String] account which account to update @param [String] password which password to set @return nil

@raise [RuntimeError] if http request does not report success

# File lib/calabash-cucumber/keychain_helpers.rb, line 167
def keychain_set_password(service, account, password)
  _keychain_post(:service => service, :account => account, :password => password)
end