mapkit_token 1.0.0 → 1.2.0

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: 45bea3e3d390b755069255b64c3d7feb217d8c724db38c3030403d1449cd01d9
4
- data.tar.gz: ab38b4f43b735ce4ecd7ddca3d1a1a1453f6430489c85d1c2381b5ec71302413
3
+ metadata.gz: '0366869d9c259cd6a25c28915b9f71b851b6a283bd881802f6af2b8e7c8a805c'
4
+ data.tar.gz: 29e882698f549c01f296d9d77ba3f96ea4d7905eaeca113fd57e66c2d9a3bb9d
5
5
  SHA512:
6
- metadata.gz: 3cae35f9190898e2101da404c1deeb600fa72d2a9d9d11a39b7c1fec7a7270bd2d78bcdace8156c00b5e11ed6a725e1d3094a595c4692bb14e49c29fe36e720f
7
- data.tar.gz: d822fe17f5db923ce272321a6ecee1a403337f46b1e45ad24517b62e2a50c68823fa3bd75fb614b424a13614e38d69aa5dff68e67b919d75d591d63f711ed9e5
6
+ metadata.gz: e80969e65ab3322b4d9e2712333f995bd1ec46fef965c89af2bda595e2fb6575c04ffec16f18c2c398066fea59c97d0a7cd361c078dc2136c25b17d145acb828
7
+ data.tar.gz: dc34fe4c6b9210ce2f0a4849cd44e94f246c65c0e054443bc87965f5a6c5b4fce157e9c47ae5bafe1324f4ecd0410e569e75d2331d3443441884fce4c48a5425
data/README.md CHANGED
@@ -24,30 +24,86 @@ Before you can use this gem, you need a Maps Identifer (i.e., Maps ID) and priva
24
24
 
25
25
  [Creating a Maps Identifier and a Private Key](https://developer.apple.com/documentation/mapkitjs/creating_a_maps_identifier_and_a_private_key)
26
26
 
27
- Add your AuthKey to your application folder, and make sure you have these pieces of information:
27
+ You need three pieces of information: the private key, the MapKit JS Key ID, and your Apple Developer Team ID.
28
28
 
29
- - Path to AuthKey
30
- - MapKit JS Key ID
31
- - Apple Developer Team ID
29
+ You can store them in an initializer, in your Rails credentials, or in environment variables. Use whichever fits the machine your application runs on. The gem checks those places in that order for each setting.
32
30
 
33
- Edit your application credentials:
31
+ The key itself can be given either as the contents of the `.p8` file or as a path to it. The gem looks for the contents in all three places before it looks for a path. This means that if a server sets the key contents in its environment, that value is used even when the credentials point to a file that doesn't exist on that server.
32
+
33
+ ### Option 1: Path to the key file in credentials
34
+
35
+ Add the `.p8` file from Apple to your application folder, then edit your credentials:
34
36
 
35
37
  $ EDITOR=vim rails credentials:edit
36
38
 
37
- In case you have different AuthKey files for your different environments, edit your environment credentials separately:
39
+ ```yaml
40
+ mapkit:
41
+ auth_key_path: AuthKey_XXXXXXXXXX.p8
42
+ auth_key_id: XXXXXXXXXX
43
+ apple_team_id: XXXXXXXXXX
44
+ ```
45
+
46
+ A relative path is resolved from `Rails.root`. An absolute path is used as is. If you have different AuthKey files for different environments, edit each environment's credentials separately:
38
47
 
39
48
  $ EDITOR=vim rails credentials:edit --environment development
40
49
 
41
- Add your credentials:
50
+ The gem provides legacy support for Rails secrets, so if your app uses Rails 4.1 through 5.1, you can store the same information in `/config/secrets.yml` and it will just work.
51
+
52
+ ### Option 2: Key contents in credentials
53
+
54
+ If shipping the `.p8` file is inconvenient (for example, in a container image or on a server built only from the repository), you can paste the contents of the file into your credentials instead:
42
55
 
43
56
  ```yaml
44
57
  mapkit:
45
- auth_key_path: AuthKey_XXXXXXXXXX.p8
58
+ auth_key: |
59
+ -----BEGIN PRIVATE KEY-----
60
+ MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg...
61
+ -----END PRIVATE KEY-----
46
62
  auth_key_id: XXXXXXXXXX
47
63
  apple_team_id: XXXXXXXXXX
48
64
  ```
49
65
 
50
- After reloading your application, it will have a new endpoint `/mapkit_token` that returns JWTs that are valid for 30 minutes. The application's hostname is added to the JWT payload to specify that the tokens only can used by the application itself.
66
+ ### Option 3: Environment variables
67
+
68
+ You can also set everything with environment variables. This works well for deployments that keep secrets outside the repository:
69
+
70
+ ```sh
71
+ MAPKIT_AUTH_KEY_ID=XXXXXXXXXX
72
+ MAPKIT_APPLE_TEAM_ID=XXXXXXXXXX
73
+
74
+ # Either the contents of the .p8 file...
75
+ MAPKIT_AUTH_KEY="$(cat AuthKey_XXXXXXXXXX.p8)"
76
+
77
+ # ...or the path to it, if the file is on the machine
78
+ MAPKIT_AUTH_KEY_PATH=/etc/mapkit/AuthKey_XXXXXXXXXX.p8
79
+ ```
80
+
81
+ The key spans several lines, and some tools can't set an environment variable that contains newlines. For those cases, `MAPKIT_AUTH_KEY` also accepts two single-line formats:
82
+
83
+ - The key with each newline written as `\n`
84
+ - The whole file encoded as base64 (`base64 -w0 AuthKey_XXXXXXXXXX.p8`)
85
+
86
+ ### Option 4: An initializer
87
+
88
+ If you'd rather configure the gem in code (for example, to read the key from a secrets manager or from environment variables with your own names), create `config/initializers/mapkit_token.rb`:
89
+
90
+ ```ruby
91
+ MapkitToken.setup do |config|
92
+ config.auth_key = Vault.read("mapkit").data[:p8]
93
+ config.auth_key_id = ENV.fetch("MY_MAPKIT_KEY_ID")
94
+ config.apple_team_id = ENV.fetch("MY_APPLE_TEAM_ID")
95
+ end
96
+ ```
97
+
98
+ You can also set `config.app_root` here to resolve a relative `auth_key_path` from a folder other than `Rails.root`.
99
+
100
+ ### Missing settings
101
+
102
+ If a setting can't be found, the gem raises `MapkitToken::ConfigurationError` with a message that says what's missing and where you can set it. You get this clear error instead of a confusing failure later on from an unreadable key.
103
+
104
+ To check whether a key is configured without raising an error, call `MapkitToken.config.auth_key?`. This is useful if you want to skip rendering a map when no token is available.
105
+
106
+ After reloading your application, it will have a new endpoint `/mapkit_token` that returns JWTs that are valid for 30 minutes. The application's hostname is added to the JWT payload to specify that the tokens only can used by the application itself.
51
107
 
52
108
  Use the endpoint for the `authorizationCallback` function that MapKit JS calls whenever it detects that a new token is needed.
53
109
 
@@ -1,28 +1,23 @@
1
1
  module MapkitToken
2
2
  class MapkitTokenController < ApplicationController
3
3
 
4
- def mapkit
5
- Rails.application.credentials.mapkit
6
- end
7
-
8
- def auth_key
9
- File.read(mapkit[:auth_key_path])
4
+ def show
5
+ render plain: Mapkit.token.generate(
6
+ auth_key: mapkit.auth_key,
7
+ auth_key_id: mapkit.auth_key_id,
8
+ apple_team_id: mapkit.apple_team_id,
9
+ base_url: base_url
10
+ )
10
11
  end
11
12
 
12
- def auth_key_id
13
- mapkit[:auth_key_id]
14
- end
13
+ private
15
14
 
16
- def apple_team_id
17
- mapkit[:apple_team_id]
15
+ def mapkit
16
+ MapkitToken.config
18
17
  end
19
18
 
20
19
  def base_url
21
20
  request.protocol + request.host
22
21
  end
23
-
24
- def show
25
- render plain: Mapkit.token.generate(auth_key: auth_key, auth_key_id: auth_key_id, apple_team_id: apple_team_id, base_url: base_url)
26
- end
27
22
  end
28
23
  end
@@ -0,0 +1,138 @@
1
+ require "pathname"
2
+
3
+ module MapkitToken
4
+ class ConfigurationError < StandardError; end
5
+
6
+ class Config
7
+ ENV_NAMES = {
8
+ :auth_key => "MAPKIT_AUTH_KEY",
9
+ :auth_key_path => "MAPKIT_AUTH_KEY_PATH",
10
+ :auth_key_id => "MAPKIT_AUTH_KEY_ID",
11
+ :apple_team_id => "MAPKIT_APPLE_TEAM_ID"
12
+ }.freeze
13
+
14
+ PEM_MARKER = "-----BEGIN".freeze
15
+
16
+ def auth_key
17
+ carried = setting(:auth_key)
18
+ return pem(carried) if carried.present?
19
+
20
+ path = auth_key_path
21
+ if path.blank?
22
+ raise ConfigurationError, explain("No MapKit auth key. Set the contents " \
23
+ "of the .p8 with #{places(:auth_key)}, or a path to it with " \
24
+ "#{places(:auth_key_path)}.")
25
+ end
26
+
27
+ file = expand_path(path)
28
+ unless File.exist?(file)
29
+ raise ConfigurationError, "MapKit auth key file not found at #{file}"
30
+ end
31
+ pem(File.read(file))
32
+ end
33
+
34
+ def auth_key_path
35
+ setting(:auth_key_path)
36
+ end
37
+
38
+ def auth_key_id
39
+ require_setting(:auth_key_id, "No MapKit key id.")
40
+ end
41
+
42
+ def apple_team_id
43
+ require_setting(:apple_team_id, "No Apple team id.")
44
+ end
45
+
46
+ def auth_key?
47
+ auth_key
48
+ true
49
+ rescue ConfigurationError
50
+ false
51
+ end
52
+
53
+ private
54
+
55
+ def setting(name)
56
+ from_initializer(name) || from_credentials(name) || from_env(name)
57
+ end
58
+
59
+ def require_setting(name, message)
60
+ value = setting(name)
61
+ if value.blank?
62
+ raise ConfigurationError, explain("#{message} Set it with #{places(name)}.")
63
+ end
64
+ value
65
+ end
66
+
67
+ def places(name)
68
+ "config.#{name} in MapkitToken.setup, `mapkit: #{name}` in the " \
69
+ "credentials, or #{ENV_NAMES.fetch(name)}"
70
+ end
71
+
72
+ # A credentials file that can't be decrypted reads as empty, so the
73
+ # environment still gets its turn; say so when nothing is found there.
74
+ def explain(message)
75
+ return message if @credentials_error.nil?
76
+ "#{message} The credentials could not be read " \
77
+ "(#{@credentials_error.class}), so any MapKit settings in them were skipped."
78
+ end
79
+
80
+ def from_initializer(name)
81
+ MapkitToken.public_send(name).presence
82
+ end
83
+
84
+ def from_credentials(name)
85
+ credentials[name].presence
86
+ end
87
+
88
+ def from_env(name)
89
+ ENV[ENV_NAMES.fetch(name)].presence
90
+ end
91
+
92
+ def credentials
93
+ store = credentials_store
94
+ return {} if store.nil?
95
+ store.respond_to?(:to_h) ? store.to_h.symbolize_keys : {}
96
+ rescue StandardError => e
97
+ @credentials_error = e
98
+ {}
99
+ end
100
+
101
+ def credentials_store
102
+ app = application
103
+ return nil if app.nil?
104
+
105
+ if app.respond_to?(:credentials)
106
+ app.credentials.mapkit
107
+ elsif app.respond_to?(:secrets)
108
+ app.secrets.mapkit
109
+ end
110
+ end
111
+
112
+ def application
113
+ return nil unless defined?(Rails) && Rails.respond_to?(:application)
114
+ Rails.application
115
+ end
116
+
117
+ def app_root
118
+ MapkitToken.app_root || (application && Rails.root) || Dir.pwd
119
+ end
120
+
121
+ def expand_path(path)
122
+ pathname = Pathname.new(path.to_s)
123
+ pathname.absolute? ? pathname.to_s : File.join(app_root.to_s, pathname.to_s)
124
+ end
125
+
126
+ def pem(value)
127
+ key = value.to_s.strip.gsub('\n', "\n")
128
+ return terminate(key) if key.include?(PEM_MARKER)
129
+
130
+ decoded = key.unpack1("m").force_encoding(Encoding::UTF_8)
131
+ decoded.include?(PEM_MARKER) ? terminate(decoded) : key
132
+ end
133
+
134
+ def terminate(key)
135
+ key.end_with?("\n") ? key : key + "\n"
136
+ end
137
+ end
138
+ end
@@ -1,3 +1,5 @@
1
+ require "rails/engine"
2
+
1
3
  module MapkitToken
2
4
  class Engine < Rails::Engine
3
5
  end
@@ -1,3 +1,3 @@
1
1
  module MapkitToken
2
- VERSION = "1.0.0"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/mapkit_token.rb CHANGED
@@ -1,15 +1,23 @@
1
1
  require "active_support/all"
2
2
  require "mapkit_token/version"
3
+ require "mapkit_token/config"
3
4
  require "mapkit_token/app/models/mapkit.rb"
4
5
  require "jwt"
5
6
 
6
7
  module MapkitToken
7
8
  mattr_accessor :app_root
9
+ mattr_accessor :auth_key
10
+ mattr_accessor :auth_key_path
11
+ mattr_accessor :auth_key_id
12
+ mattr_accessor :apple_team_id
8
13
 
9
14
  def self.setup
10
15
  yield self
11
16
  end
17
+
18
+ def self.config
19
+ Config.new
20
+ end
12
21
  end
13
22
 
14
23
  require "mapkit_token/engine"
15
-
data/mapkit_token.gemspec CHANGED
@@ -19,8 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_development_dependency "bundler", "~> 1.16"
23
- spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "rake", ">= 13.0"
24
23
  spec.add_development_dependency "rspec", "~> 3.0"
25
24
 
26
25
  spec.add_dependency "activesupport"
metadata CHANGED
@@ -1,43 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mapkit_token
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Edlund
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2019-08-14 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.16'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.16'
27
12
  - !ruby/object:Gem::Dependency
28
13
  name: rake
29
14
  requirement: !ruby/object:Gem::Requirement
30
15
  requirements:
31
- - - "~>"
16
+ - - ">="
32
17
  - !ruby/object:Gem::Version
33
- version: '10.0'
18
+ version: '13.0'
34
19
  type: :development
35
20
  prerelease: false
36
21
  version_requirements: !ruby/object:Gem::Requirement
37
22
  requirements:
38
- - - "~>"
23
+ - - ">="
39
24
  - !ruby/object:Gem::Version
40
- version: '10.0'
25
+ version: '13.0'
41
26
  - !ruby/object:Gem::Dependency
42
27
  name: rspec
43
28
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +79,6 @@ dependencies:
94
79
  - - ">="
95
80
  - !ruby/object:Gem::Version
96
81
  version: '0'
97
- description:
98
82
  email:
99
83
  - medlund@mac.com
100
84
  executables: []
@@ -114,13 +98,13 @@ files:
114
98
  - config/routes.rb
115
99
  - lib/mapkit_token.rb
116
100
  - lib/mapkit_token/app/models/mapkit.rb
101
+ - lib/mapkit_token/config.rb
117
102
  - lib/mapkit_token/engine.rb
118
103
  - lib/mapkit_token/version.rb
119
104
  - mapkit_token.gemspec
120
105
  homepage: https://github.com/arcticleo/mapkit_token
121
106
  licenses: []
122
107
  metadata: {}
123
- post_install_message:
124
108
  rdoc_options: []
125
109
  require_paths:
126
110
  - lib
@@ -135,8 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
119
  - !ruby/object:Gem::Version
136
120
  version: '0'
137
121
  requirements: []
138
- rubygems_version: 3.0.3
139
- signing_key:
122
+ rubygems_version: 4.0.20
140
123
  specification_version: 4
141
124
  summary: MapKit JS token endpoint provider.
142
125
  test_files: []