foobara-auth 0.0.5 → 0.0.7
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/CHANGELOG.md +9 -0
- data/src/build_access_token.rb +46 -0
- data/src/create_refresh_token.rb +51 -0
- data/src/create_user.rb +8 -1
- data/src/login.rb +5 -44
- data/src/logout.rb +61 -0
- data/src/refresh_login.rb +7 -50
- data/src/register.rb +8 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1aa9644452f2df69c840be3976c4ea0c9b4d7af09ae432a20c98bdb71f87393e
|
4
|
+
data.tar.gz: f28a748760a24e913af0f53d47be631aaaa93394e5747978f2cd22f42048bd3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dad7b1b7193abe3753b6d7f592a1b2fcd5c7c9b229c5025dbc3ecffb645c97c195eb6199a410a9b49fd70e032c05349d298b3fd153a78bebee9862df5da64ff1
|
7
|
+
data.tar.gz: 04a75cf7418015a6399442c2b0cd6244cfd1410b747f49adaa2ca7cf5da03f8c511b4c8caa38bfdf4d849c1edfb5cb270a2edac685475d0185dd0917bee5394c
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "jwt"
|
2
|
+
|
3
|
+
module Foobara
|
4
|
+
module Auth
|
5
|
+
class BuildAccessToken < Foobara::Command
|
6
|
+
inputs do
|
7
|
+
user Types::User, :allow_nil
|
8
|
+
token_ttl :integer, default: 30 * 60
|
9
|
+
end
|
10
|
+
|
11
|
+
result :string, :sensitive_exposed
|
12
|
+
|
13
|
+
def execute
|
14
|
+
determine_timestamps
|
15
|
+
generate_access_token
|
16
|
+
|
17
|
+
access_token
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_accessor :access_token, :expires_at
|
21
|
+
|
22
|
+
def determine_timestamps
|
23
|
+
now = Time.now
|
24
|
+
self.expires_at = now + token_ttl
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_access_token
|
28
|
+
payload = { sub: user.id, exp: expires_at.to_i }
|
29
|
+
|
30
|
+
self.access_token = JWT.encode(payload, jwt_secret, "HS256")
|
31
|
+
end
|
32
|
+
|
33
|
+
def jwt_secret
|
34
|
+
jwt_secret_text = ENV.fetch("JWT_SECRET", nil)
|
35
|
+
|
36
|
+
unless jwt_secret_text
|
37
|
+
# :nocov:
|
38
|
+
raise "You must set the JWT_SECRET environment variable"
|
39
|
+
# :nocov:
|
40
|
+
end
|
41
|
+
|
42
|
+
jwt_secret_text
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
require_relative "create_token"
|
4
|
+
|
5
|
+
module Foobara
|
6
|
+
module Auth
|
7
|
+
class CreateRefreshToken < Foobara::Command
|
8
|
+
depends_on CreateToken
|
9
|
+
|
10
|
+
inputs do
|
11
|
+
user Types::User
|
12
|
+
token_ttl :integer, default: 30 * 60
|
13
|
+
end
|
14
|
+
|
15
|
+
result :string, :sensitive_exposed
|
16
|
+
|
17
|
+
def execute
|
18
|
+
determine_timestamps
|
19
|
+
determine_token_group
|
20
|
+
|
21
|
+
generate_new_refresh_token
|
22
|
+
save_new_refresh_token_on_user
|
23
|
+
|
24
|
+
refresh_token_secret
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :expires_at, :refresh_token_record, :token_group, :refresh_token_secret
|
28
|
+
|
29
|
+
def determine_timestamps
|
30
|
+
now = Time.now
|
31
|
+
self.expires_at = now + token_ttl
|
32
|
+
end
|
33
|
+
|
34
|
+
def determine_token_group
|
35
|
+
self.token_group = refresh_token_record&.token_group || SecureRandom.uuid
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_new_refresh_token
|
39
|
+
result = run_subcommand!(CreateToken, expires_at:, token_group:)
|
40
|
+
|
41
|
+
self.refresh_token_record = result[:token_record]
|
42
|
+
self.refresh_token_secret = result[:token_string]
|
43
|
+
end
|
44
|
+
|
45
|
+
def save_new_refresh_token_on_user
|
46
|
+
# TODO: maybe override #<< on these objects to dirty the entity??
|
47
|
+
user.refresh_tokens = [refresh_token_record, *user.refresh_tokens]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/src/create_user.rb
CHANGED
@@ -4,6 +4,7 @@ module Foobara
|
|
4
4
|
inputs Types::User.attributes_for_create
|
5
5
|
|
6
6
|
add_inputs do
|
7
|
+
user_id :integer, :allow_nil
|
7
8
|
plaintext_password :string, :sensitive_exposed
|
8
9
|
end
|
9
10
|
|
@@ -24,7 +25,13 @@ module Foobara
|
|
24
25
|
attr_accessor :user
|
25
26
|
|
26
27
|
def create_user
|
27
|
-
|
28
|
+
inputs = self.inputs.except(:user_id, :plaintext_password)
|
29
|
+
|
30
|
+
if user_id
|
31
|
+
inputs[:id] = user_id
|
32
|
+
end
|
33
|
+
|
34
|
+
self.user = Types::User.create(inputs)
|
28
35
|
end
|
29
36
|
|
30
37
|
def password_present?
|
data/src/login.rb
CHANGED
@@ -1,10 +1,3 @@
|
|
1
|
-
require "jwt"
|
2
|
-
require "securerandom"
|
3
|
-
|
4
|
-
require_relative "create_token"
|
5
|
-
require_relative "verify_password"
|
6
|
-
require_relative "verify_token"
|
7
|
-
|
8
1
|
module Foobara
|
9
2
|
module Auth
|
10
3
|
class Login < Foobara::Command
|
@@ -18,7 +11,7 @@ module Foobara
|
|
18
11
|
message "No user id, email, or username given"
|
19
12
|
end
|
20
13
|
|
21
|
-
depends_on
|
14
|
+
depends_on VerifyPassword, FindUser, BuildAccessToken, CreateRefreshToken
|
22
15
|
|
23
16
|
inputs do
|
24
17
|
user Types::User, :allow_nil
|
@@ -39,17 +32,13 @@ module Foobara
|
|
39
32
|
def execute
|
40
33
|
find_user_to_login
|
41
34
|
verify_password
|
42
|
-
# TODO: DRY these 5 up
|
43
|
-
determine_timestamps
|
44
35
|
generate_access_token
|
45
|
-
determine_token_group
|
46
36
|
generate_new_refresh_token
|
47
|
-
save_new_refresh_token_on_user
|
48
37
|
|
49
38
|
tokens
|
50
39
|
end
|
51
40
|
|
52
|
-
attr_accessor :access_token, :
|
41
|
+
attr_accessor :access_token, :refresh_token_text, :user_to_login
|
53
42
|
|
54
43
|
def find_user_to_login
|
55
44
|
if user
|
@@ -83,46 +72,18 @@ module Foobara
|
|
83
72
|
end
|
84
73
|
end
|
85
74
|
|
86
|
-
def determine_timestamps
|
87
|
-
self.now = Time.now
|
88
|
-
self.expires_at = now + token_ttl
|
89
|
-
end
|
90
|
-
|
91
75
|
def generate_access_token
|
92
|
-
|
93
|
-
|
94
|
-
self.access_token = JWT.encode(payload, jwt_secret, "HS256")
|
95
|
-
end
|
96
|
-
|
97
|
-
def jwt_secret
|
98
|
-
jwt_secret_text = ENV.fetch("JWT_SECRET", nil)
|
99
|
-
|
100
|
-
unless jwt_secret_text
|
101
|
-
# :nocov:
|
102
|
-
raise "You must set the JWT_SECRET environment variable"
|
103
|
-
# :nocov:
|
104
|
-
end
|
105
|
-
|
106
|
-
jwt_secret_text
|
107
|
-
end
|
108
|
-
|
109
|
-
def determine_token_group
|
110
|
-
self.token_group = SecureRandom.uuid
|
76
|
+
self.access_token = run_subcommand!(BuildAccessToken, user: user_to_login)
|
111
77
|
end
|
112
78
|
|
113
79
|
def generate_new_refresh_token
|
114
|
-
self.
|
115
|
-
end
|
116
|
-
|
117
|
-
def save_new_refresh_token_on_user
|
118
|
-
# TODO: maybe override #<< on these objects to dirty the entity??
|
119
|
-
user_to_login.refresh_tokens = [new_refresh_token[:token_record], *user_to_login.refresh_tokens]
|
80
|
+
self.refresh_token_text = run_subcommand!(CreateRefreshToken, user: user_to_login)
|
120
81
|
end
|
121
82
|
|
122
83
|
def tokens
|
123
84
|
{
|
124
85
|
access_token:,
|
125
|
-
refresh_token:
|
86
|
+
refresh_token: refresh_token_text
|
126
87
|
}
|
127
88
|
end
|
128
89
|
end
|
data/src/logout.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Foobara
|
2
|
+
module Auth
|
3
|
+
class Logout < Foobara::Command
|
4
|
+
class InvalidRefreshTokenError < Foobara::RuntimeError
|
5
|
+
context refresh_token_id: :string
|
6
|
+
message "Invalid refresh token"
|
7
|
+
end
|
8
|
+
|
9
|
+
depends_on VerifyToken
|
10
|
+
depends_on_entity Types::Token
|
11
|
+
depends_on_entity Types::User
|
12
|
+
|
13
|
+
inputs do
|
14
|
+
refresh_token :string, :allow_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: support nil result type in typescript remote command generator
|
18
|
+
result :duck
|
19
|
+
|
20
|
+
def execute
|
21
|
+
if refresh_token?
|
22
|
+
determine_refresh_token_id_and_secret
|
23
|
+
load_refresh_token_record
|
24
|
+
verify_refresh_token
|
25
|
+
# Delete it instead maybe?
|
26
|
+
mark_refresh_token_as_used
|
27
|
+
end
|
28
|
+
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_accessor :refresh_token_record, :refresh_token_id, :refresh_token_secret
|
33
|
+
|
34
|
+
def refresh_token?
|
35
|
+
!!refresh_token
|
36
|
+
end
|
37
|
+
|
38
|
+
def determine_refresh_token_id_and_secret
|
39
|
+
self.refresh_token_id, self.refresh_token_secret = refresh_token.split("_")
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_refresh_token_record
|
43
|
+
self.refresh_token_record = Types::Token.load(refresh_token_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def verify_refresh_token
|
47
|
+
valid = run_subcommand!(VerifyToken, token_string: refresh_token)
|
48
|
+
|
49
|
+
unless valid[:verified]
|
50
|
+
# :nocov:
|
51
|
+
add_runtime_error(InvalidRefreshTokenError.new(context: { refresh_token_id: }))
|
52
|
+
# :nocov:
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def mark_refresh_token_as_used
|
57
|
+
refresh_token_record.use_up!
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/src/refresh_login.rb
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
require "jwt"
|
2
|
-
require "securerandom"
|
3
|
-
|
4
|
-
require_relative "create_token"
|
5
|
-
require_relative "verify_token"
|
6
|
-
|
7
1
|
module Foobara
|
8
2
|
module Auth
|
9
3
|
class RefreshLogin < Foobara::Command
|
@@ -17,13 +11,12 @@ module Foobara
|
|
17
11
|
message "This refresh token is not owned by this user"
|
18
12
|
end
|
19
13
|
|
20
|
-
depends_on
|
14
|
+
depends_on CreateRefreshToken, VerifyToken, BuildAccessToken
|
21
15
|
depends_on_entities Types::Token
|
22
16
|
|
23
17
|
inputs do
|
24
18
|
refresh_token :string, :required, :sensitive
|
25
|
-
|
26
|
-
token_ttl :integer, default: 30 * 60
|
19
|
+
access_token_ttl :integer, default: 30 * 60
|
27
20
|
refresh_token_ttl :integer, default: 7 * 24 * 60 * 60
|
28
21
|
end
|
29
22
|
|
@@ -38,18 +31,15 @@ module Foobara
|
|
38
31
|
verify_refresh_token
|
39
32
|
# Delete it instead maybe?
|
40
33
|
mark_refresh_token_as_used
|
41
|
-
determine_timestamps
|
42
|
-
determine_token_group
|
43
34
|
|
44
35
|
generate_access_token
|
45
36
|
generate_new_refresh_token
|
46
|
-
save_new_refresh_token_on_user
|
47
37
|
|
48
38
|
tokens
|
49
39
|
end
|
50
40
|
|
51
|
-
attr_accessor :access_token, :new_refresh_token, :
|
52
|
-
:refresh_token_id, :refresh_token_secret
|
41
|
+
attr_accessor :access_token, :new_refresh_token, :expires_at, :refresh_token_record,
|
42
|
+
:refresh_token_id, :refresh_token_secret
|
53
43
|
|
54
44
|
def determine_refresh_token_id_and_secret
|
55
45
|
self.refresh_token_id, self.refresh_token_secret = refresh_token.split("_")
|
@@ -71,55 +61,22 @@ module Foobara
|
|
71
61
|
refresh_token_record.use_up!
|
72
62
|
end
|
73
63
|
|
74
|
-
def determine_timestamps
|
75
|
-
self.now = Time.now
|
76
|
-
self.expires_at = now + token_ttl
|
77
|
-
end
|
78
|
-
|
79
64
|
def generate_access_token
|
80
|
-
|
81
|
-
user_id: user.id,
|
82
|
-
username: user.username,
|
83
|
-
exp: expires_at.to_i
|
84
|
-
}
|
85
|
-
|
86
|
-
self.access_token = JWT.encode(payload, jwt_secret, "HS256")
|
65
|
+
self.access_token = run_subcommand!(BuildAccessToken, user:, token_ttl: access_token_ttl)
|
87
66
|
end
|
88
67
|
|
89
68
|
def user
|
90
69
|
@user ||= Types::User.that_owns(refresh_token_record, "refresh_tokens")
|
91
70
|
end
|
92
71
|
|
93
|
-
def jwt_secret
|
94
|
-
jwt_secret_text = ENV.fetch("JWT_SECRET", nil)
|
95
|
-
|
96
|
-
unless jwt_secret_text
|
97
|
-
# :nocov:
|
98
|
-
raise "You must set the JWT_SECRET environment variable"
|
99
|
-
# :nocov:
|
100
|
-
end
|
101
|
-
|
102
|
-
jwt_secret_text
|
103
|
-
end
|
104
|
-
|
105
|
-
def determine_token_group
|
106
|
-
self.token_group = refresh_token_record&.token_group || SecureRandom.uuid
|
107
|
-
end
|
108
|
-
|
109
72
|
def generate_new_refresh_token
|
110
|
-
self.new_refresh_token = run_subcommand!(
|
111
|
-
end
|
112
|
-
|
113
|
-
def save_new_refresh_token_on_user
|
114
|
-
# TODO: maybe override #<< on these objects to dirty the entity??
|
115
|
-
# TODO: DRY this up!!
|
116
|
-
user.refresh_tokens = [new_refresh_token[:token_record], *user.refresh_tokens]
|
73
|
+
self.new_refresh_token = run_subcommand!(CreateRefreshToken, user:, token_ttl: refresh_token_ttl)
|
117
74
|
end
|
118
75
|
|
119
76
|
def tokens
|
120
77
|
{
|
121
78
|
access_token:,
|
122
|
-
refresh_token: new_refresh_token
|
79
|
+
refresh_token: new_refresh_token
|
123
80
|
}
|
124
81
|
end
|
125
82
|
end
|
data/src/register.rb
CHANGED
@@ -6,6 +6,7 @@ module Foobara
|
|
6
6
|
depends_on CreateUser, SetPassword
|
7
7
|
|
8
8
|
inputs do
|
9
|
+
user_id :integer, :allow_nil
|
9
10
|
username :string, :required
|
10
11
|
email :email, :allow_nil
|
11
12
|
plaintext_password :string, :allow_nil, :sensitive_exposed
|
@@ -26,7 +27,13 @@ module Foobara
|
|
26
27
|
attr_accessor :user
|
27
28
|
|
28
29
|
def create_user
|
29
|
-
|
30
|
+
inputs = { username:, email: }
|
31
|
+
|
32
|
+
if user_id
|
33
|
+
inputs[:user_id] = user_id
|
34
|
+
end
|
35
|
+
|
36
|
+
self.user = run_subcommand!(CreateUser, inputs)
|
30
37
|
end
|
31
38
|
|
32
39
|
def password?
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foobara-auth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-04-01 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: argon2
|
@@ -64,13 +64,16 @@ files:
|
|
64
64
|
- README.md
|
65
65
|
- lib/foobara/auth.rb
|
66
66
|
- src/approve_token.rb
|
67
|
+
- src/build_access_token.rb
|
67
68
|
- src/build_secret.rb
|
68
69
|
- src/create_api_key.rb
|
70
|
+
- src/create_refresh_token.rb
|
69
71
|
- src/create_role.rb
|
70
72
|
- src/create_token.rb
|
71
73
|
- src/create_user.rb
|
72
74
|
- src/find_user.rb
|
73
75
|
- src/login.rb
|
76
|
+
- src/logout.rb
|
74
77
|
- src/refresh_login.rb
|
75
78
|
- src/register.rb
|
76
79
|
- src/set_password.rb
|