shimmer 0.0.12 → 0.0.13
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 +4 -4
- data/lib/shimmer/auth/apple_provider.rb +30 -0
- data/lib/shimmer/auth/authenticating.rb +37 -0
- data/lib/shimmer/auth/current.rb +15 -0
- data/lib/shimmer/auth/dev_provider.rb +14 -0
- data/lib/shimmer/auth/device.rb +23 -0
- data/lib/shimmer/auth/google_provider.rb +16 -0
- data/lib/shimmer/auth/user.rb +22 -0
- data/lib/shimmer/auth.rb +47 -0
- data/lib/shimmer/tasks/auth.rake +19 -0
- data/lib/shimmer/utils/config.rb +33 -0
- data/lib/shimmer/version.rb +1 -1
- data/lib/shimmer.rb +1 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa623a504a48b7e6f3a1c0d4ccf748b2068b8934288094524a8039c52588c384
|
4
|
+
data.tar.gz: 67ccb1224024c812aad171ddca3437c3d130fb1bbf71dc5c9326da143061be1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9de1f128d5baafb0c5effb645c59ccecec08b7c7319761802cfb8ed7bbeb55cc01abb9f365f85e0397ceff692e835dc5131683bac01f514619bf1623be831c37
|
7
|
+
data.tar.gz: 856718e8800d539c1c31c9b867768c9db4939fe979019f44e6eebf6203cb1d60f8daca6ce42d3b21cab1027d00106345a531cb28bd912bcdea31028885042803
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shimmer
|
4
|
+
module Auth
|
5
|
+
class AppleProvider < Provider
|
6
|
+
self.token_column = :apple_id
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def request_details(params)
|
11
|
+
name = params[:user] ? JSON.parse(params[:user])["name"] : {}
|
12
|
+
headers = {
|
13
|
+
'Content-Type': "application/x-www-form-urlencoded"
|
14
|
+
}
|
15
|
+
form = {
|
16
|
+
grant_type: "authorization_code",
|
17
|
+
code: params[:code],
|
18
|
+
client_id: ENV.fetch("APPLE_BUNDLE_ID"),
|
19
|
+
client_secret: ENV.fetch("APPLE_CLIENT_SECRET"),
|
20
|
+
scope: "name email"
|
21
|
+
}
|
22
|
+
response = HTTParty.post("https://appleid.apple.com/auth/token", body: URI.encode_www_form(form), headers: headers)
|
23
|
+
raise InvalidTokenError, "Login check failed: #{response.body}" unless response.ok?
|
24
|
+
|
25
|
+
token = JWT.decode(response["id_token"], nil, false).first
|
26
|
+
UserDetails.new token: token["sub"], email: token["email"], first_name: name["firstName"], last_name: name["lastName"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shimmer
|
4
|
+
module Auth
|
5
|
+
module Authenticating
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
before_action :authenticate
|
10
|
+
helper_method :current_user
|
11
|
+
|
12
|
+
def require_login
|
13
|
+
redirect_to login_path unless current_user
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_user
|
17
|
+
::Current.user
|
18
|
+
end
|
19
|
+
|
20
|
+
def login(device:)
|
21
|
+
::Current.device = device
|
22
|
+
cookies.encrypted[:device_token] = {value: device.token, expires: 2.years.from_now}
|
23
|
+
end
|
24
|
+
|
25
|
+
def logout
|
26
|
+
cookies.delete :device_token
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def authenticate
|
32
|
+
::Current.device = cookies.encrypted[:device_token].presence&.then { |e| ::Device.find_by token: e }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shimmer
|
4
|
+
module Auth
|
5
|
+
class DevProvider < Provider
|
6
|
+
def login(email:, user_agent: nil, ip: nil)
|
7
|
+
user = model.find_or_create_by!(email: email)
|
8
|
+
device = user.devices.create! user_agent: user_agent
|
9
|
+
log_login(user, device_id: device.id, user_agent: user_agent, ip: ip)
|
10
|
+
device
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shimmer
|
4
|
+
module Auth
|
5
|
+
module Device
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
has_secure_token
|
10
|
+
|
11
|
+
def name
|
12
|
+
[browser.platform.name, browser.name].join(" ")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def browser
|
18
|
+
@browser ||= Browser.new user_agent
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shimmer
|
4
|
+
module Auth
|
5
|
+
class GoogleProvider < Provider
|
6
|
+
self.token_column = :google_id
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def request_details(params)
|
11
|
+
payload = GoogleIDToken::Validator.new.check(params[:credential], ENV.fetch("GOOGLE_CLIENT_ID"))
|
12
|
+
UserDetails.new token: payload["sub"], email: payload["email"], first_name: payload["given_name"].presence, last_name: payload["family_name"].presence
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shimmer
|
4
|
+
module Auth
|
5
|
+
module User
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
def authenticate!(user_agent: nil, ip: nil)
|
10
|
+
Provider.new(self.class).create_device(user: self, user_agent: user_agent, ip: ip)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class_methods do
|
15
|
+
def login!(provider:, **attributes)
|
16
|
+
"Shimmer::Auth::#{provider.to_s.classify}Provider".constantize
|
17
|
+
.new(self).login(**attributes)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/shimmer/auth.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shimmer
|
4
|
+
module Auth
|
5
|
+
class Provider
|
6
|
+
class InvalidTokenError < StandardError; end
|
7
|
+
UserDetails = Struct.new(:token, :email, :first_name, :last_name, keyword_init: true)
|
8
|
+
attr_reader :model
|
9
|
+
cattr_accessor :token_column
|
10
|
+
|
11
|
+
def initialize(model)
|
12
|
+
@model = model
|
13
|
+
end
|
14
|
+
|
15
|
+
def login(params:, user_agent: nil, ip: nil)
|
16
|
+
user = fetch_user request_details(params)
|
17
|
+
create_device user: user, user_agent: user_agent, ip: ip
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_device(user:, user_agent: nil, ip: nil)
|
21
|
+
user.devices.create!(user_agent: user_agent).tap do |device|
|
22
|
+
log_login(user, device_id: device.id, user_agent: user_agent, ip: ip)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def log_login(user, device_id:, user_agent: nil, ip: nil)
|
29
|
+
return unless user.respond_to? :publish
|
30
|
+
|
31
|
+
user.publish :login, provider: self.class.name.demodulize.underscore, device_id: device_id, user_agent: user_agent, ip: ip
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch_user(details)
|
35
|
+
user = model.find_by(token_column => details.token) || model.find_by(email: details.email) || model.new
|
36
|
+
user[token_column] ||= details.token
|
37
|
+
user.email ||= details.email
|
38
|
+
user.first_name ||= details.first_name
|
39
|
+
user.last_name ||= details.last_name
|
40
|
+
user.save! if user.changed?
|
41
|
+
user
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Dir["#{File.expand_path("./auth", __dir__)}/*"].sort.each { |e| require e }
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :auth do
|
4
|
+
desc "Generates a Sign in with Apple Token"
|
5
|
+
task :apple_token do
|
6
|
+
ecdsa_key = OpenSSL::PKey::EC.new IO.read ".apple-key.p8"
|
7
|
+
headers = {
|
8
|
+
"kid" => Shimmer::Config.instance.apple_key_id!
|
9
|
+
}
|
10
|
+
claims = {
|
11
|
+
"iss" => Shimmer::Config.instance.apple_team_id!,
|
12
|
+
"iat" => Time.now.to_i,
|
13
|
+
"exp" => 180.days.from_now.to_i,
|
14
|
+
"aud" => "https://appleid.apple.com",
|
15
|
+
"sub" => Shimmer::Config.instance.apple_bundle_id!
|
16
|
+
}
|
17
|
+
puts JWT.encode claims, ecdsa_key, "ES256", headers
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Shimmer
|
4
|
+
class Config
|
5
|
+
include Singleton
|
6
|
+
class MissingConfigError < StandardError; end
|
7
|
+
|
8
|
+
def method_missing(method_name)
|
9
|
+
method_name = method_name.to_s
|
10
|
+
type = :string
|
11
|
+
key = method_name.delete_suffix("!").delete_suffix("?")
|
12
|
+
required = method_name.end_with?("!")
|
13
|
+
type = :bool if method_name.end_with?("?")
|
14
|
+
value = ENV[key.upcase].presence
|
15
|
+
value ||= Rails.application.credentials.send(key)
|
16
|
+
raise MissingConfigError, "#{key.upcase} environment value is missing" if required && value.blank?
|
17
|
+
|
18
|
+
coerce value, type
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to_missing?(method_name)
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def coerce(value, type)
|
28
|
+
return !value.in?(["n", "0", "no", "false"]) if type == :bool && value.is_a?(String)
|
29
|
+
|
30
|
+
value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/shimmer/version.rb
CHANGED
data/lib/shimmer.rb
CHANGED
@@ -6,6 +6,7 @@ Dir["#{File.expand_path("../lib/shimmer/middlewares", __dir__)}/*"].sort.each {
|
|
6
6
|
Dir["#{File.expand_path("../lib/shimmer/controllers", __dir__)}/*"].sort.each { |e| require e }
|
7
7
|
Dir["#{File.expand_path("../lib/shimmer/jobs", __dir__)}/*"].sort.each { |e| require e }
|
8
8
|
Dir["#{File.expand_path("../lib/shimmer/utils", __dir__)}/*"].sort.each { |e| require e }
|
9
|
+
require_relative "shimmer/auth"
|
9
10
|
|
10
11
|
module Shimmer
|
11
12
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shimmer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jens Ravens
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-06-
|
11
|
+
date: 2022-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -135,13 +135,23 @@ files:
|
|
135
135
|
- bin/solargraph
|
136
136
|
- config/rubocop_base.yml
|
137
137
|
- lib/shimmer.rb
|
138
|
+
- lib/shimmer/auth.rb
|
139
|
+
- lib/shimmer/auth/apple_provider.rb
|
140
|
+
- lib/shimmer/auth/authenticating.rb
|
141
|
+
- lib/shimmer/auth/current.rb
|
142
|
+
- lib/shimmer/auth/dev_provider.rb
|
143
|
+
- lib/shimmer/auth/device.rb
|
144
|
+
- lib/shimmer/auth/google_provider.rb
|
145
|
+
- lib/shimmer/auth/user.rb
|
138
146
|
- lib/shimmer/controllers/files_controller.rb
|
139
147
|
- lib/shimmer/controllers/sitemaps_controller.rb
|
140
148
|
- lib/shimmer/jobs/sitemap_job.rb
|
141
149
|
- lib/shimmer/middlewares/cloudflare.rb
|
142
150
|
- lib/shimmer/railtie.rb
|
151
|
+
- lib/shimmer/tasks/auth.rake
|
143
152
|
- lib/shimmer/tasks/db.rake
|
144
153
|
- lib/shimmer/tasks/lint.rake
|
154
|
+
- lib/shimmer/utils/config.rb
|
145
155
|
- lib/shimmer/utils/file_helper.rb
|
146
156
|
- lib/shimmer/utils/file_proxy.rb
|
147
157
|
- lib/shimmer/utils/localizable.rb
|