2016-04-03 17:59:27 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2016-04-05 20:22:13 +00:00
|
|
|
"crypto/md5"
|
2017-06-17 16:11:10 +00:00
|
|
|
"crypto/sha256"
|
2016-04-03 17:59:27 +00:00
|
|
|
"database/sql"
|
2016-04-05 20:22:13 +00:00
|
|
|
"fmt"
|
2016-12-01 22:16:36 +00:00
|
|
|
"time"
|
2016-08-15 11:45:42 +00:00
|
|
|
|
2016-12-01 22:16:36 +00:00
|
|
|
"github.com/jmoiron/sqlx"
|
2019-02-25 21:04:55 +00:00
|
|
|
"github.com/osuyozora/api/common"
|
2016-04-03 17:59:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// GetTokenFull retrieves an user ID and their token privileges knowing their API token.
|
2016-08-15 11:45:42 +00:00
|
|
|
func GetTokenFull(token string, db *sqlx.DB) (common.Token, bool) {
|
2016-08-27 10:04:12 +00:00
|
|
|
var (
|
2016-12-01 22:16:36 +00:00
|
|
|
t common.Token
|
2016-08-27 10:04:12 +00:00
|
|
|
tokenPrivsRaw uint64
|
|
|
|
userPrivsRaw uint64
|
2016-12-01 22:16:36 +00:00
|
|
|
priv8 bool
|
2016-08-27 10:04:12 +00:00
|
|
|
)
|
2017-06-17 16:11:10 +00:00
|
|
|
err := db.QueryRow(`SELECT
|
2016-08-27 10:04:12 +00:00
|
|
|
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`,
|
2016-06-14 10:01:30 +00:00
|
|
|
fmt.Sprintf("%x", md5.Sum([]byte(token)))).
|
|
|
|
Scan(
|
2016-08-27 10:04:12 +00:00
|
|
|
&t.ID, &t.UserID, &tokenPrivsRaw, &priv8, &userPrivsRaw,
|
2016-06-14 10:01:30 +00:00
|
|
|
)
|
2016-12-01 22:16:36 +00:00
|
|
|
updateTokens <- t.ID
|
2016-05-15 05:20:11 +00:00
|
|
|
if priv8 {
|
2016-12-12 20:35:18 +00:00
|
|
|
// all privileges, they'll get removed by canOnly anyway.
|
|
|
|
tokenPrivsRaw = (common.PrivilegeBeatmap << 1) - 1
|
2016-05-15 05:20:11 +00:00
|
|
|
}
|
2016-08-27 10:04:12 +00:00
|
|
|
t.UserPrivileges = common.UserPrivileges(userPrivsRaw)
|
2016-12-12 20:35:18 +00:00
|
|
|
t.TokenPrivileges = common.Privileges(tokenPrivsRaw).CanOnly(t.UserPrivileges)
|
2016-04-03 17:59:27 +00:00
|
|
|
switch {
|
|
|
|
case err == sql.ErrNoRows:
|
|
|
|
return common.Token{}, false
|
|
|
|
case err != nil:
|
|
|
|
panic(err)
|
|
|
|
default:
|
2016-06-14 10:01:30 +00:00
|
|
|
t.Value = token
|
|
|
|
return t, true
|
2016-04-03 17:59:27 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-01 22:16:36 +00:00
|
|
|
|
|
|
|
var updateTokens = make(chan int, 100)
|
|
|
|
|
|
|
|
func tokenUpdater(db *sqlx.DB) {
|
|
|
|
for {
|
|
|
|
// prepare a queue of tokens to update.
|
|
|
|
tokensToUpdate := make([]int, 0, 50)
|
|
|
|
AwaitLoop:
|
|
|
|
for {
|
|
|
|
// if we got ten, move on and update
|
|
|
|
if len(tokensToUpdate) >= 50 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// if we ain't got any, add what we get straight from updateTokens
|
|
|
|
if len(tokensToUpdate) == 0 {
|
|
|
|
x := <-updateTokens
|
|
|
|
tokensToUpdate = append(tokensToUpdate, x)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, wait from updateTokens with a timeout of 10 seconds
|
|
|
|
select {
|
|
|
|
case x := <-updateTokens:
|
|
|
|
tokensToUpdate = append(tokensToUpdate, x)
|
|
|
|
case <-time.After(10 * time.Second):
|
|
|
|
// wondering what this means?
|
|
|
|
// https://golang.org/ref/spec#Break_statements
|
|
|
|
break AwaitLoop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
q, a, _ := sqlx.In("UPDATE tokens SET last_updated = ? WHERE id IN (?)", time.Now().Unix(), tokensToUpdate)
|
|
|
|
|
|
|
|
q = db.Rebind(q)
|
|
|
|
_, err := db.Exec(q, a...)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-17 16:11:10 +00:00
|
|
|
|
2017-07-25 12:49:14 +00:00
|
|
|
// BearerToken parses a Token given in the Authorization header, with the
|
2017-06-17 16:11:10 +00:00
|
|
|
// Bearer prefix.
|
|
|
|
func BearerToken(token string, db *sqlx.DB) (common.Token, bool) {
|
|
|
|
var x struct {
|
|
|
|
Scope string
|
|
|
|
Extra int
|
|
|
|
}
|
|
|
|
db.Get(&x, "SELECT scope, extra FROM osin_access WHERE access_token = ? LIMIT 1", fmt.Sprintf("%x", sha256.Sum256([]byte(token))))
|
|
|
|
if x.Extra == 0 {
|
|
|
|
return common.Token{}, false
|
|
|
|
}
|
|
|
|
|
|
|
|
var privs uint64
|
|
|
|
db.Get(&privs, "SELECT privileges FROM users WHERE id = ? LIMIT 1", x.Extra)
|
|
|
|
|
|
|
|
var t common.Token
|
|
|
|
t.ID = -1
|
|
|
|
t.UserID = x.Extra
|
|
|
|
t.Value = token
|
|
|
|
t.UserPrivileges = common.UserPrivileges(privs)
|
2017-07-25 12:49:14 +00:00
|
|
|
t.TokenPrivileges = common.OAuthPrivileges(x.Scope).CanOnly(t.UserPrivileges)
|
2017-06-17 16:11:10 +00:00
|
|
|
|
|
|
|
return t, true
|
|
|
|
}
|