Programação Por Equipe DevBras

Capa do artigo: Botão copiar no app: o que pode ir para a área de transferência e por quanto tempo

Botão copiar no app: o que pode ir para a área de transferência e por quanto tempo

Decida o que seu app MAUI pode copiar, marque conteúdo sensível no Android, limpe a área de transferência depois de um prazo e ofereça alternativas melhores para senha e código.

O painel do app mostra a chave de API recém-criada com um botão "copiar". O desenvolvedor copia, cola no servidor e segue o dia. Duas horas depois, cola um link no grupo da empresa e percebe que o teclado do celular sugeriu, como primeira opção, a chave. Ela continuava lá, no histórico do teclado, e poderia ter ido para o grupo inteiro. A resposta curta: tudo que você copia fica disponível para outros apps, para o histórico do teclado e, às vezes, para outros aparelhos da mesma conta. Copie à vontade o que é público; para segredo, marque como sensível, limpe depois de um prazo curto e, sempre que der, ofereça um caminho que não passe pela área de transferência.

O exemplo é um app .NET MAUI de um SaaS com três botões de copiar: o link de convite da equipe, o número do pedido e a chave de API. Cada um pede um tratamento diferente. Este post trata de copiar; o caminho inverso, ler o que a pessoa colou, está em colar da área de transferência com cuidado.

Por que copiar é mais público do que parece

A área de transferência é um espaço compartilhado do sistema. O que entra nela fica até ser substituído, e vários componentes podem ver:

  • Teclados com histórico. Teclados populares no Android guardam os últimos itens copiados e os oferecem como sugestão em qualquer campo.
  • Histórico do sistema. No Windows, o histórico da área de transferência (Win+V) guarda vários itens e pode sincronizar entre computadores da mesma conta, se a pessoa ativou.
  • Sincronização entre aparelhos. Nos aparelhos Apple, a área de transferência universal pode levar o conteúdo copiado no iPhone para o Mac próximo.
  • Outros apps. As versões recentes de Android e iOS restringiram a leitura em segundo plano e mostram aviso quando um app lê, mas o app em primeiro plano ainda consegue ler o que você deixou lá.

No Android 13 em diante, o sistema também mostra uma prévia visual do texto copiado no canto da tela. Útil para link, péssimo para chave de API numa reunião com tela compartilhada.

Como decidir o que pode ser copiado

  1. Público ou sem poder de autenticar: link de convite com expiração, número de pedido, endereço, código de rastreio. Copie normalmente e mostre "copiado".
  2. Sensível, mas que a pessoa precisa transportar: chave de API exibida uma vez, código de recuperação. Copie marcado como sensível e limpe depois de um prazo curto, avisando o prazo na tela.
  3. Segredo que tem caminho melhor: senha e código de uso único. Senha deve ser preenchida pelo gerenciador de senhas; código de SMS pode ser preenchido pelo próprio sistema com o tipo de campo certo. Não ofereça botão de copiar.
  4. Nunca: token de sessão, documento completo de cliente, dados de cartão. Não há motivo de interface que justifique.

Como copiar no .NET MAUI

Para o que é público, a API multiplataforma resolve:

async Task CopiarConviteAsync(string link)
{
    await Clipboard.Default.SetTextAsync(link);
    await Toast.Make("Link copiado").Show(); // CommunityToolkit.Maui
}

Se não usa o CommunityToolkit, troque o toast por um rótulo que aparece por alguns segundos. O importante é o retorno visual: sem ele, a pessoa aperta o botão três vezes.

Para a chave de API, o Android oferece uma marcação de conteúdo sensível, documentada pelo próprio Android: a prévia do sistema mostra pontos no lugar do texto. Em MAUI, isso exige código da plataforma:

#if ANDROID
using Android.Content;
using Android.OS;
#endif

public static class CopiaSensivel
{
    public static async Task CopiarAsync(string valor, TimeSpan validade)
    {
#if ANDROID
        var cm = (ClipboardManager)Platform.AppContext
            .GetSystemService(Context.ClipboardService)!;
        var clip = ClipData.NewPlainText("chave", valor);
        var extras = new PersistableBundle();
        extras.PutBoolean("android.content.extra.IS_SENSITIVE", true);
        clip.Description!.Extras = extras;
        cm.PrimaryClip = clip;
#else
        await Clipboard.Default.SetTextAsync(valor);
#endif
        _ = LimparDepoisAsync(validade);
    }

    static async Task LimparDepoisAsync(TimeSpan validade)
    {
        await Task.Delay(validade);
        await MainThread.InvokeOnMainThreadAsync(
            () => Clipboard.Default.SetTextAsync(null));
    }
}

Chame com CopiaSensivel.CopiarAsync(chave, TimeSpan.FromSeconds(60)) e mostre na tela: "Chave copiada. A área de transferência será limpa em 60 segundos." A limpeza tem limites: se o app for encerrado antes do prazo, ela não acontece, e o histórico do teclado pode já ter guardado o valor. Por isso ela reduz o risco, não o elimina.

No iOS, a API nativa UIPasteboard aceita opções de data de expiração e de conteúdo só local (sem ir para outros aparelhos). Se o seu app tem segredo copiável no iOS, vale escrever o trecho de plataforma com essas opções, seguindo a documentação da Apple.

A alternativa melhor: não passar pela área de transferência

A chave de API que só aparece uma vez pode ter um botão "baixar arquivo .env" ou um comando pronto para a CLI do produto, com a chave lida de um fluxo autenticado. O login pode usar o gerenciador de senhas do sistema, se os campos tiverem o tipo certo. Na web, o mesmo raciocínio vale para navigator.clipboard.writeText, que só funciona em página segura e a partir de um gesto do usuário. E se o segredo for uma senha de banco ou um token de bot, o lugar dele é o servidor, como em log sem senha e token do bot fora do Git.

Erros comuns

  • Botão copiar ao lado da senha "para facilitar". A senha vai para o histórico do teclado e aparece como sugestão em qualquer app.
  • Copiar token de sessão para "suporte". Quem recebe o texto entra na conta da pessoa sem senha.
  • Sem aviso de "copiado". A pessoa repete o toque, cola o valor antigo ou acha que nada aconteceu.
  • Limpar sem avisar. A pessoa vai colar no minuto seguinte, não encontra nada e conclui que o app falhou.
  • Confiar só na limpeza. Teclados e históricos do sistema já podem ter guardado o valor antes do prazo.
  • Copiar dado pessoal completo. CPF inteiro ou endereço com nome viajam para outros aparelhos da mesma conta sem a pessoa perceber.

Checklist

  • Lista dos botões de copiar do app, cada um classificado como público, sensível ou proibido.
  • Retorno visual em toda cópia.
  • Conteúdo sensível marcado no Android 13 ou superior.
  • Limpeza com prazo curto e aviso do prazo na tela.
  • Nenhum botão de copiar em senha, token de sessão ou cartão.
  • Campos de senha e código com o tipo certo para o preenchimento automático.
  • Teste num aparelho real com teclado que guarda histórico.

Copie a chave de teste no seu app e abra o teclado em outro aplicativo. Ela aparece como sugestão de colagem? Então qualquer campo daquele aparelho pode recebê-la com um toque. E a pergunta para revisar o app inteiro: algum botão de copiar coloca na área de transferência algo que autenticaria a pessoa?

Avalie este artigo

Referência: https://learn.microsoft.com/dotnet/maui/platform-integration/data/clipboard