Skip to content

Instantly share code, notes, and snippets.

@arosien
Last active September 6, 2020 22:16
Show Gist options
  • Save arosien/ccc05238250d887097394ce04d671c25 to your computer and use it in GitHub Desktop.
Save arosien/ccc05238250d887097394ce04d671c25 to your computer and use it in GitHub Desktop.
Variation of https://alexn.org/snippets/2020/08/27/safe-password.scala.html using cats-effect concurrency primitives.
final case class PasswordValue(value: String) {
override def toString = "PasswordValue(****)"
}
object SafePassword {
def resource[F[_]: Sync](value: String): F[Resource[F, PasswordValue]] =
for {
used <- Ref.of[F, Boolean](false)
chars = value.toCharArray
givePasswordAndNullify = Sync[F].delay {
val s = new String(chars)
for (i <- chars.indices)
chars(i) = 0
PasswordValue(s)
}
illegalState = Sync[F].raiseError[PasswordValue](
new IllegalAccessException(
"the data has already been used once"
)
)
validateState = Sync[F].delay(assert(chars.forall(_ == 0)))
res = Resource.make(
used
.getAndSet(true)
.ifM(illegalState, givePasswordAndNullify)
)(_ => validateState)
} yield res
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment