demarches-normaliennes/app/models/api_token.rb

108 lines
2.6 KiB
Ruby
Raw Normal View History

2022-11-30 10:06:33 +01:00
class APIToken < ApplicationRecord
include ActiveRecord::SecureToken
2022-11-30 10:06:33 +01:00
belongs_to :administrateur, inverse_of: :api_tokens
2023-08-03 17:53:34 +02:00
before_save :sanitize_targeted_procedure_ids
def context
2023-08-03 17:53:34 +02:00
{
administrateur_id:,
procedure_ids:,
write_access:
}
end
2023-08-03 17:53:34 +02:00
def procedure_ids
if full_access?
2023-08-03 17:53:34 +02:00
administrateur.procedures.ids
else
2023-08-03 17:53:34 +02:00
sanitized_targeted_procedure_ids
end
end
2023-08-03 17:53:34 +02:00
def procedures
Procedure.where(id: procedure_ids)
end
def full_access?
2023-08-03 17:53:34 +02:00
targeted_procedure_ids.nil?
end
2023-08-03 17:53:34 +02:00
def targetable_procedures
administrateur
.procedures
.where.not(id: targeted_procedure_ids)
.select(:id, :libelle, :path)
.order(:libelle)
end
2023-08-03 17:53:34 +02:00
def untarget_procedure(procedure_id)
new_target_ids = targeted_procedure_ids - [procedure_id]
update!(allowed_procedure_ids: new_target_ids)
end
2023-08-03 17:53:34 +02:00
def sanitized_targeted_procedure_ids
administrateur.procedures.ids.intersection(targeted_procedure_ids || [])
end
def become_full_access!
update_column(:allowed_procedure_ids, nil)
end
2022-11-30 10:06:33 +01:00
# Prefix is made of the first 6 characters of the uuid base64 encoded
# it does not leak plain token
def prefix
Base64.urlsafe_encode64(id).slice(0, 5)
end
2022-11-30 10:06:33 +01:00
class << self
def generate(administrateur)
plain_token = generate_unique_secure_token
encrypted_token = BCrypt::Password.create(plain_token)
api_token = create!(administrateur:, encrypted_token:, name: Date.today.strftime('Jeton dAPI généré le %d/%m/%Y'))
2023-08-03 12:04:08 +02:00
bearer = BearerToken.new(api_token.id, plain_token)
[api_token, bearer.to_string]
2022-11-30 10:06:33 +01:00
end
2023-08-03 15:27:33 +02:00
def authenticate(bearer_string)
2023-08-03 12:04:08 +02:00
bearer = BearerToken.from_string(bearer_string)
return if bearer.nil?
api_token = find_by(id: bearer.api_token_id, version: 3)
2022-11-30 10:06:33 +01:00
2023-08-03 12:04:08 +02:00
return if api_token.nil?
2022-11-30 10:06:33 +01:00
2023-08-03 12:04:08 +02:00
BCrypt::Password.new(api_token.encrypted_token) == bearer.plain_token ? api_token : nil
2022-11-30 10:06:33 +01:00
end
end
private
2023-08-03 17:53:34 +02:00
def sanitize_targeted_procedure_ids
if targeted_procedure_ids.present?
write_attribute(:allowed_procedure_ids, sanitized_targeted_procedure_ids)
end
end
2023-08-03 12:04:08 +02:00
2023-08-03 17:53:34 +02:00
def targeted_procedure_ids
read_attribute(:allowed_procedure_ids)
end
2023-08-03 12:04:08 +02:00
class BearerToken < Data.define(:api_token_id, :plain_token)
def to_string
Base64.urlsafe_encode64([api_token_id, plain_token].join(';'))
end
def self.from_string(bearer_token)
return if bearer_token.nil?
api_token_id, plain_token = Base64.urlsafe_decode64(bearer_token).split(';')
BearerToken.new(api_token_id, plain_token)
rescue ArgumentError
end
end
end