aha_builder_core 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/lib/aha/auth/version.rb +1 -1
- data/lib/aha/auth.rb +45 -6
- data/lib/generators/aha_builder_core/auth/USAGE +27 -0
- data/lib/generators/aha_builder_core/auth/auth_generator.rb +138 -0
- data/lib/generators/aha_builder_core/auth/templates/authentication.rb.tt +57 -0
- data/lib/generators/aha_builder_core/auth/templates/current.rb.tt +3 -0
- data/lib/generators/aha_builder_core/auth/templates/migration.rb.tt +21 -0
- data/lib/generators/aha_builder_core/auth/templates/sessions_controller.rb.tt +50 -0
- data/lib/generators/aha_builder_core/auth/templates/user.rb.tt +8 -0
- data/lib/generators/aha_builder_core/blob_storage/USAGE +19 -0
- data/lib/generators/aha_builder_core/blob_storage/blob_storage_generator.rb +43 -0
- data/lib/generators/aha_builder_core/blob_storage/templates/storage.yml.tt +16 -0
- metadata +12 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8242fcb16eead2a99076077e2722d5815501f5fc3234eebfbf53a37648d79e5d
|
|
4
|
+
data.tar.gz: 854469a275e4e2cc06469e9d3fd967c3039b565c66ca344ac2df39f37daf94d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 51e7277709855e865c53940dfec85081cab5c9c2b0b74c53cfd383a70c5cc01ad4cd725451f0268ae3515d2c0985ec17704ae3fb1d51a4f8204a398f438aa13b
|
|
7
|
+
data.tar.gz: 9385a9e023d76fc58f4dd802cb0dcacd2f773e055f75b549e2be59f11c2832dd9cc357de0c31c13e857ccf85e9645d26c760b1a765e8a61f9f95886f0976b50d
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Aha Builder Core Client
|
|
2
2
|
|
|
3
|
-
Ruby client for Aha! Builder core authentication services.
|
|
3
|
+
Ruby client for Aha! Builder core authentication services which provides login and signup using email/password, social logins (Google, Github, Microsoft), SAML SSO and password reset.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -18,6 +18,8 @@ No configuration is necessary and no environment variables are necessary.
|
|
|
18
18
|
|
|
19
19
|
The authentication UI is provided completely by the core system. During authentication the user is redirected to the login page, and will return (via HTTP redirect) to the `/callback` URL when authentication is complete. Your application must implement a callback action at `/callback` to receive the code. Any value passed in as `state` is returned verbatim to the callback.
|
|
20
20
|
|
|
21
|
+
Protection against CSRF atacks is handled internally by the Aha::Auth library and there is no need to use a nonce in the state parameter.
|
|
22
|
+
|
|
21
23
|
### Generate Login URL
|
|
22
24
|
|
|
23
25
|
Redirect users to the authentication and signup UI:
|
data/lib/aha/auth/version.rb
CHANGED
data/lib/aha/auth.rb
CHANGED
|
@@ -4,6 +4,8 @@ require "faraday"
|
|
|
4
4
|
require "faraday/retry"
|
|
5
5
|
require "jwt"
|
|
6
6
|
require "concurrent"
|
|
7
|
+
require "active_support"
|
|
8
|
+
require "active_support/core_ext"
|
|
7
9
|
|
|
8
10
|
require_relative "auth/version"
|
|
9
11
|
require_relative "auth/errors"
|
|
@@ -40,11 +42,28 @@ module Aha
|
|
|
40
42
|
|
|
41
43
|
# Generate login URL for redirecting users to the auth server
|
|
42
44
|
#
|
|
45
|
+
# @param session [Hash] Session hash to store the nonce for CSRF verification
|
|
43
46
|
# @param state [String] Optional state parameter to pass through the auth flow
|
|
44
47
|
# @return [String] The login URL
|
|
45
|
-
def login_url(state: nil)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
def login_url(session:, state: nil)
|
|
49
|
+
# Generate a nonce for CSRF protection
|
|
50
|
+
nonce = SecureRandom.hex(10)
|
|
51
|
+
|
|
52
|
+
# Store nonce in the client's session if provided
|
|
53
|
+
session[:auth_nonce] = nonce if session
|
|
54
|
+
|
|
55
|
+
# Encode the state with nonce
|
|
56
|
+
state_data = {
|
|
57
|
+
tunneled_state: state,
|
|
58
|
+
nonce: nonce,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
encoded_state = Base64.urlsafe_encode64(state_data.to_json, padding: false)
|
|
62
|
+
|
|
63
|
+
params = {
|
|
64
|
+
client_id: configuration.client_id,
|
|
65
|
+
state: encoded_state
|
|
66
|
+
}
|
|
48
67
|
|
|
49
68
|
query = URI.encode_www_form(params)
|
|
50
69
|
"#{configuration.server_url}/auth_ui/start?#{query}"
|
|
@@ -52,10 +71,30 @@ module Aha
|
|
|
52
71
|
|
|
53
72
|
# Exchange an authorization code for tokens
|
|
54
73
|
#
|
|
55
|
-
# @param code [String] The authorization code from the callback
|
|
74
|
+
# @param code [String] The authorization code from the callback (may include nonce)
|
|
75
|
+
# @param session [Hash] Session hash containing the nonce for CSRF verification
|
|
56
76
|
# @return [Hash] Token response with :session_token, :refresh_token, :expires_at, :user
|
|
57
|
-
def authenticate_with_code(code:)
|
|
58
|
-
|
|
77
|
+
def authenticate_with_code(code:, session:)
|
|
78
|
+
# Split the code and nonce if present
|
|
79
|
+
actual_code, nonce = code.split(".", 2)
|
|
80
|
+
|
|
81
|
+
# Verify CSRF protection if nonce is present
|
|
82
|
+
if nonce
|
|
83
|
+
session_nonce = session[:auth_nonce]
|
|
84
|
+
|
|
85
|
+
# Verify nonce matches
|
|
86
|
+
if session_nonce.blank? || session_nonce != nonce
|
|
87
|
+
raise "CSRF verification failed: nonce mismatch"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Clear the nonce from session after verification
|
|
91
|
+
session.delete(:auth_nonce)
|
|
92
|
+
else
|
|
93
|
+
# If we fon't have a none, we can't verify CSRF.
|
|
94
|
+
raise "CSRF verification failed: unable to verify nonce"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
client.authenticate_with_code(code: actual_code)
|
|
59
98
|
end
|
|
60
99
|
|
|
61
100
|
# Refresh tokens using a refresh token
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Generates authentication scaffolding for Aha Builder Core integration.
|
|
3
|
+
Creates User model, migration, SessionsController, Authentication concern,
|
|
4
|
+
Current model, and routes.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
bin/rails generate aha_builder_core:auth
|
|
8
|
+
|
|
9
|
+
This will create:
|
|
10
|
+
app/models/user.rb
|
|
11
|
+
app/models/current.rb
|
|
12
|
+
app/controllers/sessions_controller.rb
|
|
13
|
+
app/controllers/concerns/authentication.rb
|
|
14
|
+
db/migrate/XXXXXXXXXXXXXX_create_users.rb
|
|
15
|
+
|
|
16
|
+
And add routes:
|
|
17
|
+
get "login" => "sessions#new"
|
|
18
|
+
get "callback" => "sessions#callback"
|
|
19
|
+
delete "logout" => "sessions#logout"
|
|
20
|
+
|
|
21
|
+
You can add custom attributes to the User model:
|
|
22
|
+
bin/rails generate aha_builder_core:auth company:string role:string
|
|
23
|
+
|
|
24
|
+
This adds company and role columns to the users table migration.
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--skip-migration Skip generating the database migration
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/active_record"
|
|
5
|
+
|
|
6
|
+
module AhaBuilderCore
|
|
7
|
+
class AuthGenerator < Rails::Generators::Base
|
|
8
|
+
include ActiveRecord::Generators::Migration
|
|
9
|
+
|
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
|
11
|
+
|
|
12
|
+
argument :attributes, type: :array, default: [], banner: "field[:type] field[:type]"
|
|
13
|
+
|
|
14
|
+
class_option :skip_migration, type: :boolean, default: false, desc: "Skip migration generation"
|
|
15
|
+
|
|
16
|
+
def generate_migration_file
|
|
17
|
+
return if options[:skip_migration]
|
|
18
|
+
|
|
19
|
+
migration_template "migration.rb.tt", File.join(db_migrate_path, "create_users.rb")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create_user_model
|
|
23
|
+
template "user.rb.tt", "app/models/user.rb"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def create_current_model
|
|
27
|
+
template "current.rb.tt", "app/models/current.rb"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def create_sessions_controller
|
|
31
|
+
template "sessions_controller.rb.tt", "app/controllers/sessions_controller.rb"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create_authentication_concern
|
|
35
|
+
template "authentication.rb.tt", "app/controllers/concerns/authentication.rb"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def add_routes
|
|
39
|
+
route <<~RUBY
|
|
40
|
+
get "login", to: "sessions#new", as: :new_session
|
|
41
|
+
get "callback", to: "sessions#callback", as: :session_callback
|
|
42
|
+
delete "logout", to: "sessions#logout", as: :logout
|
|
43
|
+
RUBY
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def add_inertia_auth_share
|
|
47
|
+
return unless File.exist?("app/controllers/inertia_controller.rb")
|
|
48
|
+
|
|
49
|
+
inject_into_file "app/controllers/inertia_controller.rb",
|
|
50
|
+
after: "inertia_share flash: -> { flash.to_hash }\n" do
|
|
51
|
+
<<-RUBY
|
|
52
|
+
inertia_share auth: -> {
|
|
53
|
+
{
|
|
54
|
+
user: current_user&.as_json(only: %i[id email first_name last_name])
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
RUBY
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def add_authentication_to_application_controller
|
|
62
|
+
inject_into_file "app/controllers/application_controller.rb",
|
|
63
|
+
after: "class ApplicationController < ActionController::Base\n" do
|
|
64
|
+
" include Authentication\n"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def add_typescript_types
|
|
69
|
+
types_file = "app/frontend/types/index.ts"
|
|
70
|
+
return unless File.exist?(types_file)
|
|
71
|
+
|
|
72
|
+
gsub_file types_file,
|
|
73
|
+
/export interface Flash \{\n alert\?: string\n notice\?: string\n\}\n\nexport interface SharedData \{\n flash: Flash\n \[key: string\]: unknown\n\}/,
|
|
74
|
+
<<~TYPESCRIPT.chomp
|
|
75
|
+
export interface Flash {
|
|
76
|
+
alert?: string
|
|
77
|
+
notice?: string
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface AuthUser {
|
|
81
|
+
id: number
|
|
82
|
+
email: string
|
|
83
|
+
first_name: string | null
|
|
84
|
+
last_name: string | null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface SharedData {
|
|
88
|
+
flash: Flash
|
|
89
|
+
auth: {
|
|
90
|
+
user: AuthUser | null
|
|
91
|
+
}
|
|
92
|
+
[key: string]: unknown
|
|
93
|
+
}
|
|
94
|
+
TYPESCRIPT
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def generate_js_routes
|
|
98
|
+
say "\nRegenerating js-routes file...", :green
|
|
99
|
+
rails_command "js:routes"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def display_instructions
|
|
103
|
+
say "\nAha Auth setup complete!", :green
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def auth_attributes
|
|
109
|
+
%w[
|
|
110
|
+
auth_identifier:string
|
|
111
|
+
email:string
|
|
112
|
+
first_name:string
|
|
113
|
+
last_name:string
|
|
114
|
+
email_verified:boolean
|
|
115
|
+
]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def all_attributes
|
|
119
|
+
@all_attributes ||= (auth_attributes + attributes.map(&:to_s)).map do |attr|
|
|
120
|
+
Rails::Generators::GeneratedAttribute.parse(attr)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def custom_attributes
|
|
125
|
+
@custom_attributes ||= attributes.map do |attr|
|
|
126
|
+
Rails::Generators::GeneratedAttribute.parse(attr.to_s)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def migration_class_name
|
|
131
|
+
"CreateUsers"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def table_name
|
|
135
|
+
"users"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Authentication
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
before_action :authenticate
|
|
6
|
+
helper_method :current_user, :logged_in?
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def authenticate
|
|
12
|
+
return unless session[:session_token].present?
|
|
13
|
+
|
|
14
|
+
session_result = Aha::Auth.validate_session(
|
|
15
|
+
session[:session_token],
|
|
16
|
+
refresh_token: session[:refresh_token]
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if session_result.valid?
|
|
20
|
+
if session_result.refreshed?
|
|
21
|
+
session[:session_token] = session_result.new_session_token
|
|
22
|
+
session[:refresh_token] = session_result.new_refresh_token
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
@current_user = User.find_by(id: session[:user_id])
|
|
26
|
+
Current.user = @current_user
|
|
27
|
+
else
|
|
28
|
+
clear_session
|
|
29
|
+
redirect_to login_path, alert: "Your session has expired. Please log in again."
|
|
30
|
+
end
|
|
31
|
+
rescue Aha::Auth::ApiError => e
|
|
32
|
+
Rails.logger.error "Session validation failed: #{e.message}"
|
|
33
|
+
clear_session
|
|
34
|
+
redirect_to login_path, alert: "Authentication error. Please log in again."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def current_user
|
|
38
|
+
@current_user ||= Current.user
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def logged_in?
|
|
42
|
+
current_user.present?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def require_authentication
|
|
46
|
+
return if logged_in?
|
|
47
|
+
|
|
48
|
+
redirect_to login_path(return_to: request.fullpath), alert: "You must be logged in to access this page."
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def clear_session
|
|
52
|
+
session.delete(:session_token)
|
|
53
|
+
session.delete(:refresh_token)
|
|
54
|
+
session.delete(:user_id)
|
|
55
|
+
@current_user = nil
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
|
+
def change
|
|
3
|
+
create_table :users do |t|
|
|
4
|
+
t.string :auth_identifier, null: false
|
|
5
|
+
t.string :email, null: false
|
|
6
|
+
t.string :first_name
|
|
7
|
+
t.string :last_name
|
|
8
|
+
t.boolean :email_verified, default: false, null: false
|
|
9
|
+
<% custom_attributes.each do |attribute| -%>
|
|
10
|
+
<% unless attribute.virtual? -%>
|
|
11
|
+
t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
|
|
12
|
+
<% end -%>
|
|
13
|
+
<% end -%>
|
|
14
|
+
|
|
15
|
+
t.timestamps
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
add_index :users, :auth_identifier, unique: true
|
|
19
|
+
add_index :users, :email, unique: true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
class SessionsController < ApplicationController
|
|
2
|
+
skip_before_action :authenticate, only: [ :new, :callback ]
|
|
3
|
+
|
|
4
|
+
def new
|
|
5
|
+
redirect_to Aha::Auth.login_url(
|
|
6
|
+
state: { return_to: params[:return_to] || root_path }.to_json,
|
|
7
|
+
session:
|
|
8
|
+
), allow_other_host: true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def callback
|
|
12
|
+
if params[:code].present?
|
|
13
|
+
result = Aha::Auth.authenticate_with_code(code: params[:code], session:)
|
|
14
|
+
|
|
15
|
+
user = User.find_or_initialize_by(auth_identifier: result[:user]["id"])
|
|
16
|
+
|
|
17
|
+
user.update!(
|
|
18
|
+
email: result[:user]["email"],
|
|
19
|
+
first_name: result[:user]["first_name"],
|
|
20
|
+
last_name: result[:user]["last_name"],
|
|
21
|
+
email_verified: result[:user]["email_verified"]
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
session[:session_token] = result[:session_token]
|
|
25
|
+
session[:refresh_token] = result[:refresh_token]
|
|
26
|
+
session[:user_id] = user.id
|
|
27
|
+
|
|
28
|
+
state = JSON.parse(params[:state]) rescue {}
|
|
29
|
+
redirect_to state["return_to"] || root_path
|
|
30
|
+
else
|
|
31
|
+
redirect_to new_session_path, alert: "Authentication failed. Please try again."
|
|
32
|
+
end
|
|
33
|
+
rescue Aha::Auth::ApiError => e
|
|
34
|
+
Rails.logger.error "Authentication failed: #{e.message}"
|
|
35
|
+
redirect_to new_session_path, alert: "Authentication failed. Please try again."
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def logout
|
|
39
|
+
if session[:session_token]
|
|
40
|
+
begin
|
|
41
|
+
Aha::Auth.logout(session_token: session[:session_token])
|
|
42
|
+
rescue => e
|
|
43
|
+
Rails.logger.error "Logout error: #{e.message}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
clear_session
|
|
48
|
+
redirect_to root_path, notice: "Successfully signed out."
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
class User < ApplicationRecord
|
|
2
|
+
validates :auth_identifier, presence: true, uniqueness: true
|
|
3
|
+
validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
|
|
4
|
+
|
|
5
|
+
def name
|
|
6
|
+
"#{first_name} #{last_name}".strip.presence || email
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Configures Active Storage to use Aha blob storage service.
|
|
3
|
+
|
|
4
|
+
This generator sets up S3-compatible blob storage for file uploads
|
|
5
|
+
using environment variables provided by the container orchestrator.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
bin/rails generate aha_builder_core:blob_storage
|
|
9
|
+
|
|
10
|
+
This will:
|
|
11
|
+
- Run active_storage:install to create required migrations
|
|
12
|
+
- Add aws-sdk-s3 gem to Gemfile
|
|
13
|
+
- Update config/storage.yml with blob storage configuration
|
|
14
|
+
- Set config.active_storage.service = :blob in development.rb
|
|
15
|
+
- Set config.active_storage.service = :blob in production.rb
|
|
16
|
+
|
|
17
|
+
Prerequisites:
|
|
18
|
+
The container must have blob storage attached via the SetupBlobStorageTool
|
|
19
|
+
which sets the required BLOB_UPLOADS_S3_* environment variables.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
module AhaBuilderCore
|
|
6
|
+
class BlobStorageGenerator < Rails::Generators::Base
|
|
7
|
+
source_root File.expand_path("templates", __dir__)
|
|
8
|
+
|
|
9
|
+
def install_active_storage
|
|
10
|
+
run "bin/rails active_storage:install"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def add_aws_sdk_gem
|
|
14
|
+
gem "aws-sdk-s3", require: false unless gem_exists?("aws-sdk-s3")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def update_storage_yml
|
|
18
|
+
template "storage.yml.tt", "config/storage.yml", force: true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def update_development_environment
|
|
22
|
+
gsub_file "config/environments/development.rb",
|
|
23
|
+
/config\.active_storage\.service\s*=\s*:\w+/,
|
|
24
|
+
"config.active_storage.service = :blob"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def update_production_environment
|
|
28
|
+
gsub_file "config/environments/production.rb",
|
|
29
|
+
/config\.active_storage\.service\s*=\s*:\w+/,
|
|
30
|
+
"config.active_storage.service = :blob"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def display_instructions
|
|
34
|
+
say "\nBlob storage configured!", :green
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def gem_exists?(gem_name)
|
|
40
|
+
File.read("Gemfile").include?(gem_name)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
test:
|
|
2
|
+
service: Disk
|
|
3
|
+
root: <%%= Rails.root.join("tmp/storage") %>
|
|
4
|
+
|
|
5
|
+
local:
|
|
6
|
+
service: Disk
|
|
7
|
+
root: <%%= Rails.root.join("storage") %>
|
|
8
|
+
|
|
9
|
+
blob:
|
|
10
|
+
service: S3
|
|
11
|
+
endpoint: <%%= ENV.fetch('BLOB_UPLOADS_S3_ENDPOINT') %>
|
|
12
|
+
access_key_id: <%%= ENV.fetch('BLOB_UPLOADS_S3_ACCESS_KEY_ID') %>
|
|
13
|
+
secret_access_key: <%%= ENV.fetch('BLOB_UPLOADS_S3_SECRET_ACCESS_KEY') %>
|
|
14
|
+
region: <%%= ENV.fetch('BLOB_UPLOADS_S3_REGION', 'us-east-1') %>
|
|
15
|
+
bucket: <%%= ENV.fetch('BLOB_UPLOADS_S3_BUCKET') %>
|
|
16
|
+
force_path_style: true
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aha_builder_core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aha! Labs Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -125,6 +125,16 @@ files:
|
|
|
125
125
|
- lib/aha/auth/users_resource.rb
|
|
126
126
|
- lib/aha/auth/version.rb
|
|
127
127
|
- lib/aha_builder_core.rb
|
|
128
|
+
- lib/generators/aha_builder_core/auth/USAGE
|
|
129
|
+
- lib/generators/aha_builder_core/auth/auth_generator.rb
|
|
130
|
+
- lib/generators/aha_builder_core/auth/templates/authentication.rb.tt
|
|
131
|
+
- lib/generators/aha_builder_core/auth/templates/current.rb.tt
|
|
132
|
+
- lib/generators/aha_builder_core/auth/templates/migration.rb.tt
|
|
133
|
+
- lib/generators/aha_builder_core/auth/templates/sessions_controller.rb.tt
|
|
134
|
+
- lib/generators/aha_builder_core/auth/templates/user.rb.tt
|
|
135
|
+
- lib/generators/aha_builder_core/blob_storage/USAGE
|
|
136
|
+
- lib/generators/aha_builder_core/blob_storage/blob_storage_generator.rb
|
|
137
|
+
- lib/generators/aha_builder_core/blob_storage/templates/storage.yml.tt
|
|
128
138
|
homepage: https://www.aha.io
|
|
129
139
|
licenses:
|
|
130
140
|
- MIT
|