aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/byspel/Service.scala
blob: 1d1e841c8365a988d2acc61dc207e6fc05b376f4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package byspel

import app.DatabaseApi
import java.sql.Timestamp
import java.time.Instant
import java.util.UUID
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration._

trait Service { self: DatabaseApi =>
  import profile.api._

  implicit def executionContext: ExecutionContext

  def login(id: String,
            password: String): Future[Option[(UsersRow, SessionsRow)]] = {
    val query = for {
      user <- Users
      if user.primaryEmail === id || user.id === id
      shadow <- Shadow
      if shadow.userId === user.id
    } yield {
      user -> shadow.hash
    }
    val userResult = database.run(query.result.headOption).map {
      case Some((user, hash)) if PasswordHash.verify(password, hash) =>
        Some(user)
      case _ =>
        // dummy password hash to avoid timing attacks
        PasswordHash.verify(
          password,
          "$argon2i$v=19$m=65536,t=10,p=1$gFZ4l8R2rpuhfqXDFuugNg$fOvTwLSaOMahD/5AfWlbRsSMj4E6k34VpGyl5xe24yA")
        None
    }

    userResult.flatMap {
      case Some(u) =>
        val newSession = SessionsRow(
          UUID.randomUUID().toString,
          u.id,
          Timestamp.from(Instant.now.plusSeconds(60 * 60 * 24))
        )
        database
          .run(
            Sessions += newSession
          )
          .map(_ => Some(u -> newSession))
      case None => Future.successful(None)
    }
  }

  def checkSession(sessionId: String): Future[Option[UsersRow]] = database.run {
    val query = for {
      session <- Sessions
      if session.sessionId === sessionId
      if session.expires > Timestamp.from(Instant.now())
      user <- Users
      if user.id === session.userId
    } yield {
      user
    }
    query.result.headOption
  }

  def endSession(sessionId: String) = database.run {
    Sessions.filter(_.sessionId === sessionId).delete
  }

}