This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class UsernamePasswordCredentials(username: String, password: String) | |
case class UserStore( | |
identityStore: IdentityStore[IO, UserId, User], | |
checkPassword: UsernamePasswordCredentials => IO[Option[User]] | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val httpApp = authenticator | |
.map( | |
SecuredRequestHandler(_).liftService(privateRoutes) <+> routes | |
).map(_.orNotFound) | |
def run(args: List[String]): IO[ExitCode] = | |
httpApp.flatMap(server(_)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val privateRoutes = TSecAuthService[User, TSecBearerToken[UserId], IO] { | |
case GET -> Root / "safe-resource" asAuthed user => Ok(s"Hello ${user.username}") | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val authenticator = for { | |
users <- Ref.of[IO, Map[UserId, User]](Map.empty) | |
tokens <- Ref.of[IO, Map[SecureRandomId, TSecBearerToken[UserId]]](Map.empty) | |
} yield BearerTokenAuthenticator[IO, UserId, User]( | |
userStore(users), | |
tokenStore(tokens), | |
TSecTokenSettings( | |
expiryDuration = 10.minutes, | |
maxIdle = None | |
)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def tokenStore(ref: Ref[IO, Map[SecureRandomId, TSecBearerToken[UserId]]]) = | |
new BackingStore[IO, SecureRandomId, TSecBearerToken[UserId]] { | |
override def put(elem: TSecBearerToken[UserId]) = | |
ref.modify(store => (store + (elem.id -> elem), elem)) | |
override def update(elem: TSecBearerToken[UserId]) = put(elem) | |
override def delete(id: SecureRandomId) = ref.modify(store => (store - id, ())) | |
override def get(id: SecureRandomId) = OptionT(ref.get.map(_.get(id))) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type UserId = FUUID @@ UserIdTag // shapeless.tag.@@ | |
case class User(id: UserId, | |
username: String, | |
password: PasswordHash[BCrypt]) | |
def userStore(users: Ref[IO, Map[UserId, User]]) = | |
new IdentityStore[IO, UserId, User] { | |
override def get(id: UserId) = OptionT(users.get.map(_.get(id))) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object AppServer extends IOApp { | |
val routes = HttpRoutes.of[IO] { | |
case GET -> Root / "non-safe-resource" => Ok() | |
} | |
val httpApp = routes.orNotFound | |
val server = BlazeServerBuilder[IO] | |
.bindHttp() | |
.withHttpApp(_) | |
.serve | |
.compile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class Reader[-From, +To](fn: From => To) { | |
def map[B](fn2: To => B): Reader[From, B] = Reader(fn.andThen(fn2)) | |
def flatMap[From1 <: From, B](fn2: To => Reader[From1, B]): Reader[From1, B] = | |
Reader[From1, B](r => fn2(fn(r)).fn(r)) | |
} | |
trait A { def nr: Int} | |
trait B { def str: String} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object FizzBuzzResult { | |
def fizzBuzzToString(fbz: FizzBuzz): String = fbz match { | |
case Buzz => "buzz" | |
case Fizz => "fizz" | |
case FizzAndBuzz => "fizzbuzz" | |
case number: Other[_] => number.nr.toString() | |
} | |
def apply[N <: Nat](implicit res: FizzBuzzResult[N]): String = | |
res.result.map(fizzBuzzToString).reverse.mkString("\n") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait NatToFizzBuzz[N <: Nat] { | |
type Out <: FizzBuzz | |
val value: Out | |
} | |
sealed trait NatToFizzBuzzInstances1 { | |
type Aux[N <: Nat, O <: FizzBuzz] = NatToFizzBuzz[N] { type Out = O } | |
implicit def other[N <: Nat](implicit toInt: ToInt[N]): Aux[N, Other[N]] = new NatToFizzBuzz[N] { |