Muitas vezes estamos desenvolvendo uma aplicação que interage com usuário solicitando a senha e se ele estiver fazendo isso com a presença de alguém ou gravando um vídeo, a senha irá aparecer.
Na maioria dos sistemas tipo UNIX isso já é escondido por padrão. Então vamos ver como fazer isso com C++ .
Para isso vamos precisar incluir os seguintes cabeçalhos:
#include <iostream> // Para usar 'std::cout' e 'std::cin'
#include <termios.h> // Para usar 'termios' e 'tcsetattr'
#include <unistd.h> // Para usar 'STDIN_FILENO'
A iostream
já é conhecida e comumente utilizada por nós.
Já a termios.h
é uma biblioteca que contém as definições usadas pelas interfaces de E/S do terminal , será com ela que iremos esconder o digitado.
E o unistd.h
é uma biblioteca que fornece acesso à API do sistema operacional POSIX e torna compatível com qualquer sistema operacional e compilador.
Após adicionar os cabeçalhos, basta:
termios
tcgetattr()
termios
, mas dessa vez para replicarmos os dados da instância anterior para podermos alterartcsetattr()
após estabelecer a regra: newt.c_lflag &= ~ECHO;
std::cout
, getline()
e std::cin
, armazenando em uma variável pré declaradatcsetattr
, mas para devolvermos à instância inicial.
Além disso no código adicionamos a exibição dos dados(na mesma linha com
\r
) digitados só por questões didáticas.
O código em resumo fica assim
vim hidden.cpp
#include <iostream>
#include <termios.h>
#include <unistd.h>
int main(int argc, char ** argv){
termios oldt;
tcgetattr(STDIN_FILENO, &oldt);
termios newt = oldt;
newt.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &newt); // esconde
std::string s;
std::cout << "Informe sua senha: ";
getline(std::cin, s);
std::cout << "\rSua senha é: " << s << '\n';
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // retorna à exibir
return EXIT_SUCCESS;
}
Compile e rode:
g++ hidden.cpp && ./a.out
Exemplo:
Esconde input, mostra senha.
Se durante o std::cout
opcional você ainda quiser trocar a std::string
por asteriscos(*
), adicione esse trecho ao seu código:
std::string n{};
for (int i{}; i < s.length(); ++i){
n += "*";
}
std::cout << "\rSua senha é: " << n << '\n'; // exiba agora 'n' em vez de 's'
Aparecerá:
Sua senha é: ************
.
Exemplo:
Esconde input, mostra asteriscos.
Podemos notar que o comando no terminal stty -echo
(para esconder os dados digitados no terminal) e stty echo
para retornar a exibição faz a mesma coisa. Nota-se que o programa/comando stty
faz uso da biblioteca termios.h
.
Eu vejo muita gente fazendo essa pergunta no StackOverflow e sinceramente nunca vi uma solução eficaz que realmente resolva do jeito que a pessoa deseja, nem usando a biblioteca curses.h
(Observação, curses.h
, compila também com: -lcurses -ltinfo
, não é NCURSES) .
Então, eu criei uma forma que resolve isso de maneira simples, utilizando do while
, excluindo o getline()
e utilizando getchar()
no lugar:
Só que a mágica está na linha:
newt.c_lflag &= 'a';
, eu troquei o~ECHO
por qualquer letra/caractere, nesse o'a'
.
#include <iostream>
#include <termios.h>
#include <unistd.h>
int main(int argc, char ** argv){
termios oldt;
tcgetattr(STDIN_FILENO, &oldt);
termios newt = oldt;
newt.c_lflag &= 'a'; // removi o ~ECHO
tcsetattr(STDIN_FILENO, TCSANOW, &newt); // esconde
std::string s{}, current{};
char c{};
std::cout << "Informe sua senha: ";
do {
std::cout << current;
s += c;
current = "*";
}while((c = getchar()) != '\n' && c != EOF);
std::cout << "\rSua senha é: " << s <<
" " << '\n';
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // retorna à exibir
return EXIT_SUCCESS;
}
Aparecerá:
Informe sua senha: ************
, ou seja, asteriscos em vez de vazio.
Exemplo:
Input asteriscos, mostra senha.