No description
Find a file
2024-07-11 10:51:09 -06:00
tests firmador 2024-05-17 17:56:44 -06:00
.gitignore debian & macosx 2024-05-05 19:21:58 -06:00
01-utils.sh pass env vars, shellcheck directives 2024-06-29 08:46:42 -06:00
02-language.sh pass env vars, shellcheck directives 2024-06-29 08:46:42 -06:00
03-install.sh pass env vars, shellcheck directives 2024-06-29 08:46:42 -06:00
04-main.sh pass env vars, shellcheck directives 2024-06-29 08:46:42 -06:00
Makefile pass env vars, shellcheck directives 2024-06-29 08:46:42 -06:00
README.org titles check 2024-07-11 10:51:09 -06:00

instalador-firma.sh

Script de instalación de firma digital. Busca ser compatible con el estándar de shell de POSIX a nivel de sintaxis, pero su funcionalidad está limitada a Linux y macOS.

Probado en estas distribuciones:

  • Debian 12
  • Fedora 40
  • Arch Linux [date]

TODO [0/4]

  • Configurar opciones como variables e.g. definir previamente $MENU para utilizar la terminal como menu en lugar de la opción disponible como zenity o kdialog
  • Permitir instalación no interactiva e.g. Si se tiene todo para proceder (con variables), no pedir nada.
  • Funciones reinstall_certs, uninstall_certs Nota: Mantener el uso de $PROMPT... en Main
  • Menu instalar/desinstalar/salir Nota: Mantener el uso de $PROMPT... en Main

    • Función is_installed

    0 dispara el menu, 1 dispara la instalación, 2 dispara el menu con aviso de instalación previa fallida.

Script

Shebang

#!/bin/sh

Utilidades

pseudo

``Pseudo sudo'' facilidad para ejecutar comandos como administrador.

alias pseudo='printf "%s" "$SUDO_PASSWORD" | sudo -Skp ""'

echo_debug

Notificaciones del estado del script. Uso: echo_debug "Mensaje"

echo_debug() {
    printf '\033[1mDEBUG:\033[0m \033[2m%s...\033[0m\n' "$1"
}

urlencode

Función para convertir texto al formato correcto de URL, existen programas externos o quizás se pueda lograr solamente con sed pero esta forma es más robusta. También es menos portable, pero el script depende de curl de todas formas.

Uso: printf 'hól#a' | urlencode, output: h%c3%b3l%23a

urlencode() {
    ENCODEDURL="$(curl -Gs -w '%{url_effective}' --data-urlencode @- ./ ||: )"
    printf '%s' "$ENCODEDURL" | sed 's/%0[aA]$//;s/^.*[?]//' # %0a al final de la línea es
}                                                            # un comportamiento no deseado.

get_asp_var

Esta función requiere de una variable $RESPONSE que sería el html respuesta de un request, a partir de esto, devuelve la string de data que tiene retorna al servicio en un request posterior.

get_asp_var() {
    i=0
    for VAR in __VIEWSTATE __VIEWSTATEGENERATOR __EVENTVALIDATION ; do
        VAL="$(printf '%s' "$RESPONSE" | grep "id=\"$VAR\"" | cut -d '"' -f 8 | urlencode)"
        [ "$i" != 0 ] && printf '&'
        printf '%s=%s' "$VAR" "$VAL"
        i=+1
    done
}

set_version

Sin ninguna dependiencia, solamente funciones incluidas en el estándar POSIX, determina la variable $VERSION que será utilizada para seleccionar automáticamente el fichero que debe descargar en get_archive.

Nota: Se desactiva el error de SC1090, ya que es una limitación de shellcheck y es una funcionalidad válida dentro del estándar POSIX.

set_version() {
    # shellcheck disable=SC1090
    for os in /etc/os-release /usr/lib/os-release; do
        [ -f $os ] && . $os && break
    done

    case "$ID" in
        centos) [ -n "$VERSION_ID" ] && [ "$VERSION_ID" -ge 9 ] &&
                          ID="fedora" ;;
        *suse*|sles|sled) ID="suse" ;;
        debian|ubuntu)    ID="debian" ;;
        fedora|rhel)      ID="fedora" ;;
        arch|manjaro)     ID="arch" ;;
        *)                ID="${ID_LIKE%% *}" ;;
    esac

    [ "$ID" = "ubuntu" ] && ID="debian"
    [ "$ID" = "rhel" ]   && ID="fedora"
    [ -f /System/Library/CoreServices/SystemVersion.plist ] && ID="macos"

    case "$ID" in
        debian) VERSION="Usuarios Linux (DEB 64bits)" ;;
        fedora) VERSION="Usuarios Linux (RPM 64bits)" ;;
        suse)   VERSION="Usuarios Linux (RPM 64bits)" ;;
        arch)   VERSION="Usuarios Linux (RPM 64bits)" ;;
        centos) VERSION="Usuarios Linux RPM (CentOS 7)" ;;
        macos)  VERSION="Usuarios MAC" ;;
        *) return 1 ;;
    esac
}

get_archive

Utiliza urlencode y get_asp_var para realizar el procedimiento de descarga. Necesita que $VERSION esté definida (después de ejecutar set_version) ya que utilizará este parámetro para consultar en el servicio el instalador que debe descargar (el más actualizado de y correspondiente al sistema).

get_archive() {
    URL="https://soportefirmadigital.com/sfdj/dl.aspx"
    VERSION="$(printf '%s' "$VERSION" | urlencode)"
    RESPONSE="$(curl -s --compressed "$URL" -o -)"
    ASP_VARS="$(get_asp_var)"

    FILE="$(curl -s "$URL" --data-raw "$ASP_VARS" --data-raw "ctl00%24certContents%24ddlInstaladores=$VERSION" |
        grep 'hiddenISO.*value="' | sed 's/^.*value="//g;s/".*$//g')"
    [ -z "$FILE" ] && return 1

    TEMPKEY="$(curl -s --compressed "$URL" --data-raw "$ASP_VARS" \
        --data-raw "__EVENTTARGET=ctl00%24certContents%24LinkButton3" \
        --data-raw "ctl00%24certContents%24hiddenISO=$FILE" \
        --data-raw "ctl00%24certContents%24txtSerialNumber=$SERIAL" \
        --data-raw "ctl00%24certContents%24chkConfirmo=on" \
        -o - | sed '/tempkey/!d;s/.*tempkey=//g;s/".*$//g')"
    [ -z "$TEMPKEY" ] && return 1

    printf '%s %s' "$FILE" "$TEMPKEY"
}

set_menu (revisar)

(No creo que este sea necesario)

set_menu() {
    if [ -z "$MENU" ] ; then
	command -v zenity > /dev/null && MENU="zenity" && return 0
	command -v kdialog > /dev/null && MENU="kdialog" && return 0
	MENU="term"
    fi
}

menu

Esto más que nada es una forma de abreviar los comandos y de mantener consistente la ejecución principal, de manera que se llama a esta función y determina desde un lugar cómo proceder con la notificación y entrada del usuario.

Nota: SC2034 se desactiva porque a pesar de que $nil es una variable sin utilizar, permite la portabilidad del script con otras implementaciones.

menu() {
    MODE="$1" PROMPT="$2"

    if [ "$MENU" = "zenity" ] ; then
	echo_debug "MENU: $MENU MODE: $MODE PROMPT: $PROMPT" > /dev/stderr
	[ "$MODE" = "info"  ] && zenity --title "$TITLE" --text "$PROMPT" --info
	[ "$MODE" = "error" ] && zenity --title "$TITLE" --text "$PROMPT" --error > /dev/stderr
	[ "$MODE" = "entry" ] && zenity --title "$TITLE" --text "$PROMPT" --entry
	[ "$MODE" = "pass"  ] && zenity --title "$TITLE" --password

    elif [ "$MENU" = "term" ] ; then
	# shellcheck disable=SC2034
	[ "$MODE" = "info" ]  &&
	    printf '\n\033[1m\033[34m=== %s ===\033[0m\n%s ENTER' "$TITLE" "$PROMPT" >/dev/stdin &&
	    read -r nil

	[ "$MODE" = "error" ] &&
	    printf '\n\033[1m\033[31m=== %s ===\033[0m\n%s\n'     "$TITLE" "$PROMPT" >/dev/stderr

	[ "$MODE" = "entry" ] &&
	    printf '\n\033[1m\033[34m=== %s ===\033[0m\n%s\n -> ' "$TITLE" "$PROMPT" >/dev/stdin &&
	    IFS= read -r entry &&
	    printf '%s' "$entry"

	[ "$MODE" = "pass" ] &&
	    printf '\n\033[1m\033[34m=== %s ===\033[0m\n%s\n -> ' "$TITLE" "$PROMPT" >/dev/stdin &&
	    IFS= read -r passwd &&
	    printf '%s' "$passwd"
    fi
}

Lenguaje

/etc/default/locale contiene información del lenguage por defecto, obtiene el lenguaje de esta locación si no está previamente definido (por el sistema o por el usuario utilizando, por ejemplo, LANG=es). Utiliza español por defecto si logra definir el lenguaje.

set_lang() {
    # See: /var/lib/AccountsService/users/
    ! [ "$LANG" ] && [ -f "/etc/default/locale" ] && . /etc/default/locale
    SLANG="${LANG%%_*}"
    [ -z "$SLANG" ] && SLANG="es"

    if [ "$SLANG" = "es" ] ; then
        TITLE="Instalador firma digital"
        PROMPT_WELCOME="Bienvenido al asistente de instalación de certificados para firma digial."
        PROMPT_ERR_DEPS="Error, la instalación requiere de los siguientes programas no presentes: "
        PROMPT_SERIAL="Ingrese el número serial impreso al reverso de la tarjeta."
        PROMPT_ERR_SERIAL="Error al obtener el número serial de la tarjeta, abortando."
        PROMPT_DOWNLOAD="Descargando desde Centro de Soporte Firma Digital..."
        PROMPT_DEPS_INSTALL="Instalando dependencias y otros complementos..."
        PROMPT_PASS_DEPS_INSTALL="Ingrese la contraseña del equipo para instalar los componentes"
        PROMPT_ERR_DEPS_INSTALL="Error instalando dependencias."
        PROMPT_ERR_DOWNLOAD="Error al descargar el fichero, abortando."
        PROMPT_END_SUCCESS="El instalador ha concluido."

    elif [ "$SLANG" = "en" ] ; then
        TITLE="Digital signature installer"
        PROMPT_WELCOME="Welcome to the digital signing certificate installation wizard."
        PROMPT_ERR_DEPS="Error, installation requires the following programs not present: "
        PROMPT_SERIAL="Enter the serial number printed on the back of the card."
        PROMPT_ERR_SERIAL="Error obtaining the card serial number, aborting."
        PROMPT_DOWNLOAD="Downloading from the Digital Signature Support Center..."
        PROMPT_DEPS_INSTALL="Installing dependencies and other components..."
        PROMPT_PASS_DEPS_INSTALL="Enter your computer password to install components"
        PROMPT_ERR_DEPS_INSTALL="Error installing dependencies."
        PROMPT_ERR_DOWNLOAD="Error downloading file, aborting."
        PROMPT_END_SUCCESS="The installer has completed."

    elif [ "$SLANG" = "fr" ] ; then
        TITLE="Installation de signature"
        PROMPT_WELCOME="Bienvenue dans l'assistant d'installation du certificat de signature."
        PROMPT_ERR_DEPS="Erreur, l'installation requise des programmes suivants ne présente pas: "
        PROMPT_SERIAL="Entrez le numéro de série imprimé au dos de la carte."
        PROMPT_ERR_SERIAL="Erreur d'obtention du numéro de série de la carte, abandon."
        PROMPT_DOWNLOAD="Téléchargement du fichier depuis le Centre de support des signatures numériques..."
        PROMPT_DEPS_INSTALL="Installation des dépendances et d'autres composants..."
        PROMPT_PASS_DEPS_INSTALL="Entrez le mot de passe de votre ordinateur pour installer les composants"
        PROMPT_ERR_DEPS_INSTALL="Erreur lors de l'installation des dépendances."
        PROMPT_ERR_DOWNLOAD="Erreur de téléchargement du fichier, abandon."
        PROMPT_END_SUCCESS="Le programme d'installation est terminé."

    fi
}

Instalación

Proceso de instalación para dependiendo de su base, ya sea con el $ID o $ID_LIKE, esto se define en get_version. Se deshabilita SC2016 ya que esta parte debe correr sin expandir las variables.

Debian

debian_install_certs() {
    # Source: https://fran.cr/instalar-firma-digital-costa-rica-gnu-linux-ubuntu-debian/

    echo_debug "Instalando dependencias"
    pseudo apt-get install -y unzip binutils p11-kit pcscd bubblewrap icedtea-netx > /dev/null || return 1

    echo_debug "Extraer fichero"
    [ -z "$SAVE_DIR" ] || [ -z "$SAVE_FILE" ] && return 1
    (cd "$SAVE_DIR" && unzip -u "$SAVE_FILE" > /dev/null) || return 1

    echo_debug "Copiar certificados"
    for cert in "$(find "$SAVE_DIR" -name "Certificados")"/* ; do
	certname="${cert##*/}"
	pseudo cp "$cert" /usr/local/share/ca-certificates/"${certname%.cer}.crt"
    done

    echo_debug "Extraer módulo privativo"
    PACKAGE="$(find "$SAVE_DIR" -name "idprotectclient[-_]*.deb")"
    PACKAGE_DIR="${PACKAGE%/*}"
    PACKAGE="${PACKAGE##*/}"
    [ -z "$PACKAGE_DIR" ] || [ -z "$PACKAGE" ] && return 1
    (cd "$PACKAGE_DIR" && ar p "$PACKAGE" data.tar.gz | tar zx ./usr/lib/x64-athena/libASEP11.so)
    pseudo cp -p "$PACKAGE_DIR"/usr/lib/x64-athena/libASEP11.so /usr/lib/x86_64-linux-gnu/

    echo_debug "Symlinks y componentes..."
    # shellcheck disable=SC2016
    pseudo sh -c '
# --- Certificados ---
for file in /usr/local/share/ca-certificates/*.crt ; do openssl x509 -inform DER -in "$file" -out "$file.tmp" 2> /dev/null ; done
find /usr/local/share/ca-certificates/ -type f -empty -delete
for i in /usr/local/share/ca-certificates/*.tmp ; do mv "$i" "${i%.tmp}" ; done
update-ca-certificates --fresh > /dev/null
# --- Instalación del módulo PKCS#11 ---
mkdir -p /usr/lib/x64-athena
mkdir -p /Firma_Digital/LIBRERIAS
ln -sf /usr/lib/x86_64-linux-gnu/libASEP11.so /usr/lib/x64-athena/
ln -sf /usr/lib/x86_64-linux-gnu/libASEP11.so /usr/lib/
ln -sf /usr/lib/x86_64-linux-gnu/libASEP11.so /usr/local/lib/
ln -sf /usr/lib/x86_64-linux-gnu/libASEP11.so /Firma_Digital/LIBRERIAS/
ln -sf /usr/local/share/ca-certificates /Firma_Digital/CERTIFICADOS
systemctl enable --now pcscd.socket > /dev/null
    '

    echo_debug "Configurando IDPClientDB"
    pseudo sh -c "
mkdir -p /etc/Athena
echo \"<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<IDProtect>
 <TokenLibs>
  <IDProtect>
   <Cards>
    <IDProtectXF>
     <ATR type='hexBinary'>3BDC00FF8091FE1FC38073C821106600000000000000</ATR>
     <ATRMask type='hexBinary'>FFFF00FFF0FFFFFFFFFFFFFFFFF0FF00000000000000</ATRMask>
    </IDProtectXF>
   </Cards>
  </IDProtect>
  <ChipDoc>
   <Cards>
    <ChipDocEMV>
     <ATR type='hexBinary'>3BEA00008131FE450031C173C840000090007A</ATR>
     <ATRMask type='hexBinary'>FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</ATRMask>
    </ChipDocEMV>
   </Cards>
  </ChipDoc>
 </TokenLibs>
</IDProtect>\" > /etc/Athena/IDPClientDB.xml
"

    echo_debug "Configurando p11-kit/modules"
    pseudo sh -c "
mkdir -p /usr/share/p11-kit/modules
echo 'remote: |bwrap --unshare-all --dir /tmp --ro-bind /etc/Athena /etc/Athena --proc /proc --dev /dev --ro-bind /usr /usr --ro-bind /lib /lib --ro-bind /lib64 /lib64 --ro-bind /var/run/pcscd /var/run/pcscd --ro-bind /run/pcscd /run/pcscd p11-kit remote /usr/lib/x86_64-linux-gnu/libASEP11.so' > /usr/share/p11-kit/modules/firma-digital.module
"

    echo_debug "Configurando p11-kit update symlinks"
    pseudo sh -c "
mkdir -p /usr/local/sbin
echo \"#!/bin/sh

FIREFOX_LIB=/usr/lib/firefox/libnssckbi.so
FIREFOX_ESR_LIB=/usr/lib/firefox-esr/libnssckbi.so
THUNDERBIRD_LIB=/usr/lib/thunderbird/libnssckbi.so
NSS_LIB=/usr/lib/x86_64-linux-gnu/nss/libnssckbi.so

if [ -e \"\$FIREFOX_LIB\" ]
then
    if ! [ -L \"\$FIREFOX_LIB\" ]
    then
	echo \"Firefox libnssckbi.so is not a symlink. Fixing...\"
	mv -f \"\$FIREFOX_LIB\" \"\$FIREFOX_LIB\".bak
	ln -s /usr/lib/x86_64-linux-gnu/p11-kit-proxy.so \"\$FIREFOX_LIB\"
    fi
fi

if [ -e \"\$FIREFOX_ESR_LIB\" ]
then
    if ! [ -L \"\$FIREFOX_ESR_LIB\" ]
    then
	echo \"Firefox ESR libnssckbi.so is not a symlink. Fixing...\"
	mv -f \"\$FIREFOX_ESR_LIB\" \"\$FIREFOX_ESR_LIB\".bak
	ln -s /usr/lib/x86_64-linux-gnu/p11-kit-proxy.so \"\$FIREFOX_ESR_LIB\"
    fi
fi

if [ -e \"\$THUNDERBIRD_LIB\" ]
then
    if ! [ -L \"\$THUNDERBIRD_LIB\" ]
    then
	echo \"Thunderbird libnssckbi.so is not a symlink. Fixing...\"
	mv -f \"\$THUNDERBIRD_LIB\" \"\$THUNDERBIRD_LIB\".bak
	ln -s /usr/lib/x86_64-linux-gnu/p11-kit-proxy.so \"\$THUNDERBIRD_LIB\"
    fi
fi

if [ -e \"\$NSS_LIB\" ]
then
    if ! [ -L \"\$NSS_LIB\" ]
    then
	echo \"NSS libnssckbi.so is not a symlink. Fixing...\"
	mv -f \"\$NSS_LIB\" \"\$NSS_LIB\".bak
	ln -s /usr/lib/x86_64-linux-gnu/p11-kit-proxy.so \"\$NSS_LIB\"
    fi
fi\" > /usr/local/sbin/update-p11-kit-symlinks
chmod +x /usr/local/sbin/update-p11-kit-symlinks
"

    echo_debug "Configurando módulo mantenimiento systemd"
    pseudo sh -c "
mkdir -p /etc/systemd/system
echo \"[Unit]
Description=mantenimiento de enlaces a p11-kit-proxy

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/update-p11-kit-symlinks

[Install]
WantedBy=multi-user.target
\" > /etc/systemd/system/p11-kit-proxy-updater.service
systemctl enable --now p11-kit-proxy-updater.service > /dev/null
"

    echo_debug "Instalando trust module pk11"
    pseudo sh -c "
mkdir -p /etc/pkcs11/modules
echo 'disable-in:' > /etc/pkcs11/modules/p11-kit-trust.module
"
}

Fedora

fedora_install_certs() {
    # Source: https://fran.cr/instalar-firma-digital-costa-rica-gnu-linux-fedora/

    echo_debug "Instalando dependencias"
    pseudo dnf -y install unzip pcsc-lite icedtea-web > /dev/null || return 1

    echo_debug "Extraer fichero"
    [ -z "$SAVE_DIR" ] || [ -z "$SAVE_FILE" ] && return 1
    (cd "$SAVE_DIR" && unzip -u "$SAVE_FILE" > /dev/null) || return 1

    echo_debug "Copiar certificados"
    pseudo cp -p "$(find "$SAVE_DIR" -name "Certificados")"/* /usr/share/pki/ca-trust-source/anchors/
    pseudo update-ca-trust

    echo_debug "Extraer módulo privativo"
    PACKAGE="$(find "$SAVE_DIR" -name "idprotectclient[-_]*.rpm")"
    PACKAGE_DIR="${PACKAGE%/*}"
    PACKAGE="${PACKAGE##*/}"
    [ -z "$PACKAGE_DIR" ] || [ -z "$PACKAGE" ] && return 1
    (cd "$PACKAGE_DIR" &&
	    rm -r ./usr/lib/x64-athena/libASEP11.so
	    rpm2cpio "$PACKAGE" | cpio -dim ./usr/lib/x64-athena/libASEP11.so) || return 1
    pseudo cp -p "$PACKAGE_DIR"/usr/lib/x64-athena/libASEP11.so /usr/lib64/

    echo_debug "Symlinks y componentes..."
    pseudo sh -c '
mkdir -p /usr/lib/x64-athena/
mkdir -p /Firma_Digital/LIBRERIAS/
ln -sf /usr/lib64/libASEP11.so /usr/lib/x64-athena/
ln -sf /usr/lib64/libASEP11.so /usr/lib/
ln -sf /usr/lib64/libASEP11.so /usr/local/lib/
ln -sf /usr/lib64/libASEP11.so /Firma_Digital/LIBRERIAS/
ln -sf /usr/share/pki/ca-trust-source/anchors /Firma_Digital/CERTIFICADOS
systemctl enable --now pcscd.socket > /dev/null
'

    echo_debug "Configurando IDPClientDB"
    pseudo sh -c "
mkdir -p /etc/Athena
echo \"<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<IDProtect>
 <TokenLibs>
  <IDProtect>
   <Cards>
    <IDProtectXF>
     <ATR type='hexBinary'>3BDC00FF8091FE1FC38073C821106600000000000000</ATR>
     <ATRMask type='hexBinary'>FFFF00FFF0FFFFFFFFFFFFFFFFF0FF00000000000000</ATRMask>
    </IDProtectXF>
   </Cards>
  </IDProtect>
  <ChipDoc>
   <Cards>
    <ChipDocEMV>
     <ATR type='hexBinary'>3BEA00008131FE450031C173C840000090007A</ATR>
     <ATRMask type='hexBinary'>FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</ATRMask>
    </ChipDocEMV>
   </Cards>
  </ChipDoc>
 </TokenLibs>
</IDProtect>\" > /etc/Athena/IDPClientDB.xml
"

    echo_debug "Configurando p11-kit/modules"
    pseudo sh -c "
mkdir -p /usr/share/p11-kit/modules
echo 'remote: |bwrap --unshare-all --dir /tmp --proc /proc --dev /dev --ro-bind /etc/Athena /etc/Athena --ro-bind /usr /usr --ro-bind /var/run/pcscd /var/run/pcscd --ro-bind /run/pcscd /run/pcscd --symlink /usr/lib64 /lib64 p11-kit remote /usr/lib64/libASEP11.so' > /usr/share/p11-kit/modules/firma-digital.module
"
}

Arch Linux

    arch_install_certs() {
    echo_debug "Instalando dependencias"
    pseudo pacman -S --noconfirm --needed unzip cpio rpm-tools pcsclite ccid jre8-openjdk icedtea-web > /dev/null || return 1

    echo_debug "Extraer fichero"
    [ -z "$SAVE_DIR" ] || [ -z "$SAVE_FILE" ] && return 1
    (cd "$SAVE_DIR" && unzip -u "$SAVE_FILE" > /dev/null)

    echo_debug "Copiar certificados"
    pseudo cp -p "$(find "$SAVE_DIR" -name "Certificados")"/* /usr/share/ca-certificates/trust-source/anchors/
    pseudo update-ca-trust

    echo_debug "Extraer módulo privativo"
    [ -z "$PACKAGE_DIR" ] || [ -z "$PACKAGE" ] && return 1
    (cd "$PACKAGE_DIR" && rpm2cpio "$PACKAGE" | cpio -dim ./usr/lib/x64-athena/libASEP11.so)
    pseudo cp -p "$PACKAGE_DIR"/usr/lib/x64-athena/libASEP11.so /usr/lib/

    echo_debug "Symlinks y componentes..."
    pseudo sh -c '
mkdir -p /usr/lib/x64-athena/
mkdir -p /Firma_Digital/LIBRERIAS/
ln -sf /usr/lib/libASEP11.so /usr/lib/x64-athena/
ln -sf /usr/lib/libASEP11.so /usr/local/lib/
ln -sf /usr/lib/libASEP11.so /Firma_Digital/LIBRERIAS/
ln -sf /usr/share/ca-certificates/trust-source/anchors /Firma_Digital/CERTIFICADOS
ln -sf /usr/lib/p11-kit-proxy.so /usr/lib/firefox/libosclientcerts.so
systemctl enable --now pcscd.socket > /dev/null
'

    echo_debug "Configurando IDPClientDB"
    pseudo sh -c "
mkdir -p /etc/Athena
echo \"<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<IDProtect>
 <TokenLibs>
  <IDProtect>
   <Cards>
    <IDProtectXF>
     <ATR type='hexBinary'>3BDC00FF8091FE1FC38073C821106600000000000000</ATR>
     <ATRMask type='hexBinary'>FFFF00FFF0FFFFFFFFFFFFFFFFF0FF00000000000000</ATRMask>
    </IDProtectXF>
   </Cards>
  </IDProtect>
  <ChipDoc>
   <Cards>
    <ChipDocEMV>
     <ATR type='hexBinary'>3BEA00008131FE450031C173C840000090007A</ATR>
     <ATRMask type='hexBinary'>FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF</ATRMask>
    </ChipDocEMV>
   </Cards>
  </ChipDoc>
 </TokenLibs>
</IDProtect>\" > /etc/Athena/IDPClientDB.xml
"

    echo_debug "Configurando p11-kit/modules"
    pseudo sh -c "
mkdir -p /usr/share/p11-kit/modules
echo 'remote: |bwrap --unshare-all --dir /tmp --proc /proc --dev /dev --ro-bind /etc/Athena /etc/Athena --ro-bind /usr /usr --ro-bind /lib64 /lib64 --ro-bind /run/pcscd /run/pcscd p11-kit remote /usr/lib/libASEP11.so' > /usr/share/p11-kit/modules/firma-digital.module
"
}

Función wrapper

Encargarse de la instalación simplemente llamando install_certs.

install_certs() {
    [ -z "$SUDO_PASSWORD" ] && return 1
    [ -z "$SAVE_FILE" ] && return 1
    SAVE_DIR="${SAVE_FILE%/*}"

    if   [ "$ID" = "macos" ] ; then
	open "$SAVE_FILE" || return 1

    elif [ "$ID" = "debian" ] ; then
	debian_install_certs || return 1

    elif [ "$ID" = "fedora" ] ; then
	fedora_install_certs || return 1

    elif [ "$ID" = "arch" ] ; then
	arch_install_certs || return 1

    elif [ "$ID" = "centos" ] ; then
	echo || return 1

    fi
}

Main

TODO Inicializar [0/2]

  • Tirar exit 1 en caso de no poder seleccionar una versión o un menu.
  • Agregar otras dependencias mínimas, o que no conviene instalarlas en el script (sudo)
set_lang
set_version
set_menu

if ! command -v curl > /dev/null ; then
    menu error "$PROMPT_ERR_DEPS curl"
    exit 1
fi

menu info "$PROMPT_WELCOME"

No. Serial

SERIAL="${SERIAL:=$(menu entry "$PROMPT_SERIAL")}"

if [ -z "$SERIAL" ] ; then
    menu error "$PROMPT_ERR_SERIAL"
    exit 1
fi

Proceso de descarga

Obtener URL e información del fichero
ARCHIVE="$(get_archive)"
TEMPKEY="${ARCHIVE##* }"
FILE="${ARCHIVE%% *}"

DOWNLOAD_URL="$(
    printf 'https://soportefirmadigital.com/sfdj/getiso.aspx?tempkey=%s' \
        "$TEMPKEY"
)"

SIZE="$(curl -sI "$DOWNLOAD_URL" |
    sed '/[Cc]ontent-[Ll]ength/!d;s/^.*: //g' |
    awk '{$1/=1024;printf "%d",$1}'
)"

if [ "$SIZE" -lt 500 ] || [ -z "$FILE" ] ; then
    menu error "$PROMPT_ERR_DOWNLOAD"
    exit 1
fi
Descarga

Se desactiva SC2009 para asegurarse de tener el ID correcto, ya que terminará el proceso en caso de seguir activo.

SAVE_DIR="/tmp/soportefirmadigital"
SAVE_FILE="$SAVE_DIR/$FILE"
mkdir -p "$SAVE_DIR"

if [ "$MENU" = "zenity" ] ; then
    (curl -sL "$DOWNLOAD_URL" -o "$SAVE_FILE") &
    while true ; do
        sleep 0.5
        DOWN="$(du "$SAVE_FILE" 2>/dev/null | awk '{print $1}')"
        [ -z "$DOWN" ] && DOWN=0
        r=$(((DOWN*10000)/SIZE))
        printf '%d\n' ${r%??}
    done | zenity --title "$TITLE" --text "$PROMPT_DOWNLOAD" --progress --auto-close

elif [ "$MENU" = "term" ] ; then
    menu info "$PROMPT_DOWNLOAD" && echo
    curl "$DOWNLOAD_URL" -o "$SAVE_FILE" --progress-bar

fi

# shellcheck disable=SC2009
ACTIVE="$(ps -t | grep 'curl.*soportefirmadigital' | sed '/grep/d')"
ACTIVE="${ACTIVE# }"
ACTIVEID="${ACTIVE%% *}"

if [ -n "$ACTIVE" ] ; then
    menu error "$PROMPT_ERR_DOWNLOAD"
    echo_debug "Killing process ID: $ACTIVEID from: $ACTIVE" # DEBUG
    kill "$ACTIVEID"
    exit 1
fi

Proceso de instalación

Permisos elevados
SUDO_PASSWORD="${SUDO_PASSWORD:=$(menu pass "$PROMPT_PASS_DEPS_INSTALL")}"

if [ -z "$SUDO_PASSWORD" ] || ! pseudo whoami >/dev/null 2>&1 ; then
    menu error "$PROMPT_ERR_DEPS_INSTALL"
    exit 1
fi
Instalación
if [ "$MENU" = "zenity" ] ; then
    # Attempt to install, forward output to program
    # but keep exit code of install function
    ( ( ( (install_certs; echo $? >&3) |
        zenity --title "$TITLE" --text "$PROMPT_DEPS_INSTALL" --progress --pulsate --auto-close >&4) 3>&1 ) |
        (read -r xs; exit "$xs") ) 4>&1
    #install_certs # Just run this instead to see debug info # DEBUG
    # Ignore as this is needed for this "workaround"
    # shellcheck disable=SC2181
    if [ "$?" != "0" ] ; then
        menu error "$PROMPT_ERR_DEPS_INSTALL"
        exit 1
    fi

elif [ "$MENU" = "term" ] ; then
    menu info "$PROMPT_DEPS_INSTALL" && echo
    ! install_certs && menu error "$PROMPT_ERR_DEPS_INSTALL" && exit 1

fi

Finalización

menu info "$PROMPT_END_SUCCESS\n"

exit 0