better_auth-sinatra 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 +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.md +21 -0
- data/README.md +91 -0
- data/lib/better_auth/sinatra/configuration.rb +74 -0
- data/lib/better_auth/sinatra/extension.rb +36 -0
- data/lib/better_auth/sinatra/helpers.rb +57 -0
- data/lib/better_auth/sinatra/migration.rb +122 -0
- data/lib/better_auth/sinatra/mounted_app.rb +42 -0
- data/lib/better_auth/sinatra/tasks.rb +49 -0
- data/lib/better_auth/sinatra/version.rb +7 -0
- data/lib/better_auth/sinatra.rb +86 -0
- data/lib/better_auth_sinatra.rb +3 -0
- metadata +161 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c8cfbde43e94311d211b9d355ed4fed778af108b0f6d149e4b3a6611ab3f9e90
|
|
4
|
+
data.tar.gz: 95e66c4b67168cfcb669ecfcf3aaa65798cbec20e8fd1d3b19e2833209520f0d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d158fe7e73c3a9622ebee45408fe2e6762f6372c36c310bf7b79cc1b58454c0cf507c4656d44bbbf49a7d95f84a41da1c3662bebf357fa0f9a1ddcac97e88115
|
|
7
|
+
data.tar.gz: 78125ddabbd5ea6fa93bf2f7447154ef1ba9f308bfc71c0244bdc99f970fe309488829c84bf19b7b7bce7007a11302f1f869fc19da3d57994d601d08ce9380a7
|
data/CHANGELOG.md
ADDED
data/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sebastian Sala
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Better Auth Sinatra
|
|
2
|
+
|
|
3
|
+
Sinatra adapter for Better Auth Ruby. This package is a thin integration around
|
|
4
|
+
the framework-agnostic `better_auth` Rack core.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
gem "better_auth-sinatra"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
bundle install
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
require "sinatra/base"
|
|
20
|
+
require "better_auth/sinatra"
|
|
21
|
+
|
|
22
|
+
class App < Sinatra::Base
|
|
23
|
+
register BetterAuth::Sinatra
|
|
24
|
+
|
|
25
|
+
better_auth at: "/api/auth" do |config|
|
|
26
|
+
config.secret = ENV.fetch("BETTER_AUTH_SECRET")
|
|
27
|
+
config.base_url = ENV.fetch("BETTER_AUTH_URL")
|
|
28
|
+
config.database = ->(options) {
|
|
29
|
+
BetterAuth::Adapters::Postgres.new(options, url: ENV.fetch("DATABASE_URL"))
|
|
30
|
+
}
|
|
31
|
+
config.email_and_password = {enabled: true}
|
|
32
|
+
config.plugins = []
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
get "/dashboard" do
|
|
36
|
+
require_authentication
|
|
37
|
+
current_user.fetch("email")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The extension mounts the core Rack app at `/api/auth` by default. The core app
|
|
43
|
+
still owns routes such as `/ok`, `/sign-up/email`, `/sign-in/email`, and plugin
|
|
44
|
+
endpoints.
|
|
45
|
+
|
|
46
|
+
## Helpers
|
|
47
|
+
|
|
48
|
+
- `current_session`
|
|
49
|
+
- `current_user`
|
|
50
|
+
- `authenticated?`
|
|
51
|
+
- `require_authentication`
|
|
52
|
+
|
|
53
|
+
`require_authentication` halts with `401` when no Better Auth user is present.
|
|
54
|
+
|
|
55
|
+
## Rake Tasks
|
|
56
|
+
|
|
57
|
+
Load tasks from your app Rakefile:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
require "better_auth/sinatra/tasks"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Available tasks:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
rake better_auth:install
|
|
67
|
+
rake better_auth:generate:migration
|
|
68
|
+
rake better_auth:migrate
|
|
69
|
+
rake better_auth:routes
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`better_auth:install` creates `config/better_auth.rb`. SQL migrations are
|
|
73
|
+
generated under `db/better_auth/migrate`.
|
|
74
|
+
|
|
75
|
+
## Database Notes
|
|
76
|
+
|
|
77
|
+
Sinatra does not include a Rails-style database layer or migration command.
|
|
78
|
+
This adapter uses Better Auth core SQL adapters for migrations. Set
|
|
79
|
+
`BETTER_AUTH_DIALECT=postgres`, `mysql`, or `sqlite` when generating SQL.
|
|
80
|
+
|
|
81
|
+
ActiveRecord-backed Sinatra migrations are not supported yet. Apps that already
|
|
82
|
+
use `sinatra-activerecord` can still configure Better Auth manually, but the v1
|
|
83
|
+
Rake tasks do not emit ActiveRecord migrations.
|
|
84
|
+
|
|
85
|
+
## Development
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
cd packages/better_auth-sinatra
|
|
89
|
+
rbenv exec bundle exec rspec
|
|
90
|
+
RUBOCOP_CACHE_ROOT=/private/var/folders/7x/jrsz946d2w73n42fb1_ff5000000gn/T/rubocop_cache_sinatra rbenv exec bundle exec standardrb
|
|
91
|
+
```
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterAuth
|
|
4
|
+
module Sinatra
|
|
5
|
+
class Configuration
|
|
6
|
+
AUTH_OPTION_NAMES = %i[
|
|
7
|
+
app_name
|
|
8
|
+
base_url
|
|
9
|
+
base_path
|
|
10
|
+
secret
|
|
11
|
+
database
|
|
12
|
+
plugins
|
|
13
|
+
trusted_origins
|
|
14
|
+
rate_limit
|
|
15
|
+
session
|
|
16
|
+
account
|
|
17
|
+
user
|
|
18
|
+
verification
|
|
19
|
+
advanced
|
|
20
|
+
email_and_password
|
|
21
|
+
password_hasher
|
|
22
|
+
email_verification
|
|
23
|
+
social_providers
|
|
24
|
+
experimental
|
|
25
|
+
secondary_storage
|
|
26
|
+
database_hooks
|
|
27
|
+
hooks
|
|
28
|
+
on_api_error
|
|
29
|
+
disabled_paths
|
|
30
|
+
logger
|
|
31
|
+
].freeze
|
|
32
|
+
|
|
33
|
+
attr_accessor(*AUTH_OPTION_NAMES)
|
|
34
|
+
|
|
35
|
+
def initialize
|
|
36
|
+
@base_path = BetterAuth::Configuration::DEFAULT_BASE_PATH
|
|
37
|
+
@plugins = []
|
|
38
|
+
@trusted_origins = []
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_auth_options
|
|
42
|
+
AUTH_OPTION_NAMES.each_with_object({}) do |name, options|
|
|
43
|
+
value = public_send(name)
|
|
44
|
+
next if value.nil?
|
|
45
|
+
next if value.respond_to?(:empty?) && value.empty?
|
|
46
|
+
|
|
47
|
+
options[name] = value
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def copy
|
|
52
|
+
self.class.new.tap do |copy|
|
|
53
|
+
AUTH_OPTION_NAMES.each do |name|
|
|
54
|
+
value = public_send(name)
|
|
55
|
+
copy.public_send("#{name}=", deep_dup(value))
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def deep_dup(value)
|
|
63
|
+
case value
|
|
64
|
+
when Hash
|
|
65
|
+
value.transform_values { |entry| deep_dup(entry) }
|
|
66
|
+
when Array
|
|
67
|
+
value.map { |entry| deep_dup(entry) }
|
|
68
|
+
else
|
|
69
|
+
value
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterAuth
|
|
4
|
+
module Sinatra
|
|
5
|
+
module Extension
|
|
6
|
+
def self.registered(app)
|
|
7
|
+
app.extend ClassMethods
|
|
8
|
+
app.helpers Helpers
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
def better_auth(at: BetterAuth::Configuration::DEFAULT_BASE_PATH, auth: nil, **overrides)
|
|
13
|
+
mount_path = normalize_better_auth_mount_path(at)
|
|
14
|
+
config = BetterAuth::Sinatra.configuration.copy
|
|
15
|
+
yield config if block_given?
|
|
16
|
+
config.base_path = mount_path
|
|
17
|
+
options = config.to_auth_options.merge(overrides)
|
|
18
|
+
auth_instance = auth || BetterAuth.auth(options)
|
|
19
|
+
|
|
20
|
+
set :better_auth_auth, auth_instance
|
|
21
|
+
set :better_auth_mount_path, mount_path
|
|
22
|
+
use BetterAuth::Sinatra::MountedApp, -> { settings.better_auth_auth }, mount_path: mount_path
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def normalize_better_auth_mount_path(path)
|
|
28
|
+
normalized = path.to_s
|
|
29
|
+
normalized = "/#{normalized}" unless normalized.start_with?("/")
|
|
30
|
+
normalized = normalized.squeeze("/")
|
|
31
|
+
(normalized == "/") ? normalized : normalized.delete_suffix("/")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterAuth
|
|
4
|
+
module Sinatra
|
|
5
|
+
module Helpers
|
|
6
|
+
def current_session
|
|
7
|
+
data = better_auth_session_data
|
|
8
|
+
data&.fetch(:session, nil) || data&.fetch("session", nil)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def current_user
|
|
12
|
+
data = better_auth_session_data
|
|
13
|
+
data&.fetch(:user, nil) || data&.fetch("user", nil)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def authenticated?
|
|
17
|
+
!current_user.nil?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def require_authentication
|
|
21
|
+
return true if authenticated?
|
|
22
|
+
|
|
23
|
+
halt 401, ""
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def better_auth_session_data
|
|
29
|
+
return request.env["better_auth.session"] if request.env.key?("better_auth.session")
|
|
30
|
+
|
|
31
|
+
request.env["better_auth.session"] = resolve_better_auth_session
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def resolve_better_auth_session
|
|
35
|
+
context = BetterAuth::Endpoint::Context.new(
|
|
36
|
+
path: request.path_info,
|
|
37
|
+
method: request.request_method,
|
|
38
|
+
query: request.GET,
|
|
39
|
+
body: {},
|
|
40
|
+
params: params,
|
|
41
|
+
headers: {"cookie" => request.env["HTTP_COOKIE"]},
|
|
42
|
+
context: better_auth_auth.context,
|
|
43
|
+
request: request
|
|
44
|
+
)
|
|
45
|
+
BetterAuth::Session.find_current(context, disable_refresh: true)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def better_auth_auth
|
|
49
|
+
if respond_to?(:settings) && settings.respond_to?(:better_auth_auth)
|
|
50
|
+
settings.better_auth_auth
|
|
51
|
+
else
|
|
52
|
+
BetterAuth::Sinatra.auth
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module BetterAuth
|
|
6
|
+
module Sinatra
|
|
7
|
+
module Migration
|
|
8
|
+
DEFAULT_MIGRATIONS_PATH = "db/better_auth/migrate"
|
|
9
|
+
|
|
10
|
+
class UnsupportedAdapterError < StandardError; end
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def render(options, dialect:)
|
|
15
|
+
config = configuration_for(options)
|
|
16
|
+
statements = BetterAuth::Schema::SQL.create_statements(config, dialect: dialect)
|
|
17
|
+
[
|
|
18
|
+
"-- Generated by better_auth-sinatra",
|
|
19
|
+
"-- Dialect: #{dialect}",
|
|
20
|
+
"",
|
|
21
|
+
statements.join("\n\n"),
|
|
22
|
+
""
|
|
23
|
+
].join("\n")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def generate(options, dialect:, migrations_path: DEFAULT_MIGRATIONS_PATH, timestamp: Time.now.utc.strftime("%Y%m%d%H%M%S"))
|
|
27
|
+
FileUtils.mkdir_p(migrations_path)
|
|
28
|
+
path = File.join(migrations_path, "#{timestamp}_create_better_auth_tables.sql")
|
|
29
|
+
return path if File.exist?(path)
|
|
30
|
+
|
|
31
|
+
File.write(path, render(options, dialect: dialect))
|
|
32
|
+
path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def migrate(auth_or_options, migrations_path: DEFAULT_MIGRATIONS_PATH)
|
|
36
|
+
auth = auth_for(auth_or_options)
|
|
37
|
+
adapter = auth.context.adapter
|
|
38
|
+
unless adapter.respond_to?(:dialect) && adapter.respond_to?(:connection)
|
|
39
|
+
raise UnsupportedAdapterError, "better_auth-sinatra migrations require core SQL adapters with connection and dialect support"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
connection = adapter.connection
|
|
43
|
+
dialect = adapter.dialect.to_sym
|
|
44
|
+
files = Dir[File.join(migrations_path, "*.sql")].sort
|
|
45
|
+
ensure_schema_migrations!(connection, dialect)
|
|
46
|
+
applied = applied_migrations(connection, dialect)
|
|
47
|
+
|
|
48
|
+
files.reject { |file| applied.include?(File.basename(file)) }.each do |file|
|
|
49
|
+
execute_sql(connection, File.read(file))
|
|
50
|
+
record_migration(connection, dialect, File.basename(file))
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def configuration_for(options)
|
|
55
|
+
return options.options if options.is_a?(BetterAuth::Auth)
|
|
56
|
+
return options if options.is_a?(BetterAuth::Configuration)
|
|
57
|
+
|
|
58
|
+
BetterAuth::Configuration.new(options)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def auth_for(value)
|
|
62
|
+
return value if value.is_a?(BetterAuth::Auth)
|
|
63
|
+
|
|
64
|
+
BetterAuth.auth(value)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def ensure_schema_migrations!(connection, dialect)
|
|
68
|
+
sql = case dialect
|
|
69
|
+
when :postgres, :sqlite
|
|
70
|
+
%(CREATE TABLE IF NOT EXISTS #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} text PRIMARY KEY);)
|
|
71
|
+
when :mysql
|
|
72
|
+
%(CREATE TABLE IF NOT EXISTS #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} varchar(191) PRIMARY KEY) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;)
|
|
73
|
+
when :mssql
|
|
74
|
+
%(IF OBJECT_ID(N'#{quote("better_auth_schema_migrations", dialect)}', N'U') IS NULL CREATE TABLE #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} varchar(255) PRIMARY KEY);)
|
|
75
|
+
else
|
|
76
|
+
raise UnsupportedAdapterError, "Unsupported SQL dialect for better_auth-sinatra migrations: #{dialect}"
|
|
77
|
+
end
|
|
78
|
+
execute_sql(connection, sql)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def applied_migrations(connection, dialect)
|
|
82
|
+
rows = execute_sql(connection, "SELECT #{quote("version", dialect)} FROM #{quote("better_auth_schema_migrations", dialect)};")
|
|
83
|
+
Array(rows).map { |row| row["version"] || row[:version] }
|
|
84
|
+
rescue
|
|
85
|
+
[]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def record_migration(connection, dialect, version)
|
|
89
|
+
sql = "INSERT INTO #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)}) VALUES (#{literal(version)});"
|
|
90
|
+
execute_sql(connection, sql)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def execute_sql(connection, sql)
|
|
94
|
+
statements(sql).each_with_object([]) do |statement, results|
|
|
95
|
+
result =
|
|
96
|
+
if connection.respond_to?(:exec)
|
|
97
|
+
connection.exec(statement)
|
|
98
|
+
elsif connection.respond_to?(:execute)
|
|
99
|
+
connection.execute(statement)
|
|
100
|
+
elsif connection.respond_to?(:query)
|
|
101
|
+
connection.query(statement)
|
|
102
|
+
else
|
|
103
|
+
raise UnsupportedAdapterError, "SQL connection does not support exec, execute, or query"
|
|
104
|
+
end
|
|
105
|
+
results.concat(result.to_a) if result.respond_to?(:to_a)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def statements(sql)
|
|
110
|
+
sql.split(/;\s*$/).map(&:strip).reject(&:empty?)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def quote(identifier, dialect)
|
|
114
|
+
BetterAuth::Schema::SQL.quote(identifier, dialect)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def literal(value)
|
|
118
|
+
"'#{value.to_s.gsub("'", "''")}'"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterAuth
|
|
4
|
+
module Sinatra
|
|
5
|
+
class MountedApp
|
|
6
|
+
def initialize(app, auth, mount_path:)
|
|
7
|
+
@app = app
|
|
8
|
+
@auth = auth
|
|
9
|
+
@mount_path = normalize_path(mount_path)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call(env)
|
|
13
|
+
return auth.call(env) if mounted_path?(env["PATH_INFO"])
|
|
14
|
+
|
|
15
|
+
@app.call(env)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def auth
|
|
21
|
+
return @auth.call if @auth.respond_to?(:call) && !@auth.respond_to?(:context)
|
|
22
|
+
|
|
23
|
+
@auth
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def mounted_path?(path)
|
|
27
|
+
normalized = normalize_path(path)
|
|
28
|
+
return true if @mount_path == "/"
|
|
29
|
+
|
|
30
|
+
normalized == @mount_path || normalized.start_with?("#{@mount_path}/")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def normalize_path(path)
|
|
34
|
+
normalized = path.to_s
|
|
35
|
+
normalized = "/#{normalized}" unless normalized.start_with?("/")
|
|
36
|
+
normalized = normalized.squeeze("/")
|
|
37
|
+
normalized = normalized.delete_suffix("/") unless normalized == "/"
|
|
38
|
+
normalized.empty? ? "/" : normalized
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "rake"
|
|
5
|
+
require "better_auth/sinatra"
|
|
6
|
+
|
|
7
|
+
namespace :better_auth do
|
|
8
|
+
desc "Create the Better Auth Sinatra config and migration directory"
|
|
9
|
+
task :install do
|
|
10
|
+
config_path = "config/better_auth.rb"
|
|
11
|
+
FileUtils.mkdir_p(File.dirname(config_path))
|
|
12
|
+
if File.exist?(config_path)
|
|
13
|
+
puts "skip #{config_path} already exists"
|
|
14
|
+
else
|
|
15
|
+
File.write(config_path, BetterAuth::Sinatra.default_config_template)
|
|
16
|
+
puts "create #{config_path}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
FileUtils.mkdir_p(BetterAuth::Sinatra::Migration::DEFAULT_MIGRATIONS_PATH)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
namespace :generate do
|
|
23
|
+
desc "Create the Better Auth SQL migration"
|
|
24
|
+
task :migration do
|
|
25
|
+
BetterAuth::Sinatra.load_app_config
|
|
26
|
+
dialect = ENV.fetch("BETTER_AUTH_DIALECT", "postgres").to_sym
|
|
27
|
+
config = BetterAuth::Sinatra.migration_configuration
|
|
28
|
+
path = BetterAuth::Sinatra::Migration.generate(config, dialect: dialect)
|
|
29
|
+
puts "create #{path}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc "Create the Better Auth SQL migration"
|
|
34
|
+
task "generate:migration" do
|
|
35
|
+
Rake::Task["better_auth:generate:migration"].invoke
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc "Run pending Better Auth SQL migrations"
|
|
39
|
+
task :migrate do
|
|
40
|
+
BetterAuth::Sinatra.load_app_config
|
|
41
|
+
BetterAuth::Sinatra::Migration.migrate(BetterAuth::Sinatra.auth)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc "Print Better Auth Sinatra mount information"
|
|
45
|
+
task :routes do
|
|
46
|
+
BetterAuth::Sinatra.load_app_config
|
|
47
|
+
puts "#{BetterAuth::Sinatra.configuration.base_path}/* -> BetterAuth.auth"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "better_auth"
|
|
4
|
+
require "sinatra/base"
|
|
5
|
+
|
|
6
|
+
require_relative "sinatra/version"
|
|
7
|
+
require_relative "sinatra/configuration"
|
|
8
|
+
require_relative "sinatra/mounted_app"
|
|
9
|
+
require_relative "sinatra/helpers"
|
|
10
|
+
require_relative "sinatra/migration"
|
|
11
|
+
require_relative "sinatra/extension"
|
|
12
|
+
|
|
13
|
+
module BetterAuth
|
|
14
|
+
module Sinatra
|
|
15
|
+
class << self
|
|
16
|
+
def registered(app)
|
|
17
|
+
Extension.registered(app)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def configuration
|
|
21
|
+
@configuration ||= Configuration.new
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def configure
|
|
25
|
+
yield configuration
|
|
26
|
+
@auth = nil
|
|
27
|
+
self
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def reset!
|
|
31
|
+
@configuration = nil
|
|
32
|
+
@auth = nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def auth(overrides = nil)
|
|
36
|
+
options = configuration.to_auth_options
|
|
37
|
+
return @auth ||= BetterAuth.auth(options) if overrides.nil? || overrides.empty?
|
|
38
|
+
|
|
39
|
+
BetterAuth.auth(options.merge(overrides))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def migration_configuration
|
|
43
|
+
options = configuration.to_auth_options
|
|
44
|
+
options[:secret] ||= BetterAuth::Configuration::DEFAULT_SECRET
|
|
45
|
+
BetterAuth::Configuration.new(options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def load_app_config(path = "config/better_auth.rb")
|
|
49
|
+
load path if File.exist?(path)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def default_config_template
|
|
53
|
+
<<~RUBY
|
|
54
|
+
# frozen_string_literal: true
|
|
55
|
+
|
|
56
|
+
require "better_auth/sinatra"
|
|
57
|
+
|
|
58
|
+
BetterAuth::Sinatra.configure do |config|
|
|
59
|
+
config.secret = ENV.fetch("BETTER_AUTH_SECRET", "change-me-sinatra-secret-12345678901234567890")
|
|
60
|
+
config.base_url = ENV["BETTER_AUTH_URL"]
|
|
61
|
+
config.base_path = "/api/auth"
|
|
62
|
+
|
|
63
|
+
config.database = ->(options) do
|
|
64
|
+
case ENV.fetch("BETTER_AUTH_DATABASE_DIALECT", "postgres")
|
|
65
|
+
when "postgres", "postgresql"
|
|
66
|
+
BetterAuth::Adapters::Postgres.new(options, url: ENV.fetch("DATABASE_URL"))
|
|
67
|
+
when "mysql"
|
|
68
|
+
BetterAuth::Adapters::MySQL.new(options, url: ENV.fetch("DATABASE_URL"))
|
|
69
|
+
when "sqlite", "sqlite3"
|
|
70
|
+
BetterAuth::Adapters::SQLite.new(options, path: ENV.fetch("DATABASE_URL", "db/better_auth.sqlite3"))
|
|
71
|
+
else
|
|
72
|
+
raise "Unsupported BETTER_AUTH_DATABASE_DIALECT for better_auth-sinatra"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
config.email_and_password = {
|
|
77
|
+
enabled: true
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
config.plugins = []
|
|
81
|
+
end
|
|
82
|
+
RUBY
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: better_auth-sinatra
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Sebastian Sala
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: better_auth
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.1'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: sinatra
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3.0'
|
|
33
|
+
- - "<"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '5'
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '3.0'
|
|
43
|
+
- - "<"
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '5'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: bundler
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - "~>"
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '2.5'
|
|
53
|
+
type: :development
|
|
54
|
+
prerelease: false
|
|
55
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - "~>"
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '2.5'
|
|
60
|
+
- !ruby/object:Gem::Dependency
|
|
61
|
+
name: rack-test
|
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - "~>"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '2.2'
|
|
67
|
+
type: :development
|
|
68
|
+
prerelease: false
|
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - "~>"
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '2.2'
|
|
74
|
+
- !ruby/object:Gem::Dependency
|
|
75
|
+
name: rake
|
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - "~>"
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '13.2'
|
|
81
|
+
type: :development
|
|
82
|
+
prerelease: false
|
|
83
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - "~>"
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '13.2'
|
|
88
|
+
- !ruby/object:Gem::Dependency
|
|
89
|
+
name: rspec
|
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - "~>"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '3.13'
|
|
95
|
+
type: :development
|
|
96
|
+
prerelease: false
|
|
97
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - "~>"
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '3.13'
|
|
102
|
+
- !ruby/object:Gem::Dependency
|
|
103
|
+
name: standardrb
|
|
104
|
+
requirement: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - "~>"
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '1.0'
|
|
109
|
+
type: :development
|
|
110
|
+
prerelease: false
|
|
111
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
112
|
+
requirements:
|
|
113
|
+
- - "~>"
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: '1.0'
|
|
116
|
+
description: Sinatra integration for Better Auth Ruby. Provides mounting helpers,
|
|
117
|
+
request helpers, and SQL migration tasks.
|
|
118
|
+
email:
|
|
119
|
+
- sebastian.sala.tech@gmail.com
|
|
120
|
+
executables: []
|
|
121
|
+
extensions: []
|
|
122
|
+
extra_rdoc_files: []
|
|
123
|
+
files:
|
|
124
|
+
- CHANGELOG.md
|
|
125
|
+
- LICENSE.md
|
|
126
|
+
- README.md
|
|
127
|
+
- lib/better_auth/sinatra.rb
|
|
128
|
+
- lib/better_auth/sinatra/configuration.rb
|
|
129
|
+
- lib/better_auth/sinatra/extension.rb
|
|
130
|
+
- lib/better_auth/sinatra/helpers.rb
|
|
131
|
+
- lib/better_auth/sinatra/migration.rb
|
|
132
|
+
- lib/better_auth/sinatra/mounted_app.rb
|
|
133
|
+
- lib/better_auth/sinatra/tasks.rb
|
|
134
|
+
- lib/better_auth/sinatra/version.rb
|
|
135
|
+
- lib/better_auth_sinatra.rb
|
|
136
|
+
homepage: https://github.com/sebasxsala/better-auth
|
|
137
|
+
licenses:
|
|
138
|
+
- MIT
|
|
139
|
+
metadata:
|
|
140
|
+
homepage_uri: https://github.com/sebasxsala/better-auth
|
|
141
|
+
source_code_uri: https://github.com/sebasxsala/better-auth
|
|
142
|
+
changelog_uri: https://github.com/sebasxsala/better-auth/blob/main/packages/better_auth-sinatra/CHANGELOG.md
|
|
143
|
+
bug_tracker_uri: https://github.com/sebasxsala/better-auth/issues
|
|
144
|
+
rdoc_options: []
|
|
145
|
+
require_paths:
|
|
146
|
+
- lib
|
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - ">="
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: 3.2.0
|
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
|
+
requirements:
|
|
154
|
+
- - ">="
|
|
155
|
+
- !ruby/object:Gem::Version
|
|
156
|
+
version: '0'
|
|
157
|
+
requirements: []
|
|
158
|
+
rubygems_version: 3.6.9
|
|
159
|
+
specification_version: 4
|
|
160
|
+
summary: Sinatra adapter for Better Auth
|
|
161
|
+
test_files: []
|