feature(api): setup securite
This commit is contained in:
parent
8a9e5754a1
commit
943368c68f
5 changed files with 196 additions and 0 deletions
BIN
app/assets/images/spider-128.png
Normal file
BIN
app/assets/images/spider-128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -15,6 +15,9 @@ class APITokensController < ApplicationController
|
|||
.map { |libelle, id| ["#{id} - #{libelle}", id] }
|
||||
end
|
||||
|
||||
def securite
|
||||
end
|
||||
|
||||
def create
|
||||
@api_token, @packed_token = APIToken.generate(current_administrateur)
|
||||
|
||||
|
|
99
app/javascript/controllers/api_token_securite_controller.ts
Normal file
99
app/javascript/controllers/api_token_securite_controller.ts
Normal file
|
@ -0,0 +1,99 @@
|
|||
import { ApplicationController } from './application_controller';
|
||||
|
||||
export class ApiTokenSecuriteController extends ApplicationController {
|
||||
static targets = [
|
||||
'continueButton',
|
||||
'networkFiltering',
|
||||
'infiniteLifetime',
|
||||
'customLifetime',
|
||||
'customLifetimeInput',
|
||||
'networks'
|
||||
];
|
||||
|
||||
declare readonly continueButtonTarget: HTMLButtonElement;
|
||||
declare readonly networkFilteringTarget: HTMLElement;
|
||||
declare readonly infiniteLifetimeTarget: HTMLInputElement;
|
||||
declare readonly customLifetimeTarget: HTMLElement;
|
||||
declare readonly customLifetimeInputTarget: HTMLInputElement;
|
||||
declare readonly networksTarget: HTMLInputElement;
|
||||
|
||||
showNetworkFiltering() {
|
||||
this.networkFilteringTarget.classList.remove('hidden');
|
||||
this.setContinueButtonState();
|
||||
this.infiniteLifetimeTarget.disabled = false;
|
||||
}
|
||||
|
||||
hideNetworkFiltering() {
|
||||
this.networkFilteringTarget.classList.add('hidden');
|
||||
this.setContinueButtonState();
|
||||
this.infiniteLifetimeTarget.checked = false;
|
||||
this.infiniteLifetimeTarget.disabled = true;
|
||||
}
|
||||
|
||||
showCustomLifetime() {
|
||||
this.customLifetimeTarget.classList.remove('hidden');
|
||||
this.setContinueButtonState();
|
||||
}
|
||||
|
||||
hideCustomLifetime() {
|
||||
this.customLifetimeTarget.classList.add('hidden');
|
||||
this.setContinueButtonState();
|
||||
}
|
||||
|
||||
setContinueButtonState() {
|
||||
if (this.networkDefined() && this.lifetimeDefined()) {
|
||||
this.continueButtonTarget.disabled = false;
|
||||
} else {
|
||||
this.continueButtonTarget.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
networkDefined() {
|
||||
if (
|
||||
this.element.querySelectorAll(
|
||||
"[name='networkFiltering'][value='none']:checked"
|
||||
).length > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
this.element.querySelectorAll(
|
||||
"[name='networkFiltering'][value='customNetworks']:checked"
|
||||
).length > 0 &&
|
||||
this.networksTarget.value.trim() != ''
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
lifetimeDefined() {
|
||||
if (
|
||||
this.element.querySelectorAll(
|
||||
"[name='lifetime'][value='oneWeek']:checked"
|
||||
).length > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
this.element.querySelectorAll(
|
||||
"[name='lifetime'][value='infinite']:checked"
|
||||
).length > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
this.element.querySelectorAll("[name='lifetime'][value='custom']:checked")
|
||||
.length > 0 &&
|
||||
this.customLifetimeInputTarget.value.trim() != ''
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
93
app/views/api_tokens/securite.html.haml
Normal file
93
app/views/api_tokens/securite.html.haml
Normal file
|
@ -0,0 +1,93 @@
|
|||
- content_for :title, "Sécurité du jeton « #{@name} »"
|
||||
|
||||
= render partial: 'administrateurs/breadcrumbs',
|
||||
locals: { steps: [['Tableau de bord', tableau_de_bord_helper_path],
|
||||
[t('users.profil.show.profile'), profil_path],
|
||||
[t('api_tokens.nom.new_token')]] }
|
||||
|
||||
.fr-container.fr-mt-2w
|
||||
%h1 Sécurité
|
||||
|
||||
.flex.align-center
|
||||
%div
|
||||
= image_tag("spider-128.png", width: '128px', style: 'display: block;')
|
||||
%div
|
||||
%blockquote{ cite: "https://fr.wikipedia.org/wiki/Un_grand_pouvoir,_grandes_responsabilit%C3%A9s#Utilisation_dans_Spider-Man" }
|
||||
%p « Avec un grand pouvoir vient une grande responsabilité »
|
||||
%p.fr-text--sm Oncle Ben dans Spider-Man
|
||||
|
||||
%p.fr-mt-2w
|
||||
Votre jeton va proprablement vous permettre de manipuler des données confidentielles, voir personnelles.<br />
|
||||
%b Il est de votre responsabilité de le conserver en sécurité et d'en limiter l'utilisation aux seules personnes habilitées.
|
||||
%p Pour vous aider, nous vous proposons des fonctionnalités de filtrage réseau et de durée de vie du jeton.
|
||||
|
||||
= form_with url: api_tokens_path,
|
||||
method: :post,
|
||||
html: { class: 'fr-mt-2w' },
|
||||
data: { controller: 'api-token-securite' } do |f|
|
||||
|
||||
= render Dsfr::RadioButtonListComponent.new(form: f,
|
||||
target: :networkFiltering,
|
||||
buttons: [ { label: 'Je veux spécifier les réseaux autorisées à utiliser mon jeton',
|
||||
value: :customNetworks,
|
||||
'data-action': 'click->api-token-securite#showNetworkFiltering' },
|
||||
{ label: 'Mon jeton peut être utilisé depuis nʼimporte quelle adresse IP dans le monde',
|
||||
hint: 'dangereux',
|
||||
value: :none,
|
||||
'data-action': 'click->api-token-securite#hideNetworkFiltering' }]) do
|
||||
Filtrage réseau :
|
||||
|
||||
.fr-input-group.fr-mb-4w.hidden{ 'data-api-token-securite-target': 'networkFiltering' }
|
||||
= f.label :name, class: 'fr-label' do
|
||||
Entrez les adresses IP autorisées
|
||||
%span.fr-hint-text adresses réseaux séparées par des espaces. Ex: 176.31.79.200 192.168.33.0/24 2001:41d0:304:400::52f/128
|
||||
= f.text_field :networks,
|
||||
class: 'fr-input',
|
||||
autocomplete: 'off',
|
||||
autocapitalize: 'off',
|
||||
autocorrect: 'off',
|
||||
spellcheck: false,
|
||||
'data-action': 'input->api-token-securite#setContinueButtonState'
|
||||
|
||||
= render Dsfr::RadioButtonListComponent.new(form: f,
|
||||
target: :lifetime,
|
||||
buttons: [ { label: '1 semaine',
|
||||
value: :oneWeek,
|
||||
'data-action': 'click->api-token-securite#hideCustomLifetime' },
|
||||
{ label: 'durée personnalisée inférieure à 1 an',
|
||||
value: :custom,
|
||||
'data-action': 'click->api-token-securite#showCustomLifetime'},
|
||||
{ label: 'Infini (le filtrage réseau doit être activé)',
|
||||
value: :infinite,
|
||||
disabled: true,
|
||||
'data-api-token-securite-target': 'infiniteLifetime',
|
||||
'data-action': 'click->api-token-securite#hideCustomLifetime' }]) do
|
||||
Durée de vie du jeton :
|
||||
|
||||
.fr-input-group.fr-mb-4w.hidden{ 'data-api-token-securite-target': 'customLifetime' }
|
||||
= f.label :name, class: 'fr-label' do
|
||||
Entrez la date de fin de validité du jeton
|
||||
|
||||
%input{ type: 'date',
|
||||
class: 'fr-input width-33 fr-mb-4w',
|
||||
name: 'customLifetime',
|
||||
'data-action': 'input->api-token-securite#setContinueButtonState',
|
||||
'data-api-token-securite-target': 'customLifetimeInput',
|
||||
min: Date.tomorrow.iso8601,
|
||||
max: 1.year.from_now.to_date.iso8601 }
|
||||
|
||||
= f.hidden_field :name, value: params[:name]
|
||||
= f.hidden_field :access, value: params[:access]
|
||||
= f.hidden_field :target, value: params[:target]
|
||||
- params[:targets]&.each do |target|
|
||||
= f.hidden_field 'targets[]', value: target
|
||||
|
||||
%ul.fr-btns-group.fr-btns-group--inline
|
||||
%li
|
||||
= f.button type: :submit,
|
||||
class: "fr-btn fr-btn--primary",
|
||||
disabled: true,
|
||||
'data-api-token-securite-target': 'continueButton' do
|
||||
créer le jeton
|
||||
%li
|
||||
= link_to 'retour', autorisations_api_tokens_path(name: params[:name], access: params[:access], target: params[:target], targets: params[:targets]), class: "fr-btn fr-btn--secondary"
|
|
@ -212,6 +212,7 @@ Rails.application.routes.draw do
|
|||
collection do
|
||||
get :nom
|
||||
get :autorisations
|
||||
get :securite
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue