Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve syntax #44

Merged
merged 3 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ Please, drop a ⭐️ if you are interested in this project and you want to supp
libraryDependencies += "com.github.geirolz" %% "secret" % "0.0.11"
```

## Usage

```scala
import com.geirolz.secret.*
import scala.util.Try

val reusableSecret: Secret[String] = Secret("password") // reusable secret
// reusableSecret: Secret[String] = ** SECRET **
val oneShotSecret: Secret.OneShot[String] = Secret.oneShot("password") // one shot secret
// oneShotSecret: OneShotSecret[String] = ** SECRET **
val deferredSecret: Secret.Deferred[Try, String] = Secret.deferred(Try("password")) // deferred secret
// deferredSecret: DeferredSecret[[T >: Nothing <: Any] => Try[T], String] = com.geirolz.secret.DeferredSecret$$anon$1@2ed6f149
```

## Obfuscation

By default the value is obfuscated when creating the `Secret` instance using the implicit `SecretStrategy` which, by default, transform the value into a xor-ed
Expand Down Expand Up @@ -52,8 +66,8 @@ val database: Either[SecretDestroyed, Database] = secretString.euseAndDestroy(pa

// if you try to access the secret value once used, you'll get an error
secretString.euse(println(_))
// res1: Either[SecretDestroyed, Unit] = Left(
// value = SecretDestroyed(destructionLocation = README.md:25:113)
// res2: Either[SecretDestroyed, Unit] = Left(
// value = SecretDestroyed(destructionLocation = README.md:50:113)
// )
```

Expand Down Expand Up @@ -150,7 +164,7 @@ given SecretStrategy[String] = SecretStrategy[String](
)

Secret("my_password").euse(secret => secret)
// res9: Either[SecretDestroyed, String] = Right(value = "CUSTOM")
// res10: Either[SecretDestroyed, String] = Right(value = "CUSTOM")
```

## Custom Obfuscation Strategy algebra
Expand All @@ -173,26 +187,25 @@ val myCustomAlgebra = new SecretStrategyAlgebra:

final def deObfuscator[P](f: PlainValueBuffer => P): DeObfuscator[P] =
DeObfuscator.of { bufferTuple => f(bufferTuple.roObfuscatedBuffer) }
// myCustomAlgebra: SecretStrategyAlgebra = repl.MdocSession$MdocApp10$$anon$9@55a1c811
// myCustomAlgebra: SecretStrategyAlgebra = repl.MdocSession$MdocApp11$$anon$12@6512f34b

// build factory based on the algebra
val myCustomStrategyFactory = myCustomAlgebra.newFactory
// myCustomStrategyFactory: SecretStrategyFactory = com.geirolz.secret.strategy.SecretStrategyFactory@1ffbad11

// myCustomStrategyFactory: SecretStrategyFactory = com.geirolz.secret.strategy.SecretStrategyFactory@5be15840

// ----------------------------- USAGE -----------------------------
// implicitly in the scope

import myCustomStrategyFactory.given

Secret("my_password").euse(secret => secret)
// res11: Either[SecretDestroyed, String] = Right(value = "my_password")
// res12: Either[SecretDestroyed, String] = Right(value = "my_password")

// or restricted to a specific scope
myCustomStrategyFactory {
Secret("my_password").euse(secret => secret)
}
// res12: Either[SecretDestroyed, String] = Right(value = "my_password")
// res13: Either[SecretDestroyed, String] = Right(value = "my_password")
```

## Contributing
Expand Down
10 changes: 8 additions & 2 deletions core/src/main/scala/com/geirolz/secret/Secret.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import com.geirolz.secret.util.*
import scala.util.Try

/** Memory-safe and type-safe secret value of type `T`.
*
* A.K.A. `ReusableSecret`
*
* `Secret` does the best to avoid leaking information in memory and in the code BUT an attack is possible and I don't
* give any certainties or guarantees about security using this class, you use it at your own risk. Code is open
Expand Down Expand Up @@ -116,8 +118,12 @@ abstract sealed class Secret[T] private (vault: Vault[T]) extends SecretApi[T](v
evalUse[Try, Boolean](thisValue => that.use[Try, Boolean](_ === thisValue)).getOrElse(false)

object Secret extends SecretCompanionApi[Secret]:
export DeferredSecret.apply as defer
export DeferredSecret.fromEnv as deferFromEnv

type OneShot[T] = OneShotSecret[T]
final val oneShot = OneShotSecret

type Deferred[F[_], T] = DeferredSecret[F, T]
final val deferred = DeferredSecret

/** Create a destroyed secret */
override def destroyed[T](location: Location = Location.unknown): Secret[T] =
Expand Down
12 changes: 3 additions & 9 deletions core/src/main/scala/com/geirolz/secret/types.scala
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
package com.geirolz.secret

import cats.{MonadError, Show}
import com.geirolz.secret.util.Location
import cats.MonadError
import com.geirolz.secret.strategy.SecretStrategy
import com.geirolz.secret.util.Hasher

import java.nio.ByteBuffer
import scala.util.control.NoStackTrace

type PlainValueBuffer = ByteBuffer
type ObfuscatedValueBuffer = ByteBuffer
type KeyBuffer = ByteBuffer

// alias
type SPassword = Secret[String]
object SPassword:
type OneShot = OneShotSecret[String]
def apply(value: String): SPassword = Secret(value)

// private
private[secret] type MonadSecretError[F[_]] = MonadError[F, ? >: SecretDestroyed]
private[secret] val vaultTag: String = "** VAULT **"
Expand Down
6 changes: 3 additions & 3 deletions core/src/test/scala/com/geirolz/secret/SecretSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ abstract class SecretSuite(using SecretStrategyFactory) extends munit.ScalaCheck
)
}

test("Secret.deferredFromEnv") {
test("Secret.deferred.fromEnv") {
given SysEnv[Try] = SysEnv.fromMap[Try](Map("TEST" -> "VALUE"))
Secret
.deferFromEnv[Try]("TEST")
Secret.deferred
.fromEnv[Try]("TEST")
.use(value =>
assertEquals(
obtained = value,
Expand Down
29 changes: 21 additions & 8 deletions docs/compiled/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ Please, drop a ⭐️ if you are interested in this project and you want to supp
libraryDependencies += "com.github.geirolz" %% "secret" % "0.0.11"
```

## Usage

```scala
import com.geirolz.secret.*
import scala.util.Try

val reusableSecret: Secret[String] = Secret("password") // reusable secret
// reusableSecret: Secret[String] = ** SECRET **
val oneShotSecret: Secret.OneShot[String] = Secret.oneShot("password") // one shot secret
// oneShotSecret: OneShotSecret[String] = ** SECRET **
val deferredSecret: Secret.Deferred[Try, String] = Secret.deferred(Try("password")) // deferred secret
// deferredSecret: DeferredSecret[[T >: Nothing <: Any] => Try[T], String] = com.geirolz.secret.DeferredSecret$$anon$1@2ed6f149
```

## Obfuscation

By default the value is obfuscated when creating the `Secret` instance using the implicit `SecretStrategy` which, by default, transform the value into a xor-ed
Expand Down Expand Up @@ -52,8 +66,8 @@ val database: Either[SecretDestroyed, Database] = secretString.euseAndDestroy(pa

// if you try to access the secret value once used, you'll get an error
secretString.euse(println(_))
// res1: Either[SecretDestroyed, Unit] = Left(
// value = SecretDestroyed(destructionLocation = README.md:25:113)
// res2: Either[SecretDestroyed, Unit] = Left(
// value = SecretDestroyed(destructionLocation = README.md:50:113)
// )
```

Expand Down Expand Up @@ -150,7 +164,7 @@ given SecretStrategy[String] = SecretStrategy[String](
)

Secret("my_password").euse(secret => secret)
// res9: Either[SecretDestroyed, String] = Right(value = "CUSTOM")
// res10: Either[SecretDestroyed, String] = Right(value = "CUSTOM")
```

## Custom Obfuscation Strategy algebra
Expand All @@ -173,26 +187,25 @@ val myCustomAlgebra = new SecretStrategyAlgebra:

final def deObfuscator[P](f: PlainValueBuffer => P): DeObfuscator[P] =
DeObfuscator.of { bufferTuple => f(bufferTuple.roObfuscatedBuffer) }
// myCustomAlgebra: SecretStrategyAlgebra = repl.MdocSession$MdocApp10$$anon$9@55a1c811
// myCustomAlgebra: SecretStrategyAlgebra = repl.MdocSession$MdocApp11$$anon$12@6512f34b

// build factory based on the algebra
val myCustomStrategyFactory = myCustomAlgebra.newFactory
// myCustomStrategyFactory: SecretStrategyFactory = com.geirolz.secret.strategy.SecretStrategyFactory@1ffbad11

// myCustomStrategyFactory: SecretStrategyFactory = com.geirolz.secret.strategy.SecretStrategyFactory@5be15840

// ----------------------------- USAGE -----------------------------
// implicitly in the scope

import myCustomStrategyFactory.given

Secret("my_password").euse(secret => secret)
// res11: Either[SecretDestroyed, String] = Right(value = "my_password")
// res12: Either[SecretDestroyed, String] = Right(value = "my_password")

// or restricted to a specific scope
myCustomStrategyFactory {
Secret("my_password").euse(secret => secret)
}
// res12: Either[SecretDestroyed, String] = Right(value = "my_password")
// res13: Either[SecretDestroyed, String] = Right(value = "my_password")
```

## Contributing
Expand Down
11 changes: 11 additions & 0 deletions docs/source/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ Please, drop a ⭐️ if you are interested in this project and you want to supp
libraryDependencies += "com.github.geirolz" %% "secret" % "@VERSION@"
```

## Usage

```scala mdoc:reset
import com.geirolz.secret.*
import scala.util.Try

val reusableSecret: Secret[String] = Secret("password") // reusable secret
val oneShotSecret: Secret.OneShot[String] = Secret.oneShot("password") // one shot secret
val deferredSecret: Secret.Deferred[Try, String] = Secret.deferred(Try("password")) // deferred secret
```

## Obfuscation

By default the value is obfuscated when creating the `Secret` instance using the implicit `SecretStrategy` which, by default, transform the value into a xor-ed
Expand Down
Loading