dramatically improve user spy

This commit is contained in:
Thibault Duplessis 2013-05-15 19:09:25 -03:00
parent 86442e42fe
commit ff73b353bf
3 changed files with 56 additions and 23 deletions

View file

@ -19,9 +19,37 @@
</div>
<div class="user_spy">
<br />
<strong>Other usernames:</strong>
<div class="usernames">@Html(spy.otherUsernames.map(userIdLinkMini).mkString(", "))</div>
@if(spy.otherUsers.isEmpty) {
<strong>No user found with same IPs</strong>
} else {
<strong>Shares IP addresses with @spy.otherUsers.size user(s)</strong>
<table class="others slist">
<thead>
<tr>
<th>User</th>
<th>Games</th>
<th>Engine</th>
<th>Muted</th>
<th>IPban</th>
<th>Closed</th>
<th>Created</th>
</tr>
</thead>
<tbody>
@spy.otherUsers.map { o =>
<tr>
<td>@userLink(o)</td>
<td>@o.nbGames</td>
<td>@{o.engine.??("X")}</td>
<td>@{o.muted.??("X")}</td>
<td></td>
<td>@{o.disabled.??("X")}</td>
<td>@showDate(o.createdAt)</td>
</tr>
}
</tbody>
</table>
}
<strong>IP addresses:</strong> <ul>@spy.ips.map { ip =>
<li>@ip</li>
}</ul>

View file

@ -17,10 +17,12 @@ import scala.concurrent.Future
case class UserSpy(
ips: List[String],
uas: List[String],
otherUsers: Set[User])
otherUsers: List[User])
object Store {
type IP = String
def save(sessionId: String, userId: String, req: RequestHeader): Funit =
$insert(Json.obj(
"_id" -> sessionId,
@ -50,36 +52,36 @@ object Store {
private[security] def userSpy(userId: String): Fu[UserSpy] = for {
user UserRepo byId userId flatten "[spy] user not found"
objs $find(selectUser(user.id))
users explore(user)
users explore(Set(user), Set.empty, Set(user))
} yield UserSpy(
ips = objs.map(_ str "ip").flatten.distinct,
uas = objs.map(_ str "ua").flatten.distinct,
otherUsers = users
otherUsers = (users - user).toList.sortBy(_.createdAt)
)
private def explore(user: User, withKnown: Set[User] = Set.empty): Fu[Set[User]] = {
val known = Seq(user) ++: withKnown
newSiblings(user.id, known) flatMap { children
children.foldLeft(fuccess(children)) {
case (siblings, child) siblings flatMap { sibs
explore(child, known ++ sibs) map (sibs ++)
}
private def explore(users: Set[User], ips: Set[IP], _users: Set[User]): Fu[Set[User]] = {
nextIps(users, ips) flatMap { nIps
nextUsers(nIps, users) flatMap { nUsers
nUsers.isEmpty ? fuccess(users) | explore(nUsers, nIps ++: ips, nUsers ++: users)
}
}
}
private def newSiblings(user: String, without: Set[User]): Fu[Set[User]] =
userIps(user) flatMap { ips
usersByIps(ips) map (_ diff without)
private def nextIps(users: Set[User], ips: Set[IP]): Fu[Set[IP]] =
users.nonEmpty ?? {
$primitive(
Json.obj("user" -> $in(users.map(_.id)), "ip" -> $nin(ips)), "ip"
)(_.asOpt[IP]) map (_.toSet)
}
private def userIps(user: String): Fu[Set[String]] =
$primitive(selectUser(user), "ip")(_.asOpt[String]) map (_.toSet)
private def usersByIps(ips: Set[String]): Fu[Set[User]] =
$primitive(
Json.obj("ip" -> $in(ips)), "user"
)(_.asOpt[String]) flatMap UserRepo.byIds map (_.toSet)
private def nextUsers(ips: Set[IP], users: Set[User]): Fu[Set[User]] =
ips.nonEmpty ?? {
$primitive(
Json.obj("ip" -> $in(ips), "user" -> $nin(users.map(_.id))), "user"
)(_.asOpt[String]) flatMap { userIds
userIds.nonEmpty ?? (UserRepo byIds userIds) map (_.toSet)
}
}
private def ip(req: RequestHeader) = req.remoteAddress

View file

@ -84,6 +84,9 @@ div.user_show .mod_zone {
display: none;
margin: 1em 0 0 20px;
}
div.user_show .mod_zone form {
margin: 0 25px 0 0;
}
div.user_show .mod_zone .usernames a {
text-decoration: none;
}