Allow users with AdminManageUsers to see banned users
Also: - General code refactoring - Allow banned/restricted users to see their scores etc - common.MethodData now contains UserPrivileges - UserPrivileges have now their own type - Implement md.HasQuery, to know if there's a GET querystring parameter or not
This commit is contained in:
parent
476cd385f8
commit
e4d27f8d6b
|
@ -75,7 +75,7 @@ func initialCaretaker(c *gin.Context, f func(md common.MethodData) common.CodeMe
|
||||||
|
|
||||||
missingPrivileges := 0
|
missingPrivileges := 0
|
||||||
for _, privilege := range privilegesNeeded {
|
for _, privilege := range privilegesNeeded {
|
||||||
if int(md.User.Privileges)&privilege == 0 {
|
if uint64(md.User.TokenPrivileges)&uint64(privilege) == 0 {
|
||||||
missingPrivileges |= privilege
|
missingPrivileges |= privilege
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,13 +95,13 @@ func initialCaretaker(c *gin.Context, f func(md common.MethodData) common.CodeMe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := c.GetQuery("pls200"); exists {
|
if md.HasQuery("pls200") {
|
||||||
c.Writer.WriteHeader(200)
|
c.Writer.WriteHeader(200)
|
||||||
} else {
|
} else {
|
||||||
c.Writer.WriteHeader(resp.GetCode())
|
c.Writer.WriteHeader(resp.GetCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := c.GetQuery("callback"); exists {
|
if md.HasQuery("callback") {
|
||||||
c.Header("Content-Type", "application/javascript; charset=utf-8")
|
c.Header("Content-Type", "application/javascript; charset=utf-8")
|
||||||
} else {
|
} else {
|
||||||
c.Header("Content-Type", "application/json; charset=utf-8")
|
c.Header("Content-Type", "application/json; charset=utf-8")
|
||||||
|
|
|
@ -62,7 +62,6 @@ func Start(conf common.Conf, dbO *sqlx.DB) *gin.Engine {
|
||||||
// Auth-free API endpoints (public data)
|
// Auth-free API endpoints (public data)
|
||||||
gv1.GET("/ping", Method(v1.PingGET))
|
gv1.GET("/ping", Method(v1.PingGET))
|
||||||
gv1.GET("/surprise_me", Method(v1.SurpriseMeGET))
|
gv1.GET("/surprise_me", Method(v1.SurpriseMeGET))
|
||||||
gv1.GET("/privileges", Method(v1.PrivilegesGET))
|
|
||||||
gv1.GET("/doc", Method(v1.DocGET))
|
gv1.GET("/doc", Method(v1.DocGET))
|
||||||
gv1.GET("/doc/content", Method(v1.DocContentGET))
|
gv1.GET("/doc/content", Method(v1.DocContentGET))
|
||||||
gv1.GET("/doc/rules", Method(v1.DocRulesGET))
|
gv1.GET("/doc/rules", Method(v1.DocRulesGET))
|
||||||
|
|
|
@ -13,17 +13,25 @@ import (
|
||||||
// GetTokenFull retrieves an user ID and their token privileges knowing their API token.
|
// GetTokenFull retrieves an user ID and their token privileges knowing their API token.
|
||||||
func GetTokenFull(token string, db *sqlx.DB) (common.Token, bool) {
|
func GetTokenFull(token string, db *sqlx.DB) (common.Token, bool) {
|
||||||
var t common.Token
|
var t common.Token
|
||||||
var privs uint64
|
var (
|
||||||
|
tokenPrivsRaw uint64
|
||||||
|
userPrivsRaw uint64
|
||||||
|
)
|
||||||
var priv8 bool
|
var priv8 bool
|
||||||
err := db.QueryRow("SELECT id, user, privileges, private FROM tokens WHERE token = ? LIMIT 1",
|
err := db.QueryRow(`SELECT
|
||||||
|
t.id, t.user, t.privileges, t.private, u.privileges
|
||||||
|
FROM tokens t
|
||||||
|
LEFT JOIN users u ON u.id = t.user
|
||||||
|
WHERE token = ? LIMIT 1`,
|
||||||
fmt.Sprintf("%x", md5.Sum([]byte(token)))).
|
fmt.Sprintf("%x", md5.Sum([]byte(token)))).
|
||||||
Scan(
|
Scan(
|
||||||
&t.ID, &t.UserID, &privs, &priv8,
|
&t.ID, &t.UserID, &tokenPrivsRaw, &priv8, &userPrivsRaw,
|
||||||
)
|
)
|
||||||
if priv8 {
|
if priv8 {
|
||||||
privs = common.PrivilegeReadConfidential | common.PrivilegeWrite
|
tokenPrivsRaw = common.PrivilegeReadConfidential | common.PrivilegeWrite
|
||||||
}
|
}
|
||||||
t.Privileges = common.Privileges(privs)
|
t.TokenPrivileges = common.Privileges(tokenPrivsRaw)
|
||||||
|
t.UserPrivileges = common.UserPrivileges(userPrivsRaw)
|
||||||
switch {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
return common.Token{}, false
|
return common.Token{}, false
|
||||||
|
|
|
@ -71,7 +71,7 @@ type blogPostContent struct {
|
||||||
// BlogPostsContentGET retrieves the content of a specific blog post.
|
// BlogPostsContentGET retrieves the content of a specific blog post.
|
||||||
func BlogPostsContentGET(md common.MethodData) common.CodeMessager {
|
func BlogPostsContentGET(md common.MethodData) common.CodeMessager {
|
||||||
field := "markdown"
|
field := "markdown"
|
||||||
if _, present := md.C.GetQuery("html"); present {
|
if md.HasQuery("html") {
|
||||||
field = "html"
|
field = "html"
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -21,7 +21,7 @@ type docResponse struct {
|
||||||
// DocGET retrieves a list of documentation files.
|
// DocGET retrieves a list of documentation files.
|
||||||
func DocGET(md common.MethodData) common.CodeMessager {
|
func DocGET(md common.MethodData) common.CodeMessager {
|
||||||
var wc string
|
var wc string
|
||||||
if !md.User.Privileges.HasPrivilegeBlog() || md.Query("public") == "1" {
|
if md.User.TokenPrivileges&common.PrivilegeBlog == 0 || md.Query("public") == "1" {
|
||||||
wc = "WHERE public = '1'"
|
wc = "WHERE public = '1'"
|
||||||
}
|
}
|
||||||
rows, err := md.DB.Query("SELECT id, doc_name, public, is_rule FROM docs " + wc)
|
rows, err := md.DB.Query("SELECT id, doc_name, public, is_rule FROM docs " + wc)
|
||||||
|
@ -55,7 +55,7 @@ func DocContentGET(md common.MethodData) common.CodeMessager {
|
||||||
return common.SimpleResponse(404, "Documentation file not found!")
|
return common.SimpleResponse(404, "Documentation file not found!")
|
||||||
}
|
}
|
||||||
var wc string
|
var wc string
|
||||||
if !md.User.Privileges.HasPrivilegeBlog() || md.Query("public") == "1" {
|
if md.User.TokenPrivileges&common.PrivilegeBlog == 0 || md.Query("public") == "1" {
|
||||||
wc = "AND public = '1'"
|
wc = "AND public = '1'"
|
||||||
}
|
}
|
||||||
var r docContentResponse
|
var r docContentResponse
|
||||||
|
|
|
@ -157,7 +157,8 @@ func addFriend(md common.MethodData, u int) common.CodeMessager {
|
||||||
|
|
||||||
// userExists makes sure an user exists.
|
// userExists makes sure an user exists.
|
||||||
func userExists(md common.MethodData, u int) (r bool) {
|
func userExists(md common.MethodData, u int) (r bool) {
|
||||||
err := md.DB.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE id = ? AND users.privileges & 1 > 0)", u).Scan(&r)
|
err := md.DB.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE id = ? AND "+
|
||||||
|
md.User.OnlyUserPublic(true)+")", u).Scan(&r)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,10 @@ INNER JOIN users_stats ON users_stats.id = leaderboard_%[1]s.user
|
||||||
// LeaderboardGET gets the leaderboard.
|
// LeaderboardGET gets the leaderboard.
|
||||||
func LeaderboardGET(md common.MethodData) common.CodeMessager {
|
func LeaderboardGET(md common.MethodData) common.CodeMessager {
|
||||||
m := getMode(md.Query("mode"))
|
m := getMode(md.Query("mode"))
|
||||||
query := fmt.Sprintf(lbUserQuery, m, `WHERE users.privileges & 1 > 0 ORDER BY leaderboard_`+m+`.position `+
|
// Admins may not want to see banned users on the leaderboard.
|
||||||
common.Paginate(md.Query("p"), md.Query("l"), 100))
|
// This is the default setting. In case they do, they have to activate see_everything.
|
||||||
|
query := fmt.Sprintf(lbUserQuery, m, `WHERE `+md.User.OnlyUserPublic(md.HasQuery("see_everything"))+
|
||||||
|
` ORDER BY leaderboard_`+m+`.position `+common.Paginate(md.Query("p"), md.Query("l"), 100))
|
||||||
rows, err := md.DB.Query(query)
|
rows, err := md.DB.Query(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
|
|
|
@ -21,21 +21,15 @@ func UserManageSetAllowedPOST(md common.MethodData) common.CodeMessager {
|
||||||
return common.SimpleResponse(400, "Allowed status must be between 0 and 2")
|
return common.SimpleResponse(400, "Allowed status must be between 0 and 2")
|
||||||
}
|
}
|
||||||
var banDatetime int64
|
var banDatetime int64
|
||||||
var privileges int32
|
var privsSet string
|
||||||
var newPrivileges int32
|
|
||||||
err := md.DB.QueryRow("SELECT privileges FROM users WHERE id = ?", data.UserID).Scan(&privileges)
|
|
||||||
if err != nil {
|
|
||||||
md.Err(err)
|
|
||||||
return Err500
|
|
||||||
}
|
|
||||||
if data.Allowed == 0 {
|
if data.Allowed == 0 {
|
||||||
banDatetime = time.Now().Unix()
|
banDatetime = time.Now().Unix()
|
||||||
newPrivileges = privileges &^ (common.UserPrivilegeNormal | common.UserPrivilegePublic)
|
privsSet = "privileges = (privileges & ~3)"
|
||||||
} else {
|
} else {
|
||||||
banDatetime = 0
|
banDatetime = 0
|
||||||
newPrivileges = privileges | (common.UserPrivilegeNormal | common.UserPrivilegePublic)
|
privsSet = "privileges = (privileges | 3)"
|
||||||
}
|
}
|
||||||
_, err = md.DB.Exec("UPDATE users SET privileges = ?, ban_datetime = ? WHERE id = ?", newPrivileges, banDatetime, data.UserID)
|
_, err := md.DB.Exec("UPDATE users SET "+privsSet+", ban_datetime = ? WHERE id = ?", banDatetime, data.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
return Err500
|
return Err500
|
||||||
|
|
|
@ -88,7 +88,7 @@ func surpriseMe() string {
|
||||||
type pingResponse struct {
|
type pingResponse struct {
|
||||||
common.ResponseBase
|
common.ResponseBase
|
||||||
ID int `json:"user_id"`
|
ID int `json:"user_id"`
|
||||||
Privileges int `json:"privileges"`
|
Privileges uint64 `json:"privileges"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PingGET is a message to check with the API that we are logged in, and know what are our privileges.
|
// PingGET is a message to check with the API that we are logged in, and know what are our privileges.
|
||||||
|
@ -103,7 +103,7 @@ func PingGET(md common.MethodData) common.CodeMessager {
|
||||||
}
|
}
|
||||||
|
|
||||||
r.ID = md.ID()
|
r.ID = md.ID()
|
||||||
r.Privileges = int(md.User.Privileges)
|
r.Privileges = uint64(md.User.TokenPrivileges)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.zxq.co/ripple/rippleapi/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
type privilegesData struct {
|
|
||||||
common.ResponseBase
|
|
||||||
Read bool `json:"read"`
|
|
||||||
ReadConfidential bool `json:"read_confidential"`
|
|
||||||
Write bool `json:"write"`
|
|
||||||
ManageBadges bool `json:"manage_badges"`
|
|
||||||
BetaKeys bool `json:"beta_keys"`
|
|
||||||
ManageSettings bool `json:"manage_settings"`
|
|
||||||
ViewUserAdvanced bool `json:"view_user_advanced"`
|
|
||||||
ManageUser bool `json:"manage_user"`
|
|
||||||
ManageRoles bool `json:"manage_roles"`
|
|
||||||
ManageAPIKeys bool `json:"manage_api_keys"`
|
|
||||||
Blog bool `json:"blog"`
|
|
||||||
APIMeta bool `json:"api_meta"`
|
|
||||||
Beatmap bool `json:"beatmap"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrivilegesGET returns an explaination for the privileges, telling the client what they can do with this token.
|
|
||||||
func PrivilegesGET(md common.MethodData) common.CodeMessager {
|
|
||||||
r := privilegesData{}
|
|
||||||
r.Code = 200
|
|
||||||
// This code sucks.
|
|
||||||
r.Read = true
|
|
||||||
r.ReadConfidential = md.User.Privileges.HasPrivilegeReadConfidential()
|
|
||||||
r.Write = md.User.Privileges.HasPrivilegeWrite()
|
|
||||||
r.ManageBadges = md.User.Privileges.HasPrivilegeManageBadges()
|
|
||||||
r.BetaKeys = md.User.Privileges.HasPrivilegeBetaKeys()
|
|
||||||
r.ManageSettings = md.User.Privileges.HasPrivilegeManageSettings()
|
|
||||||
r.ViewUserAdvanced = md.User.Privileges.HasPrivilegeViewUserAdvanced()
|
|
||||||
r.ManageUser = md.User.Privileges.HasPrivilegeManageUser()
|
|
||||||
r.ManageRoles = md.User.Privileges.HasPrivilegeManageRoles()
|
|
||||||
r.ManageAPIKeys = md.User.Privileges.HasPrivilegeManageAPIKeys()
|
|
||||||
r.Blog = md.User.Privileges.HasPrivilegeBlog()
|
|
||||||
r.APIMeta = md.User.Privileges.HasPrivilegeAPIMeta()
|
|
||||||
r.Beatmap = md.User.Privileges.HasPrivilegeBeatmap()
|
|
||||||
return r
|
|
||||||
}
|
|
|
@ -83,7 +83,8 @@ SELECT
|
||||||
FROM scores
|
FROM scores
|
||||||
INNER JOIN users ON users.id = scores.userid
|
INNER JOIN users ON users.id = scores.userid
|
||||||
INNER JOIN users_stats ON users_stats.id = scores.userid
|
INNER JOIN users_stats ON users_stats.id = scores.userid
|
||||||
WHERE scores.beatmap_md5 = ? AND scores.completed = '3' AND users.privileges & 1 > 0 `+genModeClause(md)+`
|
WHERE scores.beatmap_md5 = ? AND scores.completed = '3' AND `+md.User.OnlyUserPublic(true)+
|
||||||
|
` `+genModeClause(md)+`
|
||||||
`+sort+common.Paginate(md.Query("p"), md.Query("l"), 100), beatmapMD5)
|
`+sort+common.Paginate(md.Query("p"), md.Query("l"), 100), beatmapMD5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
|
|
|
@ -63,10 +63,10 @@ func TokenNewPOST(md common.MethodData) common.CodeMessager {
|
||||||
rank int
|
rank int
|
||||||
pw string
|
pw string
|
||||||
pwVersion int
|
pwVersion int
|
||||||
privileges int
|
privilegesRaw uint64
|
||||||
)
|
)
|
||||||
|
|
||||||
err = q.Scan(&r.ID, &r.Username, &rank, &pw, &pwVersion, &privileges)
|
err = q.Scan(&r.ID, &r.Username, &rank, &pw, &pwVersion, &privilegesRaw)
|
||||||
switch {
|
switch {
|
||||||
case err == sql.ErrNoRows:
|
case err == sql.ErrNoRows:
|
||||||
return common.SimpleResponse(404, "No user with that username/id was found.")
|
return common.SimpleResponse(404, "No user with that username/id was found.")
|
||||||
|
@ -74,6 +74,7 @@ func TokenNewPOST(md common.MethodData) common.CodeMessager {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
return Err500
|
return Err500
|
||||||
}
|
}
|
||||||
|
privileges := common.UserPrivileges(privilegesRaw)
|
||||||
|
|
||||||
if nFailedAttempts(r.ID) > 20 {
|
if nFailedAttempts(r.ID) > 20 {
|
||||||
return common.SimpleResponse(429, "You've made too many login attempts. Try again later.")
|
return common.SimpleResponse(429, "You've made too many login attempts. Try again later.")
|
||||||
|
@ -231,9 +232,14 @@ LEFT JOIN users ON users.id = tokens.user
|
||||||
privsRaw uint64
|
privsRaw uint64
|
||||||
privs common.Privileges
|
privs common.Privileges
|
||||||
newPrivs common.Privileges
|
newPrivs common.Privileges
|
||||||
privileges int
|
privilegesRaw uint64
|
||||||
)
|
)
|
||||||
rows.Scan(&id, &privsRaw, &privileges)
|
err := rows.Scan(&id, &privsRaw, &privilegesRaw)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
privileges := common.UserPrivileges(privilegesRaw)
|
||||||
privs = common.Privileges(privsRaw)
|
privs = common.Privileges(privsRaw)
|
||||||
newPrivs = privs.CanOnly(privileges)
|
newPrivs = privs.CanOnly(privileges)
|
||||||
if newPrivs != privs {
|
if newPrivs != privs {
|
||||||
|
|
|
@ -36,7 +36,7 @@ SELECT users.id, users.username, register_datetime, privileges,
|
||||||
FROM users
|
FROM users
|
||||||
LEFT JOIN users_stats
|
LEFT JOIN users_stats
|
||||||
ON users.id=users_stats.id
|
ON users.id=users_stats.id
|
||||||
WHERE ` + whereClause + ` AND users.privileges & 1 > 0
|
WHERE ` + whereClause + ` AND ` + md.User.OnlyUserPublic(true) + `
|
||||||
LIMIT 1`
|
LIMIT 1`
|
||||||
return userPuts(md, md.DB.QueryRowx(query, param))
|
return userPuts(md, md.DB.QueryRowx(query, param))
|
||||||
}
|
}
|
||||||
|
@ -92,10 +92,11 @@ type whatIDResponse struct {
|
||||||
func UserWhatsTheIDGET(md common.MethodData) common.CodeMessager {
|
func UserWhatsTheIDGET(md common.MethodData) common.CodeMessager {
|
||||||
var (
|
var (
|
||||||
r whatIDResponse
|
r whatIDResponse
|
||||||
privileges int
|
privileges uint64
|
||||||
)
|
)
|
||||||
err := md.DB.QueryRow("SELECT id, privileges FROM users WHERE username = ? LIMIT 1", md.Query("name")).Scan(&r.ID, &privileges)
|
err := md.DB.QueryRow("SELECT id, privileges FROM users WHERE username = ? LIMIT 1", md.Query("name")).Scan(&r.ID, &privileges)
|
||||||
if err != nil || ((privileges&common.UserPrivilegePublic) == 0 && !md.User.Privileges.HasPrivilegeViewUserAdvanced()) {
|
if err != nil || ((privileges&uint64(common.UserPrivilegePublic)) == 0 &&
|
||||||
|
(md.User.UserPrivileges&common.AdminPrivilegeManageUsers == 0)) {
|
||||||
return common.SimpleResponse(404, "That user could not be found!")
|
return common.SimpleResponse(404, "That user could not be found!")
|
||||||
}
|
}
|
||||||
r.Code = 200
|
r.Code = 200
|
||||||
|
@ -167,7 +168,7 @@ LEFT JOIN leaderboard_ctb
|
||||||
ON users.id=leaderboard_ctb.user
|
ON users.id=leaderboard_ctb.user
|
||||||
LEFT JOIN leaderboard_mania
|
LEFT JOIN leaderboard_mania
|
||||||
ON users.id=leaderboard_mania.user
|
ON users.id=leaderboard_mania.user
|
||||||
WHERE ` + whereClause + ` AND users.privileges & 1 > 0
|
WHERE ` + whereClause + ` AND ` + md.User.OnlyUserPublic(true) + `
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`
|
`
|
||||||
// Fuck.
|
// Fuck.
|
||||||
|
@ -278,7 +279,8 @@ func UserLookupGET(md common.MethodData) common.CodeMessager {
|
||||||
return common.SimpleResponse(400, "please provide an username to start searching")
|
return common.SimpleResponse(400, "please provide an username to start searching")
|
||||||
}
|
}
|
||||||
name = "%" + name + "%"
|
name = "%" + name + "%"
|
||||||
rows, err := md.DB.Query("SELECT users.id, users.username FROM users WHERE username LIKE ? AND privileges & 1 > 0 LIMIT 25", name)
|
rows, err := md.DB.Query("SELECT users.id, users.username FROM users WHERE username LIKE ? AND "+
|
||||||
|
md.User.OnlyUserPublic(true)+" LIMIT 25", name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
md.Err(err)
|
md.Err(err)
|
||||||
return Err500
|
return Err500
|
||||||
|
|
|
@ -52,7 +52,7 @@ func UserScoresBestGET(md common.MethodData) common.CodeMessager {
|
||||||
scores.completed = '3'
|
scores.completed = '3'
|
||||||
AND %s
|
AND %s
|
||||||
%s
|
%s
|
||||||
AND users.privileges & 1 > 0
|
AND `+md.User.OnlyUserPublic(true)+`
|
||||||
ORDER BY scores.pp DESC, scores.score DESC %s`,
|
ORDER BY scores.pp DESC, scores.score DESC %s`,
|
||||||
wc, mc, common.Paginate(md.Query("p"), md.Query("l"), 100),
|
wc, mc, common.Paginate(md.Query("p"), md.Query("l"), 100),
|
||||||
), param)
|
), param)
|
||||||
|
@ -68,7 +68,7 @@ func UserScoresRecentGET(md common.MethodData) common.CodeMessager {
|
||||||
`WHERE
|
`WHERE
|
||||||
%s
|
%s
|
||||||
%s
|
%s
|
||||||
AND users.privileges & 1 > 0
|
AND `+md.User.OnlyUserPublic(true)+`
|
||||||
ORDER BY scores.time DESC %s`,
|
ORDER BY scores.time DESC %s`,
|
||||||
wc, genModeClause(md), common.Paginate(md.Query("p"), md.Query("l"), 100),
|
wc, genModeClause(md), common.Paginate(md.Query("p"), md.Query("l"), 100),
|
||||||
), param)
|
), param)
|
||||||
|
|
|
@ -30,6 +30,13 @@ func (md MethodData) Query(q string) string {
|
||||||
return md.C.Query(q)
|
return md.C.Query(q)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasQuery returns true if the parameter is encountered in the querystring.
|
||||||
|
// It returns true even if the parameter is "" (the case of ?param&etc=etc)
|
||||||
|
func (md MethodData) HasQuery(q string) bool {
|
||||||
|
_, has := md.C.GetQuery(q)
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
// RequestData is the body of a request. It is wrapped into this type
|
// RequestData is the body of a request. It is wrapped into this type
|
||||||
// to implement the Unmarshal function, which is just a shorthand to
|
// to implement the Unmarshal function, which is just a shorthand to
|
||||||
// json.Unmarshal.
|
// json.Unmarshal.
|
||||||
|
|
|
@ -22,66 +22,6 @@ const (
|
||||||
// Privileges is a bitwise enum of the privileges of an user's API key.
|
// Privileges is a bitwise enum of the privileges of an user's API key.
|
||||||
type Privileges uint64
|
type Privileges uint64
|
||||||
|
|
||||||
// HasPrivilegeReadConfidential returns whether the ReadConfidential privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeReadConfidential() bool {
|
|
||||||
return p&PrivilegeReadConfidential != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeWrite returns whether the Write privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeWrite() bool {
|
|
||||||
return p&PrivilegeWrite != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeManageBadges returns whether the ManageBadges privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeManageBadges() bool {
|
|
||||||
return p&PrivilegeManageBadges != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeBetaKeys returns whether the BetaKeys privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeBetaKeys() bool {
|
|
||||||
return p&PrivilegeBetaKeys != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeManageSettings returns whether the ManageSettings privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeManageSettings() bool {
|
|
||||||
return p&PrivilegeManageSettings != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeViewUserAdvanced returns whether the ViewUserAdvanced privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeViewUserAdvanced() bool {
|
|
||||||
return p&PrivilegeViewUserAdvanced != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeManageUser returns whether the ManageUser privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeManageUser() bool {
|
|
||||||
return p&PrivilegeManageUser != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeManageRoles returns whether the ManageRoles privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeManageRoles() bool {
|
|
||||||
return p&PrivilegeManageRoles != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeManageAPIKeys returns whether the ManageAPIKeys privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeManageAPIKeys() bool {
|
|
||||||
return p&PrivilegeManageAPIKeys != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeBlog returns whether the Blog privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeBlog() bool {
|
|
||||||
return p&PrivilegeBlog != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeAPIMeta returns whether the APIMeta privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeAPIMeta() bool {
|
|
||||||
return p&PrivilegeAPIMeta != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPrivilegeBeatmap returns whether the Beatmap privilege is included in the privileges.
|
|
||||||
func (p Privileges) HasPrivilegeBeatmap() bool {
|
|
||||||
return p&PrivilegeBeatmap != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var privilegeString = [...]string{
|
var privilegeString = [...]string{
|
||||||
"Read",
|
"Read",
|
||||||
"ReadConfidential",
|
"ReadConfidential",
|
||||||
|
@ -101,14 +41,14 @@ var privilegeString = [...]string{
|
||||||
func (p Privileges) String() string {
|
func (p Privileges) String() string {
|
||||||
var pvs []string
|
var pvs []string
|
||||||
for i, v := range privilegeString {
|
for i, v := range privilegeString {
|
||||||
if int(p)&(1<<uint(i)) != 0 {
|
if uint64(p)&uint64(1<<uint(i)) != 0 {
|
||||||
pvs = append(pvs, v)
|
pvs = append(pvs, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strings.Join(pvs, ", ")
|
return strings.Join(pvs, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
var privilegeMustBe = [...]int{
|
var privilegeMustBe = [...]UserPrivileges{
|
||||||
1 << 30, // read is deprecated, and should be given out to no-one.
|
1 << 30, // read is deprecated, and should be given out to no-one.
|
||||||
UserPrivilegeNormal,
|
UserPrivilegeNormal,
|
||||||
UserPrivilegeNormal,
|
UserPrivilegeNormal,
|
||||||
|
@ -125,7 +65,7 @@ var privilegeMustBe = [...]int{
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanOnly removes any privilege that the user has requested to have, but cannot have due to their rank.
|
// CanOnly removes any privilege that the user has requested to have, but cannot have due to their rank.
|
||||||
func (p Privileges) CanOnly(userPrivs int) Privileges {
|
func (p Privileges) CanOnly(userPrivs UserPrivileges) Privileges {
|
||||||
newPrivilege := 0
|
newPrivilege := 0
|
||||||
for i, v := range privilegeMustBe {
|
for i, v := range privilegeMustBe {
|
||||||
wants := p&1 == 1
|
wants := p&1 == 1
|
||||||
|
|
|
@ -1,9 +1,23 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
// Token Is an API token.
|
import "fmt"
|
||||||
|
|
||||||
|
// Token is an API token.
|
||||||
type Token struct {
|
type Token struct {
|
||||||
ID int
|
ID int
|
||||||
Value string
|
Value string
|
||||||
UserID int
|
UserID int
|
||||||
Privileges Privileges
|
TokenPrivileges Privileges
|
||||||
|
UserPrivileges UserPrivileges
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnlyUserPublic returns a string containing "(user.privileges & 1 = 1 OR users.id = <userID>)"
|
||||||
|
// if the user does not have the UserPrivilege AdminManageUsers, and returns "1" otherwise.
|
||||||
|
func (t Token) OnlyUserPublic(userManagerSeesEverything bool) string {
|
||||||
|
if userManagerSeesEverything &&
|
||||||
|
t.UserPrivileges&AdminPrivilegeManageUsers == AdminPrivilegeManageUsers {
|
||||||
|
return "1"
|
||||||
|
}
|
||||||
|
// It's safe to use sprintf directly even if it's a query, because UserID is an int.
|
||||||
|
return fmt.Sprintf("(user.privileges & 1 = 1 OR users.id = '%d')", t.UserID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
// user/admin privileges
|
// user/admin privileges
|
||||||
const (
|
const (
|
||||||
UserPrivilegePublic = 1 << iota
|
UserPrivilegePublic UserPrivileges = 1 << iota
|
||||||
UserPrivilegeNormal
|
UserPrivilegeNormal
|
||||||
UserPrivilegeDonor
|
UserPrivilegeDonor
|
||||||
AdminPrivilegeAccessRAP
|
AdminPrivilegeAccessRAP
|
||||||
|
@ -22,4 +24,42 @@ const (
|
||||||
AdminPrivilegeSendAlerts
|
AdminPrivilegeSendAlerts
|
||||||
AdminPrivilegeChatMod
|
AdminPrivilegeChatMod
|
||||||
AdminPrivilegeKickUsers
|
AdminPrivilegeKickUsers
|
||||||
|
UserPrivilegePendingVerification
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// UserPrivileges represents a bitwise enum of the privileges of an user.
|
||||||
|
type UserPrivileges uint64
|
||||||
|
|
||||||
|
var userPrivilegeString = [...]string{
|
||||||
|
"UserPublic",
|
||||||
|
"UserNormal",
|
||||||
|
"UserDonor",
|
||||||
|
"AdminAccessRAP",
|
||||||
|
"AdminManageUsers",
|
||||||
|
"AdminBanUsers",
|
||||||
|
"AdminSilenceUsers",
|
||||||
|
"AdminWipeUsers",
|
||||||
|
"AdminManageBeatmap",
|
||||||
|
"AdminManageServer",
|
||||||
|
"AdminManageSetting",
|
||||||
|
"AdminManageBetaKey",
|
||||||
|
"AdminManageReport",
|
||||||
|
"AdminManageDocs",
|
||||||
|
"AdminManageBadges",
|
||||||
|
"AdminViewRAPLogs",
|
||||||
|
"AdminManagePrivilege",
|
||||||
|
"AdminSendAlerts",
|
||||||
|
"AdminChatMod",
|
||||||
|
"AdminKickUsers",
|
||||||
|
"UserPendingVerification",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p UserPrivileges) String() string {
|
||||||
|
var pvs []string
|
||||||
|
for i, v := range userPrivilegeString {
|
||||||
|
if uint64(p)&uint64(1<<uint(i)) != 0 {
|
||||||
|
pvs = append(pvs, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(pvs, ", ")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user