fmrest-core 0.15.2 → 0.17.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01ec00e52b9c84c094188e3b9b4e3f869063294ebf695364b9141dbce28a2e7c
4
- data.tar.gz: 00b228812583d4b256e0c2f9be8336db9d47b14fd2e1324ecdf6012c91af3c6f
3
+ metadata.gz: 4fe47fc97c28e7098accafef4a2974e959f8f910619fdec2177abb8048a9cf53
4
+ data.tar.gz: 4439686866ddd5023f98b8d1651992fbb068e36b0872d47d66923303c2eeaee7
5
5
  SHA512:
6
- metadata.gz: cadaee1025630ff4e0e2110bc9d294262861a9baa578b84e88fca0c7ed15e8a73edba710232d535197f0c74cd0bb2af8758998710876f1ead48532bb0f69c27e
7
- data.tar.gz: 15e8c19893fc459e29f924352b1657dadfadc242201811719b1a2e871106af7616c99ab4f8adfd76f775021b288002c6d98d04ba64f30b549eb3802618e23b34
6
+ metadata.gz: f0d1c9af0e393ac39c7a4625afcf1301d9756116e511baf80f313cff15ffaa75bf1e4fbbbad60d548a8fe4101bfad59704aa0d40e08a334881cfec68ad823d7f
7
+ data.tar.gz: c1e372106b999c00d93d83e8ae14ef5bf06b094c6c53eabca44ee7d56d1f1f67114614d0adc323c5b4b817494be14a5f25518e57a392f21c73aafa1130fe59f0
data/CHANGELOG.md CHANGED
@@ -1,8 +1,23 @@
1
1
  ## Changelog
2
2
 
3
+ ### 0.17.1
4
+
5
+ * Fixed crash when `fmid_token` is set but `username` isn't
6
+
7
+ ### 0.17.0
8
+
9
+ * Added support for Claris ID token login
10
+ * Added ability to use procs in settings
11
+ * Added `Rescuable` mixin
12
+
13
+ ### 0.16.0
14
+
15
+ * Added `FmRest.logger=`
16
+ * Handle serialization of `nil`, `true` and `false` values
17
+
3
18
  ### 0.15.2
4
19
 
5
- * Fix autoloading of `FmRest::Layout`
20
+ * Fixed autoloading of `FmRest::Layout`
6
21
 
7
22
  ### 0.15.0
8
23
 
@@ -18,13 +33,13 @@
18
33
 
19
34
  ### 0.13.1
20
35
 
21
- * Fix downloading of container field data from FMS19+
36
+ * Fixed downloading of container field data from FMS19+
22
37
 
23
38
  ### 0.13.0
24
39
 
25
40
  * Split `fmrest` gem into `fmrest-core` and `fmrest-spyke`. `fmrest` becomes a
26
41
  wrapper for the two new gems.
27
- * Fix bug preventing connection databases with spaces in their names.
42
+ * Fixed bug preventing connection databases with spaces in their names.
28
43
  * Improved portal support with ability to delete portal records, and better
29
44
  refreshing of portal records after saving the parent.
30
45
  * `FmRest::Spyke::Base#__record_id` and `FmRest::Spyke::Base#__mod_id` now
@@ -39,7 +54,7 @@
39
54
 
40
55
  ### 0.11.1
41
56
 
42
- * Fix a couple crashes due to missing constants
57
+ * Fixed a couple crashes due to missing constants
43
58
 
44
59
  ### 0.11.0
45
60
 
@@ -54,7 +69,7 @@
54
69
 
55
70
  ### 0.10.1
56
71
 
57
- * Fix `URI.escape` obsolete warning messages in Ruby 2.7 by replacing it with
72
+ * Fixed `URI.escape` obsolete warning messages in Ruby 2.7 by replacing it with
58
73
  `URI.encode_www_form_component`
59
74
  ([PR#40](https://github.com/beezwax/fmrest-ruby/pull/40))
60
75
 
@@ -128,20 +143,20 @@
128
143
 
129
144
  ### 0.3.2
130
145
 
131
- * Fix support for ActiveSupport < 5.2
146
+ * Fixed support for ActiveSupport < 5.2
132
147
  ([#27](https://github.com/beezwax/fmrest-ruby/issues/27))
133
148
 
134
149
  ### 0.3.0
135
150
 
136
- * Add Moneta token store
151
+ * Added Moneta token store
137
152
 
138
153
  ### 0.2.5
139
154
 
140
- * Fix crash in `fetch_container_data` when no proxy options were set
155
+ * Fixed crash in `fetch_container_data` when no proxy options were set
141
156
 
142
157
  ### 0.2.4
143
158
 
144
159
  * Use `String#=~` instead of `String#match?` for Ruby <2.4 compatibility (Fixes
145
160
  [#26](https://github.com/beezwax/fmrest-ruby/issues/26))
146
- * Deprecate `FmRest.config` in favor of `FmRest.default_connection_settings`
161
+ * Deprecated `FmRest.config` in favor of `FmRest.default_connection_settings`
147
162
  * Honor Faraday SSL and proxy settings when fetching container files
data/README.md CHANGED
@@ -125,6 +125,10 @@ The minimum required connection settings are `:host`, `:database`, `:username`
125
125
  and `:password`, but fmrest-ruby has many other options you can pass when
126
126
  setting up a connection (see [full list](#full-list-of-available-options) below).
127
127
 
128
+ If you're using FileMaker Cloud you may need to pass `:fmid_token` instead
129
+ of the regular `:username` and `:password`. See the [main document on
130
+ connecting to FileMaker Cloud](docs/FileMakerCloud.md) for more info.
131
+
128
132
  `:ssl` and `:proxy` are forwarded to the underlying
129
133
  [Faraday](https://github.com/lostisland/faraday) connection. You can use this
130
134
  to, for instance, disable SSL verification:
@@ -149,9 +153,11 @@ Option | Description | Format
149
153
  `:username` | A Data API-ready account | String | None
150
154
  `:password` | Your password | String | None
151
155
  `:account_name` | Alias of `:username` | String | None
156
+ `:fmid_token` | Claris ID token (only needed for FileMaker Cloud) | String | None
152
157
  `:ssl` | SSL options to be forwarded to Faraday | Faraday SSL options | None
153
158
  `:proxy` | Proxy options to be forwarded to Faraday | Faraday proxy options | None
154
159
  `:log` | Log JSON responses to STDOUT | Boolean | `false`
160
+ `:log_level` | Which log level to log into | Values accepted by `Logger#level=` | `:debug`
155
161
  `:coerce_dates` | See section on [date fields](#date-fields-and-timezones) | Boolean \| `:hybrid` \| `:full` | `false`
156
162
  `:date_format` | Date parsing format | String (FM date format) | `"MM/dd/yyyy"`
157
163
  `:timestamp_format` | Timestmap parsing format | String (FM date format) | `"MM/dd/yyyy HH:mm:ss"`
@@ -282,10 +288,12 @@ Also, if not set, your model will try to use
282
288
  #### Connection settings overlays
283
289
 
284
290
  There may be cases where you want to use a different set of connection settings
285
- depending on context. For example, if you want to use username and password
286
- provided by the user in a web application. Since `.fmrest_config`
287
- is set at the class level, changing the username/password for the model in one
288
- context would also change it in all other contexts, leading to security issues.
291
+ depending on context, or simply change the connection settings over time. For
292
+ example, if you want to use username and password provided by the user in a web
293
+ application, or if you're connecting using an expiring Claris ID token. Since
294
+ `.fmrest_config` is set at the class level, changing the username/password for
295
+ the model in one context would also change it in all other contexts, leading to
296
+ security issues.
289
297
 
290
298
  To solve this scenario, fmrest-ruby provides a way of defining thread-local and
291
299
  reversible connection settings overlays through
@@ -322,7 +330,7 @@ Requests a Data API session token using the connection settings in
322
330
 
323
331
  You normally don't need to use this method as fmrest-ruby will automatically
324
332
  request and store session tokens for you (provided that `:autologin` is
325
- `true`).
333
+ `true` in the connection settings, which it is by default).
326
334
 
327
335
  ### FmRest::Layout.logout
328
336
 
@@ -451,13 +459,48 @@ field values on the database that model is configured for.
451
459
  See the [main document on setting global field values](docs/GlobalFields.md)
452
460
  for details.
453
461
 
462
+ ### Rescuable mixin
463
+
464
+ Sometimes you may want to handle Data API errors at the model level. For
465
+ instance, if you're logging in to a file hosted by FileMaker Cloud using a
466
+ Claris ID token, and you want to be able to renew said token when it fails to
467
+ log you in. For such cases fmrest-ruby provides an off-by-default mixin called
468
+ `Rescuable` that provides convenience macros for that. If you've used Ruby on
469
+ Rails you may be familiar with its syntax from controllers. E.g.
470
+
471
+ ```ruby
472
+ class BeeBase < FmRest::Layout
473
+ include FmRest::Spyke::Model::Rescuable
474
+
475
+ rescue_from FmRest::APIError::SystemError, with: :notify_admin_of_system_error
476
+
477
+ # Shorthand for rescue_with FmRest::APIError::AccountError, ...
478
+ rescue_account_error { ClarisIDTokenManager.expire_token }
479
+
480
+ def self.notify_admin_of_system_error(e)
481
+ # Shoot an email to the FM admin...
482
+ end
483
+ end
484
+ ```
485
+
486
+ Since `Rescuable` uses `ActiveSupport::Rescuable` internally, you may want to
487
+ check [Rails'
488
+ documentation](https://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html)
489
+ too for details on how it works.
490
+
491
+ One caveat of using `rescue_from` is that it always catches exceptions at the
492
+ class level, so if you pass a method name to `with:` that method has to be a
493
+ class method. Also note that this will only catch exceptions raised during an
494
+ API call to the Data API server (in other words, only on actions that perform
495
+ an HTTP request).
496
+
454
497
  ## Logging
455
498
 
456
499
  If using `fmrest-spyke` with Rails then pretty log output will be set up for
457
500
  you automatically by Spyke (see [their
458
501
  README](https://github.com/balvig/spyke#log-output)).
459
502
 
460
- You can also enable simple Faraday STDOUT logging of raw requests (useful for
503
+ You can also enable simple Faraday logging of raw requests (useful for
461
504
  debugging) by passing `log: true` in the options hash for either
462
505
  `FmRest.default_connection_settings=` or your models' `fmrest_config=`, e.g.:
463
506
 
@@ -478,7 +521,17 @@ class LoggyBee < FmRest::Layout
478
521
  end
479
522
  ```
480
523
 
481
- If you need to set up more complex logging for your models can use the
524
+ You can also pass `log_level` to connection settings to change the severity of
525
+ log output (defaults to `:debug`).
526
+
527
+ By default fmrest-ruby logs to STDOUT or to Rails' logger object if available.
528
+ You can change this by providing your own logger object to `FmRest.logger=`:
529
+
530
+ ```ruby
531
+ FmRest.logger = Logger.new("fmrest.log")
532
+ ```
533
+
534
+ If you need to set up more complex logging for your models you can use the
482
535
  `faraday` block inside your class to inject your own logger middleware into the
483
536
  Faraday connection, e.g.:
484
537
 
@@ -499,7 +552,7 @@ FM Data API reference: https://fmhelp.filemaker.com/docs/18/en/dataapi/
499
552
  | Log in using HTTP Basic Auth | Yes | Yes |
500
553
  | Log in using OAuth | No | No |
501
554
  | Log in to an external data source | No | No |
502
- | Log in using a FileMaker ID account | No | No |
555
+ | Log in using Claris ID account | Yes | Yes |
503
556
  | Log out | Yes | Yes |
504
557
  | Get product information | Manual* | No |
505
558
  | Get database names | Manual* | No |
@@ -18,12 +18,14 @@ module FmRest
18
18
  database
19
19
  username
20
20
  password
21
+ fmid_token
21
22
  token
22
23
  token_store
23
24
  autologin
24
25
  ssl
25
26
  proxy
26
27
  log
28
+ log_level
27
29
  coerce_dates
28
30
  date_format
29
31
  timestamp_format
@@ -45,6 +47,7 @@ module FmRest
45
47
  DEFAULTS = {
46
48
  autologin: true,
47
49
  log: false,
50
+ log_level: :debug,
48
51
  date_format: DEFAULT_DATE_FORMAT,
49
52
  time_format: DEFAULT_TIME_FORMAT,
50
53
  timestamp_format: DEFAULT_TIMESTAMP_FORMAT,
@@ -67,13 +70,12 @@ module FmRest
67
70
 
68
71
  PROPERTIES.each do |p|
69
72
  define_method(p) do
70
- get(p)
73
+ get_eval(p)
71
74
  end
72
75
 
73
76
  define_method("#{p}!") do
74
- r = get(p)
75
- raise MissingSetting, "Missing required setting: `#{p}'" if r.nil?
76
- r
77
+ raise MissingSetting, "Missing required setting: `#{p}'" if get(p).nil?
78
+ get_eval(p)
77
79
  end
78
80
 
79
81
  define_method("#{p}?") do
@@ -83,7 +85,7 @@ module FmRest
83
85
 
84
86
  def [](key)
85
87
  raise ArgumentError, "Unknown setting `#{key}'" unless PROPERTIES.include?(key.to_sym)
86
- get(key)
88
+ get_eval(key)
87
89
  end
88
90
 
89
91
  def to_h
@@ -102,13 +104,18 @@ module FmRest
102
104
  missing = REQUIRED.select { |r| get(r).nil? }.map { |m| "`#{m}'" }
103
105
  raise MissingSetting, "Missing required setting(s): #{missing.join(', ')}" unless missing.empty?
104
106
 
105
- unless username? || token?
106
- raise MissingSetting, "A minimum of `username' or `token' are required to be able to establish a connection"
107
+ unless username? || fmid_token? || token?
108
+ raise MissingSetting, "A minimum of `username', `fmid_token' or `token' are required to be able to establish a connection"
107
109
  end
108
110
  end
109
111
 
110
112
  private
111
113
 
114
+ def get_eval(key)
115
+ c = get(key)
116
+ c.kind_of?(Proc) ? c.call : c
117
+ end
118
+
112
119
  def get(key)
113
120
  return @settings[key.to_sym] if @settings.has_key?(key.to_sym)
114
121
  return @settings[key.to_s] if @settings.has_key?(key.to_s)
@@ -3,6 +3,8 @@
3
3
  module FmRest
4
4
  module V1
5
5
  module Auth
6
+ ACCESS_TOKEN_HEADER = "X-FM-Data-Access-Token"
7
+
6
8
  # Requests a token through basic auth
7
9
  #
8
10
  # @param connection [Faraday] the auth connection to use for
@@ -23,7 +25,7 @@ module FmRest
23
25
  # @raise [FmRest::APIError::AccountError] if authentication failed
24
26
  def request_auth_token!(connection = FmRest.V1.auth_connection)
25
27
  resp = connection.post(V1.session_path)
26
- resp.body["response"]["token"]
28
+ resp.headers[ACCESS_TOKEN_HEADER] || resp.body["response"]["token"]
27
29
  end
28
30
  end
29
31
  end
@@ -9,6 +9,7 @@ module FmRest
9
9
  DATABASES_PATH = "#{BASE_PATH}/databases"
10
10
 
11
11
  AUTH_HEADERS = { "Content-Type" => "application/json" }.freeze
12
+ CLARIS_ID_HTTP_AUTH_TYPE = "FMID"
12
13
 
13
14
  # Builds a complete DAPI Faraday connection with middleware already
14
15
  # configured to handle authentication, JSON parsing, logging and DAPI
@@ -41,7 +42,7 @@ module FmRest
41
42
  end
42
43
 
43
44
  if settings.log
44
- conn.response :logger, nil, bodies: true, headers: true
45
+ conn.response :logger, FmRest.logger, bodies: true, headers: true, log_level: settings.log_level
45
46
  end
46
47
 
47
48
  conn.adapter Faraday.default_adapter
@@ -58,10 +59,14 @@ module FmRest
58
59
  base_connection(settings, { headers: AUTH_HEADERS }) do |conn|
59
60
  conn.use RaiseErrors
60
61
 
61
- conn.basic_auth settings.username!, settings.password!
62
+ if settings.fmid_token?
63
+ conn.authorization CLARIS_ID_HTTP_AUTH_TYPE, settings.fmid_token
64
+ else
65
+ conn.basic_auth settings.username!, settings.password!
66
+ end
62
67
 
63
68
  if settings.log
64
- conn.response :logger, nil, bodies: true, headers: true
69
+ conn.response :logger, FmRest.logger, bodies: true, headers: true, log_level: settings.log_level
65
70
  end
66
71
 
67
72
  conn.response :json
@@ -100,7 +100,13 @@ module FmRest
100
100
  # Strip the host part to just the hostname (i.e. no scheme or port)
101
101
  host = @settings.host!
102
102
  host = URI(host).hostname if host =~ /\Ahttps?:\/\//
103
- "#{host}:#{@settings.database!}:#{@settings.username!}"
103
+ identity_segment = if fmid_token = @settings.fmid_token
104
+ require "digest"
105
+ Digest::SHA256.hexdigest(fmid_token)
106
+ else
107
+ @settings.username!
108
+ end
109
+ "#{host}:#{@settings.database!}:#{identity_segment}"
104
110
  end
105
111
  end
106
112
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FmRest
4
- VERSION = "0.15.2"
4
+ VERSION = "0.17.1"
5
5
  end
data/lib/fmrest.rb CHANGED
@@ -15,9 +15,13 @@ module FmRest
15
15
 
16
16
  class << self
17
17
  attr_accessor :token_store
18
+ attr_writer :logger
18
19
 
19
20
  def default_connection_settings=(settings)
20
- @default_connection_settings = ConnectionSettings.wrap(settings, skip_validation: true)
21
+ # Skip validation since we may use the defaults for half-complete
22
+ # settings
23
+ @default_connection_settings =
24
+ ConnectionSettings.wrap(settings, skip_validation: true)
21
25
  end
22
26
 
23
27
  def default_connection_settings
@@ -34,6 +38,15 @@ module FmRest
34
38
  default_connection_settings
35
39
  end
36
40
 
41
+ def logger
42
+ @logger ||= if defined?(Rails)
43
+ Rails.logger
44
+ else
45
+ require "logger"
46
+ Logger.new($stdout)
47
+ end
48
+ end
49
+
37
50
  # Shortcut for FmRest::V1.escape_find_operators
38
51
  #
39
52
  # @param (see FmRest::V1.escape_find_operators
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fmrest-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.2
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pedro Carbajal
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-06 00:00:00.000000000 Z
11
+ date: 2021-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -108,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  requirements: []
111
- rubygems_version: 3.0.6
111
+ rubygems_version: 3.2.3
112
112
  signing_key:
113
113
  specification_version: 4
114
114
  summary: FileMaker Data API client using Faraday, core library