fmrest-core 0.16.0 → 0.18.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 02e8b51abdf2fc9a5b7df29cdad8d5acef8f04b5c6167d7ff94040a716117449
4
- data.tar.gz: 6a78ce64f39cd5e41910114eb22948eb5c4f26d26a892ab2b09c0bdcaa6c3fb3
3
+ metadata.gz: 27b42f06b36c99b967649c4257ea1b4df30e70f3e30efce3c1a82e74b511a368
4
+ data.tar.gz: 46cade48892b6cedca8f18fc40ccb88c3da2e1893bb09df020fcc0847782ede4
5
5
  SHA512:
6
- metadata.gz: 3bdd91f7e25de359a7a28746d4c7be4eae7a684b63d909eacae6dd48a7053666386ff6dd3b87895aaf315e6a6b923aadcf0b8713aefa696fadbef25656dbae3b
7
- data.tar.gz: 37d292af43be4a6a42b4f4044d3078ec40edff189622e3d4390d4a9ec65e34b0b910b2542ca4293ea3d3925eea8c84f1c944a5d7c7cc22f47bf989113b1017d7
6
+ metadata.gz: 79335b4c02f13f90dde6052998cd2f11e29ff4da10a6622b8d789f7ec443828afea5a869c10b7f40c79f10cf4b16b88f69691eab0e7605a6372b69ec24b07f6b
7
+ data.tar.gz: 7f3a11e55de51d92680a76812a63b6e3e2fa8ecbc3ac37949af7a365c67911d7867625781c4f5947c6079d1a99f31a499a354a3999d6d3415e5a08a982cc08a1
data/CHANGELOG.md CHANGED
@@ -1,13 +1,29 @@
1
1
  ## Changelog
2
2
 
3
+ ### 0.18.0
4
+
5
+ * Better support for portals with mismatching field qualifiers
6
+ * Defining an attribute on a model that would collide with an existing method
7
+ now raises an error
8
+
9
+ ### 0.17.1
10
+
11
+ * Fixed crash when `fmid_token` is set but `username` isn't
12
+
13
+ ### 0.17.0
14
+
15
+ * Added support for Claris ID token login
16
+ * Added ability to use procs in settings
17
+ * Added `Rescuable` mixin
18
+
3
19
  ### 0.16.0
4
20
 
5
- * Add `FmRest.logger=`
21
+ * Added `FmRest.logger=`
6
22
  * Handle serialization of `nil`, `true` and `false` values
7
23
 
8
24
  ### 0.15.2
9
25
 
10
- * Fix autoloading of `FmRest::Layout`
26
+ * Fixed autoloading of `FmRest::Layout`
11
27
 
12
28
  ### 0.15.0
13
29
 
@@ -23,13 +39,13 @@
23
39
 
24
40
  ### 0.13.1
25
41
 
26
- * Fix downloading of container field data from FMS19+
42
+ * Fixed downloading of container field data from FMS19+
27
43
 
28
44
  ### 0.13.0
29
45
 
30
46
  * Split `fmrest` gem into `fmrest-core` and `fmrest-spyke`. `fmrest` becomes a
31
47
  wrapper for the two new gems.
32
- * Fix bug preventing connection databases with spaces in their names.
48
+ * Fixed bug preventing connection databases with spaces in their names.
33
49
  * Improved portal support with ability to delete portal records, and better
34
50
  refreshing of portal records after saving the parent.
35
51
  * `FmRest::Spyke::Base#__record_id` and `FmRest::Spyke::Base#__mod_id` now
@@ -44,7 +60,7 @@
44
60
 
45
61
  ### 0.11.1
46
62
 
47
- * Fix a couple crashes due to missing constants
63
+ * Fixed a couple crashes due to missing constants
48
64
 
49
65
  ### 0.11.0
50
66
 
@@ -59,7 +75,7 @@
59
75
 
60
76
  ### 0.10.1
61
77
 
62
- * Fix `URI.escape` obsolete warning messages in Ruby 2.7 by replacing it with
78
+ * Fixed `URI.escape` obsolete warning messages in Ruby 2.7 by replacing it with
63
79
  `URI.encode_www_form_component`
64
80
  ([PR#40](https://github.com/beezwax/fmrest-ruby/pull/40))
65
81
 
@@ -133,20 +149,20 @@
133
149
 
134
150
  ### 0.3.2
135
151
 
136
- * Fix support for ActiveSupport < 5.2
152
+ * Fixed support for ActiveSupport < 5.2
137
153
  ([#27](https://github.com/beezwax/fmrest-ruby/issues/27))
138
154
 
139
155
  ### 0.3.0
140
156
 
141
- * Add Moneta token store
157
+ * Added Moneta token store
142
158
 
143
159
  ### 0.2.5
144
160
 
145
- * Fix crash in `fetch_container_data` when no proxy options were set
161
+ * Fixed crash in `fetch_container_data` when no proxy options were set
146
162
 
147
163
  ### 0.2.4
148
164
 
149
165
  * Use `String#=~` instead of `String#match?` for Ruby <2.4 compatibility (Fixes
150
166
  [#26](https://github.com/beezwax/fmrest-ruby/issues/26))
151
- * Deprecate `FmRest.config` in favor of `FmRest.default_connection_settings`
167
+ * Deprecated `FmRest.config` in favor of `FmRest.default_connection_settings`
152
168
  * 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,6 +153,7 @@ 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`
@@ -283,10 +288,12 @@ Also, if not set, your model will try to use
283
288
  #### Connection settings overlays
284
289
 
285
290
  There may be cases where you want to use a different set of connection settings
286
- depending on context. For example, if you want to use username and password
287
- provided by the user in a web application. Since `.fmrest_config`
288
- is set at the class level, changing the username/password for the model in one
289
- 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.
290
297
 
291
298
  To solve this scenario, fmrest-ruby provides a way of defining thread-local and
292
299
  reversible connection settings overlays through
@@ -323,7 +330,7 @@ Requests a Data API session token using the connection settings in
323
330
 
324
331
  You normally don't need to use this method as fmrest-ruby will automatically
325
332
  request and store session tokens for you (provided that `:autologin` is
326
- `true`).
333
+ `true` in the connection settings, which it is by default).
327
334
 
328
335
  ### FmRest::Layout.logout
329
336
 
@@ -452,6 +459,41 @@ field values on the database that model is configured for.
452
459
  See the [main document on setting global field values](docs/GlobalFields.md)
453
460
  for details.
454
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
+
455
497
  ## Logging
456
498
 
457
499
  If using `fmrest-spyke` with Rails then pretty log output will be set up for
@@ -501,6 +543,10 @@ class LoggyBee < FmRest::Layout
501
543
  end
502
544
  ```
503
545
 
546
+ ## Gotchas
547
+
548
+ Read about unexpected scenarios in the [gotchas doc](docs/Gotchas.md).
549
+
504
550
  ## API implementation completeness table
505
551
 
506
552
  FM Data API reference: https://fmhelp.filemaker.com/docs/18/en/dataapi/
@@ -510,7 +556,7 @@ FM Data API reference: https://fmhelp.filemaker.com/docs/18/en/dataapi/
510
556
  | Log in using HTTP Basic Auth | Yes | Yes |
511
557
  | Log in using OAuth | No | No |
512
558
  | Log in to an external data source | No | No |
513
- | Log in using a FileMaker ID account | No | No |
559
+ | Log in using Claris ID account | Yes | Yes |
514
560
  | Log out | Yes | Yes |
515
561
  | Get product information | Manual* | No |
516
562
  | Get database names | Manual* | No |
@@ -18,6 +18,7 @@ module FmRest
18
18
  database
19
19
  username
20
20
  password
21
+ fmid_token
21
22
  token
22
23
  token_store
23
24
  autologin
@@ -69,13 +70,12 @@ module FmRest
69
70
 
70
71
  PROPERTIES.each do |p|
71
72
  define_method(p) do
72
- get(p)
73
+ get_eval(p)
73
74
  end
74
75
 
75
76
  define_method("#{p}!") do
76
- r = get(p)
77
- raise MissingSetting, "Missing required setting: `#{p}'" if r.nil?
78
- r
77
+ raise MissingSetting, "Missing required setting: `#{p}'" if get(p).nil?
78
+ get_eval(p)
79
79
  end
80
80
 
81
81
  define_method("#{p}?") do
@@ -85,7 +85,7 @@ module FmRest
85
85
 
86
86
  def [](key)
87
87
  raise ArgumentError, "Unknown setting `#{key}'" unless PROPERTIES.include?(key.to_sym)
88
- get(key)
88
+ get_eval(key)
89
89
  end
90
90
 
91
91
  def to_h
@@ -104,13 +104,18 @@ module FmRest
104
104
  missing = REQUIRED.select { |r| get(r).nil? }.map { |m| "`#{m}'" }
105
105
  raise MissingSetting, "Missing required setting(s): #{missing.join(', ')}" unless missing.empty?
106
106
 
107
- unless username? || token?
108
- 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"
109
109
  end
110
110
  end
111
111
 
112
112
  private
113
113
 
114
+ def get_eval(key)
115
+ c = get(key)
116
+ c.kind_of?(Proc) ? c.call : c
117
+ end
118
+
114
119
  def get(key)
115
120
  return @settings[key.to_sym] if @settings.has_key?(key.to_sym)
116
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
@@ -58,7 +59,11 @@ 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
69
  conn.response :logger, FmRest.logger, bodies: true, headers: true, log_level: settings.log_level
@@ -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
 
@@ -8,6 +8,8 @@ module FmRest
8
8
  # See https://help.claris.com/en/pro-help/content/finding-text.html
9
9
  FM_FIND_OPERATORS_RE = /([@\*#\?!=<>"])/
10
10
 
11
+ FULLY_QUALIFIED_FIELD_NAME_MATCHER = /\A[^:]+::[^:]+\Z/.freeze
12
+
11
13
  # Converts custom script options to a hash with the Data API's expected
12
14
  # JSON script format.
13
15
  #
@@ -104,6 +106,18 @@ module FmRest
104
106
  s.gsub(FM_FIND_OPERATORS_RE, "\\\\\\1")
105
107
  end
106
108
 
109
+ # Returns whether the given FileMaker field name is a fully-qualified
110
+ # name. In other words, whether it contains the string "::".
111
+ #
112
+ # Note that this is a simple naive check which doesn't account for
113
+ # invalid field names.
114
+ #
115
+ # @param field_name [String] The field name to test
116
+ # @return [Boolean] Whether the field is a FQN
117
+ def is_fully_qualified?(field_name)
118
+ FULLY_QUALIFIED_FIELD_NAME_MATCHER === field_name.to_s
119
+ end
120
+
107
121
  private
108
122
 
109
123
  def convert_script_arguments(script_arguments, suffix = nil)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FmRest
4
- VERSION = "0.16.0"
4
+ VERSION = "0.18.0.rc1"
5
5
  end
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.16.0
4
+ version: 0.18.0.rc1
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-14 00:00:00.000000000 Z
11
+ date: 2021-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -104,11 +104,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
104
  version: '0'
105
105
  required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - ">="
107
+ - - ">"
108
108
  - !ruby/object:Gem::Version
109
- version: '0'
109
+ version: 1.3.1
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