O Protocolo HTTP – Parte 06

Introdução

No post anterior (O Protocolo HTTP – Parte 05), o Web Site local de testes com o TOTVS Application Server ganhou mais uma funcionalidade, vimos como o Browse montou uma requisição de POST de um formulário HTML com campos de preenchimento do usuário, e mais detalhes sobre GET e POST. Agora, vamos fazer alguns ajustes nas páginas HTML do site de testes, e ver se ou quais impactos terão estes ajustes, e acrescentar mais algumas coisas …

Utilizando HTML5

HTML versão 5 traz novos identificadores, recursos, e já está bem suportado pelos Web Browses de mercado. Embora marcadores foram declarados “obsoletos”, já que é para colocar a mão na massa, é elegante declarar na primeira linha de cada página HTML, que a versão usada é a HTML5. Para isso, basta inserir a linha abaixo como primeira linha do arquivo:

<!DOCTYPE html>

HTML Head e HTML Body

De forma similar ao protocolo HTTP, uma página HTML possui identificadores para declaração de elementos de cabeçalho de página (Header), e para delimitar o corpo do HTML (Body), inclusive delimitar o inicio e fim do HTML. Se nada disso for colocado, e voce simplesmente criar um arquivo HTML sem estes identificadores, normalmente o Web Browse vai interpretar tudo como HTML Body… Mas é deveras recomendável que você monte as suas páginas HTML declarando onde fica o que, vide exemplo abaixo:

<!DOCTYPE html>
<html>
<head>
<title>Título do Documento</title>
</head>
<body>
Conteúdo do Documento...
</body>
</html>

Entre o inicio e final do cabeçalho HTML, delimitado pelos marcadores <head> e </head>, usamos outros marcadores HTML para identificar características (ou meta-dados) de um documento e/ou página HTML, como um título — usado na barra de navegação e por mecanismos de busca –, scripts — executados pelo web browser na estação onde a página e/ou documento HTML está sendo mostrado, entre outras coisas interessantes.

Salve esse arquivo com o nome “html5.htm” na pasta htto-root, e com o Application Server em execução, abra a URL http://locahost/html5.htm, e vejamos como a tela apareceu:

Se o arquivo foi salvo usando CodePage 1252, os caracteres acentuados serão mostrados corretamente. Se ele foi salvo pelo NOTEPAD usando UTF-8, serão mostrados caracteres “estranhos” nos acentos … Isso é UTF-8 interpretado como CP1252 …

Agora, vamos pegar esse “padrão”, e refazer os arquivos do nosso site de testes. Eles devem ficar assim:

  • Arquivo default.htm
<!DOCTYPE html>
<html>
<head>
<title>Meu primeiro Web Site - Página Inicial</title>
</head>
<body>
<h3>Meu primeiro Web Site</h3>
<a href="testepost.htm">Teste de Post</a>
</body>
</html>
  • Arquivo testepost.htm
<!DOCTYPE html>
<html>
<head>
<title>Meu primeiro Web Site - Teste de POST</title>
</head>
<body>
<h3>Teste de Post</h3>
<hr>
<form name="mydataform" method="post" action="testepost.htm">
<input type="text" name="CAMPO1"></input>
<input type="text" name="CAMPO2"></input>
input type="submit"/>
</form>
<hr>
<a href="/">Voltar ao Início</a>
</body>
</html>

Agora, com tudo funcionando, vamos passar a usar a codificação UTF-8 nos nossos arquivos HTML, bastando para isso suas coisas :

  • Usando por exemplo o editor NOTEPAD++, insira logo após a linha de abertura do header <head>, antes do <title>, a linha abaixo:
<meta charset="UTF-8">
  • Agora, use a opção Encoding -> Convert to UTF-8, e salve o arquivo. ( Verifique se o arquivo já não está com esta codificação … os editores de textos simples mais recentes, mesmo o NOTEPAD do Windows, já codifica o arquivo como UTF-8 se você cria o arquivo e preenche com algum caractere acentuado.)

E, finalmente, vamos abrir novamente os arquivos no Web Browser. Com o conteúdo codificado em UTF-8, e a informação meta charset no HTML head, tudo deve ser mostrado corretamente pelo Web Browser.

Executando o POST novamente, agora informando caracteres acentuados

No teste de post anterior, sem utilizar o charset UTF-8 nos nossos HTML(s), a letra “a” minúsculo acentuado foi enviada pelo Web Browser ao realizar o POST usando o (Codepage) CP-1252, e enviada pelo post codificada como “%E1″. Agora que estamos usando UTF-8, se acessarmos a tela de teste de post, digitarmos no primeiro campo “Olá” e no segundo “Mundo”, e verificarmos usando o painel do desenvolvedor como o Google Chrome codificou a letra “á”, veremos novidades:

Reparem que agora a letra “á” foi codificada como “%C3%A1” .. Essa é a seqüência de bytes no padrão UTF-8 que representa a letra a minúscula com acento agudo no alfabeto latino. Deste ponto em diante, todos os arquivos HTML dos nossos testes passam a declarar HTML5 e codificação em UTF-8. 😀 E, conseqüentemente, o Web Browser vai entender que, se o conteúdo do arquivo é UTF-8, e existe um formulário de entrada de dados, esses dados serão codificados como UTF-8.

Mas, o que eu ganho com isso ?

Utilizando UTF-8, é possível codificar e representar múltiplos alfabetos e caracteres de outros idiomas — mais de 1 milhão — do formato internacional “Unicode”, até “emoticons”. UTF-8 signfica “Unicode Transformation Format – 8 bits”. Eu posso por exemplo, usar uma ferramenta como o Google Translator, e traduzir “olá” de português para Russo e Chinês, e colocar dois parágrafos no arquivo “default.htm”, copiando e colando os caracteres da tradução, usando o Notepad++ ou o NOTEPAD do Windows … veja como o ficou o arquivo:

E, ao ser mostrado no Web Browser, ficou assim:

Vamos colocar uma imagem no HTML ?

Eu peguei uma foto do meu perfil do Facebook, salvei como uma uma imagem JPG, usei o PaintBrush do Windows para fazer um “resize” na imagem .. e ela ficou um “quadrado” de 192×192 pixels…. Salvei essa imagem no disco, com o nome “mypicture.jpg”, dentro de uma nova pasta chamada “pictures”, criada dentro da pasta http-root.

Agora, vamos editar a nossa pagina “default.htm”, e colocar essa imagem para ser mostrada no HTML, acrescentando as duas linha em negrito abaixo, antes do </body>:

<hr>
<img src="./pictures/mypicture.jpg">

A linha com <hr> insere uma barra horizontal no documento, e o marcador <img permite a inserção de uma imagem dentro do HTML. Reparem que, para a imagem ser localizada, eu informo na propriedade “src=” a informação “./pictures/mypicture.jpg”. Vamos ver como ficou ?

Agora, ao usar as ferramentas do desenvolvedor do Google Chrome, e pedir para recarregar essa página, vamos ver uma informação nova:

Quando o Web Browser pediu a página “default.htm” ao HTTP Server, ele recebeu apenas a página HTML… Após receber a página e começar a “desenhar” o HTML na tela, o Web Browse encontrou o marcador de imagem, para mostrar a imagem “./pictures/mypicture.jpg” … Então, o Web Browse abre internamente uma nova solicitação de GET, pedindo esse arquivo para o HTTP Server. O HTTP Server, ao receber o pedido, verifica que o arquivo existe em disco, na pasta identificada, e retorna o arquivo ao Browser, que mostra a imagem na tela.

Como o HTTP server sabia que a imagem era do tipo JPEG ?

Então, existem algumas extensões de arquivo conhecidas e tratadas pelo Totvs Application Server como servidor de HTTP. Ao receber uma instrução GET, foi informado no protocolo que o recurso “mypicture.jpg” foi solicitado .. Ao receber uma solicitação, o servidor verifica qual o path, nome e extensão do recurso solicitado, e baseado na extensão informada (.jpg ou .jpeg), ele já sabe que é um arquivo em disco, e que o formato do arquivo é “image/jpeg”. Veja abaixo a lista de arquivos tratadas pelo HTTP Server — Totvs Application Server, e o content-type retornado para cada uma:

HTM ou HTML : text/html
XML         : text/xml
TXT         : text/plain
GIF         : image/gif
JPG ou JPEG : image/jpeg
BMP         : image/bmp
SVG         : image/svg+xml
ZIP         : application/zip
DOC         : application/msword
AU          : audio/au
WAV         : audio/wav
MPEG ou MPG : video/mpeg
AVI         : video/avi
CSS         : text/css
JS          : application/x-javascript
TODAS AS DEMAIS : application/octet-stream";

Dessa forma, baseado na extensão utilizada no nome do recurso solicitado pelo Browser, verificando a extensão do recurso, ele já sabe qual Content-type de retorno deve ser utilizado para o Web Browser interpretar o recurso corretamente. Caso seja um arquivo de extensão desconhecida pelo Application Server, ele retorna ao Browser que o conteúdo do arquivo é uma seqüencia de bytes (
octet stream“, ou “seqüencia de octetos” — afinal 1 byte corresponde a uma seqüência de 8 bits) 😛

Por que foi criada a pasta “pictures” ? A imagem não poderia estar na pasta “http-root”?

Sim, claro que poderia. Criar pastas ou subdiretórios a partir da pasta raiz de publicação (no nosso caso, http-root) permite ORGANIZAR melhor os arquivos dentro do site. Podemos criar uma pasta para centralizar ou agrupar as folhas de estilo utilizadas (CSS), imagens, scripts (JavaScript), etc …. Calma que a gente chega lá ..rs..

Referências

O Protocolo HTTP – Parte 02 – Glossário

Introdução

No post anterior, vimos com alguns detalhes “internos” uma requisição HTTP, e várias terminologias — como HTTP, Web Browser, Web Server — e alguma coisas “por dentro” do protocolo. Agora, para continuar sem ficar “voando” muito, vamos ver o que significam algumas terminologias usadas para definir componentes do universo de redes, conectividade e internet, de uma forma “conectada”.

Glossário

Rede de computadores — Dois ou mais computadores, ligados entre si — conectados — por um meio físico (cabeamento) ou sem fio (wireless), onde os equipamentos conectados trocam informações entre si usando a rede.

Wireless (Rede Sem Fio)— Termo utilizado para indicar que a conexão entre os equipamentos é “sem fio” (Wi-fi, Bluetooth e 3G são exemplos de conexões Wireless).

Rede cabeada — (ou wired — com fio) — Termo utilizado para indicar que a conexão entre os equipamentos possui um ou mais “fios” e/ou “cabos”. Os tipos dos fios e cabos podem variar muito dependendo do tipo da rede. Pode ser desde cabo coaxial (NET/Claro, TVs a Cabo), cabo de par trançado (redes cabeadas domésticas e industriais), Fibra Óptica (redes de alta velocidade ou “Banda Larga”).

Roteador — (Router) — Equipamento responsável por direcionamento e encaminhamento de pacotes de rede entre redes diferentes. É uma das peças chave responsáveis pelo funcionamento da Internet.

Switch (ou Comutador) e Hub — Outros dois tipos de equipamento para conectar computadores em rede. São mais simples que um roteador, vamos ver depois onde e por quê.

MODEM — Nome dado a um equipamento de telecomunicações, capaz de converter e desconverter (ou modular e demodular — MO-DEM) uma informação de um determinado tipo de sinal ou informação para ser trafegado por um meio físico. Por exemplo, as conexões primeiras conexões com a Internet para uso doméstico no Brasil foram feitas através de linhas telefônicas convencionais, que suportavam apenas modulação de áudio (linhas analógicas). Usando um MODEM no seu computador, você estabelecia uma conexão com outro MODEM, no servidor ou provedor de internet, e o MODEM transformava os pacotes TCP em áudio analógico para serem enviados pela linha telefônica, e o MODEM no servidor recebia esse áudio, e recodificava o pacote original que o seu computador enviou, e vice-versa.

Protocolo de comunicação — Conjunto de regras e definições de como os dados são transmitidos (enviados e recebidos) em telecomunicações e redes de computadores. Por exemplo TCP/IP, HTTP, FTP, SMTP, IMAP, POP, SSH…

Cliente (Client) — Aplicação que inicia uma conexão para uma aplicação Servidora (Server).

Servidor (Server) — Aplicação que espera e atende a requisições de conexões feitas por uma aplicação Cliente.

IP – Numero de identificação único de uma interface de rede atribuído manualmente ou automaticamente, que permite endereçar (acessar) portas de comunicação da interface através da rede. Ele “identifica” o computador na rede.

Porta (TCP) – Número atribuído a um canal de conexão, associado ao IP. Uma conexão de rede TCP envolve o par de informações IP + Porta da interface de rede de origem e de destino. No protocolo TCP/IP v4, uma interface de rede suporta 65536 portas diferentes por interface — numeradas de 0 a 65535. Vale lembrar que a faixa de portas de 0 a 1024 possuem uso reservado para determinados protocolos, e as as demais portas são utilizadas a critério do sistema operacional do equipamento — incluindo uma faixa de portas reservada para aceite de conexões — conhecidas por “faixa de portas efêmeras”.

Porta efêmera (TCP – Ephemeral port) — Número de porta atribuído automaticamente para um IP em uma conexão.

Porta ouvinte (TCP – Listening Port) — Número de porta fixo, atribuído a uma interface de rede, para ficar esperando (listening) por uma conexão de rede. Por exemplo, um Web Server HTTP aloca a porta 80 (que faz parte de uma faixa de numeração pré-definida) em uma ou mais interfaces de rede de um equipamento para aceitar as conexões HTTP vindas de um ou mais navegadores Web ou aplicativos.

DDOS (Distributed Denial of Service) — Um tipo de ataque coordenado utilizando vários computadores a um determinado Web Site/ Web Server, tendo como objetivo “metralhar” o Web Server com requisições, até que haja o esgotamento de recursos computacionais e ele não consiga responder as requisições — causando a “negação de serviço” (Denial of Service).

DHCP (Dynamic Host Configuration Protocol) — Protocolo utilizado entre os equipamentos de uma rede e um equipamento ou serviço dedicado (DHCP Server) para atribuir dinamicamente um IP a um equipamento que quer ingressar em uma rede.

Pacote de Rede TCP (TCP Packet) — Nome dado a uma sequência de bytes que são transferidos entre interfaces de rede através de uma linha de comunicação (ou conexão). Um Cliente envia um pacote contendo uma requisição HTTP GET para um servidor HTTP, o servidor responde essa requisição para este cliente, enviando um ou mais pacotes em sequência com a resposta.

Socket — Como uma conexão TCP é identificada pelo par de informações IP+Porta das duas interfaces envolvidas, cada uma dessas “pontas” (end points) é chamada de Socket. Ao criar uma conexão, usamos um conjunto de funções (API) do sistema operacional para criar e manipular conexões. Um programa Cliente, ao criar uma conexão, recebe um número identificador dessa conexão, chamado de manipulador de socket (Socket Handle), e através dele usamos as demais funções da API para usar este Socket para enviar e receber pacotes de dados.

Firewall – Nome dado a uma barreira de proteção entre redes, ou entre um determinado equipamento e a rede. Permite criar regras de bloqueio para aceite e respostas de conexões, entre outros recursos. Firewall em si é uma funcionalidade, que pode ser exercida por um software em um equipamento, ou um equipamento inteiro dedicado para esta finalidade.

F.A.Q.

A estas alturas do campeonato muitas informações de uma vez dão um nó na cabeça da gente, e geram mais dúvidas… vamos tentar tirar algumas dessas dúvidas com alguns questionamentos devidamente respondidos.

  • Eu tenho NET com Internet em casa. Aquele MODEM da Net, o que ele faz ?
    R:
    Ele não é “apenas” um modem, ele acumula as funções de um roteador, decodificador, um DHCP local, e um modulador Wi-fi (rede sem fio). Ao aceitar a conexão de um dispositivo qualquer (Computador, telefone celular. SmartTV), ele atribui um endereço IP para cada equipamento — através do DHCP — criando uma rede local dentro da sua casa, fazendo a “ponte” de comunicação entre os seus dispositivos, e entre cada dispositivo e a Internet.
  • Tem umas entradas para cabos de rede atrás do modem da NET … pra que serve isso?
    R:
    Cada entrada daquela permite uma conexão cabeada entre os dispositivos e o modem. A conexão cabeada é mais rápida que a conexão wireless (Wi-fi). Se você tem uma SmartTv com NetFlix, por exemplo, embora a SmartTv tenha configuração de conexão por Wi-fi, procure instalar o Modem da Net perto da TV, e prefira uma conexão cabeada para ligar a SmartTv ao modem da NET.
  • Dá pra conectar dois computadores sem roteador ou modem ?
    R:
    Sim, a mais simples possível seria uma rede cabeada com um HUB ou SWITCH — dê preferência ao switch — Basta ter dois computadores com conexões para o cabo de rede RJ45 (aquele cabo com fiozinhos coloridos nas pontas)… mas sem um roteador e um DHCP, você tem que atribuir “manualmente” um endereço de IP para os 2, e ligar os dois em um Hub ou Switch. Você não vai ter uma “rede” efetivamente, mas vai conseguir abrir conexões via aplicativos entre uma máquina e outra. Como você não tem um DNS, ao colocar um servidor HTTP em uma das máquinas, você deve usar o IP da máquina que você definiu para abrir o site através da outra máquina.
  • Quais linguagens tem suporte a sockets e conexão TCP/IP ?
    R:
    Praticamente todas as linguagens de mercado possuem este recurso. Algumas como um recurso nativo da linguagem, outras mediante a utilização de Libs (bibliotecas de funções) ou Plugins. A maioria delas já possui classes ou componentes para lidar diretamente com os protocolos HTTP, FTP, IMAP, SMTP, etc..
  • O quanto a Internet é “segura” ?
    R:
    Depende do que você usa e de como você usa. Existem várias formas de colocar conteúdo na Internet, e algumas pessoas ou grupos de pessoas mal intencionadas, que buscam formas de usar as suas informações em benefício próprio. Phishing, Spam, Virus, Trojans, Ransomare, tem de tudo .. é prudente e importante estar atento a isso, uma vez que você vai usar esses recursos no seu dia-a-dia. Mas não importa o quanto se invista em segurança nos protocolos e equipamentos, os procedimentos de segurança começam no usuário.
  • Têm tudo isso no AdvPL ?
    R: SIM,
    com recursos nativos do servidor de aplicação — TOTVS Application Server — e da linguagem AdvPL. Vamos entrar nos detalhes de alguns posts anteriores, só que agora explicando a coisa “por dentro”, e usando AdvPL na brincadeira.

Conclusão

Eu sei, o tamanho disso assusta, mas é um conhecimento muito legal, e as tecnologias vindas dele são muito utilizadas — em larga escala e para implementar soluções integradas. Envolvem conhecimentos em diversas áreas — eletrônica, telecomunicações, hardware, software — mas abrem um universo de possibilidades. Espero que tenham gostado do post, já já sai mais !!!! E desejo a todos TERABYTES DE SUCESSO !!!

Referências

Programa de testes com Interface para API NETiZAP – Update 2

Fontes atualizados disponíveis no GITHUB

Através do link https://github.com/siga0984/NETiZAP ,você pode baixar os fontes atualizados relacionados a integração com a API NETIZAP!

NETiZAP.prw -- Classe AdvPL NETIZAP que encapsula as requisições dos serviços 
IzapClient.prw -- Fonte de exemplo e teste de uso da classe com interface gráfica -- SmartClient.
USAZAP.PRW -- Fonte de exemplo de uso da classe para o ERP -- contribuição do desenvolvedor Patrick Zerbinatti

Documentação da Classe

A classe de encapsulamento de requisições e uso do serviço está sendo documentada no GITHUB, no link “Wiki” do Projeto — https://github.com/siga0984/NETiZAP/wiki 😀

Contato com o provedor do serviço

Para maiores informações sobre a forma de provisionamento do serviço, contratação comercial, obtenção de uma chave de testes personalizada e afins, entre em contato com o Thiago, desenvolvedor/provedor dessa API, no telefone/WhatsApp +55(27)99802-2075, ou pelo e-mail thiagopedro.br@gmail.com

E NOVAMENTE DESEJO A TODOS TERABYTES DE SUCESSO !!! 

Agradecimento especial ao nobre colega Patrick Zerbinatti, pelo primeiro pull request no GITHUB para compartilhar um novo fonte de exemplo de uso da classe 😀 

Programa de testes com Interface para API NETiZAP

Introdução

No post anterior (Integração com WhatsAPP através de API – NETiZAP), foi disponibilizada uma classe que utiliza um serviço de envio de mensagens via WhatsApp, chamado NETIZAP. Agora, vamos ver um fonte em AdvPL que utiliza essa classe para envio de mensagens.

Aplicativo IZAPCLIENT

O fonte da aplicação abaixo chama-se IzapClient.prw, e está disponível para Download no GITHUB, no link https://github.com/siga0984/NETiZAP. Basta adicionar a um projeto, junto do fonte da classe de integração (NETiZAP.prw), compilar e executar o aplicativo U_IZAPCLIENT diretamente pelo SmartClient. Ao ser executado, ele deve abrir a janela abaixo:

iZapClient01

O programa já vêm com uma chave de acesso de testes, disponibilizada pelo provedor do serviço. Para utilizá-la, basta clicar no botão “Chaves de Demonstração“, e os campos com os dados da linha de origem, chave e porta do serviço serão preenchidos automaticamente.

*** ATENÇÃO ***

  • A chave de demonstração disponibilizada está atrelada a uma linha / WhatsApp de origem ou remetente da mensagem FIXO — A chave é associada a este número. Para obter uma chave de testes com o seu número de telefone de origem, entre em contato com o provedor do serviço ( Thiago ) pelo WhatsApp (27) 998022075 .
  • O uso da chave de demonstração é apenas para você fazer um teste de funcionalidade — envio de mensagem / pergunta / arquivo para, por exemplo, o seu celular / WhatsApp.
  • Não use este aplicativo ou a chave de demonstração para fazer brincadeiras ou spam.

Usando o programa

Na aba inferior esquerda estão disponíveis todas as opções da API de envio de mensagens: Desde envio de mensagens, arquivos, perguntas com respostas pre-definidas, consulta de status de envio e recebimento das mensagens, perguntas respondidas, grupos e listas de envio associadas a conta de envio, etc. Basta selecionar a aba desejada, preencher os dados e enviar. O painel do lado direito da tela mostra a resposta da requisição JSON obtida pela API.

Caso você obtenha uma chave de uso personalizada da API, basta clicar no botão “Informar Chaves“, que os campos da parte superior da tela serão abertos para edição, e você pode informar a chave e a linha de origem associados.

Exemplo de envio de mensagem

Veja a mensagem abaixo, eu enviei para o meu telefone. Após preencher os campos e clicar em “Enviar”, o painel do lado direito mostra o JSON retornado pela API — informando o ID gerado para esta mensagem enviada.

iZapClient02

Após enviada a mensagem, você pode copiar o Identificador da mensagem retornado, acessar a aba “MessageSearch“, e informar este identificador para saber se a mensagem foi enviada:

iZapClient03.png

E, claro, a mensagem recebida no celular está aqui — obtida pela interface do WhatsApp WEB:

iZapClient04

Agora, enviando uma pergunta, com aceite de duas respostas válidas:

iZapClient05.png

E, apos obter o ID da pergunta enviada, vamos ver se a pergunta foi respondida, usando a opção “QuestionSearch

iZapClient06

E, claro, a pergunta e resposta no WhatsApp :

iZapClient07

Conclusão

Embora o fonte de exemplo seja bem básico, ele serve de base para implementações mais avançadas, como por exemplo guardar em uma tabela as mensagens enviadas e os retornos da API, para registro e/ou buscas posteriores — principalmente quando enviada uma pergunta.

Espero que este fonte lhe seja muito útil, e desejo novamente a todos TERABYTES DE SUCESSO . 

 

Criptografia em AdvPL – Parte 08

Introdução

No post anterior, vimos alguns pacotes de rede e requisições feitas com HTTP e com HTTPS, e um FAQ com algumas perguntas intrigantes e respectivas respostas. Agora, vamos aproveitar que já temos um certificado digital de testes e habilitar a conexão segura entre o TOTVS SmartClient e o TOTVS Application Server ?!

Posts anteriores

Conexão SmartClient com SSL

A seção de configuração [sslconfigure] do TOTVS Application Server foi criada para definir as configurações default para uso de criptografia na infraestrutura do servidor de aplicação, e auxiliar na portabilidade de funções nativas da linguagem para suporte a protocolos seguros. Ela possui diversas chaves de configuração, o que vimos até agora no post 06 foi apenas configurar o uso de um certificado digital e uma chave criptográfica em modo “servidor”, utilizada pela engine de servidor WEB nativa da plataforma para publicar um site ou serviço acessado por HTTPS.

Porém, também podemos habilitar uma conexão segura e criptografada entre o SmartClient e o Application Server, e quando fazemos isso, o certificado configurado como “ServerCertificate” e a sua chave correspondente serão usados para permitir essa implementação.

Configuração DRIVERS

No arquivo de configuração do TOTVS Application Server (appserver.ini), existe uma seção chamada [drivers], responsável por indicar a seção TCP para especificar a porta de conexão a ser usada pelo TOTVS SmartClient, Monitor, IDE/TDS e afins. Para habilitar a conexão segura para o SmartClient, acrescentamos as chaves em negrito:

[drivers]
active=tcp
secure=ssl

[tcp]
type=tcpip
port=12010

[ssl]
type=tcpip
port=13010

Pronto, com isso o Application Server vai usar a porta 13010 para atender a conexões seguras de SmartClient. Lembre-se que o certificado digital e a chave deve estar configurados na seção SSLConfigure, senão o Application Server não inicia…

[sslconfigure]
CertificateServer=C:\Protheus12LG\certificates\note-juliow-ssd.cer
KeyServer=C:\Protheus12LG\certificates\note-juliow-ssd.key

Para as conexões do SmartClient, pode ser usado o mesmo certificado que foi gerado para o HTTPS, inclusive pode até ser um certificado mais “simples”, sem as extensões obrigatórias que um navegador Web exige.

E uma vez feito isso e reiniciado o Application Server, você não precisa fazer nada nas configurações do SmartClient. O Application Server continua aceitando as conexões do SmartClient na porta da seção TCP, porém ao receber uma conexão de SmartClient na porta não segura, o próprio Application Server sabe que existe uma porta segura de conexão, então ele devolve para o SmartClient uma mensagem de reconexão segura, informando a porta configurada na seção SSL 😀

Quando o Application Server com estas configurações for iniciado, repare que no log de console devem aparecer algumas novas mensagens:

Secure Application Server.

[ERROR][STORE] Certificates loaded from [C:\Protheus12LG\certificates\note-juliow-ssd.cer].
[INFO ][SERVER] [Thread 11048] Secure Server started on port 13010.

The callback state information is active.
The PassPhrase is supplied.

*** Existe uma mensagem informando “ERROR” no log acima, que provavelmente está equivocada, deveria ser “INFO” — pois o certificado foi carregado com sucesso.

Configurando o SmartClient para conectar direto na porta segura

Embora apenas a configuração do Application Server já resolve a questão de conexão segura, existe uma forma de você configurar o SmartClient para conectar direto na porta segura, assim o SmartClient não precisa conectar na porta não segura para receber o número da porta segura e reconectar. Basta editar o arquivo de configuração do SmartClient (smartclient.ini), e criar uma nova seção de configuração de conexão, informando na seção a porta segura, e acrescentando a configuração SecureConnection=1, por exemplo:

[drivers]
active=tcp

[tcp]
server=note-juliow-ssd
port=12010

[ssltest]
server=note-juliow-ssd
port=13010
SecureConnection=1

Ao executar o SmartClient, basta trocar a conexão tcp para ssltest, e ele conectará direto na porta de conexão segura especificada, veja imagem abaixo:

Smartclient_ssl

Informações adicionais de depuração de SSL

Caso exista algum problema com uso de certificado ou criptografia no TOTVS Application Server, em qualquer funcionalidade que use chaves criptográficas e certificados e afins, é possível colocar na seção [sslconfigure] a chave verbose=1 . Com isso qualquer processo que envolver a camada de segurança e criptografia do Application Server vai gerar mensagens adicionais de diagnóstico no log de console do servidor. Vale lembrar que isso deve ser ligado apenas para fins de depuração, pois ela pode gerar muito conteúdo adicional e os detalhes gerados são apenas úteis para levantar mais informações sobre um problema relacionado a este mecanismo.

A seção [sslconfigure] possui muito mais chaves, se você está curioso em saber todas elas, veja os links de referência no final do post para a documentação oficial do TDN. Cada post explorando um novo recurso ou funcionalidade vai abordar sob demanda as chaves necessárias e explicando mais detalhes do seu funcionamento 😀

Conclusão

Com o que vimos até agora, já foi possível testar conexões seguras de HTTPS e SmartClient. No próximo post, vamos ver um pouco mais sobre os certificados digitais, e onde as funções do AdvPL se encaixam no uso desses certificados para diversos fins.

Agradeço novamente pela audiência, e desejo a todos TERABYTES DE SUCESSO !!! 

Referências

 

Criptografia em AdvPL – Parte 06

Introdução

No post anterior, vimos o procedimento passo a passo para instalar a biblioteca de ferramentas OpenSSL 1.1.1c no Windows. Agora, vamos abordar o primeiro caso de uso: Como gerar um certificado digital para testes do TOTVS Application Server como um servidor HTTP com conexão segura (HTTPS) 😀

Posts anteriores

O que é HTTP e HTTPS ?

Bem, HTTP é o protocolo de comunicação criado sobre uma conexão TCP/IP, usado entre os navegadores de internet (ou Web Browsers) e sites que você acessa. O protocolo HTTP permite a transferência de vários tipos de conteúdos, desde páginas HTML estáticas, imagens, vídeos , arquivos, páginas dinâmicas, etc… Os dados podem ser trafegados em diversas codificações, inclusive compactados. Mas o HTTP usa uma conexão TCP “simples”, não segura. Desse modo, existem utilitários que permitem “farejar” conexões de rede (Sniffers) que podem interceptar e ver os conteúdos dos pacotes de dados trocados entre o navegador de Internet que você usa e o site que você está acessando.

Quando você acessa  um site que pode prover uma conexão segura, criptografada, o protocolo HTTPS é utilizado — o sufixo “S” significa “Secured”. A conexão segura é feita sobre SSL/TLS, onde no início da conexão existe uma etapa chamada de “Handshake” (aperto de mãos) entre o navegador e o servidor do site, onde eles literalmente “negociam” uma conexão criptografada — vamos ver mais pra frente os detalhes dessa negociação.

Uma vez estabelecida a conexão segura, os dados transferidos entre o navegador e o site são apenas encapsulados em pacotes codificados — criptografados –, mas ao serem decodificados, as mensagens trocadas estão no padrão HTTP. Apenas o meio de comunicação faz a ponte segura entre ambos.

TOTVS Application Server como servidor HTTP

Nos posts abaixo, eu explico como configurar o TOTVS Application Server como um servidor HTTP, recomendo essa leitura antes de prosseguir:

Refrescou a memória ? Legal, vamos partir da configuração inicial do TOTVS Application Server como um servidor HTTP de páginas estáticas, e criar a configuração para ele também aceitar conexões seguras. O Arquivo de configuração appserver.ini deve ficar assim:

[http]
enable=1
port=80
path=c:\Protheus12LG\Http\note-juliow-ssd

[https]
enable=1
port=443
path=c:\Protheus12LG\Http\note-juliow-ssd

Dessa forma eu configuro o Application Server para ser, ao mesmo tempo, servidor para conexões HTTP (não seguras) e HTTPS (seguras). As portas default usada para conexões HTTP e HTTPS são 80 e 443, respectivamente.

Dentro da pasta c:\Protheus12LG\Http\note-juliow-ssd, eu vou colocar apenas um arquivo, chamado index.html. Trata-se de um arquivo texto simples, que pode ser criado com o Bloco de Notas do Windows, apenas com o seguinte conteúdo para teste:

<html>
<body>
<h1><center>Olá Mundo HTTP do Protheus
</h1></center>
</body>
</html>

Agora, quando você tenta subir o TOTVS Application Server em modo console ou serviço … ele não sobe 😀 Aparece a tela de console, e desaparece rapidinho … quando abrimos o log de console ( console.log ) do servidor, encontramos as seguintes mensagens:

[INFO ][SERVER] [Thread 17340] HTTP Server started on port 80.

Http server is ready.
Root path is c:\protheus12lg\http\note-juliow-ssd\
Listening port 80 (default)

[INFO ][SSL] [tSSLSocketAPI][Initialize] Initializing SSL/TLS.
[ERROR][SSL] [tSSLSocketAPI][Initialize] There is no configuration of SSL certificates for the server.
[FATAL][SERVER] [14/08/2019 19:54:29][Thread 17340] *** HTTPS SERVER FAILED TO START ***

[INFO ][SERVER] [Thread 17340][14/08/2019 19:54:29] Application SHUTDOWN in progress...

Bem, como eu configurei o TOTVS Application Server para ser um servidor de conexões seguras para HTTPS, eu preciso ter um certificado digital configurado para isso. Bem, como o HTTPS ainda não sobe, altere para 0 o valor da configuração Enable da seção [https], e tente iniciar novamente o TOTVS Application Server.

[INFO ][SERVER] [Thread 1092] HTTP Server started on port 80.

Http server is ready.
Root path is c:\protheus12lg\http\note-juliow-ssd\
Listening port 80 (default)

Ótimo, agora parou “de pé” 😀 Vamos testar o acesso para ver a página Index.html no Browser. Você pode usar o nome do seu computador na URL do browse. Se você não lembra ou não sabe o nome do seu computador na rede, utilize o prompt de comando (cmd.exe) e digite echo %COMPUTERNAME%:

c:\>echo %COMPUTERNAME%
NOTE-JULIOW-SSD

No caso foi mostrado o nome do meu notebook. Agora, abrimos qualquer navegador (Chrome, Firefox, Internet Explorer, Opera ,…) e montamos uma URL com “http://&#8221; + o nome do computador+’/index.html’. No meu caso, http://note-juliow-ssd/index.html , e vejamos abaixo o que deve aparecer no Browse:

ola mundo http

Eu abri a URL usando o Google Chrome … reparem no texto circulado em vermelho: “Não seguro”. O navegador avisa que a conexão estabelecida não é “segura” — isso indica que a conexão atual não usa criptografia.

Como implementar e fazer funcionar o HTTPS ?!

Então, voltando pra conexão segura, temos basicamente duas etapas para conseguir habilitar o HTTPS no TOTVS Application Server:

  • Arrumar um certificado digital
  • Configurar o certificado para o Protheus usar.

Inicialmente, um certificado digital “oficial” para um servidor HTTP deve ser gerado por uma Autoridade Certificadora (ou CA – Certification Authority ). Entre as autoridades certificadoras brasileiras estão a Certisign, Serasa Experian e outras — para a lista completa veia o link https://www.iti.gov.br/icp-brasil/estrutura

Basicamente um certificado oficial deve possuir uma cadeia de autenticação — são certificados intermediários usados pelos navegadores para confirmar a autenticidade do certificado digital em uso pelo servidor HTTPS. Como não vamos publicar um site oficial, mas sim um teste de conexão segura, vamos a nossa primeira missão usando a OPENSSL: Criar um certificado digital auto-assinado 😀

Este tipo de certificado pode ser gerado por você mesmo, e da forma que ele é gerado, ele mesmo “se autentica” — na prática, é como eu criar um certificado digital com o os dados e propriedades que eu mesmo preencho, e eu mesmo digo que “esse certificado é de verdade” 😀

Criando um certificado auto-assinado para testes usando OPENSSL

Primeiramente, apenas em caráter informativo … Eu apanhei que nem “gato no saco” até chegar a uma receita de bolo que fizesse o navegador aceitar o certificado. As informações mais importantes são as seguintes:

  • O certificado requer parâmetros adicionais — chamados de “extensões” — para que o navegador entendesse que o certificado era para um site com o nome da minha máquina — note-juliow-ssd
  • O navegador de internet, por questões de segurança, verifica se o certificado possui uma Autoridade Certificadora válida, que não seja “eu mesmo”. Logo, a única forma de eu fazer o navegador ‘confiar” no meu certificado foi importar ele pelo gerenciador de certificados do próprio navegador — no meu caso o Chrome — como um “Trusted Root Certificate Authority”.

Agora, vamos para a receita de bolo — lembre-se que é necessário ter a ferramenta OPENSSL instalada para gerar a chave e o certificado. E, para o certificado que você gerar funcionar no seu computador, lembre-se de trocar note-automan-ssd para o nome do host do seu equipamento, e seguir os passos abaixo:

Passo 1:

Crie uma pasta no seu computador para guardar a chave e o certificado a serem gerado e utilizados, por exemplo c:\Protheus12LG\certificates

Passo 2:

Na instalação da OPENSSL, foi criada uma variável de ambiente apontando para o arquivo de configuração da openssl — no meu caso, “C:\Program Files\OpenSSL-Win64\bin\openssl.cfg”. Confirme o aquivo de configuração usado na sua instalação, execute o seu editor de textos ( notepad ou notepad++ por exemplo) em Modo “Administrador” — senão você não consegue mexer nesse arquivo — e abra o arquivo de configuração no editor, vá no final do arquivo, e acrescente o conteúdo abaixo:

[ v3_self_signed ]

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName=DNS:note-juliow-ssd

Com isso, eu criei uma seção de configuração nova para colocar no meu certificado os dados necessários para o Browse entender que eu vou usar esse certificado para conexão segura em um site de testes na minha máquina ( note-juliow-ssd ). Salve o arquivo e feche o editor.

Esse passo aqui é que deu trabalho descobrir — sem ele, mesmo que eu importasse o certificado como “confiável”, o Chrome retornava o erro “ERR_CERT_INVALID_COMMON_NAME”, como se o certificado não tivesse as informações corretas para ser usado em um site usando o nome da minha maquina … 

Passo 3:

Abra um prompt de comando (cmd.exe) no Windows, entre na pasta onde você vai gerar o certificado digital e a chave privada do certificado, e execute o comando abaixo:

openssl req -x509 -nodes -newkey rsa:4096 -keyout note-juliow-ssd.key -out note-juliow-ssd.cer -days 365 -subj “/C=BR/ST=SP/L=Sao Paulo/O=Tudo em AdvPL/CN=note-juliow-ssd” -extensions v3_self_signed -reqexts v3_self_signed

Com esse pequeno monstrinho, em apenas uma etapa eu consigo fazer a OpenSSL criar para mim uma chave privada de 4096 bits, usando criptografia RSA, gravar a chave SEM SENHA no arquivo note-juliow-ssd.key, criar um certificado no padrão x509 usando esta chave, com validade de um ano, colocando alguns dos meus dados no certificado, e acrescentando as extensões necessárias que colocamos no passo 2 na configuração da OpenSSL, salvando o certificado criado no arquivo note-juliow-ssd.cer

Agora vamos ver o resultado:

C:\>cd Protheus12LG\certificates

C:\Protheus12LG\certificates>openssl req -x509 -nodes -newkey rsa:4096 -keyout note-juliow-ssd.key -out note-juliow-ssd.cer -days 365 -subj "/C=BR/ST=SP/L=Sao Paulo/O=Tudo em AdvPL/CN=note-juliow-ssd" -extensions v3_self_signed -reqexts v3_self_signed
Generating a RSA private key
.......................................................................................................++++
..........................++++
writing new private key to 'note-juliow-ssd.key'
-----

C:\Protheus12LG\certificates>

Para conferir o conteúdo do certificado que foi gerado, executamos o seguinte comando:

openssl x509 -text -in note-juliow-ssd.cer -noout

E, abaixo vamos ver o que foi retornado:

Certificate:
Data:
Version: 3 (0x2)
Serial Number:
5e:a9:76:38:db:c0:3c:5e:cf:f6:8b:e0:cf:7c:b8:5c:ad:87:59:d9
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = BR, ST = SP, L = Sao Paulo, O = Tudo em AdvPL, CN = note-juliow-ssd
Validity
Not Before: Aug 16 00:06:19 2019 GMT
Not After : Aug 15 00:06:19 2020 GMT
Subject: C = BR, ST = SP, L = Sao Paulo, O = Tudo em AdvPL, CN = note-juliow-ssd
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (4096 bit)
Modulus:
00:bc:5b:56:04:e2:8a:58:88:65:22:86:ce:33:42:
c4:15:1a:ca:9b:4e:ad:7e:7b:42:92:7e:64:e9:3b:
5c:30:f9:de:34:b0:c3:fb:e2:62:69:e7:d7:3c:f1:
cb:78:c2:84:da:15:c3:2b:22:2c:30:7d:71:3f:d4:
47:34:0a:39:50:d4:8f:bc:fa:17:0b:ee:6e:38:28:
1a:06:b3:38:82:51:64:bf:7b:d0:75:ea:fd:e1:f9:
85:ac:21:fa:f8:ee:fb:b5:79:6a:02:f5:83:15:fa:
95:b5:18:1f:76:e7:57:41:a1:f7:84:23:bd:8c:31:
ee:02:c6:58:43:6a:40:ff:24:41:b6:33:ce:eb:7b:
ad:14:d0:43:cf:bf:75:ec:6d:5a:be:94:83:6e:d7:
71:ec:40:b8:68:36:c8:2a:90:9c:d0:6e:64:9c:e6:
3e:28:6e:c5:3b:70:a4:c5:7d:ff:91:0d:f8:f2:f7:
27:dd:cd:04:06:2c:3a:ce:78:23:d3:43:2f:49:77:
e5:4e:13:2d:18:8c:43:5d:2e:7d:70:c4:db:5f:dc:
9a:b1:e6:05:37:14:f8:82:8a:5a:0c:47:22:07:ab:
61:20:43:83:b5:cc:8f:09:93:5f:b4:32:9b:19:b9:
50:35:91:2b:bb:8b:f7:5c:a6:7b:1e:29:b4:73:0d:
f8:93:e9:d6:9a:90:f8:49:a4:ab:89:8a:56:9f:8f:
6b:e1:7b:64:b4:aa:f8:11:6b:b9:92:66:aa:46:04:
5d:bb:5d:17:52:e1:17:36:86:80:70:1f:64:45:47:
6f:12:f2:cb:37:20:2b:6c:36:32:a7:ed:5a:9b:a9:
fa:47:34:a8:1a:79:8d:1d:84:e1:29:9e:a9:64:97:
f3:83:64:79:9e:9d:72:2a:05:0d:4e:58:ec:ff:2c:
d7:c5:a2:5c:b2:e6:08:26:8e:17:12:e3:99:2e:50:
7f:a6:3f:ef:6c:aa:45:08:0d:f8:db:fc:15:f4:42:
29:2d:13:d1:4c:2b:3e:72:1f:e9:0c:2a:bd:38:60:
5c:27:dd:63:7c:32:ac:c0:f0:06:85:1a:dc:64:67:
d9:44:bc:bc:83:fc:65:2a:1a:0c:04:77:ea:29:06:
f8:de:35:ba:4b:cd:23:c6:87:11:bf:4d:cc:d8:d0:
20:54:28:50:dd:b2:e3:21:f2:9d:67:1a:27:11:15:
6e:92:ac:3c:ac:66:70:86:31:bc:55:39:85:fe:9f:
65:02:29:d6:cc:36:51:f2:e2:15:93:13:6f:a1:b5:
47:af:cc:20:c7:94:fe:44:37:59:90:98:46:fd:be:
7a:1c:c1:87:7a:57:94:05:db:0a:60:f3:ca:42:1b:
01:89:35
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier:
DirName:/C=BR/ST=SP/L=Sao Paulo/O=Tudo em AdvPL/CN=note-juliow-ssd
serial:5E:A9:76:38:DB:C0:3C:5E:CF:F6:8B:E0:CF:7C:B8:5C:AD:87:59:D9

X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
X509v3 Subject Alternative Name:
DNS:note-juliow-ssd
Signature Algorithm: sha256WithRSAEncryption
78:55:d6:bf:57:6e:69:8b:c6:7e:27:7d:bc:e6:df:bc:17:26:
62:3b:73:e5:a5:46:51:6d:09:fa:45:c6:c3:6f:d3:9f:70:d3:
cb:2c:42:c8:48:fa:b5:ec:14:8a:d9:4c:c8:d9:eb:ab:bb:3a:
d7:35:e5:ad:88:90:1c:2d:91:ea:08:e1:87:f9:b8:dc:d4:d7:
58:77:8f:6b:b9:da:65:3c:e3:7a:fb:08:91:94:c4:43:08:53:
64:1f:ad:f9:93:66:bf:fa:58:af:25:a7:09:c8:f4:a9:77:fb:
4e:f5:33:02:f8:86:26:6e:f6:77:d1:7c:74:be:6d:09:4d:0e:
4a:38:44:08:bd:b8:a2:d3:85:c3:e7:a0:1d:81:57:3e:40:cc:
0e:08:8a:60:56:b7:c2:27:78:c1:6a:30:1e:58:ab:ab:44:a4:
9e:c6:7b:15:a9:e6:14:65:e0:b2:88:85:66:f1:cc:32:34:6b:
d9:a6:f5:e7:3d:5b:b5:a9:a8:a4:82:17:48:4e:f3:6d:26:80:
3c:72:66:23:c9:ee:d3:ed:0b:fe:0d:8d:04:b5:17:da:01:f4:
20:21:79:0f:18:7b:04:cd:c6:90:5f:a4:71:82:bd:90:d5:ce:
f0:c2:ea:1c:70:f7:5f:3c:d6:1c:cd:54:eb:7d:70:75:03:7c:
3f:49:02:3c:65:69:89:a2:c2:aa:9a:62:64:45:2f:e2:51:c2:
8f:d5:00:85:a1:e6:ec:48:4d:bb:5f:4f:09:73:4f:56:70:54:
04:0b:60:5f:2c:c0:cb:61:45:3b:5c:ff:cc:ac:67:9f:2a:67:
12:5e:38:16:af:b3:96:f1:24:2f:27:fe:63:9f:0b:d6:11:31:
08:7c:26:b9:2d:48:66:0b:b8:c3:4e:b3:0f:62:f7:79:17:0f:
a8:c7:fa:71:ad:40:7a:2c:92:a5:d8:5b:b9:ff:a5:4e:d7:88:
ad:59:ab:c4:1d:9b:ed:52:20:d0:20:70:dc:ed:09:03:f9:4e:
5d:5b:ed:51:86:74:d5:8d:62:ab:cc:5a:45:00:9d:28:d2:45:
bc:02:c1:c8:76:15:94:04:34:fe:68:69:52:72:68:13:31:ca:
6b:ac:17:0e:2c:3d:f0:4e:b8:ba:b3:48:f2:06:5b:e6:aa:be:
35:e8:81:48:78:14:3b:f6:48:eb:13:ef:bd:9b:3f:83:1c:4e:
24:be:b7:b8:c6:30:c0:00:cb:6c:74:50:3e:3d:84:d3:a5:ce:
fb:6e:ac:2c:62:eb:5f:96:d4:77:8a:46:e0:9f:6c:43:13:e9:
4f:09:3b:e1:9a:12:b6:35:83:19:8e:4b:59:78:a5:9f:cd:fc:
6d:ce:d6:53:fc:72:15:db

Se verificarmos o diretório atual, veremos que os dois arquivos — chave privada e certificado — foram criados. UFA … agora, vamos configurar o certificado e a chave privada para o Protheus utilizar e virar servidor HTTPS.

Passo 4:

Abra o arquivo de configurações do TOTVS Application Server ( appserver.ini ) , e acrescente o conteúdo abaixo:

[sslconfigure]
CertificateServer=C:\Protheus12LG\certificates\note-juliow-ssd.cer
KeyServer=C:\Protheus12LG\certificates\note-juliow-ssd.key

Com isso, eu informo ao Protheus que ele pode ser um servidor de conexão segura, usando o certificado e a chave privada informadas na configuração. Por hora é tudo o que precisamos saber e fazer pra mágica funcionar.

Aproveite que o arquivo de configuração está aberto, configure novamente a chave Enable=1 na seção [HTTPS] e salve o arquivo de configuração.

Passo 5: 

Inicie novamente o TOTVS Application Server. Se tudo estiver certo, agora ele tem que subir "certinho"

[INFO ][SERVER] [Thread 13104] HTTP Server started on port 80.

Http server is ready.
Root path is c:\protheus12lg\http\note-juliow-ssd\
Listening port 80 (default)

[ERROR][STORE] Certificates loaded from [C:\Protheus12LG\certificates\note-juliow-ssd.cer].
[INFO ][SERVER] [Thread 13104] HTTPS Server started on port 443.

Https server is ready.
Listening port 443 (default)

Passo 6: 

Abra o Chrome, e informe a URL de acesso da página de testes, mas agora usando HTTPS ao invés de HTTP

https://note-juliow-ssd/index.html

E, para nossa surpresa ….

chrome_cert_authority_invalid

O navegador de internet fez o “HandShake” com o HTTPS do Protheus, e viu que o certificado usado não tem uma Autoridade Certificadora válida. Logo, ele avisa que o site que você está acessando pode ser uma roubada …. Reparem no erro no meio da tela : ERR_CERT_AUTHORITY_INVALID. Como o certificado foi eu mesmo que gerei, e está na minha máquina, e é para testes, eu posso fazer o navegador “confiar cegamente” no meu certificado e funcionar redondinho sem mostrar mais essa mensagem.

Passo 7:

Vamos importar o certificado de testes utilizado para dentro do navegador, dizendo pra ele que este certificado é um “Trusted Root Certificate” — ATENÇÃO : PELO AMOR DE DEUS, NÃO FACA ISSO COM UM CERTIFICADO QUE NÃO FOI VOCÊ QUE GEROU OU QUE VOCÊ NÃO SABE A PROCEDÊNCIA. O certificado que a gente acabou de gerar é confiável por que você gerou ele e vai usar na sua máquina.

No Google Chrome, clique nos três pontinhos do canto superior direito da janela’e clique em “Configurações”. Ao abrir a janela de configurações, expanda a opção “Avançado”, e clique em “Privacidade e Segurança”, e depois em “Gerenciar Certificados”

chrome_avancado

Será mostrada a janela de controle de certificados. Localize e posicione na aba “Trusted Root Certification Authorities”, e depois no botão “Import”

chrome_certificates

Ao clicar em “Import”, será aberto um assistente de importação de cerificado digital:

chrome_import_1

Clique em “Next”, e na próxima tela informe o caminho completo do certificado a ser importado, ou use o botão “Browse” para localizar e selecionar o certificado que acabamos de criar.

chrome_import_2

Ao clicar em “Next” será mostrada uma tela para perguntar onde o certificado deve ser importado. Já vi vir preenchido com “Trusted Root Certification Authorities”, clique em “Next”.

chrome_import_3

Chegamos na última tela, o assistente mostra o resumo do que será feito. Clique em “Finish”.

chrome_import_4

Ao clicar em Finish, é mostrado um aviso de segurança, dizendo que você está para instalar uma Autoridade Certificadora que não pode ser verificada — por que não existe — e que diz representar o nome do host da sua máquina, e diz também que se você fizer isso, o Windows vai passar a confiar em qualquer certificado subsequente que seja emitido a partir desse. Pode confirmar 😀

chrome_import_5

Pronto! Insalado 😀

chrome_import_6

Passo 8:

Agora sim, abra novamente a página de testes com o protocolo seguro — pode ser necessário fechar e abrir novamente o navegador para o acesso funcionar. Tudo dando certo, devemos ver isso aqui:

chrome_agora_foi

Repare no “cadeado” destacado em vermelho. Isso informa que, agora sim, finalmente, estamos usando uma conexão SEGURA / CRIPTOGRAFADA. Agora, para ver os detalhes dessa criptografia do ponto de vista do browse, clique no cadeado:

chrome_valido

Vamos ver mais detalhes, clicando em cima da palavra  “Certificado”, e consultar as suas propriedades.

certificate_properties

Na aba de detalhes do certificado, podemos ver todas as propriedades que colocamos ao criá-lo, e como instalamos ele como um certificado confiável na máquina, o Windows agora confia nele 😀

Conclusão

Bem, com apenas esses “poucos passos” conseguimos montar um servidor de páginas HTTP com conexão segura … agora, no próximo post, vou mostrar o que um hacker consegue ver ao rastrear uma conexão não segura e uma conexão segura 😀

Agradeço a todos pela audiência, e lhes desejo TERABYTES DE SUCESSO !!!

Referências

 

 

Utilizando THF com AdvPL – Parte 01

Introdução

O THF (Totvs Html Framework) é um projeto aberto e colaborativo de um Framework para aplicações WEB responsivas e dispositivos móveis. Baseado em Angular e Typescript, disponibiliza uma série de componentes que facilitam a criação de aplicações. O site oficial com tudo sobre o THF é https://thf.totvs.com.br/

É altamente recomendável que você tenha algum conhecimento sobre Angular e TypeScript, senão você corre o risco de ficar meio perdido — assim como eu fiquei — ao tentar usar o THF.

Iniciando

Basta seguir o tutorial do site para instalar o NodeJS e NPM, e o AngularCli. Sem truques, apenas next-next-finish. Uma vez instaladas as aplicações necessárias, uma dica importante na criação de um novo projeto — Ao configurar as dependências do projeto criado para instalação, é disponibilizada uma lista de chaves e valores das dependências no site. Para atualizar o arquivo package.json que foi criado com o novo projeto, procure cada chave informada no site no arquivo gerado para o seu projeto. Caso a chave já exista, atualize o valor da versão, e caso a chave não exista, acrescente ela no arquivo.

Criação do Projeto AgendaTHF

Em posts anteriores, sobre o CRUD AdvPL, foi construída uma agenda simples de contatos para ser acessada via SmartClient. Então, num projeto posterior, foi construída uma interface em AdvPL ASP usando HTML/CSS e JavaScript “puro”, sem framework algum. Vamos ver agora como seria a criação de uma interface para esta Agenda usando o Totvs Html Framework.

Todas as etapas para a criação do projeto foram feitas de acordo com as instruções detalhadas no tópico “Começando com o THF”, inclusive as etapas foram seguidas até o final, com a criação do componente “hello-world” e de um menu do THF para chamá-lo na tela.

Ao criar um novo projeto, devemos abrir um prompt de comando do Windows (cmd) e usar  o comando abaixo: — onde AgendaTHF é o nome do projeto.

ng new AgendaTHF --skip-install

Após reconfigurar as dependências e versões de dependências no arquivo package.json, gerado dentro da nova pasta AgendaTHF — criada automaticamente para o Projeto — executamos o comando de instalação das dependências, e depois a instalação do THS neste projeto, executando os seguintes comandos dentro da pasta AgendaTHF:

npm install
npm install @totvs/thf-ui --save

Não se assuste, a instalação de tudo pode demorar mais de um minuto. As sub-pastas com os componentes instalados somam quase 300 MB de arquivos.

Configuração do módulo principal e demais etapas

Procure o arquivo “app.module.ts“, ele deve estar dentro da pasta “AgendaTHF\src\app“. Neste arquivo é que deve ser acrescentado o import do THFModule — os detalhes estão no Passo 2.2 do tutorial “Começando com o THF”

Os demais procedimentos são relativamente simples, ligados a edição dos arquivos modelo gerados para a aplicação, para adequá-lo ao uso do THF. A criação do componente “hello-world” é feita pelo prompt de comando ma pasta raiz do projeto (AgendaTHF), e o resultado final — depois de colocar um servidor http no ar usando o comando “ng serve”, deve ser algo assim:

THF Hello World

Teste do Hello World

A primeira impressão é muito bonita, e logo percebe-se a responsividade da interface alterando o tamanho da janela do Browser. Em tela maximizada, a página do Hello World é aberta na área de conteúdo e o menu continua visível. Ao reduzir o tamanho da interface, o menu é automaticamente “escondida”, sendo acessível novamente por um link na parte superior esquerda.

THF Hello World Option

Atualmente existem aproximadamente 81 componentes disponíveis para você codificar uma aplicação responsiva usando o THF — Vide índice de API no link “https://thf.totvs.com.br/documentation“. Além dos componentes, são disponibilizados Serviços, Diretivas, Modelos de Dados — para armazenamento em dispositivo local — enfim, têm muita coisa.

A pasta criada com este projeto é para desenvolvimento. No momento de fazer a publicação, deve-se executar uma instrução de build, explicada no portal do THF, que vai gerar uma pasta com os arquivo estáticos e scripts. A publicação da aplicação exige apenas um servidor HTML estático, o Protheus como servidor HTTP atende perfeitamente — exceto por alguns detalhes de configuração de página não encontrada, que precisam ser customizados.

Conclusão

Este artigo ficou na banheira desde o Natal de 2018, provavelmente a documentação já deve ter mais atualizações e componentes. O projeto da Agenda usando o THF vai ser continuado ao longo dos próximos posts, em breve 😀

Novamente agradeço a audiência e desejo a todos TERABYTES DE SUCESSO !!! 

Referências

 

CRUD em AdvPL ASP – Parte 04

Introdução

No post anterior (CRUD em AdvPL ASP – Parte 03), foi implementada a consulta básica da Agenda em ADVPL ASP — pelo menos os quatro botões de navegação (Primeiro, Anterior, Próximo e Último). Agora, vamos ver como mostrar no Browse a imagem de cada contato, gravada no Banco de Dados.

Trocando o retorno para o Browse

Qualquer link apw solicitado ao Web Server do Protheus executará uma função AdvPL definida em uma configuração de pool de processos, que por default devem retornar uma string em AdvPL, que será interpretada pelo Web Browse como sendo texto HTML.

Este comportamento default é implementado pelo Web Server, que por default informa no Header HTTP de retorno da requisição a informação Content-Type: text/html — Quando utilizamos a função AdvPL HTTPCTTYPE(), dentro do processamento de uma requisição AdvPL ASP, nós podemos TROCAR o tipo do conteúdo de retorno. Por exemplo, se eu quiser retornar uma imagem do tipo PNG para o Web Browse, a partir de uma requisição de link .apw, basta eu chamar a função HttpCTType(“image/png”), e ao invés de retornar ao Browse um HTML, eu retorno o conteúdo (bytes) do arquivo da imagem.

Logo, vamos implementar o retorno da imagem de forma BEM SIMPLES. Primeiro, vamos aproveitar a requisição “agenda.apw”, e verificar se ela recebeu um identificador adicional na URL, que vamos chamar de IMGID. Este identificador vai conter o numero do registro do contato da agenda que nós gostaríamos de recuperar a imagem. E, no fonte WAGENDA.PRW, vamos acrescentar o seguinte tratamento, logo no inicio da função WAGENDA() — pouco depois de abrir a tabela ‘AGENDA” no Banco de Dados.

If !empty(HTTPGET->IMGID)
  DbSelectArea("AGENDA")
  Dbgoto( val(HTTPGET->IMGID) )
  cBuffer := AGENDA->IMAGE
  HTTPCTType('image/png') 
  Return cBuffer
Endif

Simples assm, caso seja recebida a URL agenda.apw?IMGID=nnn, o programa vai posicionar no registro correspondente da tabela de agenda, ler o conteúdo da imagem gravada no campo memo “IMAGE”, e retornar ela ao Browser, avisando antes pela função HTTPCTType() que o Browse deve interpretar este conteúdo como uma IMAGEM.

Agora, dentro do fonte WAGENDA.APH, que compõe a página da agenda, vamos fazer uma alteração na tag “img”, responsável por mostrar a imagem do contato atual da agenda.

<tr><td>
<%If HTTPPOST->_SHOWRECORD .and. !Empty(AGENDA->IMAGE) %>
<img style="width: 120px;height: 160px;" src="agenda.apw?IMGID=<%=cValToChar(recno())%>">
<% else %>
<img style="width: 120px;height: 160px;" src="./images/Agenda_3x4.png">
<% Endif %>
</td></tr>

Dentro do APH em questão, eu já estou com a tabela da Agenda aberta. Caso eu vá mostrar o registro de algum contato no Browse, e o campo de imagem deste contato possua conteúdo, eu coloco que a imagem deve ser buscada no endereço

agenda.apw?IMGID=<%=cValToChar(recno())%>

Desta forma, quando o Browse receber o HTML de retorno de uma página da Agenda, o Browse vai desenhar a tela, e na hora de mostrar a imagem, o Browse internamente dispara mais uma requisição para a a URL agenda.apw, informando via URL o identificador da imagem desejada.

Vou fazer um teste no Browse, por exemplo retornando a foto do registro 2 da agenda no meu ambiente, digitando direto a URL “http://localhost/agenda.apw?IMGID=2

WEB Agenda IMGID

Ao navegar na agenda, e posicionar no contato, a imagem passa a ser atualizada na tela, veja exemplo abaixo:

WEB Agenda Imagem

Conclusão

Utilizando a troca do retorno, eu consigo informar ao browser o que eu estou retornando, e isso me permite eu retornar por exemplo XML, Imagens, Documentos, o céu (e a String AdvPL) são o limite!

Agradeço novamente a audiência, e desejo a todos TERABYTES DE SUCESSO !!! 

Referências

 

CRUD em AdvPL ASP – Parte 03

Introdução

No post anterior (CRUD em AdvPL ASP – Parte 02), foi mostrado um pouco da forma como as páginas de uma aplicação WEB foram e são atualizadas e o que é o AJAX, e a primeira verão — apenas desing — da página da Agenda em HTML. Agora, vamos começar a adaptar alguns fontes da Agenda para utilizá-los no AdvPL ASP.

Separar processamento da interface

Este é um dos mandamentos do bom desenvolvimento de sistemas. O projeto do CRUD em AdvPL, com foco em uma agenda de contatos, foi escrito da forma mais simples de desenvolver um sistema: O mesmo código é responsável pela interface e pelo processamento e acesso aos dados.

Embora seja uma das formas mais simples e rápidas de desenvolver, o processamento depende das interface, e isso acaba dobrando o trabalho para você criar uma nova interface para fazer as mesmas tarefas. No exemplo do CRUD, o processo em execução é persistente, isto é, o SmartClient possui uma conexão com o Protheus Server, e nesta conexão o arquivo da agenda é mantido aberto e posicionado, e a conexão da aplicação é mantida junto com o seu contexto até o usuário finalizar a interface.

Já em uma aplicação Web, cada chamada de atualização de interface cria uma nova conexão com o servidor de aplicação, que pode ser atendida por qualquer um dos processos (também chamados de Working Threads, ou processos de trabalho), então não há persistência do contexto de execução. Existem apenas as variáveis de seção (HTTPSESSION), onde você pode armazenar informações que são exclusivas daquela seção de navegação, que como vimos nos tópicos sobre AdvPL ASP, podem ser usadas por exemplo para guardar a existência por exemplo de uma seção de login.

Logo, como o paradigma da nova interface não parte de uma conexão persistente, precisamos desamarrar o processamento da interface, e criar algum mecanismo de persistência de um mínimo de contexto, ou emular a persistência de um contexto, para que uma ação disparada pela interface saiba de onde partir para ser executada.

A separação entre processamento e interface será feita em doses homeopáticas, vamos primeiro fazer a implementação funcionar com o que temos disponível implementando alguns pontos por vez.

Iniciando o processo de consulta

Como já temos a agenda criada em AdvPL, e com uma base preenchida, vamos começar a interface WEB pela consulta dos dados da agenda. Partimos de uma tabela no banco de dados, com dois índices previamente criados. Vamos iniciar a visualização dos dados a partir do primeiro registro da tabela em ordem alfabética. Para isso, inicialmente vamos replicar (duplicar) alguns códigos na interface WEB, para realizar as operações de consulta.

Uma vez que seja mostrada ao usuário uma tela com os dados preenchidos, o processamento daquela requisição terminou. Logo, quando eu clicar por exemplo no botão “Próximo” — para mostrar o próximo registro da agenda — eu preciso pelo menos saber qual era o registro que estava sendo visualizado, para eu saber de onde partir para buscar o próximo registro.

Eu até poderia usar variáveis de seção (HTTSESSION), mas como o objetivo é minimizar o uso destas variáveis, eu posso criar dentro do meu formulário — por exemplo — um input em HTML, do tipo “hidden” — ou escondido — onde eu coloco o numero do registro atual que eu estou visualizando, no momento que eu gerei a página a ser retornada para o Browse.

Conectando com o DBAccess

Antes de mais nada, eu preciso que as minhas Working Threads tenham acesso ao Banco de Dados. Lembram-se da função U_ASPINIT(), executada para preparar cada um dos processos para AdvPL ASP? Vamos alterá-la para ela estabelecer logo de cara uma conexão com o DBAccess, que será mantida no processo e aproveitada por todas as requisições que precisarem usar o SGDB. Esta função fica no fonte ASPThreads.prw

User Function ASPInit()
Local nTopHnd

SET DATE BRITISH
SET CENTURY ON

nTopHnd := TCLInk()
If nTopHnd < 0 
  ConsoleMsg("ASPINIT - Falha de conexão "+cValToChar(nTopHnd))
  Return .F.
Endif

SET DELETED ON

ConsoleMsg("ASPINIT - Thread Advpl ASP ["+cValToChar(ThreadID())+"] Iniciada")

Return .T.

Reparem que apenas o trecho em negrito foi acrescentado na função. Agora, vamos implementar alguns controles no programa responsável pela agenda na interface AdvPL ASP — Fonte wagenda.prw

Implementando a consulta nos fontes

Dentro da User Function WAGENDA(), responsável pela interface HTML da Agenda para AdvPL ASP, vamos abrir o alias da tabela da Agenda, caso ele ainda não esteja aberto dentro do contexto do processo de trabalho (Working Thread) atual.

If Select("AGENDA") == 0 
   USE (cFile) ALIAS AGENDA SHARED NEW VIA "TOPCONN"
   DbSetIndex(cFile+'1')
   DbSetIndex(cFile+'2')
Endif
DbSelectArea("AGENDA")

Partimos de duas premissas. A primeira é que a tabela e os índices existem. E, a segunda é que, uma vez que eu deixe o alias da tabela aberto neste processo, as próximas requisições que precisarem consultar esta tabela vão encontrar ela já aberta.

As operações feitas no CRUD em AdvPL foram numeradas. Vamos seguir a mesma numeração. Como por hora estamos implementando apenas a consulta de dados, as operações são: 4 – Primeiro contato, 5 = Contato anterior, 6 = Próximo contato e 7 = Último contato. Para este controle, vamos usar um campo input de formulário escondido no HTML, chamado “OP”. Caso este campo não seja recebido na requisição, eu assumo que a agenda está sendo aberta, e que a operação default é “4” = Primeiro registro.

If empty(HTTPPOST->OP)
  // Caso nao tenha sido informada operação, a operação 
  // default é posicionar no primeiro registro da tabela
  // em ordem alfabérica
  HTTPPOST->OP := '4'
Endif

Antes do fonte chamar a montagem da tela da agenda, encapsulada no arquivo wagenda.aph — correspondendo a chamada de função H_WAGENDA() em AdvPL — vamos tratar as quatro opções possíveis.

If HTTPPOST->OP == '4' // Primeiro

  DBSetOrder(2)
  Dbgotop()
  HTTPPOST->_SHOWRECORD := .T.

ElseIf HTTPPOST->OP == '5' // Anterior

  DBSetOrder(2)
  Dbgoto( val(HTTPPOST->RECNO) )
  DbSkip(-1)
  IF bof()
    HTTPPOST->_ERRORMSG := 'Este é o primeiro contato.'
  Endif
  HTTPPOST->_SHOWRECORD := .T.

ElseIf HTTPPOST->OP == '6' // Próximo

  DbSetOrder(2) 
  Dbgoto( val(HTTPPOST->RECNO) )
  DbSkip() 
  If Eof()
    Dbgobottom()
    HTTPPOST->_ERRORMSG := 'Este é o último contato.'
  Endif
  HTTPPOST->_SHOWRECORD := .T.

ElseIf HTTPPOST->OP == '7' // Último

  DBSetOrder(2)
  Dbgobottom() 
  HTTPPOST->_SHOWRECORD := .T.

Endif

Dentro deste fonte nós criamos duas variáveis dentro do alias virtual HTTPPOST, chamadas de _SHOWRECORD e _ERRORMSG. Estas variáveis foram criadas desta fora para servirem como containers de troca de valores entre o programa AdvPL que estamos rodando agora, e a página AdvPL ASP que vamos rodar em seguida.

Cada operação já assume que o Alias da tabela de AGENDA está aberto, e realiza o posicionamento do registro correspondente. Para fazer o posicionamento no registro anterior ou no próximo do registro mostrado no Web Browse, vamos no AdvPL ASP criar um campo do tipo INPUT HIDDEN, escondido em um formulário de controle invisível, e cada requisição de POST feita para trazer um novo registro vai receber o registro que estava sendo visto no Browse naquele momento.

Implementando no AdvPL ASP

Agora que já preparamos as operações dentro do fonte AdvPL, vamos preparar o fonte AdvPL ASP para tratar a existência destes dados e as operações solicitadas. Primeiro, dentro do fonte WAGENDA.APH, na parte de Scripts no inicio da página, vamos acrescentar duas funções novas em JavaScript.

function onLoad()
{
<%If HTTPPOST->_SHOWRECORD %>
<% aStru := DbStruct() %>
<% For nI := 1 to fCount() %>
<% If aStru[ni][2] != 'M' %>
document.getElementById("I_<%=alltrim(fieldname(nI))%>").value = "<%=cValToChar(fieldget(nI))%>";
<% Endif %>
<% Next %>
<% Endif %>
<% IF !empty(HTTPPOST->_ERRORMSG) %>
window.alert("<%=HTTPPOST->_ERRORMSG%>");
<% Endif %>
};

function CallOp(nOp)
{
document.getElementById("I_OP").value = nOp;
var f = document.getElementById("F_STATUS"); 
f.action="agenda.apw"
f.submit();
}

A primeira função chama-se onLoad(), e vamos fazer o Browse chamá-la imediatamente após a carga da página, inserindo na tag de abertura do corpo da página HTML (body) a chamada desta função:

<body onload="onLoad()" style="font-family:Courier New;font-size: 12px;background-color:rgb(128,128,128);">

O corpo da função onLoad() será montado dinamicamente para cada requisição. Seu objetivo é, quando houver a visualização de um determinado registro, este script vai encontrar todos os campos INPUT da página, destinados a mostrar os valores dos campos da Agenda, e preencher estes campos com os valores lidos do Banco de Dados.

Já a função CallOp() será chamada em JavaScript pelos botões de navegação de consulta na página HTML. Os novos botões vão ficar assim:

<tr><td><a class="agbutton" href="javascript:void(0)" onclick="CallOp(4)">Primeiro</a></td></tr>
<tr><td><a class="agbutton" href="javascript:void(0)" onclick="CallOp(5)">Anterior</a></td></tr>
<tr><td><a class="agbutton" href="javascript:void(0)" onclick="CallOp(6)">Próximo</a></td></tr>
<tr><td><a class="agbutton" href="javascript:void(0)" onclick="CallOp(7)">Último</a></td></tr>

E, finalmente, antes do final do corpo do HTML (/body), vamos acrescentar um formulário de controle, para através dele fazer as requisições via POST — para não deixar rastro, cache ou histórico no Web Browse — das operações solicitadas de navegação.

<form id="F_STATUS" action="agenda.apw" method="post">
<input type="hidden" id="I_OP" name="OP" type="text" value="">
<input type="hidden" id="I_RECNO" name="RECNO" type="text" value="<%=cValToChar(recno())%>">
</form>

Neste formulário vamos criar apenas dois campos de INPUT HIDDEN, um para guardar a operação a ser solicitada, e outro para guardar o registro que está atualmente sendo visualizado. No momento que eu pedir por exemplo o próximo registro, o botão “Próximo” vai executar a função javascript CallOp(6), que vai preencher o input “I_OP” com o valor “6” e submeter novamente o formulário para o link “agenda.apw

Desta forma, o programa U_WAGENDA() vai receber a operação e o registro anteriormente posicionado, reposicionar no registro, fazer a navegação, e se por um acaso não houver registro anterior ou próximo, será mostrada na tela uma mensagem de alerta no Browse, repare no finalzinho da função onLoad().

Implementação funcionando

Com tudo atualizado e compilado, o comportamento esperado do acesso ao link http://localhost/agenda.apw deve ser:

  • Caso o usuário não esteja logado na seção atual, será exibida a tela de login
  • Após o login, deve ser exibida a tela da agenda com o primeiro contato em ordem alfabética.
  • Os quatro botões de navegação devem funcionar atualizando a página inteira e trazendo o contato correspondente.

WEB Agenda 3

Houve mais uma alteração importante no arquivo WAGENDA.APH: Todos os campos INPUT do formulário, que antes estavam com a propriedade “disabled”, passaram para “readonly”. Caso um campo não esteja habilitado, ele sequer pode receber ou mostrar um valor novo.

Conclusão

Aos poucos vamos implementando as funcionalidades da agenda original. Normalmente eu começaria pelo mais complicado — API de Cadastro — porém, como o estado default da interface é a consulta, vamos começar por ela. No próximo post, vamos fazer a consulta atualizar a foto do contato da agenda, sem precisar gravar a imagem que está no banco de dados na pasta de publicações Web.

Agradeço a todos novamente as curtidas, compartilhamentos, comentários e afins, e lhes desejo TERABYTES DE SUCESSO !!!

Referências

 

CRUD em AdvPL ASP – Parte 02

Introdução

No post anterior (CRUD em AdvPL ASP – Parte 01), montamos um controle de login, usando um formulário em AdvPL ASP, e uma variável de seção (HTTPSESSION). E, para servir de base para a continuação do CRUD, foram publicados uma sequência de posts para abordar o “básico” do AdvPL ASP:

Agora, vamos começar a montar a interface em HTML e JavaScript para montar as funcionalidades da Agenda via WEB.

Design da Interface

Poderíamos usar algum framework Web, por exemplo o THF – Totvs Html Framework , mas por hora vamos fazer a tela usando o arroz-com-feijão das páginas WEB com AdvPL ASP, e de quebra ver um pouco mais sobre como as coisas funcionam por dentro, e ver algumas alternativas de desenvolvimento. A interface da agenda está sendo desenhada originalmente para ter um layout muito parecido com o layout do programa original, que roda pelo SmartClient.

A ideia é que a interface HTML permita realizar todas as operações a partir da mesma tela, porém cada operação que requer atualização de dados desta tela deve submeter uma requisição via POST para o Web Server, que receberá novamente a tela inteira para executar a ação desejada.

Atualização de Páginas

Nos primórdios da Internet, navegar em qualquer Web Site na Internet construído com HTML, não tinha a possibilidade de alteração ou atualização dinâmica de conteúdo. Imagine um Web Site com um layout de menu lateral, com vários links e opções, uma área de topo ou Header com um logotipo e algumas informações sobre a parte do site que você está navegando, e uma área de conteúdo mostrando duas ou três notícias. Caso você clicasse em um link para ver a próxima página de notícias, a tela inteira é apagada e recarregada, com os mesmos menus laterais, a mesma área de topo, e uma página nova de notícias.

Isso acabava tornando pesada a navegação em alguns Web Sites. Com a possibilidade de criação de páginas de FRAMES em HTML —  acho que a partir do Internet Explorer 4 — você poderia definir um lay-out com frames — por exemplo um superior, um lateral e um central, onde a carga de uma página de notícias apenas recarregava uma página do frame, colocando as notícias desejadas.

Com as melhorias feitas no JavaScript, e sendo possível alterar dinamicamente o conteúdo de um HTML já desenhado na tela do Web Browser, vários Web Sites usavam um frame “escondido” na tela, onde através dele era feita uma requisição de uma nova página. Nesta página, que na verdade não era visível — frame escondido — era carregado um JavaScript retornado pelo Web Server, para atualizar dinamicamente o conteúdo da página sendo mostrada no frame de conteúdo — esse sim visível — sem a necessidade de recarregar (ou fazer REFRESH) da página inteira.

Algum tempo depois, foram descobertas vulnerabilidades nos navegadores Web relacionados ao uso de Frames, que poderiam mascarar um Web Site malicioso que poderia usar o JavaScript para interagir — e roubar dados e credenciais por exemplo — com frames de outros domínios, e a mecânica de atualização dos Frames tornava mais complicado desde o desenvolvimento do site, até a usabilidade do usuário — como usar o botão Voltar do Browse ou mesmo fazer um BookMark.

AJAX – Seus problemas terminaram

Mais melhorias e implementações foram feitas no JavaScript, e surgiu  o AJAX  —  Asynchronous Javascript And XML. NA verdade, este recurso é a união de duas funcionalidades: Primeira, uma função assíncrona do JavaScript foi criada para enviar ou solicitar informações para um Web Server, sem a necessidade de recarga da página atual. E, quando o Web Server retornar os dados solicitados (não necessariamente precisa ser um XML, pode ser usado texto plano, JSON, …), um JavaScript é acionado para processar os dados da requisição, que podem ser usados para atualizar o conteúdo HTML da página sendo atualmente exibida ao usuário.

Vamos pegar por exemplo o FACEBOOK — Uma vez que você  entra no seu “Feed de Notícias”, a URL permanece a mesma, e conforme você vai rolando a tela para baixo, usando a barra de rolagem do lado direito do Browse, ou mesmo o botão “Scroll” presente hoje até nos modelos mais simples de Mouse, novos posts vão sendo trazidos para a sua tela, sem a necessidade de repintar a tela inteira.

É claro que podemos usar AJAX com AdvPL ASP, inclusive vamos abordar este assunto mais para a frente, no decorrer do desenvolvimento do CRUD em AdvPL ASP, por hora estamos entrando neste assunto para fins informativos e didáticos.

Página AdvPL ASP da AGENDA

Sem mais delongas, vamos ver como está a primeira versão — ainda não funcional, mas apresentável — da interface AdvPL ASP da Agenda — futuro arquivo “agenda.aph”

<!DOCTYPE html>
<html>
<head>
<meta charset="ANSI">
<title>Agenda em AdvPL ASP</title>
<style>
.agbutton {
display: inline-block;
text-decoration : none;
width: 120px;
height: 18px;
background: rgb(240, 240, 240);
text-align: center;
color: black;
padding-top: 4px;
}
.agget { 
display: block;
width: 110px;
height: 22px; 
color: black; 
padding-top: 6px; 
text-align: right;
}
.aginput { 
width: 320px;
height: 22px; 
color: black; 
padding-top: 0px; 
padding-right: 10px; 
text-align: left;
}
</style>
</head>

function doLogoff() { 
var f = document.getElementById("F_AGENDA"); 
f.action="/logoff.apw"
f.submit();
};

<body style="font-family:Courier New;font-size: 12px;background-color:rgb(128,128,128);">

<table align="left">
<tr>

<!-- Primeira Tabela - Opções e Imagem 3x4 -->
<td align="left" valign="top">
<table>
<tr><td><a class="agbutton" href="?Op=1">Incluir</a></td></tr>
<tr><td><a class="agbutton" href="?Op=2">Alterar</a></td></tr>
<tr><td><a class="agbutton" href="?Op=3">Excluir</a></td></tr>
<tr><td style="height: 22px;">&nbsp;</td></tr>
<tr><td><a class="agbutton" href="javascript:void(0)" onclick="doLogoff()">Sair</a></td></tr>
<tr><td style="height: 22px;">&nbsp;</td></tr>
<tr><td><img style="width: 120px;height: 160px;" src="./images/Agenda_3x4.png"></td></tr>
</table>
</td>

<!-- Segunda Tabela - Mais Opções -->
<td align="left" valign="top">
<table>
<tr><td><a class="agbutton" href="?Op=4">Primeiro</a></td></tr>
<tr><td><a class="agbutton" href="?Op=5">Anterior</a></td></tr>
<tr><td><a class="agbutton" href="?Op=6">Próximo</a></td></tr>
<tr><td><a class="agbutton" href="?Op=7">Último</a></td></tr>
<tr><td><a class="agbutton" href="?Op=8">Pesquisa</a></td></tr>
<tr><td><a class="agbutton" href="?Op=9">Ordem</a></td></tr>
<tr><td><a class="agbutton" href="?Op=10">Mapa</a></td></tr>
<tr><td><a class="agbutton" href="?Op=11">G-Mail</a></td></tr>
<tr><td><a class="agbutton" href="?Op=12">Foto 3x4</a></td></tr>
</table>
</td>

<!-- Terceira Tabela - Dados do Contato -->
<td align="left" valign="top"> 
<form id="F_AGENDA" action="#" method="post">
<table style="border-spacing: 1px; background: rgb(192,192,192);">
<tr><td colspan="2" style="width: 500px; height: 22px; color: white; padding-top: 4px; background: rgb(0,0,128);">&nbsp;Ordem ...</td></tr>
<tr><td class="agget">ID</td> <td class="aginput"><input id="I_D" type="text" name="ID" disabled size="6" ></td></tr>
<tr><td class="agget">Nome</td> <td class="aginput"><input id="I_NOME" type="text" name="NOME" disabled size="50" ></td></tr>
<tr><td class="agget">Endereço</td> <td class="aginput"><input id="I_ENDER" type="text" name="ENDER" disabled size="50" ></td></tr>
<tr><td class="agget">Complemento</td><td class="aginput"><input id="I_COMPL" type="text" name="COMPL" disabled size="20" ></td></tr>
<tr><td class="agget">Bairro</td> <td class="aginput"><input id="I_BAIRRO" type="text" name="BAIRRO" disabled size="30" ></td></tr>
<tr><td class="agget">Cidade</td> <td class="aginput"><input id="I_CIDADE" type="text" name="CIDADE" disabled size="40" ></td></tr>
<tr><td class="agget">UF</td> <td class="aginput"><input id="I_UF" type="text" name="UF" disabled size="2" ></td></tr>
<tr><td class="agget">CEP</td> <td class="aginput"><input id="I_CEP" type="text" name="CEP" disabled size="9" ></td></tr>
<tr><td class="agget">Fone 1</td> <td class="aginput"><input id="I_FONE1" type="text" name="FONE1" disabled size="20" ></td></tr>
<tr><td class="agget">Fone 2</td> <td class="aginput"><input id="I_FONE2" type="text" name="FONE2" disabled size="20" ></td></tr>
<tr><td class="agget">e-Mail</td> <td class="aginput"><input id="I_EMAIL" type="text" name="EMAIL" disabled size="40" ></td></tr>
<tr>
<td class="agget">&nbsp;</td>
<td>
<a class="agbutton" id="btnConfirm" href="?Op=13">Confirmar</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a class="agbutton" id="btnVoltar" href="?Op=14">Voltar</a>
</td>
</tr>
</table>
</form>

</td>
</tr>
</table>

</body>
</html>

Por hora, o resultado da apresentação desta tela no Web Browse pode ser visto abaixo:

Web Agenda 2

Ainda não há conteúdo dinâmico, as ações dos botões ainda estão sendo escritas, e a foto mostrada na tela é o arquivo “Agenda_3x4.png”, que por hora precisa estar dentro de uma pasta chamada “images” a partir da pasta raiz de publicação WEB (No caso do meu ambiente, a pasta images deve estar dentro do Path especificado na seção HTTP).

Pontos de Atenção

  • Por se tratar de uma rotina de consulta dinâmica, não há interesse em manter ou permitir que sejam feitos “BookMarks” das operações da Agenda, mesmo a de consulta. Por isso, boa parte das operações desta rotina vão requisitar o próprio link da agenda.apw passando parâmetros usando POST, e para isso os campos INPUT do formulário. E, inclusive, existe um tipo de campo INPUT que pode ser usado dentro do código HTML, mas que não é mostrado para o usuário, permitindo submeter valores adicionais dentro da requisição POST feita pelo Web Browse, onde podemos por exemplo usar JavaScript para colocar valor nestes campos. Veremos isso em detalhes no decorrer desta sequência de posts.
  • Mesmo que o JavaScript possa nos permitir colocar algumas validações no lado do Web Browse, como não submeter uma página com campos obrigatórios faltando, ou até mesmo implementar algumas verificações de consistência, não devemos confiar cegamente que isto será respeitado. Isto é, como qualquer script retornado ao Web Browse pode e vai ser interpretado pelo mesmo, qualquer um com um pouco de maldade no coração pode abrir uma interface de desenvolvedor no Web Browse, alterar ou desligar dinamicamente uma validação da página em questão, e burlar a validação ou consistência do lado do Client. Logo, sempre critique os dados vindos do Browse, pois eles não necessariamente podem vir da forma que você está esperando. Quer um exemplo simples? Você cria uma página de busca de itens em uma loja virtual, e permite no Browse que o cliente escolha receber os dados em páginas de 10, 20 ou 50 registros, e exige que o usuário informe um termo de busca com pelo menos três letras. Estes parâmetros são enviados junto da requisição de busca, que no servidor monta uma Query no banco, e limita os resultados baseado no número de linhas por página informado. Se esta validação estiver apenas no lado do cliente, um cidadão com más intenções pode burlar esta validação, e submeter uma busca pela letra “A”, estipulando um tamanho de página de  30 mil registros. Pronto, o Web Server vai disparar uma Query contra o banco de dados que vai retornar um volume medonho de registros, e o Web Server vai sofrer pra montar uma página de retorno que pode passar de 1 MB para retornar isso ao Browse.
  • Para evitar dores de cabeça desnecessárias, independente da metodologia ou ferramental aplicado, procure conhecer e seguir o principio “Keep It Simple” — MANTENHA SIMPLES — valorização da simplicidade e descarte de toda a complexidade desnecessária.

Conclusão

Devagar a gente chega lá. Fazer uma tela de login com dois campos é moleza… agora fazer uma tela com atualização dinâmica de um cadastro de 11 campos, 14 opções e uma foto 3×4, vamos por partes.

Referências