#!/bin/bash
# Por Tales A. Mendonça (talesam@gmail.com)
# Faz a instalação da aplicação IHX Access Pro em Docker
# Versão do script
Ver="v1.8.6"
# Definição de Cores
CIN='\e[30;1m' # Cinza
RED='\e[31;1m' # Vermelho
GRE='\e[32;1m' # Verde
YEL='\e[33;1m' # Amarelo
BLU='\e[34;1m' # Azul
ROS='\e[35;1m' # Rosa
CYA='\e[36;1m' # Ciano
NEG='\e[37;1m' # Negrito
CUI='\e[40;31;5m' # Vermelho pisacando, aviso!
STD='\e[m' # Fechamento de cor
### INÍCIO FUNÇÕES ###
# Função pause
pause(){
read -p "$*"
}
### Função Alerta Vermelho
alertaVermelho() {
echo -e "${RED}*${STD} ${NEG} $1 ${STD}"
echo ""
}
### Função Alerta Amarelo
alertaAmarelo() {
echo -e "${YEL}*${STD} ${NEG} $1 ${STD}"
echo ""
sleep 1
}
### Função Alerta Verde
alertaVerde() {
echo -e "${GRE}*${STD} ${NEG} $1 ${STD}"
echo ""
sleep 1
}
### Função Alerta Verde
alertaAzul() {
echo -e "${BLU}*${STD} ${NEG} $1 ${STD}"
echo ""
sleep 1
}
### Função coleta de dados
coletaDados() {
# Este é um loop infinito que continuará até que seja quebrado com 'break'
while : ; do
# Solicitar entrada do usuário
alertaAzul "Insira o nome do cliente:"
read cliente
# Definir o caminho para o diretório do cliente
caminho="$HOME/Docker/IHX_Access_Pro/$cliente"
# Converte a entrada do usuário para minúsculas
cliente=${cliente,,}
# Verificar se a entrada não está vazia
if [ -z "$cliente" ]; then
alertaAmarelo "O nome do cliente não pode ser vazio."
else
break # Se a entrada não estiver vazia, quebra o loop e continua o script
fi
done
# Verificar se o diretório já existe
if [ -d "$caminho" ]; then
alertaAmarelo "Diretório $caminho já existe."
else
# Criar o diretório se ele não existir
mkdir -p "$caminho"
alertaVerde "Diretório $caminho criado com sucesso."
fi
# caminho para o arquivo .env
envPath="$caminho/.env"
# Encontra e configura a porta disponível
if ! encontrarPortaDisponivel "$envPath"; then
alertaVermelho "Erro ao encontrar uma porta disponível."
exit 1
fi
# Escrever as variáveis no arquivo .env para o docker-compose.yml
{
echo "cliente=$cliente"
echo "db_Container_Name=db_ihx_$cliente"
echo "db_Root_Password=1hx@p4550rd"
echo "db_Name=ihx_access_pro"
echo "db_User=db_user"
echo "db_Password=1hx@p4550rd"
echo "app_Container_Name=ihx_$cliente"
echo "network_Name=ihx-net_$cliente"
} >> "$envPath"
# Carregar arquivo .env
source "$envPath"
}
# Função para encontrar uma porta disponível
encontrarPortaDisponivel() {
local envPath="$1" # Adiciona um argumento para o caminho do arquivo .env
local basePort=33601 # Porta base para começar a busca
local maxPort=34000 # Porta máxima que queremos verificar
local port=$basePort
# Loop para encontrar uma porta disponível
while : ; do
# Checa se a porta está em uso (necessário ter o net-tools instalado)
if ! netstat -tuln | grep -q ":$port"; then
# Porta está disponível
alertaVerde "Porta disponível encontrada: $port"
# Escreve a porta disponível no arquivo .env e verifica se foi bem-sucedido
echo "porta_db=$port" >> "$envPath" && \
alertaVerde "Porta escrita no arquivo .env com sucesso." || \
{ alertaVermelho "Falha ao escrever a porta no arquivo .env."; return 1; }
# Adiciona a regra no firewall para permitir a porta encontrada (necessário ter permissões de superusuário)
if ! sudo ufw allow $port/tcp; then
alertaVermelho "Falha ao adicionar regra no firewall para a porta $port."
return 1
else
alertaVerde "Regra no firewall adicionada com sucesso para a porta $port."
return 0
fi
else
# Porta está em uso, incrementa e tenta a próxima
((port++))
if [ $port -ge $maxPort ]; then
alertaVermelho "Não foi possível encontrar uma porta disponível."
return 1
fi
fi
done
}
### Função para baixa os arquivos necessários
arquivosNecessarios() {
# Diretório temporário para extração dos arquivos baixados
dirTmp="/tmp/IHX"
rm -rf $dirTmp
# Cria o diretório temporário
mkdir -p $dirTmp
# Nome do arquivo
arquivo="docker-compose_v1.8.tar.bz2"
# Baixa o arquivo
wget -q https://cloud.talesam.org/s/zekHJye2ncwM4pk/download/$arquivo -P $dirTmp
# Verifica se o arquivo foi baixado corretamente
if [ ! -f "$dirTmp/$arquivo" ]; then
alertaVermelho "Erro: O arquivo não foi baixado corretamente."
exit 1
fi
# Extrai o arquivo
tar -xvJf $dirTmp/$arquivo -C $caminho
# Verifica se o arquivo foi extraído corretamente
if [ $? -ne 0 ]; then
alertaVermelho "Erro: Falha ao extrair o arquivo."
exit 1
else
alertaVerde "Arquivos extraídos com sucesso para $caminho."
fi
}
### Função para instalar aplicação IHX
instalarIHX() {
# Limpa a tela
clear
# Chama a função para coleta de dados
coletaDados
# Chama a funçao para baixar os arquivos
arquivosNecessarios
# Inicia os Conteiners
alertaAzul "Ativando todos os containers, aguarde..."
# Deixa os conteiners rodando em segundo plano
cd $caminho
docker-compose up -d && sleep 1
# Nomes dos contêineres a serem verificados
containers=("$db_Container_Name")
# Verifica a saúde dos contêineres
for container in "${containers[@]}"; do
statusSaude=""
tentativasMax=100
tentativas=0
pontos=""
while [[ "$statusSaude" != "healthy" && $tentativas -lt $tentativasMax ]]; do
statusSaude=$(docker inspect --format='{{json .State.Health.Status}}' "$container" | tr -d '"')
if [[ "$statusSaude" == "healthy" ]]; then
alertaVerde "Contêiner $container saudável!"
else
pontos+="."
printf " ${YEL}*${STD} ${NEG}Contêiner{STD} ${YEL}%-22s${STD} ${NEG}ainda está iniciando, aguardando$pontos${STD}\r" "$container"
fi
((tentativas++))
sleep 1
done
echo ""
if [[ "$statusSaude" != "healthy" ]]; then
alertaVermelho "Contêiner $container não ficou saudável após $tentativasMax tentativas."
exit 1
fi
# O contêiner está saudável, executar criação de tabelas
alertaAzul "Iniciando a criação das tabelas e importação do banco de dados no contêiner $app_Container_Name..."
docker exec $app_Container_Name bash -c "source /ihx_access_pro/env/bin/activate && python2 /ihx_access_pro/manage.py syncdb --noinput"
if [[ $? -eq 0 ]]; then
alertaVerde "Tabelas criadas e sincronizadas com sucesso!"
sqlFileS=("funcoes.sql" "inserts.sql" "updates.sql")
sucessoImportacao=true
for sqlFile in "${sqlFileS[@]}"; do
alertaAzul "Copiando e importando $sqlFile"
docker cp $caminho/Config/db/$sqlFile $db_Container_Name:/tmp/$sqlFile
docker exec $db_Container_Name mysql -u$db_User -p$db_Password ihx_access_pro -e "source /tmp/$sqlFile"
if [[ $? -ne 0 ]]; then
alertaVermelho "Falha ao importar $sqlFile"
sucessoImportacao=false
break
else
alertaVerde "$sqlFile importado com sucesso!"
fi
done
else
alertaVermelho "Falha ao criar tabelas ou importar banco de dados!"
exit 1
fi
done
# Chama a função pause
pause " Tecle [Enter] para voltar ao menu..." && sleep 1 ; clear
}
### Função para instalar certificado SSL
instalarCertificado() {
# Limpa a tela
clear
# Listar os Diretórios
baseDir="$HOME/Docker/IHX_Access_Pro/"
IFS=$'\n' read -d '' -r -a dirArray < <(ls -d "$baseDir"*/ && printf '\0')
# Exibir o Menu
alertaAzul "Escolha onde deseja instalar o certificado SSL:"
for i in "${!dirArray[@]}"; do
dirName=$(basename "${dirArray[$i]}")
echo -e "${BLU}$((i + 1)))${STD} $dirName"
done
# Adicionada a opção de voltar
echo -e "${ROS}$(( ${#dirArray[@]} + 1 )))${STD} Voltar ao menu principal"
# Seleção do Usuário
echo ""
read -p "Escolha um número: " choice
# Se o usuário escolher 'Voltar ao menu principal'
if [ "$choice" -eq "$(( ${#dirArray[@]} + 1 ))" ]; then
return
fi
cliente=$(basename "${dirArray[$((choice - 1))]}")
# Define o caminho para o diretório do cliente
caminho="$HOME/Docker/IHX_Access_Pro/$cliente"
# Desativando contêineres para gerar e importar das chaves e certificados SSL
alertaAzul "Desativando os contêineres para gerar e importar as chaves e certificados SSL, aguarde..."
if ! cd "$caminho" || ! docker-compose down; then
alertaVermelho "Falha ao desativar os contêineres."
exit 1
fi
# Define o diretório para armazenar as chaves SSL
sslKeyDir="$caminho/mysql_keys"
# Cria o diretório para armazenar as chaves SSL, se não existir
if ! mkdir -p "$sslKeyDir"; then
alertaVermelho "Erro ao criar o diretório $sslKeyDir"
exit 1
fi
# Modifica a propriedade do diretório para o usuário ihx e o grupo ihx
if ! sudo chown ihx:ihx "$sslKeyDir"; then
alertaVermelho "Erro ao mudar a propriedade do diretório $sslKeyDir para ihx:ihx"
exit 1
fi
# Gera uma senha randômica
senhaChave=$(openssl rand -base64 48)
echo "$senhaChave" > "$sslKeyDir/senha.txt"
chmod 600 "$sslKeyDir/senha.txt"
# Gera a chave e o certificado do servidor
if ! openssl req -x509 -newkey rsa:2048 -keyout "$sslKeyDir/server-key-enc.pem" \
-out "$sslKeyDir/server-cert.pem" \
-subj "/C=BR/ST=MG/L=Juiz de Fora/O=IHX Sistema/OU=Tecnologia/CN=server/emailAddress=contato@ihxsistema.com.br" \
-passout pass:"$senhaChave"; then
alertaVermelho "Erro ao gerar a chave e certificado do servidor."
exit 1
else
alertaVerde "Chave e o certificado do servidor gerados com sucesso!"
fi
# Decodifica a chave do servidor
if ! openssl rsa -in "$sslKeyDir/server-key-enc.pem" -out "$sslKeyDir/server-key.pem" \
-passin pass:"$senhaChave" -passout pass:"$senhaChave"; then
alertaVermelho "Erro ao decodificar chave servidor."
exit 1
else
alertaVerde "Chave do servidor decodificada com sucesso!"
fi
# Gera a chave e o certificado do cliente
if ! openssl req -x509 -newkey rsa:2048 -keyout "$sslKeyDir/client-key-enc.pem" \
-out "$sslKeyDir/client-cert.pem" \
-subj "/C=BR/ST=MG/L=Juiz de Fora/O=IHX Sistema/OU=Tecnologia/CN=client/emailAddress=contato@ihxsistema.com.br" \
-passout pass:"$senhaChave"; then
alertaVermelho "Erro ao gerar a chave e certificado do cliente."
exit 1
else
alertaVerde "Chave e o certificado do cliente gerados com sucesso!"
fi
# Decodifica a chave do cliente
if ! openssl rsa -in "$sslKeyDir/client-key-enc.pem" -out "$sslKeyDir/client-key.pem" \
-passin pass:"$senhaChave" -passout pass:"$senhaChave"; then
alertaVermelho "Erro ao decodificar chave cliente."
exit 1
else
alertaVerde "Chave do cliente decodificada com sucesso!"
fi
# Combina os certificados de cliente e servidor no arquivo de certificados CA
if ! cat "$sslKeyDir/server-cert.pem" "$sslKeyDir/client-cert.pem" > "$sslKeyDir/ca-cert.pem"; then
alertaVermelho "Erro ao combinar certificado do cliente e servidor no arquivo de certificados CA."
exit 1
else
alertaVerde "Certificado do cliente e servidor combinados no arquivo de certificados CA com sucesso!"
fi
# Verifica o Certificado do Servidor
if ! openssl verify -CAfile "$sslKeyDir/ca-cert.pem" "$sslKeyDir/server-cert.pem"; then
alertaVermelho "Erro ao verificar certificado do servidor."
exit 1
else
alertaVerde "Certificado do servidor verificado com sucesso!"
fi
# Verifica o Certificado do Cliente
if ! openssl verify -CAfile "$sslKeyDir/ca-cert.pem" "$sslKeyDir/client-cert.pem"; then
alertaVermelho "Erro ao verificar certificado do cliente."
exit 1
else
alertaVerde "Certificado do cliente verificado com sucesso!"
fi
# Substituição do arquivo custom_ssl.cnf pelo arquivo custom.cnf
alertaAzul "Substituindo o arquivo custom_ssl.cnf pelo arquivo custom.cnf..."
if ! cp -f "$caminho/Config/custom_ssl.cnf" "$caminho/Config/custom.cnf"; then
alertaVermelho "Erro ao realizar a substituição do arquivo custom.cnf."
exit 1
else
alertaVerde "Substituição do arquivo custom.cnf realizada com sucesso!"
fi
# Remove as chaves codificadas para garantir a segurança
alertaAzul "Removendo as chaves codificadas..."
if ! rm -f "$sslKeyDir/client-key-enc.pem" "$sslKeyDir/server-key-enc.pem"; then
alertaVermelho "Erro ao remover as chaves codificadas."
exit 1
else
alertaVerde "Chaves codificadas removidas com sucesso!"
fi
# Obtém a data atual no formato AAAA-MM-DD
dataAtual=$(date +%F)
# Nome do arquivo zip seguindo o padrão keys_data_cliente.zip
nomeArquivoZip="keys_${dataAtual}_${cliente}.zip"
# Compacta os arquivos especificados em um arquivo .zip
alertaAzul "Compactando as chaves..."
if zip -j "$sslKeyDir/$nomeArquivoZip" \
"$sslKeyDir/ca-cert.pem" \
"$sslKeyDir/client-cert.pem" \
"$sslKeyDir/client-key.pem"; then
alertaVerde "Chaves compactadas com sucesso no arquivo $nomeArquivoZip."
# Altera a propriedade do arquivo zip para o usuário ihx e o grupo ihx
if sudo chown ihx:ihx "$sslKeyDir/$nomeArquivoZip"; then
alertaVerde "Propriedade do arquivo $nomeArquivoZip alterada para ihx:ihx com sucesso."
else
alertaVermelho "Erro ao alterar a propriedade do arquivo $nomeArquivoZip."
exit 1
fi
else
alertaVermelho "Erro ao compactar as chaves."
exit 1
fi
# Define os detalhes de login do Nextcloud
nextcloudUser='talesam@gmail.com'
nextcloudPass='nmYiiahisDA5653' # Substitua MINHA_SENHA pela sua senha real
nextcloudURL="https://cloud.talesam.org/remote.php/dav/files/$nextcloudUser/"
# O caminho completo da pasta no Nextcloud onde o arquivo será salvo
# Os espaços e caracteres especiais são codificados para URL
nextcloudDirPath="Servidor/Docker/Fran%C3%A7ois/IHX%20Access%20Pro/Keys"
# Caminho local do arquivo que deseja enviar
localFilePath="$sslKeyDir/$nomeArquivoZip"
# Nome do arquivo no Nextcloud, incluindo o caminho da pasta onde deve ser salvo
nextcloudFilePath="$nextcloudDirPath/$nomeArquivoZip"
# Envia o arquivo para o Nextcloud e captura a resposta HTTP
alertaAzul "Enviando o arquivo com as keys para o Nextcloud..."
response=$(curl -w "%{http_code}" -u "$nextcloudUser:$nextcloudPass" -T "$localFilePath" "$nextcloudURL$nextcloudFilePath" -o /dev/null -s)
# Verifica se o upload foi bem-sucedido analisando o código de resposta HTTP
if [ "$response" -eq 201 ]; then
alertaVerde "Arquivo enviado para o Nextcloud com sucesso!!"
elif [ "$response" -eq 204 ]; then
alertaVerde "Arquivo substituído com sucesso no Nextcloud."
else
alertaVermelho "Erro ao enviar arquivo para o Nextcloud: HTTP status $response."
exit 1
fi
# Iniciar os contêineres
alertaAzul "Iniciando os contêineres com SSL ativo no banco de dados..."
if ! cd "$caminho" || ! docker-compose up -d; then
alertaVermelho "Erro ao iniciar contêineres."
exit 1
else
alertaVerde "Contêineres iniciados com sucesso!"
fi
# Chama a função pause
pause " Tecle [Enter] para voltar ao menu..." && sleep 1 && clear
}
### Função para remover uma aplicação
removerAplicacao() {
# Limpa a tela
clear
# Listar os Diretórios
baseDir="$HOME/Docker/IHX_Access_Pro/"
IFS=$'\n' read -d '' -r -a dirArray < <(ls -d "$baseDir"*/ && printf '\0')
# Exibir o Menu
alertaAzul "Escolha a aplicação que deseja remover:"
for i in "${!dirArray[@]}"; do
dirName=$(basename "${dirArray[$i]}")
echo -e "${BLU}$((i + 1)))${STD} $dirName"
done
# Adicionada a opção de voltar
echo -e "${ROS}$(( ${#dirArray[@]} + 1 )))${STD} Voltar ao menu principal"
# Seleção do Usuário
echo ""
read -p "Escolha um número: " choice
# Se o usuário escolher 'Voltar ao menu principal'
if [ "$choice" -eq "$(( ${#dirArray[@]} + 1 ))" ]; then
return
fi
cliente=$(basename "${dirArray[$((choice - 1))]}")
# Define o caminho do diretório do cliente
caminho="$HOME/Docker/IHX_Access_Pro/$cliente"
# Entra no diretório do cliente
if ! cd "$caminho"; then
alertaVermelho "Erro ao entrar no diretório $caminho."
exit 1
fi
# Desativa a aplicação
alertaAzul "Desativando a aplicação para ser removida..."
if ! docker-compose down; then
alertaVermelho "Erro ao desativar a aplicação com docker-compose down."
exit 1
else
alertaVerde "Aplicação desativada com sucesso."
fi
# Lê a porta que estava em uso a partir do arquivo .env
if [ -f ".env" ]; then
source .env
porta=${porta_db:-}
if [ -z "$porta" ]; then
alertaVermelho "Porta não definida no arquivo .env."
exit 1
fi
else
alertaVermelho "Arquivo .env não encontrado. Não é possível determinar a porta para bloquear no firewall."
exit 1
fi
# Retorna ao diretório anterior
cd - > /dev/null 2>&1 || { alertaVermelho "Erro ao retornar ao diretório anterior."; return 1; }
# Remove o diretório da aplicação
if ! sudo rm -rf "$caminho"; then
alertaVermelho "Erro ao remover o diretório $caminho."
exit 1
else
alertaVerde "Diretório $caminho removido com sucesso."
fi
# Bloqueia a porta no firewall
if ! sudo ufw delete allow "$porta/tcp"; then
alertaVermelho "Erro ao bloquear a porta $porta no firewall."
exit 1
else
alertaVerde "Porta $porta bloqueada no firewall com sucesso."
fi
alertaVerde "Aplicação removida e porta bloqueada com sucesso."
# Chama a função pause
pause " Tecle [Enter] para voltar ao menu..."
}
### FIM FUNÇÕES ###
# ------- MENU -------
# Mostra o menu
while true; do
clear
echo -e " ${BLU}SCRIPT DE INSTALAÇÃO DO IHX ACCESS PRO -${STD} ${YEL}${Ver}${STD}"
echo ""
echo ""
echo -e " ${BLU}1) Instalar aplicação IHX${STD}"
echo -e " ${GRE}2) Instalar certificado${STD}"
echo -e " ${RED}3) Remover aplicação IHX${STD}"
echo -e " ${YEL}0) Sair${STD}"
echo ""
read -p " Escolha uma opção: " escolha
case $escolha in
1) instalarIHX ;;
2) instalarCertificado ;;
3) removerAplicacao ;;
0) exit ;;
*) alertaAmarelo "Opção inválida" ;;
esac
done