Slide 25 de 74

Segredos

Guardado, comparado, nunca mostrado
type Login {
	user:     Str
	password: Secret
}

proc main(): void {
	typed := hide("hunter2")
	if typed is Result.Error(why) {
		echo "{why.reason}: {why.message}"
	} else if typed is Result.Ok(password) {
		echo reveal(password)                // hunter2
		echo password == bypass("hunter2")   // true
		echo Login("ada", password).user     // ada
		// echo password                      — um erro de compilação
		// echo Login("ada", password)        — e este também
	}
}

Um Secret é um texto que não pode vazar — uma senha, uma chave, um token — e o tipo transforma isso numa regra que o compilador cumpre:

  • echo, panic e a interpolação recusam um, e também qualquer coisa que guarde um: um campo, um elemento, um Result. Escrever um como JSON também. reveal(secret) é o único caminho de volta para uma Str.
  • O que ele guarda mora em memória que o sistema operacional é instruído a nunca levar para o swap, e é zerado assim que nada mais o segura.
  • == compara o que dois guardam em tempo constante, então quanto tempo leva não diz nada sobre onde eles diferem. Não existe ordem.

Memória travada é finita, então hide(text) responde com um Result<Secret, SecretError>, cujo reason é "LimitExceeded" quando o limite se esgota e "Unsupported" onde a plataforma não consegue travar memória nenhuma. bypass(text) faz um Secret que não falha, guardado em memória comum que pode ir para o swap — para um texto que nunca foi segredo de verdade na chegada, como um literal, que o executável já guarda de qualquer jeito.

Um programa que declara o seu próprio Secret ainda tem o nativo como hive.Secret, e o erro dele como hive.SecretError.