whitelabel token page
This commit is contained in:
parent
951f588ea2
commit
396cb4ae47
@ -3,9 +3,11 @@ package api
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||
"github.com/TicketsBot/GoPanel/rpc/ratelimit"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/TicketsBot/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rxdn/gdl/objects/channel"
|
||||
@ -32,10 +34,10 @@ func CreatePanel(ctx *gin.Context) {
|
||||
data.MessageId = 0
|
||||
|
||||
// Check panel quota
|
||||
premiumChan := make(chan bool)
|
||||
go utils.IsPremiumGuild(guildId, premiumChan)
|
||||
isPremium := <-premiumChan
|
||||
if !isPremium {
|
||||
// TODO: Whitelabel tokens & ratelimiters
|
||||
premiumTier := rpc.PremiumClient.GetTierByGuildId(guildId, true, config.Conf.Bot.Token, ratelimit.Ratelimiter)
|
||||
|
||||
if premiumTier == premium.None {
|
||||
panels, err := dbclient.Client.Panel.GetByGuild(guildId)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
@ -57,7 +59,7 @@ func CreatePanel(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
msgId, err := data.sendEmbed(isPremium)
|
||||
msgId, err := data.sendEmbed(premiumTier > premium.None)
|
||||
if err != nil {
|
||||
if err == request.ErrForbidden {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
|
@ -1,17 +1,20 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
"github.com/TicketsBot/GoPanel/rpc/ratelimit"
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func PremiumHandler(ctx *gin.Context) {
|
||||
guildId := ctx.Keys["guildid"].(uint64)
|
||||
|
||||
isPremium := make(chan bool)
|
||||
go utils.IsPremiumGuild(guildId, isPremium)
|
||||
// TODO: Whitelabel tokens & ratelimiters
|
||||
premiumTier := rpc.PremiumClient.GetTierByGuildId(guildId, true, config.Conf.Bot.Token, ratelimit.Ratelimiter)
|
||||
|
||||
ctx.JSON(200, gin.H{
|
||||
"premium": <-isPremium,
|
||||
"premium": premiumTier >= premium.Premium,
|
||||
})
|
||||
}
|
||||
|
@ -4,9 +4,10 @@ import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||
"github.com/TicketsBot/GoPanel/rpc/ratelimit"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rxdn/gdl/rest"
|
||||
"github.com/rxdn/gdl/rest/request"
|
||||
@ -41,9 +42,9 @@ func SendMessage(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
// Verify guild is premium
|
||||
isPremium := make(chan bool)
|
||||
go utils.IsPremiumGuild(guildId, isPremium)
|
||||
if !<-isPremium {
|
||||
// TODO: Whitelabel tokens & ratelimiters
|
||||
premiumTier := rpc.PremiumClient.GetTierByGuildId(guildId, true, config.Conf.Bot.Token, ratelimit.Ratelimiter)
|
||||
if premiumTier == premium.None {
|
||||
ctx.AbortWithStatusJSON(402, gin.H{
|
||||
"success": false,
|
||||
"error": "Guild is not premium",
|
||||
|
112
app/http/endpoints/api/whitelabel.go
Normal file
112
app/http/endpoints/api/whitelabel.go
Normal file
@ -0,0 +1,112 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/messagequeue"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/TicketsBot/common/tokenchange"
|
||||
"github.com/TicketsBot/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rxdn/gdl/rest"
|
||||
)
|
||||
|
||||
func WhitelabelHandler(ctx *gin.Context) {
|
||||
userId := ctx.Keys["userid"].(uint64)
|
||||
|
||||
premiumTier := rpc.PremiumClient.GetTierByUser(userId, false)
|
||||
if premiumTier < premium.Whitelabel {
|
||||
ctx.JSON(402, gin.H{
|
||||
"success": false,
|
||||
"error": "You must have the whitelabel premium tier",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Get token
|
||||
var data map[string]interface{}
|
||||
if err := ctx.BindJSON(&data); err != nil {
|
||||
ctx.JSON(400, gin.H{
|
||||
"success": false,
|
||||
"error": "Missing token",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
token, ok := data["token"].(string)
|
||||
if !ok {
|
||||
ctx.JSON(400, gin.H{
|
||||
"success": false,
|
||||
"error": "Missing token",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Validate token + get bot ID
|
||||
bot, err := rest.GetCurrentUser(token, nil)
|
||||
if err != nil {
|
||||
ctx.JSON(400, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if !bot.Bot {
|
||||
ctx.JSON(400, gin.H{
|
||||
"success": false,
|
||||
"error": "Token is not of a bot user",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if this is a different token
|
||||
existing, err := dbclient.Client.Whitelabel.GetByUserId(userId)
|
||||
if err != nil {
|
||||
ctx.JSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if existing.Token == token {
|
||||
// Respond with 200 to prevent information disclosure attack
|
||||
ctx.JSON(200, gin.H{
|
||||
"success": true,
|
||||
"bot": bot,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err = dbclient.Client.Whitelabel.Set(database.WhitelabelBot{
|
||||
UserId: userId,
|
||||
BotId: bot.Id,
|
||||
Token: token,
|
||||
}); err != nil {
|
||||
ctx.JSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
tokenChangeData := tokenchange.TokenChangeData{
|
||||
Token: token,
|
||||
NewId: bot.Id,
|
||||
OldId: existing.BotId,
|
||||
}
|
||||
|
||||
if err := tokenchange.PublishTokenChange(messagequeue.Client.Client, tokenChangeData); err != nil {
|
||||
ctx.JSON(500, gin.H{
|
||||
"success": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(200, gin.H{
|
||||
"success": true,
|
||||
"bot": bot,
|
||||
})
|
||||
}
|
@ -2,8 +2,12 @@ package manage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||
"github.com/TicketsBot/GoPanel/rpc/ratelimit"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
@ -122,9 +126,9 @@ func WebChatWs(ctx *gin.Context) {
|
||||
}
|
||||
|
||||
// Verify the guild is premium
|
||||
premium := make(chan bool)
|
||||
go utils.IsPremiumGuild(guildIdParsed, premium)
|
||||
if !<-premium {
|
||||
// TODO: Whitelabel tokens & ratelimiters
|
||||
premiumTier := rpc.PremiumClient.GetTierByGuildId(guildIdParsed, true, config.Conf.Bot.Token, ratelimit.Ratelimiter)
|
||||
if premiumTier == premium.None {
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
32
app/http/endpoints/root/whitelabel.go
Normal file
32
app/http/endpoints/root/whitelabel.go
Normal file
@ -0,0 +1,32 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func WhitelabelHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
userId := store.Get("userid").(uint64)
|
||||
|
||||
premiumTier := rpc.PremiumClient.GetTierByUser(userId, false)
|
||||
if premiumTier < premium.Whitelabel {
|
||||
ctx.Redirect(302, fmt.Sprintf("%s/premium", config.Conf.Server.MainSite))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.HTML(200, "main/whitelabel", gin.H{
|
||||
"name": store.Get("name").(string),
|
||||
"baseurl": config.Conf.Server.BaseUrl,
|
||||
"avatar": store.Get("avatar").(string),
|
||||
})
|
||||
}
|
@ -56,6 +56,7 @@ func StartServer() {
|
||||
authenticateGuild := authorized.Group("/", middleware.AuthenticateGuild(false))
|
||||
|
||||
authorized.GET("/", root.IndexHandler)
|
||||
authorized.GET("/whitelabel", root.WhitelabelHandler)
|
||||
authorized.GET("/logout", root.LogoutHandler)
|
||||
|
||||
authenticateGuild.GET("/manage/:id/settings", manage.SettingsHandler)
|
||||
@ -108,6 +109,7 @@ func StartServer() {
|
||||
userGroup := router.Group("/user", middleware.AuthenticateToken)
|
||||
{
|
||||
userGroup.GET("/guilds", api.GetGuilds)
|
||||
userGroup.POST("/whitelabel", api.WhitelabelHandler)
|
||||
}
|
||||
|
||||
if err := router.Run(config.Conf.Server.Host); err != nil {
|
||||
@ -119,6 +121,7 @@ func createRenderer() multitemplate.Renderer {
|
||||
r := multitemplate.NewRenderer()
|
||||
|
||||
r = addMainTemplate(r, "index")
|
||||
r = addMainTemplate(r, "whitelabel")
|
||||
|
||||
r = addManageTemplate(r, "blacklist")
|
||||
r = addManageTemplate(r, "logs")
|
||||
|
@ -9,10 +9,12 @@ import (
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/messagequeue"
|
||||
"github.com/TicketsBot/GoPanel/rpc"
|
||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||
"github.com/TicketsBot/GoPanel/rpc/ratelimit"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/archiverclient"
|
||||
"github.com/TicketsBot/common/premium"
|
||||
"github.com/apex/log"
|
||||
gdlratelimit "github.com/rxdn/gdl/rest/ratelimit"
|
||||
"math/rand"
|
||||
@ -40,6 +42,13 @@ func main() {
|
||||
messagequeue.Client = messagequeue.NewRedisClient()
|
||||
go Listen(messagequeue.Client)
|
||||
|
||||
rpc.PremiumClient = premium.NewPremiumLookupClient(
|
||||
premium.NewPatreonClient(config.Conf.Bot.PremiumLookupProxyUrl, config.Conf.Bot.PremiumLookupProxyKey),
|
||||
messagequeue.Client.Client,
|
||||
cache.Instance.PgCache,
|
||||
database.Client,
|
||||
)
|
||||
|
||||
ratelimit.Ratelimiter = gdlratelimit.NewRateLimiter(gdlratelimit.NewRedisStore(messagequeue.Client.Client, "ratelimit"), 1) // TODO: Use values from config
|
||||
|
||||
http.StartServer()
|
||||
|
8
go.mod
8
go.mod
@ -5,7 +5,8 @@ go 1.14
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/TicketsBot/archiverclient v0.0.0-20200425115930-0ca198cc8306
|
||||
github.com/TicketsBot/database v0.0.0-20200516170158-fd8a949aec2c
|
||||
github.com/TicketsBot/common v0.0.0-20200526165242-b17694befe05
|
||||
github.com/TicketsBot/database v0.0.0-20200526163954-2cb21ac72d23
|
||||
github.com/apex/log v1.1.2
|
||||
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
@ -13,15 +14,14 @@ require (
|
||||
github.com/gin-contrib/static v0.0.0-20191128031702-f81c604d8ac2
|
||||
github.com/gin-gonic/contrib v0.0.0-20191209060500-d6e26eeaa607
|
||||
github.com/gin-gonic/gin v1.6.2
|
||||
github.com/go-redis/redis v6.15.7+incompatible
|
||||
github.com/go-redis/redis v6.15.8+incompatible
|
||||
github.com/gofrs/uuid v3.3.0+incompatible
|
||||
github.com/gorilla/sessions v1.2.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/jackc/pgx/v4 v4.6.0
|
||||
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62
|
||||
github.com/rxdn/gdl v0.0.0-20200511170555-8ab2206d70df
|
||||
github.com/rxdn/gdl v0.0.0-20200522202912-4ae241eb98c1
|
||||
github.com/sirupsen/logrus v1.5.0
|
||||
github.com/ulule/limiter/v3 v3.5.0
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||
|
@ -8,6 +8,12 @@
|
||||
<p>Servers</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item sidebar-bottom" style="top: 60px">
|
||||
<a href="/whitelabel">
|
||||
<i class="fas fa-robot"></i>
|
||||
<p>Whitelabel</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item sidebar-bottom" style="bottom: 60px">
|
||||
<a href="/logout">
|
||||
|
66
public/templates/views/whitelabel.tmpl
Normal file
66
public/templates/views/whitelabel.tmpl
Normal file
@ -0,0 +1,66 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Whitelabel</h4>
|
||||
</div>
|
||||
<div class="card-body" id="card">
|
||||
<form onsubmit="updateSettings(); return false;">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label>Bot Token</label>
|
||||
<input name="token" type="text" class="form-control"
|
||||
placeholder="9ViiGeUZlFJKIfSzodnzZT6W.bX8IAh.p9gG0tElMXg1EqwAChqaYz3swFY" id="token">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12 ">
|
||||
<p class="white">Note: You will not be able to view the token after submitting it</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-2 pr-1">
|
||||
<div class="form-group">
|
||||
<button class="btn btn-primary btn-fill" type="submit"><i class="fas fa-paper-plane"></i>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative">
|
||||
<div style="position: absolute; right: 10px" id="toast-container">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function updateSettings() {
|
||||
const token = document.getElementById('token').value;
|
||||
const data = {
|
||||
token: token
|
||||
};
|
||||
|
||||
const res = await axios.post('/user/whitelabel', data);
|
||||
if (res.status !== 200 || !res.data.success) {
|
||||
showToast('Error', res.data.error);
|
||||
return;
|
||||
}
|
||||
|
||||
showToast('Success', `Started tickets whitelabel on ${res.data.bot.username}#${res.data.bot.discriminator}`);
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
5
rpc/premiumclient.go
Normal file
5
rpc/premiumclient.go
Normal file
@ -0,0 +1,5 @@
|
||||
package rpc
|
||||
|
||||
import "github.com/TicketsBot/common/premium"
|
||||
|
||||
var PremiumClient *premium.PremiumLookupClient
|
@ -1,93 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||
"github.com/TicketsBot/GoPanel/rpc/ratelimit"
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
gocache "github.com/robfig/go-cache"
|
||||
"github.com/rxdn/gdl/rest"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ProxyResponse struct {
|
||||
Premium bool
|
||||
Tier int
|
||||
}
|
||||
|
||||
// TODO: Use Redis cache
|
||||
var premiumCache = gocache.New(10 * time.Minute, 10 * time.Minute)
|
||||
|
||||
func IsPremiumGuild(guildId uint64, ch chan bool) {
|
||||
guildIdRaw := strconv.FormatUint(guildId, 10)
|
||||
|
||||
if premium, ok := premiumCache.Get(guildIdRaw); ok {
|
||||
ch<-premium.(bool)
|
||||
return
|
||||
}
|
||||
|
||||
// First lookup by premium key, then votes, then patreon
|
||||
// TODO: Lookup Patreon first
|
||||
// TODO: Handle error
|
||||
hasPremiumKey, _ := database.Client.PremiumGuilds.IsPremium(guildId)
|
||||
|
||||
if hasPremiumKey {
|
||||
if err := premiumCache.Add(guildIdRaw, true, 10 * time.Minute); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
ch<-true
|
||||
} else {
|
||||
// Get guild object
|
||||
guild, found := cache.Instance.GetGuild(guildId, false)
|
||||
|
||||
if !found {
|
||||
var err error
|
||||
guild, err = rest.GetGuild(config.Conf.Bot.Token, ratelimit.Ratelimiter, guildId)
|
||||
|
||||
if err == nil { // cache
|
||||
go cache.Instance.StoreGuild(guild)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Find a way to stop people using votes to exploit panels
|
||||
|
||||
// Lookup Patreon
|
||||
client := &http.Client{
|
||||
Timeout: time.Second * 3,
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/ispremium?key=%s&id=%d", config.Conf.Bot.PremiumLookupProxyUrl, config.Conf.Bot.PremiumLookupProxyKey, guild.OwnerId)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
|
||||
res, err := client.Do(req); if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
ch<-false
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(res.Body); if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
ch<-false
|
||||
return
|
||||
}
|
||||
|
||||
var proxyResponse ProxyResponse
|
||||
if err = json.Unmarshal(content, &proxyResponse); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
ch<-false
|
||||
return
|
||||
}
|
||||
|
||||
if err := premiumCache.Add(guildIdRaw, proxyResponse.Premium, 10 * time.Minute); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
ch <-proxyResponse.Premium
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user