captchas/experimental.sh

232 lines
6.9 KiB
Bash
Executable File

#!/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.
# The whole idea of the captcha script is to let server admins adapt it to
# their own needs. The goal is to be able to make the captcha generation as
# unique as possible, to make the captcha challenge difficult to bypass by
# a bot.
# Server admins are thus supposed to write and use their own captcha generators.
# This script relies on ImageMagick.
# 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)
# ****************************************************************************
#
# Tools
#
# ****************************************************************************
# Generate a number that is not in INPUT. Loop 10 times (should be enough)
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}
INSTRUCTIONS1="Recopiez ce nombre"
INSTRUCTIONS2="en changeant les ${DIGITS[FALSENBR]} en ${DIGITS[TARGET]}"
}
# 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]}"
INSTRUCTIONS2="et recopiez de DROITE à GAUCHE ←"
else
ADDNBR="${INPUT:$LENINPUT-1:1}"
NAME+="_LAST"
NEWINPUT=${NEWINPUT:1:$LENINPUT-1} # Do not show last INPUT NBR
INSTRUCTIONS1="Recopiez de DROITE à GAUCHE ←"
INSTRUCTIONS2="et terminez par le chiffre ${DIGIT[$ADDNBR]}"
fi
NAME+="-$ADDNBR"
}
# 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 ce nombre sans les ${DIGITS[FALSENBR]}"
}
# 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: ${DIGIT[FALSENBR]} moins ${DIGIT[RESUME]} et 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]} plus ${DIGIT[RESUME]} et copiez"
NAME="CALCULP-$FALSENBR-$RESUME"
else
RESULT=$(( FALSENBR - TARGET ))
RESUME=$(( TARGET - RESULT ))
INSTRUCTIONS1="Calculez: ${DIGIT[RESULT]} plus ${DIGIT[RESUME]} et copiez"
NAME="CALCULP-$RESULT-$RESUME"
fi
fi
INSTRUCTIONS2="en remplaçant chaque X par la somme"
}
# Sum 2 LAST numbers. Hide LAST or BEFORE LAST
CALCEND() {
END1=${INPUT:$LENINPUT-2:1}
END2=${INPUT:$LENINPUT-1:1}
ENDS=$(( END1 + END2 ))
REND=`seq 1 2 | sort -R | head -n 1`
if (( $REND == 1 ));then
# Hide LAST
NEWINPUT=${INPUT:0:LENINPUT-1}X
NAME="END-${END1}X"
else
# Hide BEFORE LAST
NEWINPUT=${INPUT:0:LENINPUT-2}X$END2
NAME="END-X$END2"
fi
INSTRUCTIONS1="La somme des 2 derniers chiffres est $ENDS"
INSTRUCTIONS2="Copiez en remplaçant X par sa valeur"
}
# Replace 2 X (smaller > bigger | bigger > smaller)
LEMO() {
MAXNBR=${INPUT:0:1}
MINNBR=${INPUT:0:1}
for i in `seq 1 $((LENINPUT-1))`
do
(( ${INPUT:$i:1} > $MAXNBR )) \
&& MAXNBR=${INPUT:$i:1}
(( ${INPUT:$i:1} < $MINNBR )) \
&& MINNBR=${INPUT:$i:1}
done
for i in `seq 0 $((LENINPUT-1))`
do
if (( ${INPUT:$i:1} == $MINNBR ));then
INSTRUCTIONS1="Remplacez les X par ${DIGIT[MAXNBR]} et ${DIGIT[MINNBR]}"
INSTRUCTIONS2="! le plus PETIT en premier"
NAME="LEMO-$MINNBR-$MAXNBR"
break
elif (( ${INPUT:$i:1} == $MAXNBR ));then
INSTRUCTIONS1="Remplacez les X par ${DIGIT[MINNBR]} et ${DIGIT[MAXNBR]}"
INSTRUCTIONS2="! Le plus GRAND en premier"
NAME="LEMO-$MAXNBR-$MINNBR"
break
fi
done
NEWINPUT=`echo $INPUT | sed "s/$MINNBR/X/"`
NEWINPUT=`echo $NEWINPUT | sed "s/$MAXNBR/X/"`
}
# ****************************************************************************
#
# Random captcha shape choice (aka main)
#
# ****************************************************************************
MODULES=(CALCUL CALCEND LEMO NOTIN REPLACE REVERSE)
RMODULE=`seq 0 $(( ${#MODULES[@]} - 1)) | sort -R | head -n 1`
eval "${MODULES[RMODULE]}"
TEXT="$NEWINPUT"
DATE="$(date "+%Y-%m-%d-%H%M%S")"
CHAPRILURI=/var/lib/ejabberd/chapril_captchas/${DATE}_${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" \
-roll +$ROLL_X+0 \
-wave "$WAVE1_AMPLITUDE"x"$WAVE1_LENGTH" \
-roll -$ROLL_X+0 \) \
-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" \
-roll +$ROLL_X+0 \
-wave "$WAVE1_AMPLITUDE"x"$WAVE1_LENGTH" \
-roll -$ROLL_X+0 \) \
-flatten -crop 300x70 +repage -quality 500 -depth 11 png:-