better_auth 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +5 -3
- data/lib/better_auth/adapters/internal_adapter.rb +168 -18
- data/lib/better_auth/adapters/memory.rb +4 -1
- data/lib/better_auth/adapters/mongodb.rb +5 -365
- data/lib/better_auth/adapters/sql.rb +17 -1
- data/lib/better_auth/api.rb +1 -1
- data/lib/better_auth/context.rb +2 -1
- data/lib/better_auth/plugin.rb +14 -1
- data/lib/better_auth/plugins/oauth_protocol.rb +403 -57
- data/lib/better_auth/plugins/organization.rb +5 -0
- data/lib/better_auth/rate_limiter.rb +19 -2
- data/lib/better_auth/router.rb +14 -1
- data/lib/better_auth/routes/email_verification.rb +5 -2
- data/lib/better_auth/routes/password.rb +19 -0
- data/lib/better_auth/routes/session.rb +27 -4
- data/lib/better_auth/routes/sign_in.rb +1 -1
- data/lib/better_auth/routes/sign_up.rb +52 -1
- data/lib/better_auth/routes/social.rb +201 -22
- data/lib/better_auth/routes/user.rb +14 -2
- data/lib/better_auth/schema/sql.rb +11 -0
- data/lib/better_auth/schema.rb +16 -0
- data/lib/better_auth/social_providers/apple.rb +44 -8
- data/lib/better_auth/social_providers/atlassian.rb +32 -0
- data/lib/better_auth/social_providers/base.rb +262 -4
- data/lib/better_auth/social_providers/cognito.rb +32 -0
- data/lib/better_auth/social_providers/discord.rb +27 -5
- data/lib/better_auth/social_providers/dropbox.rb +33 -0
- data/lib/better_auth/social_providers/facebook.rb +35 -0
- data/lib/better_auth/social_providers/figma.rb +31 -0
- data/lib/better_auth/social_providers/github.rb +21 -6
- data/lib/better_auth/social_providers/gitlab.rb +16 -3
- data/lib/better_auth/social_providers/google.rb +38 -13
- data/lib/better_auth/social_providers/huggingface.rb +31 -0
- data/lib/better_auth/social_providers/kakao.rb +32 -0
- data/lib/better_auth/social_providers/kick.rb +32 -0
- data/lib/better_auth/social_providers/line.rb +33 -0
- data/lib/better_auth/social_providers/linear.rb +44 -0
- data/lib/better_auth/social_providers/linkedin.rb +30 -0
- data/lib/better_auth/social_providers/microsoft_entra_id.rb +79 -7
- data/lib/better_auth/social_providers/naver.rb +31 -0
- data/lib/better_auth/social_providers/notion.rb +33 -0
- data/lib/better_auth/social_providers/paybin.rb +31 -0
- data/lib/better_auth/social_providers/paypal.rb +36 -0
- data/lib/better_auth/social_providers/polar.rb +31 -0
- data/lib/better_auth/social_providers/railway.rb +49 -0
- data/lib/better_auth/social_providers/reddit.rb +32 -0
- data/lib/better_auth/social_providers/roblox.rb +31 -0
- data/lib/better_auth/social_providers/salesforce.rb +38 -0
- data/lib/better_auth/social_providers/slack.rb +30 -0
- data/lib/better_auth/social_providers/spotify.rb +31 -0
- data/lib/better_auth/social_providers/tiktok.rb +35 -0
- data/lib/better_auth/social_providers/twitch.rb +39 -0
- data/lib/better_auth/social_providers/twitter.rb +32 -0
- data/lib/better_auth/social_providers/vercel.rb +47 -0
- data/lib/better_auth/social_providers/vk.rb +34 -0
- data/lib/better_auth/social_providers/wechat.rb +104 -0
- data/lib/better_auth/social_providers/zoom.rb +31 -0
- data/lib/better_auth/social_providers.rb +29 -0
- data/lib/better_auth/version.rb +1 -1
- data/lib/better_auth.rb +0 -1
- metadata +30 -15
|
@@ -1,369 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require "
|
|
3
|
+
begin
|
|
4
|
+
require "better_auth/mongo_adapter"
|
|
5
|
+
rescue LoadError => error
|
|
6
|
+
raise if error.path && error.path != "better_auth/mongo_adapter"
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
module Adapters
|
|
8
|
-
class MongoDB < Base
|
|
9
|
-
attr_reader :database, :client, :use_plural
|
|
10
|
-
|
|
11
|
-
def initialize(options = nil, database:, client: nil, transaction: nil, use_plural: false)
|
|
12
|
-
require "mongo" unless database
|
|
13
|
-
|
|
14
|
-
super(options || Configuration.new(secret: Configuration::DEFAULT_SECRET, database: :memory))
|
|
15
|
-
@database = database
|
|
16
|
-
@client = client
|
|
17
|
-
@transaction_enabled = transaction.nil? ? !client.nil? : !!transaction
|
|
18
|
-
@use_plural = !!use_plural
|
|
19
|
-
@session = nil
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def create(model:, data:, force_allow_id: false)
|
|
23
|
-
model = model.to_s
|
|
24
|
-
record = transform_input(model, data, "create", force_allow_id)
|
|
25
|
-
document = to_document(model, record)
|
|
26
|
-
collection_for(model).insert_one(document, session_options)
|
|
27
|
-
from_document(model, document)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def find_one(model:, where: [], select: nil, join: nil)
|
|
31
|
-
find_many(model: model, where: where, select: select, join: join, limit: 1).first
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def find_many(model:, where: [], sort_by: nil, limit: nil, offset: nil, select: nil, join: nil)
|
|
35
|
-
model = model.to_s
|
|
36
|
-
records = documents_for(model)
|
|
37
|
-
.select { |document| matches_where?(model, document, where || []) }
|
|
38
|
-
.map { |document| from_document(model, document) }
|
|
39
|
-
records = records.map { |record| apply_join(model, record, join) } if join
|
|
40
|
-
records = sort_records(records, sort_by) if sort_by
|
|
41
|
-
records = records.drop(offset.to_i) if offset
|
|
42
|
-
records = records.first(limit.to_i) if limit
|
|
43
|
-
records = records.map { |record| select_fields(record, select, join) } if select && !select.empty?
|
|
44
|
-
records
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def update(model:, where:, update:)
|
|
48
|
-
model = model.to_s
|
|
49
|
-
records = update_matching(model, where || [], update, first_only: true)
|
|
50
|
-
records.first
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def update_many(model:, where:, update:)
|
|
54
|
-
update_matching(model.to_s, where || [], update, first_only: false).length
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def delete(model:, where:)
|
|
58
|
-
delete_many(model: model, where: where, first_only: true)
|
|
59
|
-
nil
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def delete_many(model:, where:, first_only: false)
|
|
63
|
-
model = model.to_s
|
|
64
|
-
documents = documents_for(model)
|
|
65
|
-
matches = documents.select { |document| matches_where?(model, document, where || []) }
|
|
66
|
-
matches = matches.first(1) if first_only
|
|
67
|
-
ids = matches.map { |document| document["_id"] }
|
|
68
|
-
remaining = documents.reject { |document| ids.include?(document["_id"]) }
|
|
69
|
-
replace_documents(model, remaining)
|
|
70
|
-
ids.length
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def count(model:, where: nil)
|
|
74
|
-
find_many(model: model, where: where || []).length
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def transaction
|
|
78
|
-
return yield self unless client && @transaction_enabled && client.respond_to?(:start_session)
|
|
79
|
-
|
|
80
|
-
session = client.start_session
|
|
81
|
-
begin
|
|
82
|
-
session.start_transaction
|
|
83
|
-
@session = session
|
|
84
|
-
result = yield self
|
|
85
|
-
session.commit_transaction
|
|
86
|
-
result
|
|
87
|
-
rescue
|
|
88
|
-
session.abort_transaction
|
|
89
|
-
raise
|
|
90
|
-
ensure
|
|
91
|
-
@session = nil
|
|
92
|
-
session.end_session
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
private
|
|
97
|
-
|
|
98
|
-
def transform_input(model, data, action, force_allow_id)
|
|
99
|
-
fields = schema_for(model).fetch(:fields)
|
|
100
|
-
input = stringify_keys(data)
|
|
101
|
-
output = {}
|
|
102
|
-
|
|
103
|
-
fields.each do |field, attributes|
|
|
104
|
-
next if field == "id" && input.key?(field) && !force_allow_id
|
|
105
|
-
|
|
106
|
-
value_provided = input.key?(field)
|
|
107
|
-
value = input[field]
|
|
108
|
-
if value_provided && attributes[:input] == false && value && !force_allow_id
|
|
109
|
-
raise APIError.new("BAD_REQUEST", message: "#{field} is not allowed to be set")
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
if !value_provided && action == "create" && attributes.key?(:default_value)
|
|
113
|
-
value = resolve_default(attributes[:default_value])
|
|
114
|
-
value_provided = true
|
|
115
|
-
elsif !value_provided && action == "update" && attributes[:on_update]
|
|
116
|
-
value = resolve_default(attributes[:on_update])
|
|
117
|
-
value_provided = true
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
if !value_provided && action == "create" && attributes[:required]
|
|
121
|
-
raise APIError.new("BAD_REQUEST", message: "#{field} is required") unless field == "id"
|
|
122
|
-
end
|
|
123
|
-
output[field] = coerce_value(value, attributes) if value_provided
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
output["id"] = generated_id if action == "create" && !output.key?("id")
|
|
127
|
-
output
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def update_matching(model, where, update, first_only:)
|
|
131
|
-
data = transform_input(model, update, "update", true)
|
|
132
|
-
documents = documents_for(model)
|
|
133
|
-
matches = documents.select { |document| matches_where?(model, document, where) }
|
|
134
|
-
matches = matches.first(1) if first_only
|
|
135
|
-
updates = to_document(model, data)
|
|
136
|
-
ids = matches.map { |document| document["_id"] }
|
|
137
|
-
updated = documents.map do |document|
|
|
138
|
-
ids.include?(document["_id"]) ? document.merge(updates) : document
|
|
139
|
-
end
|
|
140
|
-
replace_documents(model, updated)
|
|
141
|
-
updated.select { |document| ids.include?(document["_id"]) }.map { |document| from_document(model, document) }
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def documents_for(model)
|
|
145
|
-
collection = collection_for(model)
|
|
146
|
-
if collection.respond_to?(:all_documents)
|
|
147
|
-
collection.all_documents
|
|
148
|
-
else
|
|
149
|
-
collection.find({}, session_options).to_a.map { |document| stringify_document(document) }
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def replace_documents(model, documents)
|
|
154
|
-
collection = collection_for(model)
|
|
155
|
-
if collection.respond_to?(:replace_documents)
|
|
156
|
-
collection.replace_documents(documents)
|
|
157
|
-
else
|
|
158
|
-
collection.delete_many({}, session_options)
|
|
159
|
-
documents.each { |document| collection.insert_one(document, session_options) }
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def collection_for(model)
|
|
164
|
-
database.collection(collection_name(model))
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
def collection_name(model)
|
|
168
|
-
return schema_for(model).fetch(:model_name) if use_plural
|
|
169
|
-
|
|
170
|
-
model.to_s
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def to_document(model, record)
|
|
174
|
-
schema_for(model).fetch(:fields).each_with_object({}) do |(field, attributes), document|
|
|
175
|
-
next unless record.key?(field)
|
|
176
|
-
|
|
177
|
-
key = (field == "id") ? "_id" : storage_field(model, field)
|
|
178
|
-
document[key] = store_value(field, record[field], attributes)
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def from_document(model, document)
|
|
183
|
-
fields = schema_for(model).fetch(:fields)
|
|
184
|
-
fields.each_with_object({}) do |(field, attributes), record|
|
|
185
|
-
key = (field == "id") ? "_id" : storage_field(model, field)
|
|
186
|
-
record[field] = output_value(field, fetch_document(document, key), attributes) if document_key?(document, key)
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
def stringify_document(document)
|
|
191
|
-
document.each_with_object({}) { |(key, value), result| result[key.to_s] = value }
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def matches_where?(model, document, where)
|
|
195
|
-
clauses = Array(where)
|
|
196
|
-
return true if clauses.empty?
|
|
197
|
-
|
|
198
|
-
result = evaluate_clause(model, document, clauses.first)
|
|
199
|
-
clauses.drop(1).each do |clause|
|
|
200
|
-
clause_result = evaluate_clause(model, document, clause)
|
|
201
|
-
if fetch_key(clause, :connector).to_s.upcase == "OR"
|
|
202
|
-
result ||= clause_result
|
|
203
|
-
else
|
|
204
|
-
result &&= clause_result
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
result
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def evaluate_clause(model, document, clause)
|
|
211
|
-
field = Schema.storage_key(fetch_key(clause, :field))
|
|
212
|
-
attributes = schema_for(model).fetch(:fields).fetch(field)
|
|
213
|
-
key = (field == "id") ? "_id" : storage_field(model, field)
|
|
214
|
-
expected = store_value(field, fetch_key(clause, :value), attributes)
|
|
215
|
-
current = fetch_document(document, key)
|
|
216
|
-
operator = (fetch_key(clause, :operator) || "eq").to_s
|
|
217
|
-
|
|
218
|
-
case operator
|
|
219
|
-
when "in"
|
|
220
|
-
Array(expected).any? { |value| same_value?(current, value) }
|
|
221
|
-
when "not_in"
|
|
222
|
-
Array(expected).none? { |value| same_value?(current, value) }
|
|
223
|
-
when "contains"
|
|
224
|
-
current.to_s.include?(expected.to_s)
|
|
225
|
-
when "starts_with"
|
|
226
|
-
current.to_s.start_with?(expected.to_s)
|
|
227
|
-
when "ends_with"
|
|
228
|
-
current.to_s.end_with?(expected.to_s)
|
|
229
|
-
when "ne"
|
|
230
|
-
!same_value?(current, expected)
|
|
231
|
-
when "gt"
|
|
232
|
-
!expected.nil? && current > expected
|
|
233
|
-
when "gte"
|
|
234
|
-
!expected.nil? && current >= expected
|
|
235
|
-
when "lt"
|
|
236
|
-
!expected.nil? && current < expected
|
|
237
|
-
when "lte"
|
|
238
|
-
!expected.nil? && current <= expected
|
|
239
|
-
else
|
|
240
|
-
same_value?(current, expected)
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
|
|
244
|
-
def same_value?(left, right)
|
|
245
|
-
left == right || left.to_s == right.to_s
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def apply_join(model, record, join)
|
|
249
|
-
joined = record.dup
|
|
250
|
-
join.each_key do |join_model|
|
|
251
|
-
join_model = join_model.to_s
|
|
252
|
-
joined[join_model] = case [model, join_model]
|
|
253
|
-
when ["session", "user"], ["account", "user"]
|
|
254
|
-
find_one(model: "user", where: [{field: "id", value: record["userId"]}])
|
|
255
|
-
when ["user", "account"]
|
|
256
|
-
find_many(model: "account", where: [{field: "userId", value: record["id"]}])
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
joined
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def sort_records(records, sort_by)
|
|
263
|
-
field = Schema.storage_key(fetch_key(sort_by, :field))
|
|
264
|
-
direction = fetch_key(sort_by, :direction).to_s
|
|
265
|
-
records.sort_by { |record| record[field].nil? ? "" : record[field] }.then do |sorted|
|
|
266
|
-
(direction == "desc") ? sorted.reverse : sorted
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
def select_fields(record, select, join)
|
|
271
|
-
fields = Array(select).map { |field| Schema.storage_key(field) }
|
|
272
|
-
selected = record.slice(*fields)
|
|
273
|
-
join&.each_key { |join_model| selected[join_model.to_s] = record[join_model.to_s] if record.key?(join_model.to_s) }
|
|
274
|
-
selected
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
def store_value(field, value, attributes)
|
|
278
|
-
return nil if value.nil?
|
|
279
|
-
return Array(value).map { |entry| store_value(field, entry, attributes) } if value.is_a?(Array)
|
|
280
|
-
|
|
281
|
-
if field == "id" || attributes.dig(:references, :field) == "id"
|
|
282
|
-
return value if custom_id_generator?
|
|
283
|
-
return bson_id(value)
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
coerce_value(value, attributes)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
def output_value(field, value, attributes)
|
|
290
|
-
return nil if value.nil?
|
|
291
|
-
return value.to_s if field == "id" || attributes.dig(:references, :field) == "id"
|
|
292
|
-
|
|
293
|
-
coerce_value(value, attributes)
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
def bson_id(value)
|
|
297
|
-
return value unless defined?(BSON::ObjectId)
|
|
298
|
-
return value if value.is_a?(BSON::ObjectId)
|
|
299
|
-
|
|
300
|
-
BSON::ObjectId.from_string(value.to_s)
|
|
301
|
-
rescue
|
|
302
|
-
value
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
def generated_id
|
|
306
|
-
generator = options.advanced.dig(:database, :generate_id)
|
|
307
|
-
return generator.call.to_s if generator.respond_to?(:call)
|
|
308
|
-
return SecureRandom.uuid if generator == "uuid"
|
|
309
|
-
return BSON::ObjectId.new.to_s if defined?(BSON::ObjectId)
|
|
310
|
-
|
|
311
|
-
SecureRandom.hex(12)
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
def custom_id_generator?
|
|
315
|
-
options.advanced.dig(:database, :generate_id).respond_to?(:call)
|
|
316
|
-
end
|
|
317
|
-
|
|
318
|
-
def resolve_default(default)
|
|
319
|
-
default.respond_to?(:call) ? default.call : default
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
def coerce_value(value, attributes)
|
|
323
|
-
return value if value.nil?
|
|
324
|
-
return Time.parse(value) if attributes[:type] == "date" && value.is_a?(String)
|
|
325
|
-
|
|
326
|
-
value
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
def session_options
|
|
330
|
-
@session ? {session: @session} : {}
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
def document_key?(document, key)
|
|
334
|
-
document.key?(key) || document.key?(key.to_sym)
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
def fetch_document(document, key)
|
|
338
|
-
return document[key] if document.key?(key)
|
|
339
|
-
|
|
340
|
-
document[key.to_sym]
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
def stringify_keys(data)
|
|
344
|
-
data.each_with_object({}) do |(key, value), result|
|
|
345
|
-
result[Schema.storage_key(key)] = value
|
|
346
|
-
end
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
def fetch_key(hash, key)
|
|
350
|
-
hash[key] || hash[key.to_s] || hash[Schema.storage_key(key)] || hash[Schema.storage_key(key).to_sym]
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
def schema_for(model)
|
|
354
|
-
Schema.auth_tables(options).fetch(model.to_s)
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
def storage_field(model, field)
|
|
358
|
-
schema_for(model).fetch(:fields).fetch(field.to_s).fetch(:field_name, physical_name(field))
|
|
359
|
-
end
|
|
360
|
-
|
|
361
|
-
def physical_name(value)
|
|
362
|
-
value.to_s
|
|
363
|
-
.gsub(/([a-z\d])([A-Z])/, "\\1_\\2")
|
|
364
|
-
.tr("-", "_")
|
|
365
|
-
.downcase
|
|
366
|
-
end
|
|
367
|
-
end
|
|
368
|
-
end
|
|
8
|
+
raise LoadError, "BetterAuth::Adapters::MongoDB requires the better_auth-mongo-adapter gem. Add `gem \"better_auth-mongo-adapter\"` and `require \"better_auth/mongo_adapter\"`."
|
|
369
9
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "securerandom"
|
|
4
|
+
require "json"
|
|
4
5
|
require "time"
|
|
5
6
|
|
|
6
7
|
module BetterAuth
|
|
@@ -379,6 +380,7 @@ module BetterAuth
|
|
|
379
380
|
return value ? 1 : 0 if dialect == :sqlite && attributes[:type] == "boolean"
|
|
380
381
|
return value.iso8601(6) if dialect == :sqlite && attributes[:type] == "date" && value.respond_to?(:iso8601)
|
|
381
382
|
return Time.parse(value) if attributes[:type] == "date" && value.is_a?(String)
|
|
383
|
+
return JSON.generate(value) if json_like?(attributes) && !value.is_a?(String)
|
|
382
384
|
|
|
383
385
|
value
|
|
384
386
|
end
|
|
@@ -387,10 +389,21 @@ module BetterAuth
|
|
|
387
389
|
return value if value.nil?
|
|
388
390
|
return coerce_boolean(value) if attributes[:type] == "boolean"
|
|
389
391
|
return Time.parse(value) if attributes[:type] == "date" && value.is_a?(String)
|
|
392
|
+
return parse_json_value(value) if json_like?(attributes) && value.is_a?(String)
|
|
390
393
|
|
|
391
394
|
value
|
|
392
395
|
end
|
|
393
396
|
|
|
397
|
+
def json_like?(attributes)
|
|
398
|
+
%w[json string[] number[]].include?(attributes[:type])
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def parse_json_value(value)
|
|
402
|
+
JSON.parse(value)
|
|
403
|
+
rescue JSON::ParserError
|
|
404
|
+
value
|
|
405
|
+
end
|
|
406
|
+
|
|
394
407
|
def coerce_boolean(value)
|
|
395
408
|
return value if value == true || value == false
|
|
396
409
|
return false if value == 0 || value.to_s == "0" || value.to_s.downcase == "f" || value.to_s.downcase == "false"
|
|
@@ -406,7 +419,10 @@ module BetterAuth
|
|
|
406
419
|
end
|
|
407
420
|
|
|
408
421
|
def fetch_key(hash, key)
|
|
409
|
-
|
|
422
|
+
[key, key.to_s, storage_key(key), storage_key(key).to_sym].each do |candidate|
|
|
423
|
+
return hash[candidate] if hash.key?(candidate)
|
|
424
|
+
end
|
|
425
|
+
nil
|
|
410
426
|
end
|
|
411
427
|
|
|
412
428
|
def storage_key(value)
|
data/lib/better_auth/api.rb
CHANGED
|
@@ -16,7 +16,7 @@ module BetterAuth
|
|
|
16
16
|
input = symbolize_keys(input || {})
|
|
17
17
|
endpoint_context = Endpoint::Context.new(
|
|
18
18
|
path: endpoint.path,
|
|
19
|
-
method: Array(endpoint.methods).first,
|
|
19
|
+
method: input[:method] || Array(endpoint.methods).first,
|
|
20
20
|
query: input[:query] || {},
|
|
21
21
|
body: input[:body] || {},
|
|
22
22
|
params: input[:params] || {},
|
data/lib/better_auth/context.rb
CHANGED
|
@@ -128,8 +128,9 @@ module BetterAuth
|
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
scheme = request.get_header("rack.url_scheme") || request.scheme
|
|
131
|
+
scheme = "https" unless valid_proxy_proto?(scheme.to_s)
|
|
131
132
|
host_header = request.get_header("HTTP_HOST")
|
|
132
|
-
return "#{scheme}://#{host_header}" if host_header &&
|
|
133
|
+
return "#{scheme}://#{host_header}" if host_header && valid_proxy_host?(host_header.to_s)
|
|
133
134
|
|
|
134
135
|
host = request.get_header("SERVER_NAME") || request.host
|
|
135
136
|
port = (request.get_header("SERVER_PORT") || request.port).to_i
|
data/lib/better_auth/plugin.rb
CHANGED
|
@@ -11,6 +11,8 @@ module BetterAuth
|
|
|
11
11
|
:schema,
|
|
12
12
|
:migrations,
|
|
13
13
|
:options,
|
|
14
|
+
:version,
|
|
15
|
+
:client,
|
|
14
16
|
:rate_limit,
|
|
15
17
|
:error_codes,
|
|
16
18
|
:on_request,
|
|
@@ -28,7 +30,8 @@ module BetterAuth
|
|
|
28
30
|
|
|
29
31
|
def initialize(data = {}, **keywords)
|
|
30
32
|
data = data.to_h if data.respond_to?(:to_h) && !data.is_a?(Hash)
|
|
31
|
-
|
|
33
|
+
input = (data || {}).merge(keywords)
|
|
34
|
+
raw = normalize_hash(input)
|
|
32
35
|
|
|
33
36
|
@id = raw[:id].to_s
|
|
34
37
|
@init = raw[:init]
|
|
@@ -38,6 +41,8 @@ module BetterAuth
|
|
|
38
41
|
@schema = raw[:schema] || {}
|
|
39
42
|
@migrations = raw[:migrations] || {}
|
|
40
43
|
@options = raw[:options] || {}
|
|
44
|
+
@version = raw[:version]
|
|
45
|
+
@client = stringify_hash(input[:client] || input["client"])
|
|
41
46
|
@rate_limit = Array(raw[:rate_limit])
|
|
42
47
|
@error_codes = normalize_error_codes(raw)
|
|
43
48
|
@on_request = raw[:on_request]
|
|
@@ -107,6 +112,14 @@ module BetterAuth
|
|
|
107
112
|
end
|
|
108
113
|
end
|
|
109
114
|
|
|
115
|
+
def stringify_hash(value)
|
|
116
|
+
return nil unless value.is_a?(Hash)
|
|
117
|
+
|
|
118
|
+
value.each_with_object({}) do |(key, object), result|
|
|
119
|
+
result[key.to_s] = object.is_a?(Hash) ? stringify_hash(object) : object
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
110
123
|
def normalize_key(key)
|
|
111
124
|
key.to_s
|
|
112
125
|
.delete_prefix("$")
|