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
}
}
|