foobara-auth 0.0.8 → 0.0.10

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: e1ba58c561a925a0c68b73d09b35bea08bd1547170c3c5cb947c97b6bbbcd91d
4
- data.tar.gz: a9a6ef33b8b8834548034c7852ec4904d1b2161e83c8190b5aacf5c76fe7d38a
3
+ metadata.gz: 45cdb3b28235c09c136eb81a09662517dd017afef86cb5fd11b1c966a264685d
4
+ data.tar.gz: 65b323560c3469fa6b1c29e20d39f4ecf4c6e42011da3a7244876863f87057ab
5
5
  SHA512:
6
- metadata.gz: de9f66fc29b5d7176198a8b03eb33b2046d0c9cf8c4130d2ecf082a65c7b215996d2c080099b1d7bdffa9f26c89d86513edd5bbab65f9bd9f756eaec983720d2
7
- data.tar.gz: 78a8c4c831f5c808cf4f675ecda90e418803a8c6d5f5d63f08679086a3e5693126f1fb4d9216a1bed7d44ef4f7c96a55d178e0dad5d6dca5cb50ff4e91079971
6
+ metadata.gz: 48db1658d6fa78ae0cfe733c7bb58288519399311007851d03c5253f2ebd44f089027820f788c1bfe7af012372520639a56594471d6f50269e75e75c47c884a7
7
+ data.tar.gz: c6c486c5f4a408177e6a534169bea9d0a77068d8208ed99f5c4217ca37d6f247ffc00743041ff4306f858c5963592ebf9bbd857b6422412a8618cb4157d29df6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [0.0.10] - 2025-04-28
2
+
3
+ - Add AuthenticateWithApiKey command
4
+
5
+ ## [0.0.9] - 2025-04-22
6
+
7
+ - Handle malformed jwt tokens
8
+
1
9
  ## [0.0.8] - 2025-04-11
2
10
 
3
11
  - Just seeing if we can successfully push new gems since there's an issue pushing foobara
@@ -0,0 +1,59 @@
1
+ require_relative "verify_token"
2
+
3
+ module Foobara
4
+ module Auth
5
+ class AuthenticateWithApiKey < Foobara::Command
6
+ class InvalidApiKeyError < Foobara::RuntimeError
7
+ context api_key_id: :string
8
+ message "Invalid api key"
9
+ end
10
+
11
+ depends_on VerifyToken
12
+ depends_on_entities Types::Token
13
+
14
+ inputs do
15
+ api_key :string, :required, :sensitive
16
+ access_token_ttl :integer, default: 30 * 60
17
+ api_key_ttl :integer, default: 7 * 24 * 60 * 60
18
+ end
19
+
20
+ result [Types::User, Types::Token]
21
+
22
+ def execute
23
+ determine_api_key_id_and_secret
24
+ load_api_key_record
25
+ verify_api_key
26
+
27
+ load_user
28
+
29
+ user_and_credential
30
+ end
31
+
32
+ attr_accessor :expires_at, :api_key_record, :api_key_id, :api_key_secret, :user
33
+
34
+ def determine_api_key_id_and_secret
35
+ self.api_key_id, self.api_key_secret = api_key.split("_")
36
+ end
37
+
38
+ def load_api_key_record
39
+ self.api_key_record = Types::Token.load(api_key_id)
40
+ end
41
+
42
+ def verify_api_key
43
+ valid = run_subcommand!(VerifyToken, token_string: api_key)
44
+
45
+ unless valid[:verified]
46
+ add_runtime_error(InvalidApiKeyError.new(context: { api_key_id: }))
47
+ end
48
+ end
49
+
50
+ def load_user
51
+ self.user ||= Types::User.that_owns(api_key_record, "api_keys")
52
+ end
53
+
54
+ def user_and_credential
55
+ [user, api_key_record]
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,45 @@
1
+ require "securerandom"
2
+
3
+ require_relative "create_token"
4
+
5
+ module Foobara
6
+ module Auth
7
+ class CreateResetPasswordToken < Foobara::Command
8
+ depends_on CreateToken
9
+
10
+ inputs do
11
+ user Types::User, :required
12
+ token_ttl :integer, default: 5 * 60
13
+ end
14
+
15
+ result :string, :sensitive_exposed
16
+
17
+ def execute
18
+ determine_timestamps
19
+
20
+ generate_new_reset_password_token
21
+ save_new_reset_password_token_on_user
22
+
23
+ reset_password_token_secret
24
+ end
25
+
26
+ attr_accessor :expires_at, :reset_password_token_record, :reset_password_token_secret
27
+
28
+ def determine_timestamps
29
+ now = Time.now
30
+ self.expires_at = now + token_ttl
31
+ end
32
+
33
+ def generate_new_reset_password_token
34
+ result = run_subcommand!(CreateToken, expires_at:)
35
+
36
+ self.reset_password_token_record = result[:token_record]
37
+ self.reset_password_token_secret = result[:token_string]
38
+ end
39
+
40
+ def save_new_reset_password_token_on_user
41
+ user.reset_password_token = reset_password_token_record
42
+ end
43
+ end
44
+ end
45
+ end
data/src/refresh_login.rb CHANGED
@@ -6,11 +6,6 @@ module Foobara
6
6
  message "Invalid refresh token"
7
7
  end
8
8
 
9
- class RefreshTokenNotOwnedByUser < Foobara::RuntimeError
10
- context refresh_token_id: :string
11
- message "This refresh token is not owned by this user"
12
- end
13
-
14
9
  depends_on CreateRefreshToken, VerifyToken, BuildAccessToken
15
10
  depends_on_entities Types::Token
16
11
 
@@ -32,6 +27,8 @@ module Foobara
32
27
  # Delete it instead maybe?
33
28
  mark_refresh_token_as_used
34
29
 
30
+ load_user
31
+
35
32
  generate_access_token
36
33
  generate_new_refresh_token
37
34
 
@@ -39,7 +36,7 @@ module Foobara
39
36
  end
40
37
 
41
38
  attr_accessor :access_token, :new_refresh_token, :expires_at, :refresh_token_record,
42
- :refresh_token_id, :refresh_token_secret
39
+ :refresh_token_id, :refresh_token_secret, :user
43
40
 
44
41
  def determine_refresh_token_id_and_secret
45
42
  self.refresh_token_id, self.refresh_token_secret = refresh_token.split("_")
@@ -65,8 +62,8 @@ module Foobara
65
62
  self.access_token = run_subcommand!(BuildAccessToken, user:, token_ttl: access_token_ttl)
66
63
  end
67
64
 
68
- def user
69
- @user ||= Types::User.that_owns(refresh_token_record, "refresh_tokens")
65
+ def load_user
66
+ self.user ||= Types::User.that_owns(refresh_token_record, "refresh_tokens")
70
67
  end
71
68
 
72
69
  def generate_new_refresh_token
data/src/register.rb CHANGED
@@ -2,6 +2,7 @@ require_relative "types/user"
2
2
 
3
3
  module Foobara
4
4
  module Auth
5
+ # TODO: should raise error if username or email already in use!
5
6
  class Register < Foobara::Command
6
7
  depends_on CreateUser, SetPassword
7
8
 
@@ -0,0 +1,123 @@
1
+ module Foobara
2
+ module Auth
3
+ class ResetPassword < Foobara::Command
4
+ class NoPasswordResetTokenOrOldPasswordGivenError < Foobara::RuntimeError
5
+ context({})
6
+ message "Must give either a password reset token or an old password"
7
+ end
8
+
9
+ class BothPasswordResetTokenAndOldPasswordGivenError < Foobara::RuntimeError
10
+ context({})
11
+ message "Cannot give both a password reset token and an old password"
12
+ end
13
+
14
+ class IncorrectOldPasswordError < Foobara::RuntimeError
15
+ context({})
16
+ message "Incorrect old password"
17
+ end
18
+
19
+ class InvalidResetPasswordTokenError < Foobara::RuntimeError
20
+ context({}) # TODO: make this the default
21
+ message "Invalid password reset token"
22
+ end
23
+
24
+ class UserNotGivenError < Foobara::RuntimeError
25
+ context({})
26
+ message "Must give a user if giving an old password to reset password"
27
+ end
28
+
29
+ class UserNotFoundForResetTokenError < Foobara::RuntimeError
30
+ context({}) # TODO: make this the default?
31
+ message "No user found for reset password token"
32
+ end
33
+
34
+ inputs do
35
+ user Types::User
36
+ old_password :string, :sensitive_exposed
37
+ reset_password_token_secret :string, :sensitive_exposed
38
+ new_password :string, :sensitive, :required
39
+ end
40
+ result Types::User
41
+
42
+ depends_on BuildSecret, VerifyPassword, VerifyToken
43
+
44
+ # TODO: should we enforce certain password requirements?
45
+ def execute
46
+ if old_password_given?
47
+ verify_old_password
48
+ else
49
+ verify_and_use_up_password_reset_token
50
+ load_user
51
+ end
52
+
53
+ build_new_password
54
+ set_password_on_user
55
+
56
+ user
57
+ end
58
+
59
+ def validate
60
+ if old_password_given?
61
+ unless user
62
+ add_runtime_error(UserNotGivenError)
63
+ end
64
+ if reset_password_token_given?
65
+ add_runtime_error(BothPasswordResetTokenAndOldPasswordGivenError)
66
+ end
67
+ else
68
+ unless reset_password_token_given?
69
+ add_runtime_error(NoPasswordResetTokenOrOldPasswordGivenError)
70
+ end
71
+ end
72
+ end
73
+
74
+ attr_accessor :password_secret, :reset_password_token_record
75
+ attr_writer :user
76
+
77
+ def old_password_given?
78
+ !!old_password
79
+ end
80
+
81
+ def reset_password_token_given?
82
+ !!reset_password_token_secret
83
+ end
84
+
85
+ def verify_old_password
86
+ unless run_subcommand!(VerifyPassword, user:, plaintext_password: old_password)
87
+ add_runtime_error(IncorrectOldPasswordError)
88
+ end
89
+ end
90
+
91
+ def verify_and_use_up_password_reset_token
92
+ verified_result = run_subcommand!(VerifyToken, token_string: reset_password_token_secret)
93
+
94
+ unless verified_result[:verified]
95
+ add_runtime_error(InvalidResetPasswordTokenError)
96
+ end
97
+
98
+ self.reset_password_token_record = verified_result[:token_record]
99
+ reset_password_token_record.use_up!
100
+ end
101
+
102
+ def load_user
103
+ self.user = Types::User.that_owns(reset_password_token_record, "reset")
104
+
105
+ unless user
106
+ add_runtime_error(UserNotFoundForResetTokenError)
107
+ end
108
+ end
109
+
110
+ def user
111
+ @user || inputs[:user]
112
+ end
113
+
114
+ def build_new_password
115
+ self.password_secret = run_subcommand!(BuildSecret, secret: new_password)
116
+ end
117
+
118
+ def set_password_on_user
119
+ user.password_secret = password_secret
120
+ end
121
+ end
122
+ end
123
+ end
data/src/types/user.rb CHANGED
@@ -13,6 +13,7 @@ module Foobara
13
13
  api_keys [Types::Token], :sensitive, default: []
14
14
  refresh_tokens [Types::Token], :sensitive, default: []
15
15
  password_secret Types::Secret, :sensitive, :allow_nil
16
+ reset_password_token Types::Token, :sensitive, :allow_nil
16
17
  end
17
18
 
18
19
  primary_key :id
@@ -10,7 +10,7 @@ module Foobara
10
10
 
11
11
  result do
12
12
  verified :boolean, :required
13
- failure_reason :string, :allow_nil, one_of: %w[invalid expired]
13
+ failure_reason :string, :allow_nil, one_of: %w[invalid expired cannot_verify]
14
14
  payload :associative_array, :allow_nil
15
15
  headers :associative_array, :allow_nil
16
16
  end
@@ -27,9 +27,11 @@ module Foobara
27
27
  def decode_access_token
28
28
  self.payload, self.headers = JWT.decode(access_token, jwt_secret)
29
29
  rescue JWT::VerificationError
30
- self.failure_reason = "invalid"
30
+ self.failure_reason = "cannot_verify"
31
31
  rescue JWT::ExpiredSignature
32
32
  self.failure_reason = "expired"
33
+ rescue JWT::DecodeError
34
+ self.failure_reason = "invalid"
33
35
  end
34
36
 
35
37
  def set_verified_flag
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.8
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
10
+ date: 2025-05-01 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: argon2
@@ -64,10 +64,12 @@ files:
64
64
  - README.md
65
65
  - lib/foobara/auth.rb
66
66
  - src/approve_token.rb
67
+ - src/authenticate_with_api_key.rb
67
68
  - src/build_access_token.rb
68
69
  - src/build_secret.rb
69
70
  - src/create_api_key.rb
70
71
  - src/create_refresh_token.rb
72
+ - src/create_reset_password_token.rb
71
73
  - src/create_role.rb
72
74
  - src/create_token.rb
73
75
  - src/create_user.rb
@@ -76,6 +78,7 @@ files:
76
78
  - src/logout.rb
77
79
  - src/refresh_login.rb
78
80
  - src/register.rb
81
+ - src/reset_password.rb
79
82
  - src/set_password.rb
80
83
  - src/types/role.rb
81
84
  - src/types/secret.rb
@@ -109,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
112
  - !ruby/object:Gem::Version
110
113
  version: '0'
111
114
  requirements: []
112
- rubygems_version: 3.6.7
115
+ rubygems_version: 3.6.2
113
116
  specification_version: 4
114
117
  summary: Provides various auth domain commands and models
115
118
  test_files: []