rodauth-openapi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0ce74f8234f280f924c119e914ee31e88ee7714ccd10770626de4034edcac7da
4
+ data.tar.gz: 42f9cd22c79d36a6ae06e4703ce80a0da926908e5bd72f4eeb0a77644db1cf68
5
+ SHA512:
6
+ metadata.gz: e3797f271d6735174e03beda40c98f2392a338d295dcb15d06d323d52cc8828a1b0c654d798a8c3380039759a7eb769f8c9747ad4a7f0678a0f293e07eaa16de
7
+ data.tar.gz: bbdd36a6a8ab3d499b4f2af8487291111084e7a51851ef3e5463b861a6118922a20d217e2f5e56c185ca74e8f2a2b01b50d9694cbebd1f6312bf51cb18316b84
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Janko Marohnić
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Rodauth OpenAPI
2
+
3
+ Generates [OpenAPI] documentation for your Rodauth endpoints.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ bundle add rodauth-openapi --group development
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ The generated OpenAPI documentation can be uploaded to renderers such as [Swagger Editor] or [Redoc].
14
+
15
+ ### Rails
16
+
17
+ Assuming you have Rodauth installed in your Rails application, you can use the generator provided by this gem:
18
+
19
+ ```sh
20
+ rails g rodauth:openapi
21
+ ```
22
+
23
+ This will generate OpenAPI documentation in YAML format for the default Rodauth configuration and print it to standard output.
24
+
25
+ The generator accepts the following options:
26
+
27
+ ```sh
28
+ rails g rodauth:openapi --name admin # secondary configuration
29
+ rails g rodauth:openapi --format json # JSON format
30
+ rails g rodauth:openapi --json # generate JSON API endpoints
31
+ rails g rodauth:openapi --no-password # assume account without password
32
+ rails g rodauth:openapi --save openapi.yml # save to a file
33
+ ```
34
+
35
+ ### Outside of Rails
36
+
37
+ If you're not using Rails, you can generate the OpenAPI documentation programmatically:
38
+
39
+ ```rb
40
+ require "rodauth/openapi"
41
+
42
+ auth_class = RodauthApp.rodauth # or RodauthApp.rodauth(:admin)
43
+ open_api = Rodauth::OpenAPI.new(auth_class)
44
+
45
+ File.write("openapi.yml", open_api.to_yaml)
46
+ ```
47
+
48
+ To generate JSON API endpoints:
49
+
50
+ ```rb
51
+ Roduath::OpenAPI.new(auth_class, json: true)
52
+ ```
53
+
54
+ To assume the account doesn't have a password:
55
+
56
+ ```rb
57
+ Roduath::OpenAPI.new(auth_class, password: false)
58
+ ```
59
+
60
+ To generate the documentation in JSON format:
61
+
62
+ ```rb
63
+ Roduath::OpenAPI.new(auth_class).to_json
64
+ ```
65
+
66
+ ## License
67
+
68
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
69
+
70
+ ## Code of Conduct
71
+
72
+ Everyone interacting in the Rodauth::Openapi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/janko/rodauth-openapi/blob/main/CODE_OF_CONDUCT.md).
73
+
74
+ [OpenAPI]: https://swagger.io/specification/
75
+ [Swagger Editor]: https://editor.swagger.io/
76
+ [Redoc]: https://redocly.github.io/redoc/
@@ -0,0 +1,46 @@
1
+ require "rodauth/openapi"
2
+ require "rails/generators"
3
+
4
+ module Rodauth
5
+ module Generators
6
+ class OpenAPIGenerator < ::Rails::Generators::Base
7
+ namespace "rodauth:openapi"
8
+
9
+ class_option :password, type: :boolean, default: true,
10
+ desc: "Whether to assume the account has a password"
11
+
12
+ class_option :json, type: :boolean,
13
+ desc: "Whether to generate JSON API documentation"
14
+
15
+ class_option :name, type: :string, default: nil,
16
+ desc: "The configuration name for which to generate documentation"
17
+
18
+ class_option :format, type: :string, default: "yaml",
19
+ desc: "The format to output the documentation in (yaml, json)"
20
+
21
+ class_option :save, type: :string, default: nil,
22
+ desc: "File to save the documentation to (by default prints to stdout)"
23
+
24
+ def print_documentation
25
+ open_api = Rodauth::OpenAPI.new(auth_class, password: options[:password], json: options[:json])
26
+ documentation = open_api.public_send(:"to_#{options[:format]}")
27
+
28
+ if options[:save]
29
+ File.write(options[:save], documentation)
30
+ else
31
+ puts documentation
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def auth_class
38
+ Rodauth::Rails.app.rodauth!(configuration_name)
39
+ end
40
+
41
+ def configuration_name
42
+ options[:name]&.to_sym
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,27 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :change_login, "Change Login" do
4
+ get :change_login, "View login change page" do
5
+ redirect_error_response :login_required, "login required"
6
+
7
+ html_response "login change form"
8
+ redirect_error_response :login_required, "login required"
9
+ redirect_error_response :two_factor_need_authentication, "2FA required" if feature?(:two_factor_base)
10
+ end
11
+
12
+ post :change_login, "Perform login change" do
13
+ param :password, "Current account password", type: :password, required: true if rodauth.change_login_requires_password?
14
+ param :login, "Email to set", type: :email, required: true
15
+ param :login_confirm, "Email confirmation", type: :email, required: true if rodauth.require_login_confirmation?
16
+
17
+ error_response :invalid_password, "invalid password" if rodauth.change_login_requires_password?
18
+ error_response :invalid_field, "login does not meet requirements"
19
+ error_response :unmatched_field, "logins do not match" if rodauth.require_login_confirmation?
20
+ error_response :invalid_field, "same as current login"
21
+ error_response :invalid_field, "already an account with this login"
22
+ redirect_error_response :login_required, "login required"
23
+ redirect_error_response :two_factor_need_authentication, "2FA required" if feature?(:two_factor_base)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :change_password, "Change Password" do
4
+ get :change_password, "View change password page" do
5
+ html_response "change password form"
6
+ redirect_error_response :login_required, "login required"
7
+ redirect_error_response :two_factor_need_authentication, "2FA required" if feature?(:two_factor_base)
8
+ end
9
+
10
+ post :change_password, "Perform password change" do
11
+ param :password, "Current account password", type: :password, example: "oldsecret123", required: true if rodauth.change_password_requires_password?
12
+ param :new_password, "Password to set", type: :password, example: "newsecret123", required: true
13
+ param :password_confirm, "Password confirmation", type: :password, example: "newsecret123", required: true if rodauth.require_password_confirmation?
14
+
15
+ success_response "successful password change"
16
+ error_response :invalid_password, "invalid previous password" if rodauth.change_password_requires_password?
17
+ error_response :invalid_field, "same as existing password"
18
+ error_response :invalid_field, "invalid password"
19
+ error_response :unmatched_field, "passwords do not match" if rodauth.require_password_confirmation?
20
+ redirect_error_response :login_required, "login required"
21
+ redirect_error_response :two_factor_need_authentication, "2FA required" if feature?(:two_factor_base)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :close_account, "Close Account" do
4
+ get :close_account, "View close account page" do
5
+ html_response "close account form"
6
+ redirect_error_response :login_required, "login required"
7
+ redirect_error_response :two_factor_need_authentication, "2FA required" if feature?(:two_factor_base)
8
+ end
9
+
10
+ post :close_account, "Perform closing account" do
11
+ param :password, "Current account password", type: :password, required: true if rodauth.close_account_requires_password?
12
+
13
+ success_response "account successfully closed"
14
+ error_response :invalid_password, "invalid password" if rodauth.close_account_requires_password?
15
+ redirect_error_response :login_required, "login required"
16
+ redirect_error_response :two_factor_need_authentication, "2FA required" if feature?(:two_factor_base)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :confirm_password, "Confirm Password" do
4
+ get :confirm_password, "View password confirmation page" do
5
+ html_response "password confirmation form"
6
+ redirect_error_response :login_required, "login required"
7
+ end
8
+
9
+ post :confirm_password, "Perform password confirmation" do
10
+ param :password, "Current account password", type: :password, required: true
11
+
12
+ success_response "password successfully confirmed"
13
+ error_response :invalid_password, "invalid password"
14
+ redirect_error_response :login_required, "login required"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :create_account, "Create Account" do
4
+ get :create_account, "View registration page" do
5
+ html_response "registration form"
6
+ end
7
+
8
+ post :create_account, "Perform registration" do
9
+ param :login, "Email address for the account", type: :email, required: true
10
+ param :login_confirm, "Email address confirmation", type: :email, required: true if rodauth.require_login_confirmation?
11
+ param :password, "Password to set", type: :password, required: true if rodauth.create_account_set_password?
12
+ param :password_confirm, "Password confirmation", type: :password, required: true if rodauth.create_account_set_password? && rodauth.require_password_confirmation?
13
+
14
+ success_response "successful registration"
15
+ error_response :invalid_field, "invalid login"
16
+ error_response :unmatched_field, "logins do not match" if rodauth.require_login_confirmation?
17
+ error_response :invalid_field, "invalid password" if rodauth.create_account_set_password?
18
+ error_response :unmatched_field, "passwords do not match" if rodauth.create_account_set_password? && rodauth.require_password_confirmation?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :email_auth, "Email Authentication" do
4
+ post :email_auth_request, "Perform email authentication request" do
5
+ param :login, "Email address for the account", type: :email, required: true
6
+
7
+ success_response "successfully sent email authentication email"
8
+ redirect_error_response :no_matching_login, "no matching login"
9
+ redirect_error_response "email recently sent"
10
+ end
11
+
12
+ get :email_auth, "View email authentication page" do
13
+ param :email_auth_key, "Email authentication token", type: :token, required: true
14
+
15
+ response 302, "token stored in session"
16
+ html_response "email authentication form"
17
+ redirect_error_response "invalid email authentication key"
18
+ end
19
+
20
+ post :email_auth, "Perform email authentication" do
21
+ param :email_auth_key, "Email authentication token", type: :token, required: json
22
+
23
+ success_response "successful email authentication"
24
+ redirect_error_response :invalid_key, "invalid email authentication key"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :jwt_refresh, "JWT Refresh" do
4
+ post :jwt_refresh, "Refresh JWT access token" do
5
+ param :jwt_refresh_token_key, "JWT refresh token", type: :string, required: true
6
+
7
+ json_response({ rodauth.jwt_refresh_token_key => "...", rodauth.jwt_access_token_key => "..." })
8
+ error_response rodauth.jwt_refresh_without_access_token_status, "no JWT access token provided"
9
+ error_response "invalid JWT refresh token"
10
+ end if json
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :lockout, "Lockout" do
4
+ post :unlock_account_request, "Perform account unlock request" do
5
+ param :login, "Email address for the account", type: :email, required: true
6
+
7
+ success_response "successfully sent unlock account email"
8
+ error_response :no_matching_login, "no matching login"
9
+ redirect_error_response "email recently sent"
10
+ end
11
+
12
+ get :unlock_account, "View account unlock page" do
13
+ param :unlock_account_key, "Account unlock token", type: :token, required: true
14
+
15
+ response 302, "token stored in session"
16
+ html_response "account unlock form"
17
+ redirect_error_response "invalid or expired unlock account key"
18
+ end
19
+
20
+ post :unlock_account, "Perform account unlock" do
21
+ param :unlock_account_key, "Account unlock token", type: :token, required: json
22
+ param :password, "Current account password", type: :password, required: true if rodauth.unlock_account_requires_password?
23
+
24
+ success_response "account successfully unlocked"
25
+ redirect_error_response :invalid_key, "invalid or expired unlock account key"
26
+ error_response :invalid_password, "invalid password" if rodauth.unlock_account_requires_password?
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :login, "Login" do
4
+ get :login, "View Login page" do
5
+ html_response "login form"
6
+ end
7
+
8
+ post :login, "Perform login" do
9
+ param :login, "Email address for the account", type: :email, required: true
10
+ param :password, "Password for the account", type: :password, required: !rodauth.use_multi_phase_login?
11
+
12
+ success_response "successful login"
13
+ error_response :no_matching_login, "no matching login"
14
+ error_response :unopen_account, "unverified account"
15
+ error_response :lockout, "account locked out" if feature?(:lockout)
16
+ error_response :login, "invalid password"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :logout, "Logout" do
4
+ get :logout, "View logout page" do
5
+ html_response "logout form"
6
+ end
7
+
8
+ post :logout, "Perform logout" do
9
+ param :global_logout, "Whether to logout all active sessions", type: :boolean if feature?(:active_sessions)
10
+ param :jwt_refresh_token_key, "JWT refresh token to delete (\"all\" deletes all tokens)", type: :string if feature?(:jwt_refresh)
11
+
12
+ success_response "successful logout"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,75 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :otp, "OTP" do
4
+ get :otp_auth, "View TOTP authentication page" do
5
+ html_response "TOTP authentication form"
6
+ redirect_error_response :login_required, "login required"
7
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via TOTP"
8
+ redirect_error_response :two_factor_not_setup, "TOTP not setup"
9
+ redirect_error_response :lockout, "TOTP locked out"
10
+ end
11
+
12
+ post :otp_auth, "Perform TOTP authentication" do
13
+ param :otp_auth, "TOTP code", type: :string, required: true
14
+
15
+ success_response "successfully authenticated via TOTP"
16
+ error_response :invalid_key, "invalid TOTP code"
17
+ redirect_error_response :login_required, "login required"
18
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via TOTP"
19
+ redirect_error_response :two_factor_not_setup, "TOTP not setup"
20
+ redirect_error_response :lockout, "TOTP locked out"
21
+ end
22
+
23
+ get :otp_setup, "View TOTP setup page" do
24
+ html_response "TOTP setup form"
25
+ redirect_error_response :login_required, "login required"
26
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
27
+ redirect_error_response "TOTP already setup"
28
+ end
29
+
30
+ post :otp_setup, "Perform TOTP setup" do
31
+ if json
32
+ description <<~MARKDOWN
33
+ In JSON mode, if TOTP secret wasn't provided (and HMACs are used), the response will include a valid TOTP secret that can be included in the subsequent setup request:
34
+ ```json
35
+ {
36
+ "#{rodauth.otp_setup_param}": "...",
37
+ "#{rodauth.otp_setup_raw_param}": "..."
38
+ }
39
+ ```
40
+ MARKDOWN
41
+ end
42
+
43
+ param :otp_setup, "TOTP secret", type: :string, required: true
44
+ param :otp_setup_raw, "TOTP raw secret", type: :string, required: true if rodauth.otp_keys_use_hmac?
45
+ param :otp_auth, "TOTP code", type: :string, required: true
46
+ param :password, "Current account password", type: :password, required: true if rodauth.two_factor_modifications_require_password?
47
+
48
+ success_response "TOTP successfully setup"
49
+ error_response :invalid_field, "invalid TOTP secret"
50
+ error_response :invalid_password, "invalid password" if rodauth.two_factor_modifications_require_password?
51
+ error_response :invalid_key, "Invalid TOTP code"
52
+ redirect_error_response :login_required, "login required"
53
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
54
+ redirect_error_response "TOTP already setup"
55
+ end
56
+
57
+ get :otp_disable, "View TOTP disable page" do
58
+ success_response "TOTP disable form"
59
+ redirect_error_response :login_required, "login required"
60
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
61
+ redirect_error_response :two_factor_not_setup, "TOTP not setup"
62
+ end
63
+
64
+ post :otp_disable, "Perform TOTP disable" do
65
+ param :password, "Current account password", type: :password, required: true if rodauth.two_factor_modifications_require_password?
66
+
67
+ success_response "TOTP successfully disabled"
68
+ error_response :invalid_password, "invalid password" if rodauth.two_factor_modifications_require_password?
69
+ redirect_error_response :login_required, "login required"
70
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
71
+ redirect_error_response :two_factor_not_setup, "TOTP not setup"
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,38 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :otp_unlock, "OTP Unlock" do
4
+ get :otp_unlock, "View TOTP unlock page" do
5
+ html_response "TOTP unlock form"
6
+ redirect_error_response :otp_unlock_not_locked_out, "TOTP not locked out"
7
+ redirect_error_response :login_required, "login required"
8
+ redirect_error_response :two_factor_not_setup, "TOTP not setup"
9
+ end
10
+
11
+ post :otp_unlock, "Perform TOTP unlock step" do
12
+ if json
13
+ description <<~MARKDOWN
14
+ In JSON mode, the response of TOTP unlock steps will include progress information:
15
+ ```json
16
+ {
17
+ "num_successes": 2,
18
+ "required_successes": 3,
19
+ "next_attempt_after": 1728512721,
20
+ "deadline": 1728512769
21
+ }
22
+ ```
23
+ MARKDOWN
24
+ end
25
+
26
+ param :otp_auth, "TOTP code", type: :string, required: true
27
+
28
+ success_response "TOTP authentication successful, TOTP successfully unlocked"
29
+ error_response :otp_unlock_auth_failure, "TOTP code invalid"
30
+ redirect_error_response :otp_unlock_auth_deadline_passed, "TOTP unlock deadline passed"
31
+ redirect_error_response :otp_unlock_auth_not_yet_available, "TOTP unlock not yet available"
32
+ redirect_error_response :otp_unlock_not_locked_out, "TOTP not locked out"
33
+ redirect_error_response :login_required, "login required"
34
+ redirect_error_response :two_factor_not_setup, "TOTP not setup"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :recovery_codes, "Recovery Codes" do
4
+ get :recovery_auth, "View recovery code authentication page" do
5
+ html_response "recovery code authentication form"
6
+ redirect_error_response :login_required, "login required"
7
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
8
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via recovery code"
9
+ end
10
+
11
+ post :recovery_auth, "Authenticate via recovery code" do
12
+ param :recovery_codes, "Recovery code", type: :string, required: true
13
+
14
+ success_response "successfully authenticated via recovery code"
15
+ error_response :invalid_key, "invalid recovery code"
16
+ redirect_error_response :login_required, "login required"
17
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
18
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via recovery code"
19
+ end
20
+
21
+ get :recovery_codes, "View recovery codes page" do
22
+ html_response "recovery codes form"
23
+
24
+ redirect_error_response :login_required, "login required"
25
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
26
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
27
+ end
28
+
29
+ post :recovery_codes, "See recovery codes" do
30
+ param :password, "Current account password", type: :password, required: true if rodauth.two_factor_modifications_require_password?
31
+ param :add_recovery_codes, "Whether to create missing recovery codes", type: :boolean
32
+
33
+ if json
34
+ json_response("available recovery codes", { "codes": ["..."] })
35
+ else
36
+ html_response "displayed recovery codes"
37
+ end
38
+ error_response :invalid_password, "invalid password" if rodauth.two_factor_modifications_require_password?
39
+ redirect_error_response :login_required, "login required"
40
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
41
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :remember, "Remember" do
4
+ get :remember, "View remember settings page" do
5
+ html_response "remember settings form"
6
+ redirect_error_response :login_required, "login required"
7
+ redirect_error_response :two_factor_need_authentication, "2FA required" if feature?(:two_factor_base)
8
+ end
9
+
10
+ post :remember, "Change remember settings" do
11
+ param :remember, "Remember action to perform", type: :string, required: true, enum: [
12
+ rodauth.remember_remember_param_value,
13
+ rodauth.remember_forget_param_value,
14
+ rodauth.remember_disable_param_value,
15
+ ]
16
+
17
+ success_response "remember setting successfully changed"
18
+ error_response :invalid_field, "invalid remember param"
19
+ redirect_error_response :login_required, "login required"
20
+ redirect_error_response :two_factor_need_authentication, "2FA required" if feature?(:two_factor_base)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :reset_password, "Reset Password" do
4
+ get :reset_password_request, "View password reset request page" do
5
+ html_response "password reset request form"
6
+ end
7
+
8
+ post :reset_password_request, "Perform password reset request" do
9
+ param :login, "Email address for the account", type: :email, required: true
10
+
11
+ success_response "successfully sent reset password email"
12
+ error_response :no_matching_login, "no matching login"
13
+ error_response :unopen_account, "unverified account"
14
+ redirect_error_response "email recently sent"
15
+ end
16
+
17
+ get :reset_password, "View password reset page" do
18
+ param :reset_password_key, "Password reset token", type: :token, required: true
19
+
20
+ response 302, "token stored in session"
21
+ html_response "password reset form"
22
+ redirect_error_response "invalid or expired password reset key"
23
+ end
24
+
25
+ post :reset_password, "Perform password reset" do
26
+ param :reset_password_key, "Password reset token", type: :token, required: json
27
+
28
+ success_response "successfully reset password"
29
+ redirect_error_response :invalid_key, "invalid or expired password reset key"
30
+ error_response :invalid_field, "invalid password"
31
+ error_response :invalid_field, "same as existing password"
32
+ error_response :unmatched_field, "passwords do no match" if rodauth.require_password_confirmation?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,99 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :sms_codes, "SMS Codes" do
4
+ get :sms_request, "View SMS code request page" do
5
+ html_response "SMS code request form"
6
+ redirect_error_response :login_required, "login required"
7
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via SMS code"
8
+ redirect_error_response :two_factor_not_setup, "SMS codes not setup"
9
+ redirect_error_response :lockout, "SMS codes locked out"
10
+ end
11
+
12
+ post :sms_request, "Request SMS code" do
13
+ success_response "SMS code successfully sent"
14
+ redirect_error_response :login_required, "login required"
15
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via SMS code"
16
+ redirect_error_response :two_factor_not_setup, "SMS codes not setup"
17
+ redirect_error_response :lockout, "SMS codes locked out"
18
+ end
19
+
20
+ get :sms_auth, "View SMS code authentication page" do
21
+ html_response "SMS code authentication form"
22
+ redirect_error_response :invalid_key, "no current SMS code"
23
+ redirect_error_response :login_required, "login required"
24
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via SMS code"
25
+ redirect_error_response :two_factor_not_setup, "SMS codes not setup"
26
+ redirect_error_response :lockout, "SMS codes locked out"
27
+ end
28
+
29
+ post :sms_auth, "Authenticate via SMS code" do
30
+ param :sms_code, "SMS code", type: :string, required: true
31
+
32
+ success_response "successfully authenticated via SMS code"
33
+ error_response :invalid_key, "invalid SMS code"
34
+ redirect_error_response :invalid_key, "no current SMS code"
35
+ redirect_error_response :login_required, "login required"
36
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via SMS code"
37
+ redirect_error_response :two_factor_not_setup, "SMS codes not setup"
38
+ redirect_error_response :lockout, "SMS codes locked out"
39
+ end
40
+
41
+ get :sms_setup, "View SMS codes setup page" do
42
+ html_response "SMS codes setup form"
43
+ redirect_error_response :login_required, "login required"
44
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
45
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
46
+ redirect_error_response :sms_already_setup, "SMS codes already setup"
47
+ redirect_error_response :sms_needs_confirmation, "SMS phone number needs confirmation"
48
+ end
49
+
50
+ post :sms_setup, "Setup SMS codes" do
51
+ param :sms_phone, "SMS phone number", type: :string, required: true
52
+ param :password, "Current account password", type: :password, required: true if rodauth.two_factor_modifications_require_password?
53
+
54
+ success_response "SMS codes successfully setup"
55
+ error_response :invalid_field, "invalid phone number"
56
+ redirect_error_response :login_required, "login required"
57
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
58
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
59
+ redirect_error_response :sms_already_setup, "SMS codes already setup"
60
+ redirect_error_response :sms_needs_confirmation, "SMS phone number needs confirmation"
61
+ end
62
+
63
+ get :sms_confirm, "View SMS phone number confirmation page" do
64
+ html_response "SMS confirmation form"
65
+ redirect_error_response :login_required, "login required"
66
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
67
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
68
+ redirect_error_response :sms_already_setup, "SMS codes already setup"
69
+ end
70
+
71
+ post :sms_confirm, "Confirm SMS phone number" do
72
+ param :sms_code, "SMS code", type: :string, required: true
73
+
74
+ success_response "SMS phone number successfully confirmed"
75
+ error_response :invalid_key, "invalid SMS code"
76
+ redirect_error_response :login_required, "login required"
77
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
78
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
79
+ redirect_error_response :sms_already_setup, "SMS codes already setup"
80
+ end
81
+
82
+ get :sms_disable, "View SMS disable page" do
83
+ html_response "SMS disable form"
84
+ redirect_error_response :login_required, "login required"
85
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
86
+ redirect_error_response :two_factor_not_setup, "SMS codes not setup"
87
+ end
88
+
89
+ post :sms_disable, "Disable SMS codes" do
90
+ param :password, "Current account password", type: :password, required: true if rodauth.two_factor_modifications_require_password?
91
+
92
+ success_response "SMS codes successfully disabled"
93
+ redirect_error_response :login_required, "login required"
94
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
95
+ redirect_error_response :two_factor_not_setup, "SMS codes not setup"
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,43 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :two_factor_base, "Two Factor Base" do
4
+ route (json ? :post : :get), :two_factor_manage, "View two factor management page" do
5
+ if json
6
+ json_response({ "setup_links": ["..."], "remove_links": ["..."] })
7
+ else
8
+ html_response "two factor management page"
9
+ end
10
+ redirect_error_response :login_required, "login required"
11
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
12
+ end
13
+
14
+ route (json ? :post : :get), :two_factor_auth, "View two factor authentication page" do
15
+ if json
16
+ json_response({ "auth_links": ["..."] })
17
+ else
18
+ html_response "two factor authentication page"
19
+ end
20
+ redirect_error_response :login_required, "login required"
21
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
22
+ redirect_error_response :two_factor_already_authenticated, "2nd factor already authenticated"
23
+ end
24
+
25
+ get :two_factor_disable, "View two factor disable page" do
26
+ html_response "two factor disable page"
27
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
28
+ redirect_error_response :login_required, "login required"
29
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
30
+ end
31
+
32
+ post :two_factor_disable, "Disable two factor authentication" do
33
+ param :password, "Current account password", type: :password, required: true if rodauth.two_factor_modifications_require_password?
34
+
35
+ success_response "2nd factor successfully disabled"
36
+ error_response :invalid_password, "invalid password" if rodauth.two_factor_modifications_require_password?
37
+ redirect_error_response :two_factor_not_setup, "2nd factor not setup"
38
+ redirect_error_response :login_required, "login required"
39
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,59 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :verify_account, "Verify Account" do
4
+ get :verify_account, "View account verification page" do
5
+ param :verify_account_key, "Account verification token", type: :token, required: true
6
+
7
+ response 302, "token stored in session"
8
+ if feature?(:webauthn_verify_account)
9
+ html_response "WebAuthn setup form"
10
+ else
11
+ html_response "account verification form"
12
+ end
13
+ redirect_error_response "invalid verify account key"
14
+ end
15
+
16
+ post :verify_account, "Perform account verification" do
17
+ if json && feature?(:webauthn_verify_account)
18
+ description <<~MARKDOWN
19
+ In JSON mode, if WebAuthn credential data wasn't provided, input credential params will be returned in the response:
20
+ ```json
21
+ {
22
+ "#{rodauth.webauthn_setup_param}": { ... },
23
+ "#{rodauth.webauthn_setup_challenge_param}": "...",
24
+ "#{rodauth.webauthn_setup_challenge_hmac_param}": "..."
25
+ }
26
+ ```
27
+ MARKDOWN
28
+ end
29
+
30
+ param :verify_account_key, "Account verification token", type: :token, required: json
31
+ param :password, "Password to set", type: :password, required: true if rodauth.verify_account_set_password?
32
+ param :password_confirm, "Password confirmation", type: :password, required: true if rodauth.verify_account_set_password? && rodauth.require_password_confirmation?
33
+ if feature?(:webauthn_verify_account)
34
+ param :webauthn_setup, "WebAuthn credential data", type: :object, required: true
35
+ param :webauthn_setup_challenge, "WebAuthn credential challenge", type: :string, required: true
36
+ param :webauthn_setup_challenge_hmac, "WebAuthn credential challenge HMAC", type: :string, required: true
37
+ end
38
+
39
+ success_response "successful account verification"
40
+ redirect_error_response :invalid_key, "missing or invalid token"
41
+ error_response :invalid_field, "invalid password" if rodauth.verify_account_set_password?
42
+ error_response :unmatched_field, "passwords do not match" if rodauth.verify_account_set_password? && rodauth.require_password_confirmation?
43
+ error_response :invalid_field, "invalid WebAuthn credential data"
44
+ end
45
+
46
+ get :verify_account_resend, "Resend account verification email page" do
47
+ html_response "resend account verification form"
48
+ end
49
+
50
+ post :verify_account_resend, "Perform resending account verification email" do
51
+ param :login, "Email address for the account", type: :email, required: true
52
+
53
+ success_response "successful resend"
54
+ redirect_error_response "email recently sent"
55
+ error_response :no_matching_login, "no matching login"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,21 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :verify_login_change, "Verify Login Change" do
4
+ get :verify_login_change, "View login change verification page" do
5
+ param :verify_login_change_key, "Login change verification token", type: :token, required: true
6
+
7
+ response 302, "token stored in session"
8
+ html_response "login change verification form"
9
+ redirect_error_response "invalid verify login change key"
10
+ end
11
+
12
+ post :verify_login_change, "Perform login change verification" do
13
+ param :verify_login_change_key, "Login change verification token", type: :token, required: json
14
+
15
+ success_response "successfully verified login change"
16
+ redirect_error_response :invalid_key, "invalid verify login change key"
17
+ redirect_error_response :invalid_key, "already an account with this login"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,103 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :webauthn, "WebAuthn" do
4
+ get :webauthn_auth, "View WebAuthn authentication page" do
5
+ html_response "WebAuthn authentication form"
6
+ redirect_error_response :login_required, "login required"
7
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via WebAuthn"
8
+ redirect_error_response :webauthn_not_setup, "WebAuthn not setup"
9
+ end
10
+
11
+ post :webauthn_auth, "Perform WebAuthn authentication" do
12
+ if json
13
+ description <<~MARKDOWN
14
+ In JSON mode, if credential data wasn't provided, input credential params will be returned in the response:
15
+ ```json
16
+ {
17
+ "#{rodauth.webauthn_auth_param}": { ... },
18
+ "#{rodauth.webauthn_auth_challenge_param}": "...",
19
+ "#{rodauth.webauthn_auth_challenge_hmac_param}": "..."
20
+ }
21
+ ```
22
+ MARKDOWN
23
+ end
24
+
25
+ param :webauthn_auth, "Credential data", type: :object, required: true
26
+ param :webauthn_auth_challenge, "Credential challenge", type: :string, required: true
27
+ param :webauthn_auth_challenge_hmac, "Credential challenge HMAC", type: :string, required: true
28
+
29
+ success_response "successfully authenticated via WebAuthn"
30
+ error_response :invalid_key, "invalid credential data"
31
+ error_response :invalid_field, "invalid credential sign count"
32
+ redirect_error_response :login_required, "login required"
33
+ redirect_error_response :two_factor_already_authenticated, "already authenticated via WebAuthn"
34
+ redirect_error_response :webauthn_not_setup, "WebAuthn not setup"
35
+ end
36
+
37
+ get :webauthn_setup, "View WebAuthn setup page" do
38
+ html_response "WebAuthn setup form"
39
+ redirect_error_response :login_required, "login required"
40
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
41
+ end
42
+
43
+ post :webauthn_setup, "Perform WebAuthn setup" do
44
+ if json
45
+ description <<~MARKDOWN
46
+ In JSON mode, if credential data wasn't provided, input credential params will be returned in the response:
47
+ ```json
48
+ {
49
+ "#{rodauth.webauthn_setup_param}": { ... },
50
+ "#{rodauth.webauthn_setup_challenge_param}": "...",
51
+ "#{rodauth.webauthn_setup_challenge_hmac_param}": "..."
52
+ }
53
+ ```
54
+ MARKDOWN
55
+ end
56
+
57
+ param :webauthn_setup, "Credential data", type: :object, required: true
58
+ param :webauthn_setup_challenge, "Credential challenge", type: :string, required: true
59
+ param :webauthn_setup_challenge_hmac, "Credential challenge HMAC", type: :string, required: true
60
+ param :password, "Current account password", type: :password, required: true if rodauth.two_factor_modifications_require_password?
61
+
62
+ success_response "WebAuthn successfully setup"
63
+ error_response :invalid_field, "invalid credential data"
64
+ error_response :invalid_field, "duplicate credential ID"
65
+ error_response :invalid_password, "invalid password" if rodauth.two_factor_modifications_require_password?
66
+ redirect_error_response :login_required, "login required"
67
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
68
+ end
69
+
70
+ get :webauthn_remove, "View WebAuthn authenticator removal page" do
71
+ html_response "WebAuthn authenticator removal form"
72
+ redirect_error_response :login_required, "login required"
73
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
74
+ redirect_error_response :webauthn_not_setup, "WebAuthn not setup"
75
+ end
76
+
77
+ post :webauthn_remove, "Remove WebAuthn authenticator" do
78
+ if json
79
+ description <<~MARKDOWN
80
+ In JSON mode, if credential ID wasn't provided, last usage of every credential will be returned in the response:
81
+ ```json
82
+ {
83
+ "#{rodauth.webauthn_remove_param}": {
84
+ "abc123": "2024-10-10 00:37:10 UTC"
85
+ }
86
+ }
87
+ ```
88
+ MARKDOWN
89
+ end
90
+
91
+ param :webauthn_remove, "Credential ID", type: :string, required: true
92
+ param :password, "Current account password", type: :password, required: true if rodauth.two_factor_modifications_require_password?
93
+
94
+ success_response "WebAuthn authenticator successfully removed"
95
+ error_response :invalid_field, "invalid credential ID"
96
+ error_response :invalid_password, "invalid password" if rodauth.two_factor_modifications_require_password?
97
+ redirect_error_response :login_required, "login required"
98
+ redirect_error_response :two_factor_need_authentication, "2nd factor required"
99
+ redirect_error_response :webauthn_not_setup, "WebAuthn not setup"
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,29 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ Routes.define :webauthn_login, "WebAuthn Login" do
4
+ post :webauthn_login, "Perform WebAuthn login" do
5
+ if json
6
+ description <<~MARKDOWN
7
+ In JSON mode, if credential data wasn't provided, input credential params will be returned in the response:
8
+ ```json
9
+ {
10
+ "#{rodauth.webauthn_auth_param}": { ... },
11
+ "#{rodauth.webauthn_auth_challenge_param}": "...",
12
+ "#{rodauth.webauthn_auth_challenge_hmac_param}": "..."
13
+ }
14
+ ```
15
+ MARKDOWN
16
+ end
17
+
18
+ param :login, "Account email", type: :email, required: !feature?(:webauthn_autofill)
19
+ param :webauthn_auth, "Credential data", type: :object, required: true
20
+
21
+ success_response "successfully logged in via WebAuthn"
22
+ error_response :invalid_key, "invalid credential data"
23
+ error_response :invalid_field, "invalid credential sign count"
24
+ error_response :invalid_field, "credential not found" if feature?(:webauthn_autofill)
25
+ error_response :no_matching_login, "no matching login"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,129 @@
1
+ module Rodauth
2
+ class OpenAPI
3
+ class Routes
4
+ FEATURES = {}
5
+
6
+ def self.define(name, tag, &definition)
7
+ FEATURES[name] = -> do
8
+ section tag, name
9
+ instance_exec(&definition)
10
+ end
11
+ end
12
+
13
+ attr_reader :data, :rodauth, :json
14
+
15
+ def initialize(data, rodauth:, json:)
16
+ @data = data
17
+ @rodauth = rodauth
18
+ @json = json
19
+ end
20
+
21
+ def section(tag, name)
22
+ data[:tags] << {
23
+ name: tag,
24
+ externalDocs: {
25
+ description: "Feature documentation",
26
+ url: "http://rodauth.jeremyevans.net/rdoc/files/doc/#{name}_rdoc.html"
27
+ }
28
+ }
29
+ end
30
+
31
+ def get(...)
32
+ route(:get, ...) unless json
33
+ end
34
+
35
+ def post(...)
36
+ route(:post, ...)
37
+ end
38
+
39
+ def route(verb, name, summary, &block)
40
+ path = rodauth.send(:"#{name}_path")
41
+ return if path.nil?
42
+
43
+ tag = data[:tags].last[:name]
44
+
45
+ data[:paths][path] ||= {}
46
+ data[:paths][path][verb] = {
47
+ tags: [tag],
48
+ summary: summary,
49
+ responses: {},
50
+ parameters: [],
51
+ }
52
+
53
+ instance_exec(&block)
54
+ end
55
+
56
+ def description(text)
57
+ data[:paths].values.last.values.last[:description] = text
58
+ end
59
+
60
+ def param(name, description, type:, example: nil, required: false, enum: nil)
61
+ example ||= case type
62
+ when :email then "user@example.com"
63
+ when :password then "secret123"
64
+ when :boolean then "true"
65
+ when :token then "{account_id}#{rodauth.token_separator}{key_hmac}"
66
+ end
67
+
68
+ parameters = data[:paths].values.last.values.last[:parameters]
69
+ parameters << {
70
+ name: rodauth.send(:"#{name}_param"),
71
+ in: "query",
72
+ description: description,
73
+ required: required,
74
+ style: "form",
75
+ example: example,
76
+ schema: { type: type == :boolean ? "boolean" : "string", enum: enum }.compact,
77
+ }.compact
78
+ end
79
+
80
+ def html_response(description)
81
+ response(200, description)
82
+ end
83
+
84
+ def json_response(description = "", example)
85
+ response(200, description, content: { "application/json" => { example: example } })
86
+ end
87
+
88
+ def success_response(description)
89
+ status = json ? 200 : 302
90
+ response(status, description)
91
+ end
92
+
93
+ def error_response(status = nil, description)
94
+ status = rodauth.send(:"#{status}_error_status") if status.is_a?(Symbol)
95
+ if json && (status.nil? || !rodauth.json_response_custom_error_status?)
96
+ status = rodauth.json_response_error_status
97
+ end
98
+ response(status, description)
99
+ end
100
+
101
+ def redirect_error_response(name = nil, description)
102
+ status = if json
103
+ if rodauth.json_response_custom_error_status? && name
104
+ rodauth.send(:"#{name}_error_status")
105
+ else
106
+ rodauth.json_response_error_status
107
+ end
108
+ else
109
+ 302
110
+ end
111
+ response(status, description)
112
+ end
113
+
114
+ def response(status, description = "", **fields)
115
+ responses = data[:paths].values.last.values.last[:responses]
116
+ if responses[status]
117
+ responses[status][:description] = [responses[status][:description], description].join(", ")
118
+ else
119
+ responses[status] = { description: description }
120
+ end
121
+ responses[status].merge!(fields)
122
+ end
123
+
124
+ def feature?(name)
125
+ rodauth.features.include?(name)
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,79 @@
1
+ require "yaml"
2
+ require "json"
3
+ require "rodauth/version"
4
+ require "rodauth/openapi/routes"
5
+
6
+ module Rodauth
7
+ class OpenAPI
8
+ DOCS_URL = "https://rodauth.jeremyevans.net/documentation.html"
9
+ SPEC_VERSION = "3.0.1"
10
+
11
+ def initialize(auth_class, json: nil, password: true)
12
+ @auth_class = auth_class
13
+ @json = json
14
+ @password = password
15
+ end
16
+
17
+ def to_yaml
18
+ YAML.dump(JSON.parse(JSON.generate(generate))).lines[1..-1].join
19
+ end
20
+
21
+ def to_json
22
+ JSON.pretty_generate(generate)
23
+ end
24
+
25
+ def generate
26
+ data = {
27
+ openapi: SPEC_VERSION,
28
+ info: {
29
+ title: "Rodauth",
30
+ description: "This lists all the endpoints provided by Rodauth features.",
31
+ version: Rodauth::VERSION,
32
+ },
33
+ externalDocs: {
34
+ description: "Rodauth documentation",
35
+ url: DOCS_URL,
36
+ },
37
+ tags: [],
38
+ paths: {},
39
+ }
40
+
41
+ rodauth.features.each do |feature|
42
+ begin
43
+ require "rodauth/openapi/routes/#{feature}"
44
+ rescue LoadError
45
+ next
46
+ end
47
+
48
+ routes = Routes.new(data, rodauth: rodauth, json: json?)
49
+ routes.instance_exec(&Routes::FEATURES[feature])
50
+ end
51
+
52
+ # remove tags that don't have any routes
53
+ all_tags = data[:paths].values.flat_map(&:values).flat_map { |route| route[:tags] }.uniq
54
+ data[:tags].select! { |tag| all_tags.include?(tag[:name]) }
55
+
56
+ data
57
+ end
58
+
59
+ private
60
+
61
+ def json?
62
+ @json || rodauth.only_json?
63
+ end
64
+
65
+ def rodauth
66
+ rodauth = @auth_class.new(scope)
67
+ rodauth.instance_variable_set(:@has_password, password?)
68
+ rodauth
69
+ end
70
+
71
+ def password?
72
+ @password
73
+ end
74
+
75
+ def scope
76
+ @auth_class.roda_class.new({ "rack.session" => {} })
77
+ end
78
+ end
79
+ end
@@ -0,0 +1 @@
1
+ require "rodauth/openapi"
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "rodauth-openapi"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ["Janko Marohnić"]
5
+ spec.email = ["janko.marohnic@gmail.com"]
6
+
7
+ spec.summary = %q{Allows dynamically generating OpenAPI documentation based on Rodauth configuration.}
8
+ spec.description = spec.summary
9
+ spec.homepage = "https://github.com/janko/rodauth-openapi"
10
+ spec.license = "MIT"
11
+
12
+ spec.required_ruby_version = ">= 2.5"
13
+
14
+ spec.files = Dir["README.md", "LICENSE.txt", "lib/**/*", "*.gemspec"]
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_dependency "rodauth"
18
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rodauth-openapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Janko Marohnić
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-10-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rodauth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Allows dynamically generating OpenAPI documentation based on Rodauth
28
+ configuration.
29
+ email:
30
+ - janko.marohnic@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - LICENSE.txt
36
+ - README.md
37
+ - lib/generators/rodauth/openapi_generator.rb
38
+ - lib/rodauth-openapi.rb
39
+ - lib/rodauth/openapi.rb
40
+ - lib/rodauth/openapi/routes.rb
41
+ - lib/rodauth/openapi/routes/change_login.rb
42
+ - lib/rodauth/openapi/routes/change_password.rb
43
+ - lib/rodauth/openapi/routes/close_account.rb
44
+ - lib/rodauth/openapi/routes/confirm_account.rb
45
+ - lib/rodauth/openapi/routes/create_account.rb
46
+ - lib/rodauth/openapi/routes/email_auth.rb
47
+ - lib/rodauth/openapi/routes/jwt_refresh.rb
48
+ - lib/rodauth/openapi/routes/lockout.rb
49
+ - lib/rodauth/openapi/routes/login.rb
50
+ - lib/rodauth/openapi/routes/logout.rb
51
+ - lib/rodauth/openapi/routes/otp.rb
52
+ - lib/rodauth/openapi/routes/otp_unlock.rb
53
+ - lib/rodauth/openapi/routes/recovery_codes.rb
54
+ - lib/rodauth/openapi/routes/remember.rb
55
+ - lib/rodauth/openapi/routes/reset_password.rb
56
+ - lib/rodauth/openapi/routes/sms_codes.rb
57
+ - lib/rodauth/openapi/routes/two_factor_base.rb
58
+ - lib/rodauth/openapi/routes/verify_account.rb
59
+ - lib/rodauth/openapi/routes/verify_login_change.rb
60
+ - lib/rodauth/openapi/routes/webauthn.rb
61
+ - lib/rodauth/openapi/routes/webauthn_login.rb
62
+ - rodauth-openapi.gemspec
63
+ homepage: https://github.com/janko/rodauth-openapi
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '2.5'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubygems_version: 3.5.11
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Allows dynamically generating OpenAPI documentation based on Rodauth configuration.
86
+ test_files: []