From bd635ae2a1991c06d77147b8eb4a46aabeab5106 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Tue, 31 Aug 2021 20:37:06 +0200 Subject: [PATCH] New captcha in prod --- captcha/captcha.sh | 237 ++++++++++++++++++++++++---------------- captcha/experimental.sh | 5 +- 2 files changed, 144 insertions(+), 98 deletions(-) diff --git a/captcha/captcha.sh b/captcha/captcha.sh index 93acd8f..daebc47 100755 --- a/captcha/captcha.sh +++ b/captcha/captcha.sh @@ -1,5 +1,13 @@ #!/bin/bash +# Copyright © 2021 Adrien Bourmault (neox@a-lec.org) +# Copyright © 2021 Echolib (echolib@dismail.de) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + # This script is an example captcha script. # It takes the text to recognize in the captcha image as a parameter. # It return the image binary as a result. ejabberd support PNG, JPEG and GIF. @@ -14,122 +22,159 @@ # It is NOT compliant with ImageMagick forks like GraphicsMagick. INPUT=$1 +LENINPUT=${#INPUT} +DIGITS=(zéros uns deux trois quatres cinqs six septs huits neufs dix) +DIGIT=(zéro un deux trois quatre cinq six sept huit neuf dix) -TRANSFORMATIONS=(INTRUS SOMME) -DIGIT=(zéros uns deux trois quatres cinqs six septs huits neufs dix) -if test -n ${BASH_VERSION:-''} ; then - get_random () - { - R=$RANDOM - } +# **************************************************************************** +# +# Tools +# +# **************************************************************************** + + +# Loops 10 times (should be enough) to check if a TARGET number is in INPUT +GENERATE__NOTIN() { +for i in {1..10} +do + FALSENBR=`seq 1 9 | sort -R | head -n 1` + ! [[ $INPUT =~ $FALSENBR ]] \ + && break +done +} + + +# **************************************************************************** +# +# Captcha shapes +# +# **************************************************************************** + + +# REPLACEs a random number in INPUT by another one randomized +REPLACE() { +NAME="REPLACE" +PLACE=`seq 1 6 | sort -R | head -n 1` +TARGET=`echo "$INPUT" | head -c $PLACE | tail -c 1` + +GENERATE__NOTIN +NAME+="-$FALSENBR-$TARGET" +NEWINPUT=${INPUT//$TARGET/$FALSENBR} +INSTRUCTIONS2="en changeant les ${DIGITS[FALSENBR]} en ${DIGITS[TARGET]}" +INSTRUCTIONS1="Recopiez" +} + + +# REVERSEs INPUT. Ask to Add first or last number in random. +REVERSE() { +NAME="REVERSE" +RFL=`seq 1 2 | sort -R | head -n 1` # Rand First (1) or Last (2) +ADDNBR=${DIGITS[ADDNBR]} + +for ((i=$LENINPUT-1;i>=0;i--)) +do + NEWINPUT="$NEWINPUT${INPUT:$i:1}" +done + +if (( $RFL == 1 ));then + ADDNBR="${INPUT:0:1}" + NAME+="_FIRST" + NEWINPUT=${NEWINPUT:0:$LENINPUT-1} # Do not show first INPUT NBR + INSTRUCTIONS1="Écrivez le chiffre ${DIGIT[$ADDNBR]} puis" + INSTRUCTIONS2="Recopiez de DROITE à GAUCHE ←" else - for n in `od -A n -t u2 -N 64 /dev/urandom`; do RL="$RL$n "; done - get_random () - { - R=${RL%% *} - RL=${RL#* } - } + ADDNBR="${INPUT:$LENINPUT-1:1}" + NAME+="_LAST" + NEWINPUT=${NEWINPUT:1:$LENINPUT-1} # Do not show last INPUT NBR + INSTRUCTIONS1="Recopiez de DROITE à GAUCHE ←" + INSTRUCTIONS2="Terminez par le chiffre ${DIGIT[$ADDNBR]}" fi - -INTRUS() -{ - LENGTH=${#INPUT} - NUMBERS=$(echo $INPUT | grep -o . | tr '\n' ' ') - SORTED_UNIQ_NUM=$(echo "${NUMBERS[@]}" | sort -u | tr '\n' ' ') - INTRUS=-1 - - for i in 1 2 3 4 5 6 7 8 9 - do - if [[ ! " ${SORTED_UNIQ_NUM[@]} " =~ " ${i} " ]]; then - INTRUS=$i - break - fi - done - - # Worst case - if [[ $INTRUS -eq "-1" ]] - then - echo Tapez "$INPUT |sans changement" - return - fi - - for num in ${NUMBERS[@]} - do - get_random - R=$(($R % 100)) - - if [[ $R -lt 60 ]]; then - NEWINPUT=${NEWINPUT}${num}${INTRUS} - else - NEWINPUT=${NEWINPUT}${num} - fi - done - - get_random - R=$(($R % 100)) - - if [[ $R -lt 50 ]]; then - echo "Tapez ce nombre en enlevant les ${DIGIT[$INTRUS]} | $NEWINPUT" - else - echo "Saisissez ce nombre sans les ${DIGIT[$INTRUS]} | $NEWINPUT" - fi +NAME+="-$ADDNBR" } -SOMME() -{ - get_random - RB=$(($R % 5)) - get_random - RA=$(($R % 10 * (10 ** $RB))) - - if [[ $(($INPUT % 2)) -eq 0 ]]; then - A=$(($INPUT - $RA)) - B=$RA - else - B=$(($INPUT - $RA)) - A=$RA - fi - - get_random - R=$(($R % 100)) - - if [[ $R -lt 25 ]]; then - echo "Tapez le résultat de | $A + $B" - elif [[ $R -lt 50 ]]; then - echo "Sommez | $A et $B" - elif [[ $R -lt 75 ]]; then - echo "Additionnez | $A et $B" - else - echo "Saisissez le résultat de | $A + $B" - fi + +# Add FALSE NBR to INPUT at three randomized place +NOTIN() { +NAME="NOTIN" +GENERATE__NOTIN +PLACE=(`seq 0 $((LENINPUT-1)) | sort -R | head -n 3 | sort -n`) +for i in `seq 0 $((LENINPUT-1))` +do + (( $i == ${PLACE[0]} )) \ + && NEWINPUT+="$FALSENBR" + (( $i == ${PLACE[1]} )) \ + && NEWINPUT+="$FALSENBR" + (( $i == ${PLACE[2]} )) \ + && NEWINPUT+="$FALSENBR" + NEWINPUT="$NEWINPUT${INPUT:$i:1}" +done +NAME+="-$FALSENBR" +INSTRUCTIONS1="Recopiez sans les ${DIGITS[FALSENBR]}" } -get_random -RAND_INDEX=$(($R % ${#TRANSFORMATIONS[@]})) -INSTRUCTIONS0=$(echo "$(${TRANSFORMATIONS[$RAND_INDEX]})") -INSTRUCTIONS1=$(echo $INSTRUCTIONS0 | cut -d "|" -f 1) -INSTRUCTIONS2=$(echo $INSTRUCTIONS0 | cut -d "|" -f 3) -TEXT=$(echo $INSTRUCTIONS0 | cut -d "|" -f 2) +# Take a random NBR from INPUT. Calculate X +CALCUL() { +PLACE=`seq 1 $((LENINPUT)) | sort -R | head -n 1` +TARGET=`echo "$INPUT" | head -c $PLACE | tail -c 1` +NEWINPUT=${INPUT//$TARGET/X} + +RC=`seq 1 2 | sort -R | head -n 1` # 1 = - | 2 = + +if (( $RC == 1 ));then + FALSENBR=`seq $TARGET 10 | sort -R | head -n 1` + RESUME=$(( FALSENBR - TARGET )) + INSTRUCTIONS1="Calculez: $FALSENBR moins $RESUME. Copiez..." + NAME="CALCULM-$FALSENBR-$RESUME" +else + FALSENBR=`seq 1 4 | sort -R | head -n 1` + if (( $FALSENBR <= $TARGET ));then + RESULT=$(( TARGET + FALSENBR )) + RESUME=$(( TARGET - FALSENBR )) + INSTRUCTIONS1="Calculez: ${DIGIT[FALSENBR]} + ${DIGIT[RESUME]}. Copiez..." + NAME="CALCULP-$FALSENBR-$RESUME" + else + RESULT=$(( FALSENBR - TARGET )) + RESUME=$(( TARGET - RESULT )) + INSTRUCTIONS1="Calculez: ${DIGIT[RESULT]} + ${DIGIT[RESUME]}. Copiez..." + NAME="CALCULP-$RESULT-$RESUME" + fi +fi +INSTRUCTIONS2="...en remplaçant chaque X par la somme" +} + + +# **************************************************************************** +# +# Random captcha shape choice (aka main) +# +# **************************************************************************** + +MODULES=(CALCUL NOTIN REPLACE REVERSE) +RMODULE=`seq 0 $(( ${#MODULES[@]} - 1)) | sort -R | head -n 1` +eval "${MODULES[RMODULE]}" + +TEXT="$NEWINPUT" +CHAPRILURI="/var/lib/ejabberd/chapril_captchas_experimental/$(date "+%Y-%m-%d-%H%M%S")_${NAME}_${INPUT}.png" convert -size 300x70 xc:none -pointsize 20 \ \( -clone 0 -fill black \ -stroke black -strokewidth 1 \ - -font Helvetica-Narrow -annotate "0x0+0+0" "\n $INSTRUCTIONS1" \ - -font Helvetica-Bold -annotate "0x0+0+22" "\n $TEXT" \ - -font Helvetica-Narrow -annotate "0x0+0+44" "\n $INSTRUCTIONS2" \ + -font Helvetica-Narrow -annotate "0x0+0+0" "\n $INSTRUCTIONS1" \ + -font Helvetica-Bold -annotate "0x0+0+22" "\n $TEXT" \ + -font Helvetica-Narrow -annotate "0x0+0+44" "\n $INSTRUCTIONS2" \ -roll +$ROLL_X+0 \ -wave "$WAVE1_AMPLITUDE"x"$WAVE1_LENGTH" \ -roll -$ROLL_X+0 \) \ - -flatten -crop 300x70 +repage -quality 500 -depth 11 png:"/var/lib/ejabberd/chapril_captchas/$(date "+%Y-%m-%d-%H%M%S")_${INPUT}.png" + -flatten -crop 300x70 +repage -quality 500 \ + -depth 11 png:"$CHAPRILURI" convert -size 300x70 xc:none -pointsize 20 \ \( -clone 0 -fill black \ -stroke black -strokewidth 1 \ - -font Helvetica-Narrow -annotate "0x0+0+0" "\n $INSTRUCTIONS1" \ - -font Helvetica-Bold -annotate "0x0+0+22" "\n $TEXT" \ - -font Helvetica-Narrow -annotate "0x0+0+44" "\n $INSTRUCTIONS2" \ + -font Helvetica-Narrow -annotate "0x0+0+0" "\n $INSTRUCTIONS1" \ + -font Helvetica-Bold -annotate "0x0+0+22" "\n $TEXT" \ + -font Helvetica-Narrow -annotate "0x0+0+44" "\n $INSTRUCTIONS2" \ -roll +$ROLL_X+0 \ -wave "$WAVE1_AMPLITUDE"x"$WAVE1_LENGTH" \ -roll -$ROLL_X+0 \) \ diff --git a/captcha/experimental.sh b/captcha/experimental.sh index fc1f7b6..daebc47 100755 --- a/captcha/experimental.sh +++ b/captcha/experimental.sh @@ -61,7 +61,8 @@ TARGET=`echo "$INPUT" | head -c $PLACE | tail -c 1` GENERATE__NOTIN NAME+="-$FALSENBR-$TARGET" NEWINPUT=${INPUT//$TARGET/$FALSENBR} -INSTRUCTIONS1="Remplacez les ${DIGITS[FALSENBR]} par des ${DIGITS[TARGET]}" +INSTRUCTIONS2="en changeant les ${DIGITS[FALSENBR]} en ${DIGITS[TARGET]}" +INSTRUCTIONS1="Recopiez" } @@ -154,7 +155,7 @@ RMODULE=`seq 0 $(( ${#MODULES[@]} - 1)) | sort -R | head -n 1` eval "${MODULES[RMODULE]}" TEXT="$NEWINPUT" -CHAPRILURI="/var/lib/ejabberd/chapril_captchas_experimental/${NAME}_${NEWINPUT}_${INPUT}.png" +CHAPRILURI="/var/lib/ejabberd/chapril_captchas_experimental/$(date "+%Y-%m-%d-%H%M%S")_${NAME}_${INPUT}.png" convert -size 300x70 xc:none -pointsize 20 \ \( -clone 0 -fill black \