2013-10-20 07:46:29 -06:00
|
|
|
package controllers
|
|
|
|
|
2018-04-02 21:11:21 -06:00
|
|
|
import play.api.libs.json._
|
2017-01-15 05:26:08 -07:00
|
|
|
import play.api.mvc._
|
2013-10-20 07:46:29 -06:00
|
|
|
|
2015-11-12 22:14:23 -07:00
|
|
|
import lila.api.Context
|
2013-10-20 07:46:29 -06:00
|
|
|
import lila.app._
|
2017-10-21 14:01:50 -06:00
|
|
|
import lila.common.LilaCookie
|
2018-05-05 09:49:05 -06:00
|
|
|
import lila.user.{ User => UserModel, UserRepo, TotpSecret }
|
2018-05-06 09:14:24 -06:00
|
|
|
import UserModel.{ ClearPassword, TotpToken, PasswordAndToken }
|
2017-07-14 12:42:01 -06:00
|
|
|
import views.html
|
2013-10-20 07:46:29 -06:00
|
|
|
|
|
|
|
object Account extends LilaController {
|
|
|
|
|
|
|
|
private def env = Env.user
|
2015-07-02 09:25:23 -06:00
|
|
|
private def relationEnv = Env.relation
|
2013-10-20 07:46:29 -06:00
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def profile = Auth { implicit ctx => me =>
|
2017-09-27 19:05:29 -06:00
|
|
|
Ok(html.account.profile(me, env.forms profileOf me)).fuccess
|
2013-10-20 07:46:29 -06:00
|
|
|
}
|
|
|
|
|
2019-04-07 15:01:14 -06:00
|
|
|
def username = Auth { implicit ctx => me =>
|
|
|
|
Ok(html.account.username(me, env.forms usernameOf me)).fuccess
|
|
|
|
}
|
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def profileApply = AuthBody { implicit ctx => me =>
|
|
|
|
implicit val req: Request[_] = ctx.body
|
2017-09-27 19:05:29 -06:00
|
|
|
FormFuResult(env.forms.profile) { err =>
|
2017-02-14 08:34:07 -07:00
|
|
|
fuccess(html.account.profile(me, err))
|
|
|
|
} { profile =>
|
|
|
|
UserRepo.setProfile(me.id, profile) inject Redirect(routes.User show me.username)
|
|
|
|
}
|
2013-10-20 07:46:29 -06:00
|
|
|
}
|
|
|
|
|
2019-04-07 15:01:14 -06:00
|
|
|
def usernameApply = AuthBody { implicit ctx => me =>
|
|
|
|
implicit val req: Request[_] = ctx.body
|
|
|
|
FormFuResult(env.forms.username(me)) { err =>
|
|
|
|
fuccess(html.account.username(me, err))
|
2019-04-08 02:43:23 -06:00
|
|
|
} { username =>
|
2019-04-08 04:49:37 -06:00
|
|
|
UserRepo.setUsernameCased(me.id, username) inject Redirect(routes.User show me.username) recoverWith {
|
|
|
|
case e => fuccess(html.account.username(me, env.forms.username(me).withGlobalError(e.getMessage)))
|
|
|
|
}
|
2019-04-07 15:01:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-31 19:48:52 -06:00
|
|
|
def info = Auth { implicit ctx => me =>
|
2016-03-01 18:27:36 -07:00
|
|
|
negotiate(
|
|
|
|
html = notFound,
|
2018-12-15 20:13:22 -07:00
|
|
|
api = _ => {
|
|
|
|
lila.mon.http.response.accountInfo.count()
|
|
|
|
relationEnv.api.countFollowers(me.id) zip
|
|
|
|
relationEnv.api.countFollowing(me.id) zip
|
|
|
|
Env.pref.api.getPref(me) zip
|
2019-08-20 07:51:40 -06:00
|
|
|
Env.round.proxy.urgentGames(me) zip
|
2018-12-15 20:13:22 -07:00
|
|
|
Env.challenge.api.countInFor.get(me.id) zip
|
|
|
|
Env.playban.api.currentBan(me.id) map {
|
|
|
|
case nbFollowers ~ nbFollowing ~ prefs ~ povs ~ nbChallenges ~ playban =>
|
|
|
|
Ok {
|
|
|
|
import lila.pref.JsonView._
|
|
|
|
Env.user.jsonView(me) ++ Json.obj(
|
|
|
|
"prefs" -> prefs,
|
2019-07-18 06:56:58 -06:00
|
|
|
"nowPlaying" -> JsArray(povs take 50 map Env.api.lobbyApi.nowPlaying),
|
2018-12-15 20:13:22 -07:00
|
|
|
"nbFollowing" -> nbFollowing,
|
|
|
|
"nbFollowers" -> nbFollowers,
|
|
|
|
"nbChallenges" -> nbChallenges
|
|
|
|
).add("kid" -> me.kid)
|
|
|
|
.add("troll" -> me.troll)
|
|
|
|
.add("playban" -> playban)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.mon(_.http.response.accountInfo.time)
|
2018-03-31 19:48:52 -06:00
|
|
|
)
|
2014-07-21 14:46:52 -06:00
|
|
|
}
|
|
|
|
|
2018-04-11 21:07:12 -06:00
|
|
|
def nowPlaying = Auth { implicit ctx => me =>
|
|
|
|
negotiate(
|
|
|
|
html = notFound,
|
2018-05-21 06:10:22 -06:00
|
|
|
api = _ => doNowPlaying(me, ctx.req)
|
2018-04-11 21:07:12 -06:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-04-26 18:04:45 -06:00
|
|
|
def apiMe = Scoped() { _ => me =>
|
2018-12-18 17:58:43 -07:00
|
|
|
Env.api.userApi.extended(me, me.some) map { JsonOk(_) }
|
2018-04-01 17:18:29 -06:00
|
|
|
}
|
|
|
|
|
2018-05-21 06:10:22 -06:00
|
|
|
def apiNowPlaying = Scoped() { req => me =>
|
|
|
|
doNowPlaying(me, req)
|
|
|
|
}
|
|
|
|
|
|
|
|
private def doNowPlaying(me: lila.user.User, req: RequestHeader) =
|
2019-08-20 07:51:40 -06:00
|
|
|
Env.round.proxy.urgentGames(me) map { povs =>
|
2018-05-21 06:18:10 -06:00
|
|
|
val nb = (getInt("nb", req) | 9) atMost 50
|
2018-05-21 06:10:22 -06:00
|
|
|
Ok(Json.obj("nowPlaying" -> JsArray(povs take nb map Env.api.lobbyApi.nowPlaying)))
|
|
|
|
}
|
|
|
|
|
2018-03-31 19:48:52 -06:00
|
|
|
def dasher = Auth { implicit ctx => me =>
|
2017-05-03 08:22:50 -06:00
|
|
|
negotiate(
|
|
|
|
html = notFound,
|
2018-03-31 19:48:52 -06:00
|
|
|
api = _ => Env.pref.api.getPref(me) map { prefs =>
|
|
|
|
Ok {
|
|
|
|
import lila.pref.JsonView._
|
|
|
|
lila.common.LightUser.lightUserWrites.writes(me.light) ++ Json.obj(
|
|
|
|
"coach" -> isGranted(_.Coach),
|
|
|
|
"prefs" -> prefs
|
|
|
|
)
|
2017-05-03 08:22:50 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def passwd = Auth { implicit ctx => me =>
|
2017-09-27 19:05:29 -06:00
|
|
|
env.forms passwd me map { form =>
|
2017-07-14 12:42:01 -06:00
|
|
|
Ok(html.account.passwd(form))
|
|
|
|
}
|
2014-12-10 15:07:43 -07:00
|
|
|
}
|
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def passwdApply = AuthBody { implicit ctx => me =>
|
2018-05-06 13:46:52 -06:00
|
|
|
controllers.Auth.HasherRateLimit(me.username, ctx.req) { _ =>
|
|
|
|
implicit val req = ctx.body
|
|
|
|
env.forms passwd me flatMap { form =>
|
|
|
|
FormFuResult(form) { err =>
|
|
|
|
fuccess(html.account.passwd(err))
|
|
|
|
} { data =>
|
2017-09-28 17:25:07 -06:00
|
|
|
Env.user.authenticator.setPassword(me.id, ClearPassword(data.newPasswd1)) inject
|
2017-09-27 18:23:16 -06:00
|
|
|
Redirect(s"${routes.Account.passwd}?ok=1")
|
|
|
|
}
|
2014-12-10 15:07:43 -07:00
|
|
|
}
|
2017-02-14 08:34:07 -07:00
|
|
|
}
|
2014-12-10 15:07:43 -07:00
|
|
|
}
|
|
|
|
|
2017-07-14 13:29:38 -06:00
|
|
|
private def emailForm(user: UserModel) = UserRepo email user.id flatMap {
|
|
|
|
Env.security.forms.changeEmail(user, _)
|
|
|
|
}
|
2014-12-14 17:32:18 -07:00
|
|
|
|
2018-04-26 17:58:29 -06:00
|
|
|
def email = Auth { implicit ctx => me =>
|
|
|
|
if (getBool("check")) Ok(renderCheckYourEmail).fuccess
|
|
|
|
else emailForm(me) map { form =>
|
|
|
|
Ok(html.account.email(me, form))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def apiEmail = Scoped(_.Email.Read) { _ => me =>
|
|
|
|
UserRepo email me.id map {
|
|
|
|
_ ?? { email =>
|
2018-12-18 17:58:43 -07:00
|
|
|
JsonOk(Json.obj("email" -> email.value))
|
2018-04-11 14:49:54 -06:00
|
|
|
}
|
2018-04-26 17:58:29 -06:00
|
|
|
}
|
|
|
|
}
|
2014-12-10 15:07:43 -07:00
|
|
|
|
2018-03-29 13:59:31 -06:00
|
|
|
def renderCheckYourEmail(implicit ctx: Context) =
|
|
|
|
html.auth.checkYourEmail(lila.security.EmailConfirm.cookie get ctx.req)
|
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def emailApply = AuthBody { implicit ctx => me =>
|
2018-05-06 13:48:56 -06:00
|
|
|
controllers.Auth.HasherRateLimit(me.username, ctx.req) { _ =>
|
|
|
|
implicit val req = ctx.body
|
2018-12-29 02:45:25 -07:00
|
|
|
Env.security.forms.preloadEmailDns >> emailForm(me).flatMap { form =>
|
2018-05-06 13:48:56 -06:00
|
|
|
FormFuResult(form) { err =>
|
|
|
|
fuccess(html.account.email(me, err))
|
|
|
|
} { data =>
|
2018-10-07 08:50:38 -06:00
|
|
|
val email = Env.security.emailAddressValidator.validate(data.realEmail) err s"Invalid email ${data.email}"
|
2019-02-19 04:09:44 -07:00
|
|
|
val newUserEmail = lila.security.EmailConfirm.UserEmail(me.username, email.acceptable)
|
2018-05-06 13:48:56 -06:00
|
|
|
controllers.Auth.EmailConfirmRateLimit(newUserEmail, ctx.req) {
|
|
|
|
Env.security.emailChange.send(me, newUserEmail.email) inject Redirect {
|
|
|
|
s"${routes.Account.email}?check=1"
|
|
|
|
}
|
2018-03-29 15:46:29 -06:00
|
|
|
}
|
2017-07-15 05:32:31 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def emailConfirm(token: String) = Open { implicit ctx =>
|
|
|
|
Env.security.emailChange.confirm(token) flatMap {
|
|
|
|
_ ?? { user =>
|
2018-05-06 09:56:50 -06:00
|
|
|
controllers.Auth.authenticateUser(user, result = Some { _ =>
|
|
|
|
Redirect(s"${routes.Account.email}?ok=1")
|
|
|
|
})
|
2017-07-14 12:42:01 -06:00
|
|
|
}
|
2017-02-14 08:34:07 -07:00
|
|
|
}
|
2013-10-20 07:46:29 -06:00
|
|
|
}
|
|
|
|
|
2018-12-24 00:05:54 -07:00
|
|
|
def emailConfirmHelp = OpenBody { implicit ctx =>
|
|
|
|
import lila.security.EmailConfirm.Help._
|
|
|
|
ctx.me match {
|
|
|
|
case Some(me) =>
|
|
|
|
Redirect(routes.User.show(me.username)).fuccess
|
|
|
|
case None if get("username").isEmpty =>
|
|
|
|
Ok(html.account.emailConfirmHelp(helpForm, none)).fuccess
|
|
|
|
case None =>
|
|
|
|
implicit val req = ctx.body
|
|
|
|
helpForm.bindFromRequest.fold(
|
|
|
|
err => BadRequest(html.account.emailConfirmHelp(err, none)).fuccess,
|
|
|
|
username => getStatus(username) map { status =>
|
|
|
|
Ok(html.account.emailConfirmHelp(helpForm fill username, status.some))
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-05 04:01:45 -06:00
|
|
|
def twoFactor = Auth { implicit ctx => me =>
|
2018-05-06 04:03:28 -06:00
|
|
|
if (me.totpSecret.isDefined)
|
|
|
|
Env.security.forms.disableTwoFactor(me) map { form =>
|
2019-02-04 09:44:29 -07:00
|
|
|
html.account.twoFactor.disable(me, form)
|
2018-05-06 03:00:39 -06:00
|
|
|
}
|
2018-05-06 04:03:28 -06:00
|
|
|
else
|
|
|
|
Env.security.forms.setupTwoFactor(me) map { form =>
|
2019-02-04 09:44:29 -07:00
|
|
|
html.account.twoFactor.setup(me, form)
|
2018-05-06 04:03:28 -06:00
|
|
|
}
|
2018-05-05 04:01:45 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
def setupTwoFactor = AuthBody { implicit ctx => me =>
|
2018-05-06 13:52:59 -06:00
|
|
|
controllers.Auth.HasherRateLimit(me.username, ctx.req) { _ =>
|
|
|
|
implicit val req = ctx.body
|
|
|
|
val currentSessionId = ~Env.security.api.reqSessionId(ctx.req)
|
|
|
|
Env.security.forms.setupTwoFactor(me) flatMap { form =>
|
|
|
|
FormFuResult(form) { err =>
|
2019-02-04 09:44:29 -07:00
|
|
|
fuccess(html.account.twoFactor.setup(me, err))
|
2018-05-06 13:52:59 -06:00
|
|
|
} { data =>
|
|
|
|
UserRepo.setupTwoFactor(me.id, TotpSecret(data.secret)) >>
|
2019-05-04 10:46:28 -06:00
|
|
|
lila.security.Store.closeUserExceptSessionId(me.id, currentSessionId) >>
|
|
|
|
Env.push.webSubscriptionApi.unsubscribeByUserExceptSession(me, currentSessionId) inject
|
2018-05-06 13:52:59 -06:00
|
|
|
Redirect(routes.Account.twoFactor)
|
|
|
|
}
|
2018-05-05 04:01:45 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-06 03:00:39 -06:00
|
|
|
def disableTwoFactor = AuthBody { implicit ctx => me =>
|
2018-05-06 13:52:59 -06:00
|
|
|
controllers.Auth.HasherRateLimit(me.username, ctx.req) { _ =>
|
|
|
|
implicit val req = ctx.body
|
|
|
|
Env.security.forms.disableTwoFactor(me) flatMap { form =>
|
|
|
|
FormFuResult(form) { err =>
|
2019-02-04 09:44:29 -07:00
|
|
|
fuccess(html.account.twoFactor.disable(me, err))
|
2018-05-06 13:52:59 -06:00
|
|
|
} { _ =>
|
|
|
|
UserRepo.disableTwoFactor(me.id) inject Redirect(routes.Account.twoFactor)
|
|
|
|
}
|
2018-05-06 03:00:39 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def close = Auth { implicit ctx => me =>
|
2018-11-28 21:04:19 -07:00
|
|
|
Env.security.forms closeAccount me map { form =>
|
|
|
|
Ok(html.account.close(me, form))
|
|
|
|
}
|
2013-10-20 07:46:29 -06:00
|
|
|
}
|
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def closeConfirm = AuthBody { implicit ctx => me =>
|
2017-09-27 20:39:55 -06:00
|
|
|
implicit val req = ctx.body
|
2018-11-28 21:04:19 -07:00
|
|
|
Env.security.forms closeAccount me flatMap { form =>
|
|
|
|
FormFuResult(form) { err =>
|
|
|
|
fuccess(html.account.close(me, err))
|
|
|
|
} { _ =>
|
|
|
|
Env.current.closeAccount(me.id, self = true) inject {
|
|
|
|
Redirect(routes.User show me.username) withCookies LilaCookie.newSession
|
2013-10-20 07:46:29 -06:00
|
|
|
}
|
2018-11-28 21:04:19 -07:00
|
|
|
}
|
2017-02-14 08:34:07 -07:00
|
|
|
}
|
2013-10-20 07:46:29 -06:00
|
|
|
}
|
2015-04-12 00:36:27 -06:00
|
|
|
|
2018-04-26 17:58:29 -06:00
|
|
|
def kid = Auth { implicit ctx => me =>
|
|
|
|
Ok(html.account.kid(me)).fuccess
|
|
|
|
}
|
|
|
|
def apiKid = Scoped(_.Preference.Read) { _ => me =>
|
2018-12-18 17:58:43 -07:00
|
|
|
JsonOk(Json.obj("kid" -> me.kid)).fuccess
|
2018-04-26 17:58:29 -06:00
|
|
|
}
|
2018-04-02 18:33:23 -06:00
|
|
|
|
|
|
|
// App BC
|
|
|
|
def kidToggle = Auth { ctx => me =>
|
|
|
|
UserRepo.setKid(me, !me.kid) inject Ok
|
2015-04-12 00:36:27 -06:00
|
|
|
}
|
|
|
|
|
2018-04-26 17:58:29 -06:00
|
|
|
def kidPost = Auth { implicit ctx => me =>
|
|
|
|
UserRepo.setKid(me, getBool("v")) inject Redirect(routes.Account.kid)
|
|
|
|
}
|
|
|
|
def apiKidPost = Scoped(_.Preference.Write) { req => me =>
|
|
|
|
UserRepo.setKid(me, getBool("v", req)) inject jsonOkResult
|
2015-04-12 00:36:27 -06:00
|
|
|
}
|
2015-11-10 07:18:03 -07:00
|
|
|
|
2015-11-12 22:14:23 -07:00
|
|
|
private def currentSessionId(implicit ctx: Context) =
|
|
|
|
~Env.security.api.reqSessionId(ctx.req)
|
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def security = Auth { implicit ctx => me =>
|
|
|
|
Env.security.api.dedup(me.id, ctx.req) >>
|
|
|
|
Env.security.api.locatedOpenSessions(me.id, 50) map { sessions =>
|
|
|
|
Ok(html.account.security(me, sessions, currentSessionId))
|
|
|
|
}
|
2015-11-10 07:18:03 -07:00
|
|
|
}
|
|
|
|
|
2017-02-14 08:34:07 -07:00
|
|
|
def signout(sessionId: String) = Auth { implicit ctx => me =>
|
|
|
|
if (sessionId == "all")
|
2019-05-04 10:46:28 -06:00
|
|
|
lila.security.Store.closeUserExceptSessionId(me.id, currentSessionId) >>
|
|
|
|
Env.push.webSubscriptionApi.unsubscribeByUserExceptSession(me, currentSessionId) inject
|
2017-02-14 08:34:07 -07:00
|
|
|
Redirect(routes.Account.security)
|
|
|
|
else
|
2019-05-04 10:46:28 -06:00
|
|
|
lila.security.Store.closeUserAndSessionId(me.id, sessionId) >>
|
|
|
|
Env.push.webSubscriptionApi.unsubscribeBySession(sessionId)
|
2015-11-10 07:18:03 -07:00
|
|
|
}
|
2013-10-20 07:46:29 -06:00
|
|
|
}
|