rodauth-openapi 0.1.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 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: []