Elixir: Forgot Password

After having deployed your account management system, you’ll (very) soon discover that a good password is a one time (at least) lost password. The remedy is the now common forgot password feature that you’ll need to add soon because sending new passwords is not safe and you’ll not explain to your customers how to setup GPG.

That’s why the easiest way is to define a process for customers to define new password for their account:
  • The user forgot his password
  • It will fill a form with his account email
  • We need to send to him a temporary route (using a temporary token) that he will use to set a new password
  • Because customers will always surprise you, you’ll need to make them validate their new password to be sure it will not be lost again
  • You can then clean the generated token





So how did we made that using Elixir/Phoenix in our application ? We used an awesome feature of Ecto, the database wrapper library provided with Elixir. It allows you to use a DSL in order to create migrations and SQL queries, thus allowing some features like logging model changes before saving them.

The get in depth knowledges about Ecto you should go check the hex documentation that is very good (one of the few sadly). So Ecto is divided in various submodules but we’re going to see only the ones we use on our project. Ecto.Repo is the tool that allows us to make queries to the datastore. It provides known function like Repo.[all, get, create, update, delete…] that you can use for simple queries. For more complicated ones, you need the Ecto.Query module to join, or subquery resources. The Ecto.Multi module allows you to use transactions to rollback complex queries. The Ecto.Migration allows you to write migrations with up and down functions allowing you to rollback a migration if necessary (feels safer). And Ecto.Changeset allows you to store all changes made to a model and/or validate those changes depending on specified constraints.

So let's see some of these constraints to make sure our customer do not bypass our beautiful authentication system. We define them in our User model as is.


defmodule MyApp.Account.User do
  use Ecto.Schema

  import Ecto.Changeset

  alias MyApp.Account.User

  @primary_key {:id, Ecto.UUID, autogenerate: true}

  @derive {Phoenix.Param, key: :id}

  schema "users" do
    field(:email, :string)

    field(:password, :string)

    field(:password_confirmation, :string, virtual: true)

    field(:token, :string)

    field(:reset_password_token, :string)

    field(:reset_token_sent_at, :utc_datetime)

    many_to_many(
      :roles,
      MyApp.Account.Role,
      join_through: "users_roles",
      on_delete: :delete_all,
      on_replace: :delete,
      unique: true
    )

    timestamps()
  end

  def changeset(%User{} = model, attrs \\ :empty) do
    model
    |> cast(attrs, [
      :email,
      :password,
      :password_confirmation,
      :token,
      :reset_password_token,
      :reset_token_sent_at
    ])
    |> unique_constraint(:email)
    |> validate_format(:email, ~r/@/)
    |> validate_required([:email])
  end

  def reset_password_changeset(%User{} = user, params \\ %{}) do
    user
    |> cast(params, [])
    |> put_reset_token()
  end

  defp put_reset_token(changeset) do
    token = SecureRandom.urlsafe_base64()

    sent_at = DateTime.utc_now()

    case changeset do
      %Ecto.Changeset{valid?: true} ->
        changeset
        |> put_change(:reset_password_token, token)
        |> put_change(:reset_token_sent_at, sent_at)

      _ ->
        changeset
    end
  end

  def update_password_changeset(%User{} = user, params \\ %{}) do
    user
    |> cast(params, [:password, :password_confirmation])
    |> validate_length(:password, min: 5)
    |> validate_required([:password, :password_confirmation])
    |> validate_confirmation(:password)
    |> put_pass_hash()
    |> clear_password_reset_token()
  end

  defp put_pass_hash(changeset) do
    case changeset do
      %Ecto.Changeset{valid?: true, changes: %{password: password}} ->
        put_change(changeset, :password, Comeonin.Bcrypt.hashpwsalt(password))

      _ ->
        changeset
    end
  end

  defp clear_password_reset_token(changeset) do
    case changeset do
      %Ecto.Changeset{valid?: true} ->
        changeset
        |> put_change(:reset_password_token, nil)
        |> put_change(:reset_token_sent_at, nil)

      _ ->
        changeset
    end
  end
end

You can see the default changes function that will cast our attributes and validate the mandatory one like the email format or the uniqueness of the email. Note that we also modified default primary key format for our model. Ecto manage integer id but we wanted UUID, you can find more about this in the documentation.

We also define a reset_password_changeset/2 that will set the :reset_password_token and :reset_token_sent_at fields when the user ask for a new password.

These will allow us to check if the token is not too old and to verify that the provided token is correct to be sure that URL will be called only once.

On the update_password/2 controller function side we’ll just get the user based on his token and email, check that the token is less than one day and call the update_password_changeset/2 to put the new hashed password if the password_confirmation is correct of course.

As you can see, you can add complex constraints, custom constraints, on a unique or on multiple fields and also defined virtual fields that are not in the datastore (check carefully the model definition for password_confirmation) using Eco.Changeset. You can also add an explicit error if necessary using Ecto.Changeset.add_error/3.

The library make your code clean for model validation, but this is just the beginning as we are going to implement a change log system for our defined models thanks to the provided Ecto.Changeset in another post.

If you like the post please add a like or a comment so I can improve it as much as I can.

Open Data : Absentéisme des élus d'Ile de France


Absentéisme des élus d’Ile-de-France

Présentation du problème

Nous souhaitons obtenir la liste des élus d’Ile de France ayant le plus d’absences injustifiées aux assemblées plénières du conseil régional, aux commissions permanentes et aux commissions thématiques sur la période 2016-2018. Pour cela nous nous basons sur les données fournies par la commission d’éthique régionale disponible à l’adresse suivante : https://data.iledefrance.fr/explore/dataset/assiduite-des-elus/information/

Présentation du jeu de données

Nous pouvons voir que les données fournies sont divisées en semestre pour chaque année écoulée de 2016 à 2018. Nous prendrons donc une moyenne des relevés pour ne pas pénaliser nos sujets d’étude. Nous pouvons voir que nous avons également quelques informations complémentaires en plus du Nom et Prénom de l’élu : son affiliation à quel parti politique ainsi que le nombre de réunions.

Méthode

Pour réaliser notre étude nous prendrons donc une moyenne des taux d’absence injustifiée sur 2 ans par semestre. Ce qui nous fait un maximum de 6 valeurs, sachant que certaines valeurs sont manquantes ou que certains élus ont pu être remplacés. Pour obtenir un taux moyen d’absentéisme par candidat. Puis nous trierons par ordre décroissant pour récupérer les 20 premiers résultats de notre étude.



function prepareData() {
  let todraw = [];
  Data.forEach(line => {
    let found = false;
    const name = `${line["Prénom"]} ${line["Nom"]}`
    const absence = line["% absences non justifiées"]
    todraw.forEach(elu => {
      if (elu.name == name) {
        found = true;
        elu.absences = [].concat(elu.absences, absence);
      }
    })
    if (!found) {
      todraw = [].concat(todraw, {
        name: name,
        absences: [absence]
      })
    }
  });

  todraw.sort(function (a, b) {
    if (math.mean(a.absences) > math.mean(b.absences)) {
      return -1;
    }
    else if (math.mean(a.absences) < math.mean(b.absences)) {
      return 1;
    }
    else if (math.mean(a.absences) == math.mean(b.absences)) {
      return 0;
    }
  })
  return todraw.slice(0, 20);
}


Suite à cela nous affichons sur une grille de 0 à 25 (le maximum étant proche de 22%) pour savoir quels sont les élus les plus absents d’Ile-de-France.

Conclusion

Je vous joins le résultat de l’étude pour que vous puissiez faire votre propre conclusion. 



A noter qu’au niveau des partis politiques on note une forte représentation du parti LR (8/20 éléments). Pour rappel les taux sont une moyenne par semestre dans notre étude.

Programmation ARM

Introduction à la programmation embarquée

Introduction

Bienvenue dans le monde de l'embarqué. J'avais écrit cet article lors de mes études en 2007 à l'époque. Ce qui est intéressant avec le monde de l'embarqué, c'est que les technologies ne peuvent pas évoluer aussi vite que sur le web car en fonctionnement autonome. Je vais tenté de vous présenter une introduction en douceur grâce à l'interface AT91M55800A. Cette carte embarque :
  • un processeur ARM7TDMI
  • 8K de SRAM
  • 1 interface JTAG
  • 2 modules d'entrées/sorties (PIOA et PIOB)
  • 6 modules d'horloge/comptage (TC Timer Counter)
  • 3 modules de communication série (USART)
  • 1 module de gestion d'énergie (APMC)
  • 1 gestionnaire d'interruptions (AIC)
  • 8 modules de convertion Analogique/Numérique (ADC)
  • 2 modules de convertion Numérique/Analogique(DAC)
  • etc...
Vous me demanderez certainement pourquoi cette carte et pas une autre ? Je vous répondrais que c'est tout simplement la seule que j'ai à disposition. De toute façon, en matière de gestion d'interruptions et de programmation bas niveau, la méthode reste toujours la même, seul change la syntaxe. Nous allons donc voir comment programmer sur cette bestiole.
Pour cela, j'utilise la suite logiciel ADS mais il existe aussi la suite GCC ARM qui est open source. Les codes fournis dans cet article ne seront pas compatible avec GCC ARM du moins la partie traitant de la gestion des interruptions. N'oubliez pas sous ADS de configurer le linker pour qu'il charge le code à l'adresse 0x0200 0000 si vous voulez le tester.
Commençons donc par les bases, l'assembleur ARM.

Syntaxe ARM

Le but de cet article n'est pas de fournir une documentation exhaustive de la syntaxe ARM, nous ne verrons ici que ce dont nous aurons besoin pour la suite du tutoriel. Tout d'abord, avant de commencer, il faut savoir que les processeurs ARM (tout comme son concurrent MIPS) sont des processeurs de type RISC contrairement aux processeurs de nos stations de travail, les CISC. C'est à dire que ces processeurs ont un set d'instructions limité du fait de leurs structures interne. L'intérêt étant qu'il est possible de programmer toutes les opérations complexes réalisées par les processeurs CISC avec ce set d'instruction limité. Du coup, on se retrouve avec des processeurs ayant une plus grande autonomie, et souvent plus petits. Par exemple, il n'existe aucune mnémonique de division en assembleur ARM. Nous avons à notre disposition 16 registres de 32 bits :
  • r0 à r12 sont des registres d'accumulation tout comme eax avec intel.
  • r13 est le registre pointant sur la pile, équivalent à esp.
  • r14 est le registre contenant l'adresse de retour d'appel d'une fonction, équivalent à ebp.
  • r15 est le registre contenant l'adresse de l'instruction en cours d'éxécution, équivalent à eip.
Ainsi qu'un ensemble de mnémoniques que je détaillerais au fur et à mesure.
Le passage de paramètres à une fonction s'effectue par le biais des registres r0 à r3 puis il faut ensuite les empiler sur la pile. C'est à la fonction de dépiler ces arguments et les sauvegarder lors d'appel récursif par exemple. La valeur de retour de la fonction est passée dans r0
Voyons tout cela avec la function dummy:
      int dummy(int a, int b, int c, int d)
      {
        return a+2*b+3*c+4*d;
      }
      
ce qui donne en assembleur ARM :
      dummy :
        ; r0 = a
        ; r1 = b
        ; r2 = c
        ; r3 = d
        stmfd r13!, {r4-r12,r14} ; sauvegarde des arguments
        add r1, r1, r1  ; r1 = r1+r1
        add r2,r2,r2,LSL #1 ; r2 = r2+r2*2
        add mov r3,r3,LSL #2 ; r3 = r3*4
        add r0, r0, r1  ; r0 = r0+r1
        add r0, r0, r2 ; r0 = r0+r2
        add r0, r0, r3 ; r0 = r0+r3
        ldmfd r13!, {r4-r12, r14} ; restauration des arguments
      
stmfd est une mnémonique permettant de pusher dans la première opérande (r13 dans notre cas) les registres entre accolade (ici on push r4 à r12 et r14). Le ! signifie que l'on veut incrémenter l'adresse de r13 d'autant de données que l'on push.
Très bien maintenant nous allons voir les tests logiques :
      if (a == b)
      {
        a += b;
      }
      else
      {
        b += a;
      } 
      
donnera :
      ; r0 = a
      ; r1 = b
        cmp r0, r1
        beq then
        b else
      then
        add r0, r0, r1 ; a += b 
        b end
      else
        add r1, r1, r0 ; b += a
      end
      
Ici le point important est la mnémonique b qui permet de sauter à un label. b sans condition est un saut inconditionnel (on s'en serait douter) exactement comme jmp. beq suit la condition "equal" et sautera à then que si a = b. Voici une liste de quelques conditions :
Flag Sens
EQ égal
NE différent
HI supérieur (non signé)
LS inférieur ou égal (non signé)
GE supérieur ou égal (signé)
LT inférieur (signé)
Enfin la dernière notion que nous devons aborder, et pas des moindre, c'est l'accès à la mémoire.
      int *ptr = var;
      ptr = ptr +4 // incrément du pointeur
      *ptr = 10 // mets 10 en valeur pointée par le pointeur
      
donnera :
      ;;; initialisation du pointeur
      ldr r0, =var  ;; récupération de l'adresse de la variable
      str r0, ptr
      ;;; modification du pointeur
      ldr r0, ptr
      add r0,r0,#4
      str r0,ptr
      ;;; modification de la valeur pointée
      ldr r0, ptr
      mov r1, #10
      str r1, [r0]
      
l'opérateur = permet de récupérer l'adresse d'une variable. la mnémonique ldr permet de charger dans le registre la seconde opérande quant à str il permet de stocker le registre dans la seconde opérande.
Nous n'avons fait que survoler très rapidement l'assembleur ARM et je ne peux que vous conseillez de lire l'ARM Assembly Language Programming pour approfondir vos connaissances. Dans la suite de l'article je reviendrais sur chaque nouvelle notion rencontrée.

Gestionnaire d'interruption

Nous rentrons maintenant dans le vif du sujet et je vous conseil de vous accrochez un peu. En effet, la gestion des interruptions est une des base de la programmation d'un micro-processeur. Il faut comprendre le principe une fois car la méthode reste similaire sur d'autres plateformes. Vous vous rappelez peut-être que je vous ai dit qu'il n'y a que 16 registres disponibles sur une architecture ARM ? Et bien ce n'est pas tout à fait vrai. En effet, il en existe en réalité 32 mais ils sont répartis sur plusieurs contextes car le processeur peut fonctionner sous différents modes :
  • User : fonctionnement normal
  • FIQ : actif lors d'une interruption de type FIQ
  • IRQ : actif lors d'une interruption de type IRQ
  • Supervisor : mode superviseur
  • Abort
  • Undefined
  • System
Le registre cpsr (et spsr en mode superviseur) permet de connaître l'état dans lequel se trouve le microprocesseur. Voici un tableau récapitulatif des registres accessibles en fonction de l'état du processeur : registres 


Et ci-après l'organisation du registre cpsr/spsr:


cpsr

On voit que les bits faibles donnent l'état courant du processeur tandis que les bits FIQ et IRQ permettent d'activé le passage en mode FIQ et IRQ. Le changement d'état du processeur s'effectue lors de la levée d'exception. Une exception est levée dans différents cas :
  • Un Reset : on passe en mode Supervisor
  • Une instruction inconnue : on passe en mode Undefined
  • Une interruption logiciel (mnémonique swi) : on passe en mode Supervisor
  • Impossibilité d'accéder à l'instruction ou à une zone mémoire : on passe en mode Abort
  • Une Interruption IRQ : on passe en mode IRQ
  • Une Interruption FIQ : on passe en mode FIQ
Nous nous intéresserons plus particulièrement à la gestion des interruptions de type IRQ. En effet les FIQ ne sont utiles que dans le cas où nous voulons gérer une interruption sans rien sauvegarder dans la pile (ce qui est impossible dans le cas de l'ordonnancement traité à la fin de l'article). Comme je l'ai dit en début d'article la carte embarque un gestionnaire d'interruption (AIC) que nous devons activer pour pouvoir gérer les interruptions. Je vous conseil vivement d'avoir la datasheet sous les yeux pour mieux comprendre les codes qui vont suivre. Bien, commençons donc par la routine de traitement d'interruption. Dans cette routine, nous passons en mode superviseur ce qui n'est faisable qu'en assembleur (inline ou non). Ce qui donne :
      EXPORT isr
        IMPORT pa9_irq_C_handler
        
        AREA EX2, CODE, READONLY
      
      AIC_BASE EQU 0xFFFFF000
      AIC_EOICR EQU 0x130
      
      isr
      
      ;/* sauvegarde de l'adresse de retour*/
        SUBS lr,lr, #4
        STMFD sp!, {r0, lr}
      ;/* sauvegarde du SPSR */
        MRS r0, SPSR
        STMFD sp!, {r0}
      ;/* on réautorise les interruptions et l'on passe en mode svc*/
      ;/* afin de bénéficier de la pile superviseur */
        MRS r0, spsr
        BIC r0, r0, #0x80 ; mise à 0 du flag Interruption IRQ
        BIC r0, r0, #0x1F ; mise à 0 des flags M4..M0
        ORR r0, r0, #0x13 ; mode superviseur activer
        MSR cpsr_c, r0
      ;/* appel de la fonction de traitement*/ 
        STMFD SP!, {r1-r3,r12,lr}
        
        BL pa9_irq_C_handler
        
        LDMFD SP!, {r1-r3,r12,lr}
      ;/* On repasse en mode irq avec interruption bloquées*/
        MRS r0, cpsr
        BIC r0, r0, #0x1F ; mise à 0 des flags M4..M0
        ORR r0, r0, #0x80 | 0x12 ; mise à 1 du flag Interruption IRQ et passage en mode IRQ
      ;/* On acquitte l'AIC pour signifier que l'interruption a été traité*/
        LDR r0, =AIC_BASE
        STR r1, [r0, #AIC_EOICR]
      ;/* on restore les registres*/
        LDMFD sp!, {r0} ; on récupère le SPSR qui avait été sauvegardé
        MSR SPSR_cxsf, r0
      ;/* retour d'interruption*/
        LDMFD sp!, {r0, pc}^
      
        END
      
Cette routine s'occupe seulement d'exécuter une fonction C (ici pa9_irq_C_handler) en mode superviseur pour traiter l'interruption.
A noter le décalage réaliser au tout début "SUBS lr,lr, #4" permettant d'exécuter l'instruction suivante après le traitement d'interruption. Le décallage dépend de l'interruption qui a été levée. En effet en modifiant le registre lr, c'est l'adresse de retour de l'interruption qui est modifiée.
Ce tableau récapitule les décalages à appliquer en fonction des différentes interruptions :
exception
Nous avons réalisé une routine de gestion d'interruption générique. Mais pour pouvoir lever des interruptions, il nous faut activer l'AIC et les ports ou interfaces sur lesquels les interruptions seront "catchées".
      #include "pio.h"
      #include "pioa.h"
      #include "piob.h"
      #include "apmc55800.h"
      #include "stdio.h"
      #include "aic.h"
      
      #define PIOA_BASE 0xFFFEC000
      #define PIOB_BASE 0xFFFF0000
      
      void InitialiseIRQ (void) ;
      
      void InitialiseBP (void) ;
      
      void InitialiseLED (void) ;
      
      void AfficheLed (unsigned char a) ;
      
      extern void isr (void) ;
      
      StructAIC *AIC ;
      StructPIO *PIOA ;
      StructPIO *PIOB ;
      StructAPMC *APMC ;
      
      unsigned char cpt = 0;
      
      int main (void)
      {
        AIC = (StructAIC*) AIC_BASE ;
        PIOA = (StructPIO*) PIOA_BASE ;
        PIOB = (StructPIO*) PIOB_BASE ;
        APMC = (StructAPMC*) APMC_BASE ;
        
        InitialiseBP () ;
        InitialiseLED () ;
        AfficheLed(0);
        InitialiseIRQ () ;
        
        
        while (1)
        {
          AfficheLed(cpt);
        }
        
        return 0;
      }
      
      void InitialiseIRQ (void)
      {
      /* interruption sur niveau et de priorité = 3 */
        AIC->AIC_SMR[13] = AIC_SRCTYPE_INT_LEVEL_SENSITIVE | 0x03 ;
      /* adresse de la routine de traitement des interruption du port A */ 
        AIC->AIC_SVR[13] = (int) isr ;
      /* activation des irq du pioa */ 
        AIC->AIC_IECR = (1<<13) ;
      /* activation des irq dues à pa9 */ 
        PIOA->PIO_IER = PA9 ;
      }
      
      void InitialiseBP (void)
      {
      /*On active les horloges de périphérique pour pioa et piob*/
        APMC->APMC_PCER = 0x6000 ;
        
      /*activation de PA9 en entrée */ 
        PIOA->PIO_PER = PA9 ;
        PIOA->PIO_ODR = PA9 ;
      }
      
      void InitialiseLED (void)
      {
      /* Les LED sont attachée au portB PB8 -> PB15 */
      /* On active les 8 bits du Port B auxquels sont attachée les led */
        PIOB->PIO_PER = 0x0000FF00 ;
      /* On met ces 8 bits en sortie */
        PIOB->PIO_OER = 0x0000FF00 ;
      /* Une led est allumée lorsque la sortie du Port B est à 0 */
      /* On les éteint toutes PB8-> PB15 = "0xFF" */
        PIOB->PIO_SODR = 0x00FF00 ;
      }
      
      void AfficheLed (unsigned char a)
      {
      /* Constitution du mot permettant de mettre le port à 0 */
      /* Les led sont allumées si la sortie est à 0 */
        PIOB->PIO_SODR = (~a << 8) & 0x00FF00 ;
      /* Constitution du mot permettant de mettre le port à 1 */
      /* On inverse les bits 8 à 15 du mot précédent */ 
        PIOB->PIO_CODR = (a << 8) & 0x00FF00 ;
      }
      
      void pa9_irq_C_handler(void)
      {
      
        /* on acquitte l'irq du périphérique par lecture du registre d'état */
        /* on vérifie par la même occasion que l'IRQ est bien due à PA9 */
        if ( PIOA->PIO_ISR == (1<< 9) )
        {
          /* test que c'est un appui */
          if ((PIOA->PIO_PDSR & (1<<9) )==0)
          /* On incrémente le compteur */
            cpt++;
        }
        else /* interruption non due à PA9 on ne fait rien de spécial*/
          {}
      }
      
Ce code est très simple, il active les interruptions sur le port 19 du PIOA (correspondant à un bouton poussoir) ainsi lors de l'appui sur le bouton, une interruption de type IRQ sera levée. Le gestionnaire d'interruption s'occupe ensuite d'afficher sur les leds de la carte une valeur s'incrémentant à chaque interruption catchée.
Ce qui nous intéresse ici c'est la fonction InitialiseIRQ(). Dans celle-ci on définit que l'interruption IRQ sera levée lors d'un changement de niveau (haut -> bas ou bas -> haut) du signal en entrée sur le port 19 du PIOA. Puis on définit quelle est la routine d'interruption à exécuter. Enfin on active les interruptions IRQ au niveau de l'AIC et au niveau du PIOA.
Voici un tableau récapitulatif des sources d'interruptions possible gérées par l'AIC. On voit que le numéro 13 correspond à l'interruption IRQ du PIOA.
arm aic interupts

Communication série

Au début de l'article, nous avons vu que la carte embarque 2 modules de communication série (USART). Nous allons donc voir comment utiliser ce module de communication. Dans un premier temps nous ne fairons qu'envoyer et recevoir des informations sans gérer d'interruptions. Puis, nous verrons comment gérer les interruptions de l'USART.

Ordonnancement

Nous allons maintenant voir comment gérer un ordonnancement basique de processus à l'aide du module TC (Timer/Counter). Le but étant de commuter la tâche en exécution toutes les millisecondes.

Conclusion

Voilà, vous savez maintenant comment gérer des interruptions sur un processeur de type ARM. Les modes de fonctionnement des processeurs ARM7 se retrouvent dans les processeurs ARM9, ce qui veut dire que la gestion des interruptions reste quasiment similaire. Vous en savez maintenant autant que moi en matière de programmation embarquée :). Si vous voulez approfondir, je vous encourage à parcourir la datasheet qui contient des informations très complémentaires et exhaustives, même si elle est quelque peu indigeste. J'espère que cet article vous aura plu et si vous avez des questions, n'hésitez pas.

Annexe

Schémas simplifié de la carte AT91M55800A.