Merge pull request #9391 from demarches-simplifiees/remove_api_token_v1_v2_logic

Tech: suppression du code d'authentification des jetons v1 et v2
This commit is contained in:
LeSim 2023-09-20 14:40:09 +00:00 committed by GitHub
commit 39368ab674
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 362 additions and 493 deletions

View file

@ -7,10 +7,10 @@ class Profile::APITokenComponent < ApplicationComponent
private private
def procedures_to_allow_options def procedures_to_allow_options
@api_token.procedures_to_allow.map { ["#{_1.id} #{_1.libelle}", _1.id] } @api_token.targetable_procedures.map { ["#{_1.id} #{_1.libelle}", _1.id] }
end end
def procedures_to_allow_select_options def procedures_to_allow_select_options
{ selected: @api_token.procedures_to_allow.first&.id } { selected: @api_token.targetable_procedures.first&.id }
end end
end end

View file

@ -27,26 +27,27 @@
= t('.allowed_full_access_html') = t('.allowed_full_access_html')
- else - else
%p.fr-text--lg %p.fr-text--lg
= t('.allowed_procedures_html', count: @api_token.allowed_procedures.size) = t('.allowed_procedures_html', count: @api_token.procedures.size)
- if @api_token.allowed_procedures.empty? - if @api_token.procedures.empty?
= button_to t('.action_all'), @api_token, method: :patch, params: { api_token: { disallow_procedure_id: '0' } }, class: "fr-btn fr-btn--secondary" = button_to t('.action_all'), @api_token, method: :patch, params: { api_token: { become_full_access: '1' } }, class: "fr-btn fr-btn--secondary"
- else - else
%ul %ul
- @api_token.allowed_procedures.each do |procedure| - @api_token.procedures.each do |procedure|
%li.flex.justify-between.align-center %li.flex.justify-between.align-center
.truncate-80 .truncate-80
= "#{procedure.id} #{procedure.libelle}" = "#{procedure.id} #{procedure.libelle}"
= button_to t('.delete'), @api_token, method: :patch, params: { api_token: { disallow_procedure_id: procedure.id } }, class: "fr-btn fr-btn--secondary" = button_to t('.delete'), @api_token, method: :patch, params: { api_token: { disallow_procedure_id: procedure.id } }, class: "fr-btn fr-btn--secondary"
.fr-card__end .fr-card__end
= form_for @api_token, namespace: dom_id(@api_token, :allowed_procedures), html: { class: 'form form-ds-fr-white mb-3', data: { turbo: true } } do |f| = form_for @api_token, namespace: dom_id(@api_token, :allowed_procedures), html: { class: 'mb-3', data: { turbo: true } } do |f|
= f.label :allowed_procedure_ids do = f.label :allowed_procedure_ids, class: 'fr-label' do
= t('.action_choice') = t('.action_choice')
- @api_token.allowed_procedures.each do |procedure| - if !@api_token.full_access?
= f.hidden_field :allowed_procedure_ids, value: procedure.id, multiple: true, id: dom_id(procedure, :allowed_procedure) - @api_token.procedures.each do |procedure|
= f.hidden_field :allowed_procedure_ids, value: procedure.id, multiple: true, id: dom_id(procedure, :allowed_procedure)
.flex.justify-between.align-center{ 'data-turbo-force': :server } .flex.justify-between.align-center{ 'data-turbo-force': :server }
= f.select :allowed_procedure_ids, procedures_to_allow_options, {prompt: t('.prompt_choose_procedure')}, { class: 'no-margin width-66 small', name: "api_token[allowed_procedure_ids][]" } = f.select :allowed_procedure_ids, procedures_to_allow_options, {prompt: t('.prompt_choose_procedure')}, { class: 'fr-select ', name: "api_token[allowed_procedure_ids][]" }
= f.button type: :submit, class: "fr-btn fr-btn--secondary" do = f.button type: :submit, class: "fr-btn fr-btn--secondary" do
= t('.add') = t('.add')

View file

@ -1,5 +1,6 @@
class API::V1::DossiersController < APIController class API::V1::DossiersController < APIController
before_action :fetch_procedure_and_check_token before_action :check_api_token
before_action :fetch_dossiers
DEFAULT_PAGE_SIZE = 100 DEFAULT_PAGE_SIZE = 100
MAX_PAGE_SIZE = 1000 MAX_PAGE_SIZE = 1000
@ -8,19 +9,17 @@ class API::V1::DossiersController < APIController
def index def index
dossiers = @dossiers.page(params[:page]).per(per_page) dossiers = @dossiers.page(params[:page]).per(per_page)
render json: { dossiers: dossiers.map { |dossier| DossiersSerializer.new(dossier) }, pagination: pagination(dossiers) }, status: 200 render json: { dossiers: dossiers.map { |dossier| DossiersSerializer.new(dossier) }, pagination: pagination(dossiers) }
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render json: {}, status: 404 render json: {}, status: :not_found
end end
def show def show
dossier = @dossiers.for_api.find(params[:id]) dossier = @dossiers.for_api.find(params[:id])
respond_to do |format| render json: { dossier: DossierSerializer.new(dossier).as_json }
format.json { render json: { dossier: DossierSerializer.new(dossier).as_json }, status: 200 }
end
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render json: {}, status: 404 render json: {}, status: :not_found
end end
private private
@ -42,24 +41,15 @@ class API::V1::DossiersController < APIController
end end
end end
def fetch_procedure_and_check_token def fetch_dossiers
@procedure = Procedure.for_api.find(params[:procedure_id]) procedure = @api_token.procedures.find(params[:procedure_id])
administrateur = find_administrateur_for_token(@procedure) order = ORDER_DIRECTIONS.fetch(params[:order], :asc)
if administrateur.nil? @dossiers = procedure
render json: {}, status: :unauthorized .dossiers
else .visible_by_administration
# allow BaseController append_info_to_payload .order_by_created_at(order)
# to log info on current_user
@current_user = administrateur.user
order = ORDER_DIRECTIONS.fetch(params[:order], :asc)
@dossiers = @procedure
.dossiers
.visible_by_administration
.order_by_created_at(order)
end
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render json: {}, status: :not_found render json: {}, status: :not_found
end end

View file

@ -1,5 +1,6 @@
class API::V1::ProceduresController < APIController class API::V1::ProceduresController < APIController
before_action :fetch_procedure_and_check_token before_action :check_api_token
before_action :fetch_procedure
def show def show
render json: { procedure: ProcedureSerializer.new(@procedure).as_json } render json: { procedure: ProcedureSerializer.new(@procedure).as_json }
@ -7,17 +8,9 @@ class API::V1::ProceduresController < APIController
private private
def fetch_procedure_and_check_token def fetch_procedure
@procedure = Procedure.for_api.find(params[:id]) @procedure = @api_token.procedures.for_api.find(params[:id])
administrateur = find_administrateur_for_token(@procedure)
if administrateur.nil?
render json: {}, status: :unauthorized
else
# allow BaseController append_info_to_payload
# to log info on current_user
@current_user = administrateur.user
end
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render json: {}, status: :not_found render json: {}, status: :not_found
end end

View file

@ -1,58 +1,45 @@
class API::V2::BaseController < ApplicationController class API::V2::BaseController < ApplicationController
# Disable forgery protection for API controllers when the request is authenticated skip_forgery_protection if: -> { request.headers.key?('HTTP_AUTHORIZATION') }
# with a bearer token. Otherwise the session will be nullified and we'll lose curent_user
protect_from_forgery with: :null_session, unless: :token?
skip_before_action :setup_tracking skip_before_action :setup_tracking
prepend_before_action :authenticate_administrateur_from_token before_action :authenticate_from_token
private private
def context def context
# new token if @api_token.present?
if api_token.present? @api_token.context
api_token.context
# web interface (/graphql) give current_administrateur # web interface (/graphql) give current_administrateur
elsif current_administrateur.present? elsif current_administrateur.present?
{ graphql_web_interface_context
administrateur_id: current_administrateur.id,
procedure_ids: current_administrateur.procedure_ids,
write_access: true
}
# old token
else else
{ unauthenticated_request_context
token: authorization_bearer_token,
write_access: true
}
end end
end end
def token? private
authorization_bearer_token.present?
def graphql_web_interface_context
{
administrateur_id: current_administrateur.id,
procedure_ids: current_administrateur.procedure_ids,
write_access: true
}
end end
def authenticate_administrateur_from_token def unauthenticated_request_context
if api_token.present? {
@current_user = api_token.administrateur.user administrateur_id: nil,
end procedure_ids: [],
write_access: false
}
end end
def api_token def authenticate_from_token
if @api_token.nil? @api_token = authenticate_with_http_token { |t, _o| APIToken.authenticate(t) }
@api_token = APIToken
.find_and_verify(authorization_bearer_token)
&.tap { _1.touch(:last_v2_authenticated_at) } || false
end
@api_token
end
def authorization_bearer_token if @api_token.present?
@authorization_bearer_token ||= begin @api_token.touch(:last_v2_authenticated_at)
received_token = nil @current_user = @api_token.administrateur.user
authenticate_with_http_token do |token, _options|
received_token = token
end
received_token
end end
end end
end end

View file

@ -1,15 +1,6 @@
class APIController < ApplicationController class APIController < ApplicationController
before_action :default_format_json before_action :default_format_json
before_action :authenticate_from_token
protected
def find_administrateur_for_token(procedure)
api_token = APIToken.find_and_verify(authorization_bearer_token, procedure.administrateurs)
if api_token.present? && api_token.context.fetch(:procedure_ids).include?(procedure.id)
api_token.touch(:last_v1_authenticated_at)
api_token.administrateur
end
end
private private
@ -17,19 +8,24 @@ class APIController < ApplicationController
request.format = "json" if !request.params[:format] request.format = "json" if !request.params[:format]
end end
def authorization_bearer_token def check_api_token
params_token.presence || header_token if @api_token.nil?
end render json: {}, status: :unauthorized
def header_token
received_token = nil
authenticate_with_http_token do |token, _options|
received_token = token
end end
received_token
end end
def params_token def authenticate_from_token
params[:token] @api_token = authenticate_with_http_token { |t, _o| APIToken.authenticate(t) }
# legacy way of sending the token by url
# not available in api v2
if @api_token.nil?
@api_token = APIToken.authenticate(params[:token])
end
if @api_token.present?
@api_token.touch(:last_v1_authenticated_at)
@current_user = @api_token.administrateur.user
end
end end
end end

View file

@ -1,44 +1,46 @@
class APITokensController < ApplicationController class APITokensController < ApplicationController
before_action :authenticate_administrateur! before_action :authenticate_administrateur!
before_action :set_api_token, only: [:update, :destroy]
def create def create
@api_token, @packed_token = APIToken.generate(current_administrateur) @api_token, @packed_token = APIToken.generate(current_administrateur)
respond_to do |format| render :index
format.turbo_stream { render :index }
format.html { redirect_back(fallback_location: profil_path) }
end
end end
def update def update
@api_token = current_administrateur.api_tokens.find(params[:id]) if become_full_access?
@api_token.become_full_access!
disallow_procedure_id = api_token_params.fetch(:disallow_procedure_id, nil) elsif disallow_procedure_id.present?
if disallow_procedure_id.present? @api_token.untarget_procedure(disallow_procedure_id.to_i)
@api_token.disallow_procedure(disallow_procedure_id.to_i)
else else
@api_token.update!(api_token_params) @api_token.update!(api_token_params)
end end
respond_to do |format| render :index
format.turbo_stream { render :index }
format.html { redirect_back(fallback_location: profil_path) }
end
end end
def destroy def destroy
@api_token = current_administrateur.api_tokens.find(params[:id])
@api_token.destroy @api_token.destroy
respond_to do |format| render :index
format.turbo_stream { render :index }
format.html { redirect_back(fallback_location: profil_path) }
end
end end
private private
def set_api_token
@api_token = current_administrateur.api_tokens.find(params[:id])
end
def become_full_access?
api_token_params[:become_full_access].present?
end
def disallow_procedure_id
api_token_params[:disallow_procedure_id]
end
def api_token_params def api_token_params
params.require(:api_token).permit(:name, :write_access, :disallow_procedure_id, allowed_procedure_ids: []) params.require(:api_token).permit(:name, :write_access, :become_full_access, :disallow_procedure_id, allowed_procedure_ids: [])
end end
end end

View file

@ -75,20 +75,7 @@ class API::V2::Context < GraphQL::Query::Context
def compute_demarche_authorization(demarche) def compute_demarche_authorization(demarche)
# procedure_ids and token are passed from graphql controller # procedure_ids and token are passed from graphql controller
if self[:procedure_ids].present? self[:procedure_ids].include?(demarche.id)
self[:procedure_ids].include?(demarche.id)
elsif self[:token].present?
token = APIToken.find_and_verify(self[:token], demarche.administrateurs)
if token.present?
token.touch(:last_v2_authenticated_at)
Current.user = token.administrateur.user
true
else
false
end
else
false
end
end end
# This is a query AST visitor that we use to check # This is a query AST visitor that we use to check

View file

@ -2,42 +2,53 @@ class APIToken < ApplicationRecord
include ActiveRecord::SecureToken include ActiveRecord::SecureToken
belongs_to :administrateur, inverse_of: :api_tokens belongs_to :administrateur, inverse_of: :api_tokens
has_many :procedures, through: :administrateur
before_save :check_allowed_procedure_ids_ownership before_save :sanitize_targeted_procedure_ids
def context def context
context = { administrateur_id: administrateur_id, write_access: write_access? } {
administrateur_id:,
procedure_ids:,
write_access:
}
end
def procedure_ids
if full_access? if full_access?
context.merge procedure_ids: administrateur.procedures.ids
else else
context.merge procedure_ids: procedure_ids & allowed_procedure_ids sanitized_targeted_procedure_ids
end end
end end
def procedures
Procedure.where(id: procedure_ids)
end
def full_access? def full_access?
allowed_procedure_ids.nil? targeted_procedure_ids.nil?
end end
def procedures_to_allow def targetable_procedures
procedures.select(:id, :libelle, :path).where.not(id: allowed_procedure_ids || []).order(:libelle) administrateur
.procedures
.where.not(id: targeted_procedure_ids)
.select(:id, :libelle, :path)
.order(:libelle)
end end
def allowed_procedures def untarget_procedure(procedure_id)
if allowed_procedure_ids.present? new_target_ids = targeted_procedure_ids - [procedure_id]
procedures.select(:id, :libelle, :path).where(id: allowed_procedure_ids).order(:libelle)
else update!(allowed_procedure_ids: new_target_ids)
[]
end
end end
def disallow_procedure(procedure_id) def sanitized_targeted_procedure_ids
allowed_procedure_ids = allowed_procedures.map(&:id) - [procedure_id] administrateur.procedures.ids.intersection(targeted_procedure_ids || [])
if allowed_procedure_ids.empty? end
allowed_procedure_ids = nil
end def become_full_access!
update!(allowed_procedure_ids:) update_column(:allowed_procedure_ids, nil)
end end
# Prefix is made of the first 6 characters of the uuid base64 encoded # Prefix is made of the first 6 characters of the uuid base64 encoded
@ -51,67 +62,46 @@ class APIToken < ApplicationRecord
plain_token = generate_unique_secure_token plain_token = generate_unique_secure_token
encrypted_token = BCrypt::Password.create(plain_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')) api_token = create!(administrateur:, encrypted_token:, name: Date.today.strftime('Jeton dAPI généré le %d/%m/%Y'))
packed_token = Base64.urlsafe_encode64([api_token.id, plain_token].join(';')) bearer = BearerToken.new(api_token.id, plain_token)
[api_token, packed_token] [api_token, bearer.to_string]
end end
def find_and_verify(maybe_packed_token, administrateurs = []) def authenticate(bearer_string)
token = case unpack(maybe_packed_token) bearer = BearerToken.from_string(bearer_string)
in { plain_token:, id: } # token v3
find_by(id:, version: 3)&.then(&ensure_valid_token(plain_token))
in { plain_token:, administrateur_id: } # token v2
# the migration to the APIToken model set `version: 1` for all the v1 and v2 token
# this is the only place where we can fix the version
where(administrateur_id:, version: 1).update_all(version: 2) # update to v2
find_by(administrateur_id:, version: 2)&.then(&ensure_valid_token(plain_token))
in { plain_token: } # token v1
where(administrateur: administrateurs, version: 1).find(&ensure_valid_token(plain_token))
end
# TODO: return if bearer.nil?
# remove all the not v3 version code
# when everyone has migrated
# it should also be a good place in case we need to feature flag old token use
if token&.version == 3 || Rails.env.test?
token
else
nil
end
end
private api_token = find_by(id: bearer.api_token_id, version: 3)
UUID_SIZE = SecureRandom.uuid.size return if api_token.nil?
def unpack(maybe_packed_token)
case message_verifier.verified(maybe_packed_token)
in [administrateur_id, plain_token]
{ plain_token:, administrateur_id: }
else
case Base64.urlsafe_decode64(maybe_packed_token).split(';')
in [id, plain_token] if id.size == UUID_SIZE # valid format "<uuid>;<random token>"
{ plain_token:, id: }
else
{ plain_token: maybe_packed_token }
end
end
rescue
{ plain_token: maybe_packed_token }
end
def message_verifier BCrypt::Password.new(api_token.encrypted_token) == bearer.plain_token ? api_token : nil
Rails.application.message_verifier('api_v2_token')
end
def ensure_valid_token(plain_token)
-> (api_token) { api_token if BCrypt::Password.new(api_token.encrypted_token) == plain_token }
end end
end end
private private
def check_allowed_procedure_ids_ownership def sanitize_targeted_procedure_ids
if allowed_procedure_ids.present? if targeted_procedure_ids.present?
self.allowed_procedure_ids = allowed_procedures.map(&:id) write_attribute(:allowed_procedure_ids, sanitized_targeted_procedure_ids)
end
end
def targeted_procedure_ids
read_attribute(:allowed_procedure_ids)
end
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 end
end end

View file

@ -34,7 +34,7 @@ describe API::V1::DossiersController do
context 'when procedure does not belong to admin' do context 'when procedure does not belong to admin' do
let(:procedure_id) { wrong_procedure.id } let(:procedure_id) { wrong_procedure.id }
it { expect(subject.code).to eq('401') } it { expect(subject.code).to eq('404') }
end end
context 'when procedure is found and belongs to admin' do context 'when procedure is found and belongs to admin' do
@ -43,28 +43,30 @@ describe API::V1::DossiersController do
let!(:dossier) { Timecop.freeze(date_creation) { create(:dossier, :with_entreprise, :en_construction, procedure: procedure) } } let!(:dossier) { Timecop.freeze(date_creation) { create(:dossier, :with_entreprise, :en_construction, procedure: procedure) } }
let(:body) { JSON.parse(retour.body, symbolize_names: true) } let(:body) { JSON.parse(retour.body, symbolize_names: true) }
it 'return REST code 200', :show_in_doc do it do
expect(retour.code).to eq('200') expect(retour.code).to eq('200')
expect(body).to have_key :pagination
expect(body).to have_key :dossiers
end end
it { expect(body).to have_key :pagination } context 'but the token is invalid' do
let(:token) { 'bad' }
it { expect(body).to have_key :dossiers } it { expect(subject.code).to eq('401') }
end
describe 'pagination' do describe 'pagination' do
subject { body[:pagination] } subject { body[:pagination] }
it { is_expected.to have_key(:page) } it do
it { expect(subject[:page]).to eq(1) } expect(subject[:page]).to eq(1)
it { is_expected.to have_key(:resultats_par_page) } expect(subject[:resultats_par_page]).to eq(described_class.const_get(:DEFAULT_PAGE_SIZE))
it { expect(subject[:resultats_par_page]).to eq(described_class.const_get(:DEFAULT_PAGE_SIZE)) } expect(subject[:nombre_de_page]).to eq(1)
it { is_expected.to have_key(:nombre_de_page) } end
it { expect(subject[:nombre_de_page]).to eq(1) }
end end
describe 'with custom resultats_par_page' do describe 'with custom resultats_par_page' do
let(:retour) { get :index, params: { token: token, procedure_id: procedure_id, resultats_par_page: 18 } } let(:retour) { get :index, params: { token: token, procedure_id: procedure_id, resultats_par_page: 18 } }
subject { body[:pagination] } subject { body[:pagination] }
it { is_expected.to have_key(:resultats_par_page) }
it { expect(subject[:resultats_par_page]).to eq(18) } it { expect(subject[:resultats_par_page]).to eq(18) }
end end
@ -73,11 +75,14 @@ describe API::V1::DossiersController do
it { expect(subject).to be_an(Array) } it { expect(subject).to be_an(Array) }
describe 'dossier' do describe 'dossier' do
subject { super().first } subject { super().first }
it { expect(subject[:id]).to eq(dossier.id) }
it { expect(subject[:updated_at]).to eq("2008-09-01T08:05:00.000Z") } it do
it { expect(subject[:initiated_at]).to eq("2008-09-01T08:06:00.000Z") } expect(subject[:id]).to eq(dossier.id)
it { expect(subject[:state]).to eq("initiated") } expect(subject[:updated_at]).to eq("2008-09-01T08:05:00.000Z")
it { expect(subject.keys.size).to eq(4) } expect(subject[:initiated_at]).to eq("2008-09-01T08:06:00.000Z")
expect(subject[:state]).to eq("initiated")
expect(subject.keys.size).to eq(4)
end
end end
describe 'order' do describe 'order' do
@ -136,7 +141,7 @@ describe API::V1::DossiersController do
context 'when procedure exists and does not belong to current admin' do context 'when procedure exists and does not belong to current admin' do
let(:procedure_id) { wrong_procedure.id } let(:procedure_id) { wrong_procedure.id }
let(:dossier_id) { 1 } let(:dossier_id) { 1 }
it { expect(subject.code).to eq('401') } it { expect(subject.code).to eq('404') }
end end
context 'when procedure is found and belongs to current admin' do context 'when procedure is found and belongs to current admin' do
@ -181,13 +186,14 @@ describe API::V1::DossiersController do
expect(retour.code).to eq('200') expect(retour.code).to eq('200')
end end
it { expect(subject[:id]).to eq(dossier.id) } it do
it { expect(subject[:state]).to eq('closed') } expect(subject[:id]).to eq(dossier.id)
it { expect(subject[:created_at]).to eq('2008-09-01T08:05:00.000Z') } expect(subject[:state]).to eq('closed')
it { expect(subject[:updated_at]).to eq('2008-09-01T08:05:00.000Z') } expect(subject[:created_at]).to eq('2008-09-01T08:05:00.000Z')
it { expect(subject[:archived]).to eq(dossier.archived) } expect(subject[:updated_at]).to eq('2008-09-01T08:05:00.000Z')
expect(subject[:archived]).to eq(dossier.archived)
it { expect(subject.keys).to match_array(field_list) } expect(subject.keys).to match_array(field_list)
end
describe 'entreprise' do describe 'entreprise' do
let(:field_list) { let(:field_list) {
@ -213,17 +219,19 @@ describe API::V1::DossiersController do
} }
subject { super()[:entreprise] } subject { super()[:entreprise] }
it { expect(subject[:siren]).to eq('440117620') } it do
it { expect(subject[:capital_social]).to eq(537_100_000) } expect(subject[:siren]).to eq('440117620')
it { expect(subject[:numero_tva_intracommunautaire]).to eq('FR27440117620') } expect(subject[:capital_social]).to eq(537_100_000)
it { expect(subject[:forme_juridique]).to eq('SA à conseil d\'administration (s.a.i.)') } expect(subject[:numero_tva_intracommunautaire]).to eq('FR27440117620')
it { expect(subject[:forme_juridique_code]).to eq('5599') } expect(subject[:forme_juridique]).to eq('SA à conseil d\'administration (s.a.i.)')
it { expect(subject[:nom_commercial]).to eq('GRTGAZ') } expect(subject[:forme_juridique_code]).to eq('5599')
it { expect(subject[:raison_sociale]).to eq('GRTGAZ') } expect(subject[:nom_commercial]).to eq('GRTGAZ')
it { expect(subject[:siret_siege_social]).to eq('44011762001530') } expect(subject[:raison_sociale]).to eq('GRTGAZ')
it { expect(subject[:code_effectif_entreprise]).to eq('51') } expect(subject[:siret_siege_social]).to eq('44011762001530')
it { expect(subject[:date_creation]).to eq('1990-04-24T00:00:00.000+00:00') } expect(subject[:code_effectif_entreprise]).to eq('51')
it { expect(subject.keys).to match_array(field_list) } expect(subject[:date_creation]).to eq('1990-04-24T00:00:00.000+00:00')
expect(subject.keys).to match_array(field_list)
end
end end
describe 'champs' do describe 'champs' do
@ -250,11 +258,13 @@ describe API::V1::DossiersController do
} }
subject { super()[:type_de_champ] } subject { super()[:type_de_champ] }
it { expect(subject.key?(:id)).to be_truthy } it do
it { expect(subject[:libelle]).to include('Libelle du champ') } expect(subject.key?(:id)).to be_truthy
it { expect(subject[:description]).to include('description du champ') } expect(subject[:libelle]).to include('Libelle du champ')
it { expect(subject.key?(:order_place)).to be_truthy } expect(subject[:description]).to include('description du champ')
it { expect(subject[:type_champ]).to eq('text') } expect(subject.key?(:order_place)).to be_truthy
expect(subject[:type_champ]).to eq('text')
end
end end
end end
@ -310,11 +320,13 @@ describe API::V1::DossiersController do
} }
subject { super()[:type_de_champ] } subject { super()[:type_de_champ] }
it { expect(subject.key?(:id)).to be_truthy } it do
it { expect(subject[:libelle]).to include('Libelle champ privé') } expect(subject.key?(:id)).to be_truthy
it { expect(subject[:description]).to include('description du champ privé') } expect(subject[:libelle]).to include('Libelle champ privé')
it { expect(subject.key?(:order_place)).to be_truthy } expect(subject[:description]).to include('description du champ privé')
it { expect(subject[:type_champ]).to eq('text') } expect(subject.key?(:order_place)).to be_truthy
expect(subject[:type_champ]).to eq('text')
end
end end
end end
end end
@ -325,11 +337,12 @@ describe API::V1::DossiersController do
subject { super()[:commentaires] } subject { super()[:commentaires] }
it { expect(subject.size).to eq 2 } it do
expect(subject.size).to eq 2
it { expect(subject.first[:body]).to eq 'plop' } expect(subject.first[:body]).to eq 'plop'
it { expect(subject.first[:created_at]).to eq '2016-03-14T13:00:00.000Z' } expect(subject.first[:created_at]).to eq '2016-03-14T13:00:00.000Z'
it { expect(subject.first[:email]).to eq 'plop@plip.com' } expect(subject.first[:email]).to eq 'plop@plip.com'
end
end end
describe 'avis' do describe 'avis' do
@ -359,19 +372,21 @@ describe API::V1::DossiersController do
} }
subject { super()[:etablissement] } subject { super()[:etablissement] }
it { expect(subject[:siret]).to eq('44011762001530') } it do
it { expect(subject[:siege_social]).to eq(true) } expect(subject[:siret]).to eq('44011762001530')
it { expect(subject[:naf]).to eq('4950Z') } expect(subject[:siege_social]).to eq(true)
it { expect(subject[:libelle_naf]).to eq('Transports par conduites') } expect(subject[:naf]).to eq('4950Z')
it { expect(subject[:adresse]).to eq("GRTGAZ\r IMMEUBLE BORA\r 6 RUE RAOUL NORDLING\r 92270 BOIS COLOMBES\r") } expect(subject[:libelle_naf]).to eq('Transports par conduites')
it { expect(subject[:numero_voie]).to eq('6') } expect(subject[:adresse]).to eq("GRTGAZ\r IMMEUBLE BORA\r 6 RUE RAOUL NORDLING\r 92270 BOIS COLOMBES\r")
it { expect(subject[:type_voie]).to eq('RUE') } expect(subject[:numero_voie]).to eq('6')
it { expect(subject[:nom_voie]).to eq('RAOUL NORDLING') } expect(subject[:type_voie]).to eq('RUE')
it { expect(subject[:complement_adresse]).to eq('IMMEUBLE BORA') } expect(subject[:nom_voie]).to eq('RAOUL NORDLING')
it { expect(subject[:code_postal]).to eq('92270') } expect(subject[:complement_adresse]).to eq('IMMEUBLE BORA')
it { expect(subject[:localite]).to eq('BOIS COLOMBES') } expect(subject[:code_postal]).to eq('92270')
it { expect(subject[:code_insee_localite]).to eq('92009') } expect(subject[:localite]).to eq('BOIS COLOMBES')
it { expect(subject.keys).to match_array(field_list) } expect(subject[:code_insee_localite]).to eq('92009')
expect(subject.keys).to match_array(field_list)
end
end end
end end
end end

View file

@ -16,6 +16,13 @@ describe API::V1::ProceduresController, type: :controller do
context 'when procedure belongs to administrateur without token' do context 'when procedure belongs to administrateur without token' do
let(:procedure_id) { create(:procedure).id } let(:procedure_id) { create(:procedure).id }
it { is_expected.to have_http_status(404) }
end
context 'when procedure exist but bad token' do
let(:token) { 'bad' }
let(:procedure_id) { create(:procedure, administrateur: admin).id }
it { is_expected.to have_http_status(401) } it { is_expected.to have_http_status(401) }
end end
@ -30,25 +37,29 @@ describe API::V1::ProceduresController, type: :controller do
subject { JSON.parse(response.body, symbolize_names: true)[:procedure] } subject { JSON.parse(response.body, symbolize_names: true)[:procedure] }
it { expect(subject[:id]).to eq(procedure.id) } it do
it { expect(subject[:label]).to eq(procedure.libelle) } expect(subject[:id]).to eq(procedure.id)
it { expect(subject[:description]).to eq(procedure.description) } expect(subject[:label]).to eq(procedure.libelle)
it { expect(subject[:organisation]).to eq(procedure.organisation) } expect(subject[:description]).to eq(procedure.description)
it { expect(subject[:archived_at]).to eq(procedure.closed_at) } expect(subject[:organisation]).to eq(procedure.organisation)
it { expect(subject[:direction]).to eq("") } expect(subject[:archived_at]).to eq(procedure.closed_at)
it { expect(subject[:total_dossier]).to eq(procedure.total_dossier) } expect(subject[:direction]).to eq("")
it { is_expected.to have_key(:types_de_champ) } expect(subject[:total_dossier]).to eq(procedure.total_dossier)
it { expect(subject[:types_de_champ]).to be_an(Array) } is_expected.to have_key(:types_de_champ)
expect(subject[:types_de_champ]).to be_an(Array)
end
describe 'type_de_champ' do describe 'type_de_champ' do
subject { super()[:types_de_champ][0] } subject { super()[:types_de_champ][0] }
let(:champ) { procedure.active_revision.types_de_champ_public.first } let(:champ) { procedure.active_revision.types_de_champ_public.first }
it { expect(subject[:id]).to eq(champ.id) } it do
it { expect(subject[:libelle]).to eq(champ.libelle) } expect(subject[:id]).to eq(champ.id)
it { expect(subject[:type_champ]).to eq(champ.type_champ) } expect(subject[:libelle]).to eq(champ.libelle)
it { expect(subject[:description]).to eq(champ.description) } expect(subject[:type_champ]).to eq(champ.type_champ)
expect(subject[:description]).to eq(champ.description)
end
end end
describe 'service' do describe 'service' do
@ -56,14 +67,16 @@ describe API::V1::ProceduresController, type: :controller do
let(:service) { procedure.service } let(:service) { procedure.service }
it { expect(subject[:id]).to eq(service.id) } it do
it { expect(subject[:email]).to eq(service.email) } expect(subject[:id]).to eq(service.id)
it { expect(subject[:name]).to eq(service.nom) } expect(subject[:email]).to eq(service.email)
it { expect(subject[:type_organization]).to eq(service.type_organisme) } expect(subject[:name]).to eq(service.nom)
it { expect(subject[:organization]).to eq(service.organisme) } expect(subject[:type_organization]).to eq(service.type_organisme)
it { expect(subject[:phone]).to eq(service.telephone) } expect(subject[:organization]).to eq(service.organisme)
it { expect(subject[:schedule]).to eq(service.horaires) } expect(subject[:phone]).to eq(service.telephone)
it { expect(subject[:address]).to eq(service.adresse) } expect(subject[:schedule]).to eq(service.horaires)
expect(subject[:address]).to eq(service.adresse)
end
end end
end end
end end

View file

@ -3,7 +3,6 @@ describe API::V2::GraphqlController do
let(:generated_token) { APIToken.generate(admin) } let(:generated_token) { APIToken.generate(admin) }
let(:api_token) { generated_token.first } let(:api_token) { generated_token.first }
let(:token) { generated_token.second } let(:token) { generated_token.second }
let(:legacy_token) { APIToken.send(:unpack, token)[:plain_token] }
let(:procedure) { create(:procedure, :published, :for_individual, :with_service, administrateurs: [admin]) } let(:procedure) { create(:procedure, :published, :for_individual, :with_service, administrateurs: [admin]) }
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) } let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
let(:dossier1) { create(:dossier, :en_construction, :with_individual, procedure: procedure, en_construction_at: 1.day.ago) } let(:dossier1) { create(:dossier, :en_construction, :with_individual, procedure: procedure, en_construction_at: 1.day.ago) }
@ -113,20 +112,6 @@ describe API::V2::GraphqlController do
subject { post :execute, params: { query: query, variables: variables, operationName: operation_name, queryId: query_id }.compact, as: :json } subject { post :execute, params: { query: query, variables: variables, operationName: operation_name, queryId: query_id }.compact, as: :json }
context "when authenticated with legacy token" do
let(:authorization_header) { ActionController::HttpAuthentication::Token.encode_credentials(legacy_token) }
before do
request.env['HTTP_AUTHORIZATION'] = authorization_header
admin.api_tokens.first.update(version: 1)
end
it "returns the demarche" do
expect(gql_errors).to eq(nil)
expect(gql_data[:demarche][:id]).to eq(procedure.to_typed_id)
end
end
context "when authenticated" do context "when authenticated" do
let(:authorization_header) { ActionController::HttpAuthentication::Token.encode_credentials(token) } let(:authorization_header) { ActionController::HttpAuthentication::Token.encode_credentials(token) }
@ -164,18 +149,6 @@ describe API::V2::GraphqlController do
expect(gql_errors.first[:message]).to eq("An object of type Demarche was hidden due to permissions") expect(gql_errors.first[:message]).to eq("An object of type Demarche was hidden due to permissions")
} }
end end
context 'v2' do
let(:token) { APIToken.send(:message_verifier).generate([another_administrateur.id, plain_token]) }
it {
expect(gql_errors.first[:message]).to eq("An object of type Demarche was hidden due to permissions")
}
end
context 'v1' do
let(:token) { plain_token }
it {
expect(gql_errors.first[:message]).to eq("An object of type Demarche was hidden due to permissions")
}
end
end end
context "when the token is revoked" do context "when the token is revoked" do
@ -1499,13 +1472,15 @@ describe API::V2::GraphqlController do
message { message {
body body
} }
errors {
message
}
} }
}" }"
end end
it "should return error" do it "should return error" do
expect(gql_data[:dossierEnvoyerMessage]).to eq(nil) expect(gql_data[:dossierEnvoyerMessage][:errors].first[:message]).to eq("Le jeton utilisé est configuré seulement en lecture")
expect(gql_errors).not_to eq(nil)
end end
end end
end end

View file

@ -1,36 +1,41 @@
describe APIController, type: :controller do describe APIController, type: :controller do
describe 'valid_token_for_procedure?' do describe 'authenticate_from_token' do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure) }
let(:admin) { procedure.administrateurs.first } let(:admin) { procedure.administrateurs.first }
subject { !!controller.send(:find_administrateur_for_token, procedure) } subject do
controller.send(:authenticate_from_token)
assigns(:api_token)
end
context 'when the admin has not any token' do context 'when the admin has not any token' do
context 'and the token is not given' do context 'and the token is not given' do
it { is_expected.to be false } it { is_expected.to be nil }
end end
end end
context 'when the admin has a token' do context 'when the admin has a token' do
let!(:token) { APIToken.generate(admin)[1] } let(:token_bearer_couple) { APIToken.generate(admin) }
let(:token) { token_bearer_couple[0] }
let(:bearer) { token_bearer_couple[1] }
context 'and the token is given by params' do context 'and the token is given by params' do
before { controller.params[:token] = token } before { controller.params[:token] = bearer }
it { is_expected.to be true } it { is_expected.to eq(token) }
end end
context 'and the token is given by header' do context 'and the token is given by header' do
before do before do
valid_headers = { 'Authorization' => "Bearer token=#{token}" } valid_headers = { 'Authorization' => "Bearer token=#{bearer}" }
request.headers.merge!(valid_headers) request.headers.merge!(valid_headers)
end end
it { is_expected.to be true } it { is_expected.to eq(token) }
end end
context 'and the token is not given' do context 'and the token is not given' do
it { is_expected.to be false } it { is_expected.to be nil }
end end
end end
end end

View file

@ -1,245 +1,160 @@
describe APIToken, type: :model do describe APIToken, type: :model do
let(:administrateur) { create(:administrateur) } let(:administrateur) { create(:administrateur) }
let(:api_token_and_packed_token) { APIToken.generate(administrateur) }
let(:api_token) { api_token_and_packed_token.first }
let(:packed_token) { api_token_and_packed_token.second }
let(:plain_token) { APIToken.send(:unpack, packed_token)[:plain_token] }
let(:packed_token_v2) { APIToken.send(:message_verifier).generate([administrateur.id, plain_token]) }
describe '#generate' do describe '#generate' do
it do let(:api_token_and_packed_token) { APIToken.generate(administrateur) }
let(:api_token) { api_token_and_packed_token.first }
let(:packed_token) { api_token_and_packed_token.second }
before { api_token_and_packed_token }
it 'with a full access token' do
expect(api_token.administrateur).to eq(administrateur) expect(api_token.administrateur).to eq(administrateur)
expect(api_token.prefix).to eq(packed_token.slice(0, 5)) expect(api_token.prefix).to eq(packed_token.slice(0, 5))
expect(api_token.version).to eq(3) expect(api_token.version).to eq(3)
expect(api_token.write_access?).to eq(true) expect(api_token.write_access?).to eq(true)
expect(api_token.procedure_ids).to eq([]) expect(api_token.procedure_ids).to eq([])
expect(api_token.allowed_procedure_ids).to eq(nil)
expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: true) expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: true)
expect(api_token.full_access?).to be_truthy expect(api_token.full_access?).to be_truthy
end end
context 'with read_only' do context 'updated read_only' do
before { api_token.update(write_access: false) } before { api_token.update(write_access: false) }
it do it do
expect(api_token.full_access?).to be_truthy
expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: false) expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: false)
end end
end end
context 'with procedure' do context 'with a new added procedure' do
let(:procedure) { create(:procedure, administrateurs: [administrateur]) } let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
before { procedure }
before do
procedure
api_token.reload
end
it do it do
expect(api_token.full_access?).to be_truthy
expect(api_token.procedure_ids).to eq([procedure.id]) expect(api_token.procedure_ids).to eq([procedure.id])
expect(api_token.procedures_to_allow).to eq([procedure]) expect(api_token.procedures).to eq([procedure])
expect(api_token.allowed_procedure_ids).to eq(nil)
expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [procedure.id], write_access: true) expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [procedure.id], write_access: true)
end end
context 'update with procedure_id' do context 'and another procedure, but access only to the first one' do
let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
let(:other_procedure) { create(:procedure, administrateurs: [administrateur]) } let(:other_procedure) { create(:procedure, administrateurs: [administrateur]) }
before { api_token.update(allowed_procedure_ids: [procedure.id]); other_procedure }
before do
other_procedure
api_token.update(allowed_procedure_ids: [procedure.id])
api_token.reload
end
it do it do
expect(api_token.procedure_ids).to match_array([procedure.id, other_procedure.id]) expect(api_token.full_access?).to be_falsey
expect(api_token.procedures_to_allow).to eq([other_procedure]) expect(api_token.procedure_ids).to match_array([procedure.id])
expect(api_token.allowed_procedure_ids).to eq([procedure.id]) expect(api_token.targetable_procedures).to eq([other_procedure])
expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [procedure.id], write_access: true) expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [procedure.id], write_access: true)
end end
context 'and then gain full access' do
before do
api_token.become_full_access!
api_token.reload
end
it do
expect(api_token.full_access?).to be(true)
expect(api_token.procedure_ids).to match_array([procedure.id, other_procedure.id])
expect(api_token.targetable_procedures).to eq([procedure, other_procedure])
end
end
end end
context 'update with wrong procedure_id' do context 'but acces to a wrong procedure_id' do
let(:other_administrateur) { create(:administrateur) } let(:forbidden_procedure) { create(:procedure) }
let(:procedure) { create(:procedure, administrateurs: [other_administrateur]) }
before { api_token.update(allowed_procedure_ids: [procedure.id]) } before do
api_token.update(allowed_procedure_ids: [forbidden_procedure.id])
api_token.reload
end
it do it do
expect(api_token.full_access?).to be_falsey expect(api_token.full_access?).to be_falsey
expect(api_token.procedure_ids).to eq([]) expect(api_token.procedure_ids).to eq([])
expect(api_token.procedures_to_allow).to eq([]) expect(api_token.targetable_procedures).to eq([procedure])
expect(api_token.allowed_procedure_ids).to eq([])
expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: true) expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: true)
end end
end end
context 'update with destroyed procedure_id' do context 'update with destroyed procedure_id' do
let(:procedure) { create(:procedure, administrateurs: [administrateur]) } let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
before { api_token.update(allowed_procedure_ids: [procedure.id]); procedure.destroy }
before do
api_token.update(allowed_procedure_ids: [procedure.id])
procedure.destroy
api_token.reload
end
it do it do
expect(api_token.full_access?).to be_falsey expect(api_token.full_access?).to be_falsey
expect(api_token.procedure_ids).to eq([]) expect(api_token.procedure_ids).to eq([])
expect(api_token.procedures_to_allow).to eq([]) expect(api_token.targetable_procedures).to eq([])
expect(api_token.allowed_procedure_ids).to eq([procedure.id])
expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: true) expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: true)
end end
end end
context 'update with detached procedure_id' do context 'update with detached procedure_id' do
let(:other_procedure) { create(:procedure, administrateurs: [administrateur]) }
let(:procedure) { create(:procedure, administrateurs: [administrateur]) } let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
before { api_token.update(allowed_procedure_ids: [procedure.id]); other_procedure; administrateur.procedures.delete(procedure) } let(:other_procedure) { create(:procedure, administrateurs: [administrateur]) }
before do
api_token.update(allowed_procedure_ids: [procedure.id])
other_procedure
administrateur.procedures.delete(procedure)
api_token.reload
end
it do it do
expect(api_token.full_access?).to be_falsey expect(api_token.full_access?).to be_falsey
expect(api_token.procedure_ids).to eq([other_procedure.id]) expect(api_token.procedure_ids).to eq([])
expect(api_token.allowed_procedure_ids).to eq([procedure.id]) expect(api_token.targetable_procedures).to eq([other_procedure])
expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: true) expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [], write_access: true)
end end
end end
end end
context 'with procedure and allowed_procedure_ids' do
let(:procedure) { create(:procedure, administrateurs: [administrateur]) }
let(:other_procedure) { create(:procedure, administrateurs: [administrateur]) }
before do
api_token.update(allowed_procedure_ids: [procedure.id])
other_procedure
end
it do
expect(api_token.procedure_ids).to match_array([procedure.id, other_procedure.id])
expect(api_token.allowed_procedure_ids).to eq([procedure.id])
expect(api_token.context).to eq(administrateur_id: administrateur.id, procedure_ids: [procedure.id], write_access: true)
end
end
end end
describe '#find_and_verify' do describe '#authenticate' do
let(:result) { APIToken.find_and_verify(token, administrateurs) } let(:api_token_and_packed_token) { APIToken.generate(administrateur) }
let(:token) { packed_token } let(:api_token) { api_token_and_packed_token.first }
let(:administrateurs) { [administrateur] } let(:packed_token) { api_token_and_packed_token.second }
let(:bearer_token) { packed_token }
context 'without administrateur' do subject { APIToken.authenticate(bearer_token) }
let(:administrateurs) { [] }
context 'with packed token' do context 'with the legit packed token' do
it { expect(result).to be_truthy } it { is_expected.to eq(api_token) }
end
context 'with packed token v2' do
before { api_token.update(version: 2) }
let(:token) { packed_token_v2 }
it { expect(result).to be_truthy }
end
context 'with plain token' do
before { api_token.update(version: 1) }
let(:token) { plain_token }
it { expect(result).to be_falsey }
end
end end
context 'with destroyed token' do context 'with destroyed token' do
before { api_token.destroy } before { api_token.destroy }
context 'with packed token' do it { is_expected.to be_nil }
it { expect(result).to be_falsey }
end
context 'with packed token v2' do
let(:token) { packed_token_v2 }
it { expect(result).to be_falsey }
end
context 'with plain token' do
let(:token) { plain_token }
it { expect(result).to be_falsey }
end
end end
context 'with destroyed administrateur' do context 'with destroyed administrateur' do
before { api_token.administrateur.destroy } before { api_token.administrateur.destroy }
let(:administrateurs) { [] }
context 'with packed token' do it { is_expected.to be_nil }
it { expect(result).to be_falsey }
end
context 'with packed token v2' do
let(:token) { packed_token_v2 }
it { expect(result).to be_falsey }
end
context 'with plain token' do
let(:token) { plain_token }
it { expect(result).to be_falsey }
end
end end
context 'with other administrateur' do context "with a bearer token with the wrong plain_token" do
let(:other_administrateur) { create(:administrateur, :with_api_token) } let(:bearer_token) do
let(:administrateurs) { [other_administrateur] } APIToken::BearerToken.new(api_token.id, 'wrong').to_string
context 'with packed token' do
it { expect(result).to be_truthy }
end end
context 'with packed token v2' do it { is_expected.to be_nil }
before { api_token.update(version: 2) }
let(:token) { packed_token_v2 }
it { expect(result).to be_truthy }
end
context 'with plain token' do
before { api_token.update(version: 1) }
let(:token) { plain_token }
it { expect(result).to be_falsey }
end
end
context 'with many administrateurs' do
let(:other_administrateur) { create(:administrateur, :with_api_token) }
let(:other_api_token_and_packed_token) { APIToken.generate(other_administrateur) }
let(:other_api_token) { other_api_token_and_packed_token.first }
let(:other_packed_token) { other_api_token_and_packed_token.second }
let(:other_plain_token) { APIToken.send(:unpack, other_packed_token)[:plain_token] }
let(:administrateurs) { [administrateur, other_administrateur] }
context 'with plain token' do
before do
api_token.update(version: 1)
other_api_token.update(version: 1)
end
let(:token) { plain_token }
it { expect(result).to be_truthy }
context 'with other plain token' do
let(:token) { other_plain_token }
it { expect(result).to be_truthy }
end
end
end
context 'with packed token' do
it { expect(result).to be_truthy }
end
context 'with packed token v2' do
before { api_token.update(version: 2) }
let(:token) { packed_token_v2 }
it { expect(result).to be_truthy }
end
context 'with plain token' do
before { api_token.update(version: 1) }
let(:token) { plain_token }
it { expect(result).to be_truthy }
end
context "with valid garbage base64" do
before { api_token.update(version: 1, encrypted_token: BCrypt::Password.create(token)) }
let(:token) { "R5dAqE7nMxfMp93PcuuevDtn" }
it { expect(result).to be_truthy }
end end
end end
end end