-
-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
50 changed files
with
2,756 additions
and
2,375 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,4 +9,5 @@ web/dist/ | |
__debug_bin | ||
deploy/ | ||
data/ | ||
.vscode/.ropeproject | ||
.vscode/.ropeproject | ||
cmd/test/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,41 @@ | ||
1.2.1 | ||
1.3.0 | ||
|
||
> MINOR PATCH | ||
> MAJOR PATCH | ||
## Minor Improvements | ||
## Major Implementations | ||
|
||
- Discord assets in web interface are now requested with a proper resolution. [#163] | ||
- Report revoke link in web interface is now only shown if the user has the permission to do so. | ||
**Karma System Settings** [#146] | ||
|
||
The Karma System is now configurable via the web interface. If you have the permission `sp.guild.config.karma`, you will see this entry in the guild settings of the web interface: | ||
![](https://i.imgur.com/HiaUhJO.png) | ||
There, you can enter the advanced guild settings interface where you can define preferences like enable or disable the karma system, emojis used to increase or decrease karma or the ammount of tokens available per hour per user. | ||
![](https://i.imgur.com/CC7AgCV.png) | ||
|
||
**Channel Locking** [#165] | ||
|
||
Added the [`lock`](https://github.com/zekroTJA/shinpuru/wiki/Commands#lock) command to write-lock text channels. By either typing `sp!lock` into the channel which shall be locked or remotely by passing a channel resolvable (i.e. `sp!lock general`), you can write-lock channels. That means, that all roles in this channel (*below the role of the executor*) are explicitly disallowed to write messages in this channel. When hitting the same command again onto this channel, the permission state before the first execution of the `lock` command are restored. | ||
![](https://i.imgur.com/wLJMDmP.gif) | ||
|
||
## Security | ||
|
||
Because shinpuru is using cookies containing a singed JWT with session information to authenticate requests against the HTTP REST API, it was vulnerable to [XSRF (Cross-site request forgery) attacks](https://en.wikipedia.org/wiki/Cross-site_request_forgery). This is now fixed by generating session-bound anti-forgery tokens, which are set using the `XSRF-TOKEN` cookie, which is readable by JavaScript. Angular then reads the cookie and sets it as `X-XSRF-TOKEN` header for each following `POST`, `PUT` or `DELETE` request. API-Token based authentications do not need to send the `X-XSRF-TOKEN`, be cause they are already authenticated using headers. | ||
|
||
## Bug Fixes | ||
|
||
- Fix permission update handling when adding the same permission rule as existent. [#161] | ||
- Fix dropdown style in web interface ([old](https://i.imgur.com/m5uQZdq.png) vs [new](https://i.imgur.com/PWet0kD.png)). | ||
- Fix color reaction spam on message edit. [#162] | ||
- Permission rules bound to `@everyone` are now correctly processed. | ||
- Also non-command specific permission rules are now correctly listed by the `GET /api/guilds/:guildID/:userID/permissions/allowed` endpoint. | ||
|
||
## Backstage | ||
|
||
- Moved the [permissions](https://github.com/zekroTJA/shinpuru/tree/master/pkg/permissions) and the [twitchnotify](https://github.com/zekroTJA/shinpuru/tree/master/pkg/twitchnotify) packages to the `pkg` public package domain. | ||
- Refactored the [SQLite3 database middleware](https://github.com/zekroTJA/shinpuru/blob/master/internal/core/middleware/sqlite.go) so that it inherits all bindings from the MySQL middleware which redured it from 952 to only 161 lines of code. | ||
- API handlers are now split up in seperate files for better overview. | ||
- The `GetMemberPermissions` function is now moved from the database middlewares to the permission middleware. | ||
|
||
# Docker | ||
|
||
[Here](https://hub.docker.com/r/zekro/shinpuru) you can find the docker hub page of shinpuru. | ||
|
||
Pull the docker image of this release: | ||
``` | ||
$ docker pull zekro/shinpuru:1.2.1 | ||
$ docker pull zekro/shinpuru:1.3.0 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## Additional API Permission Rules | ||
|
||
- `sp.guild.config.karma` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
package commands | ||
|
||
import ( | ||
"bytes" | ||
"encoding/base64" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"sort" | ||
|
||
"github.com/bwmarrin/discordgo" | ||
"github.com/zekroTJA/shinpuru/internal/core/database" | ||
"github.com/zekroTJA/shinpuru/internal/util" | ||
"github.com/zekroTJA/shinpuru/internal/util/static" | ||
"github.com/zekroTJA/shinpuru/pkg/fetch" | ||
"github.com/zekroTJA/shireikan" | ||
) | ||
|
||
const allowMask = discordgo.PermissionAll - discordgo.PermissionSendMessages | ||
|
||
type CmdLock struct { | ||
} | ||
|
||
func (c *CmdLock) GetInvokes() []string { | ||
return []string{"lock", "unlock", "lockchan", "unlockchan", "readonly", "ro", "chatlock"} | ||
} | ||
|
||
func (c *CmdLock) GetDescription() string { | ||
return "Locks the channel so that no one can write there anymore until unlocked." | ||
} | ||
|
||
func (c *CmdLock) GetHelp() string { | ||
return "`lock (<channelResolvable>)` - locks or unlocks either the current or the passed channel\n" | ||
} | ||
|
||
func (c *CmdLock) GetGroup() string { | ||
return shireikan.GroupModeration | ||
} | ||
|
||
func (c *CmdLock) GetDomainName() string { | ||
return "sp.guild.mod.lock" | ||
} | ||
|
||
func (c *CmdLock) GetSubPermissionRules() []shireikan.SubPermission { | ||
return nil | ||
} | ||
|
||
func (c *CmdLock) IsExecutableInDMChannels() bool { | ||
return false | ||
} | ||
|
||
func (c *CmdLock) Exec(ctx shireikan.Context) error { | ||
db, _ := ctx.GetObject("db").(database.Database) | ||
|
||
target, err := c.getTargetChan(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, executorID, encodedPerms, err := db.GetLockChan(target.ID) | ||
|
||
if database.IsErrDatabaseNotFound(err) { | ||
return c.lock(target, ctx, db) | ||
} else if err == nil { | ||
return c.unlock(target, ctx, db, executorID, encodedPerms) | ||
} | ||
|
||
return err | ||
} | ||
|
||
func (c *CmdLock) getTargetChan(ctx shireikan.Context) (ch *discordgo.Channel, err error) { | ||
res := ctx.GetArgs().Get(0).AsString() | ||
|
||
if res == "" { | ||
ch = ctx.GetChannel() | ||
return | ||
} | ||
|
||
ch, err = fetch.FetchChannel(ctx.GetSession(), ctx.GetGuild().ID, res, func(cc *discordgo.Channel) bool { | ||
return cc.Type == discordgo.ChannelTypeGuildText | ||
}) | ||
if err != nil { | ||
return | ||
} | ||
if ch == nil { | ||
err = errors.New("could not fetch any text channel using this resolvable") | ||
} | ||
|
||
return | ||
} | ||
|
||
func (c *CmdLock) lock(target *discordgo.Channel, ctx shireikan.Context, db database.Database) error { | ||
encodedPerms, err := c.encodePermissionOverrides(target.PermissionOverwrites) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
guildRoles := ctx.GetGuild().Roles | ||
sort.Slice(guildRoles, func(i, j int) bool { | ||
return guildRoles[i].Position < guildRoles[j].Position | ||
}) | ||
|
||
memberRoles := ctx.GetMember().Roles | ||
|
||
highest := 0 | ||
rolesMap := make(map[string]*discordgo.Role) | ||
for _, r := range guildRoles { | ||
rolesMap[r.ID] = r | ||
for _, mr := range memberRoles { | ||
if r.ID != mr { | ||
continue | ||
} | ||
if r.Position > highest { | ||
highest = r.Position | ||
} | ||
} | ||
} | ||
|
||
// The info message needs to be sent before all permissions are set | ||
// to prevent occuring errors due to potential missing permissions. | ||
err = util.SendEmbed(ctx.GetSession(), target.ID, | ||
fmt.Sprintf("This channel is chat-locked by %s.\nYou may not be able to chat "+ | ||
"into this channel until the channel is unlocked again.", ctx.GetUser().Mention()), | ||
"", static.ColorEmbedOrange). | ||
Error() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
hasSetEveryone := false | ||
for _, po := range target.PermissionOverwrites { | ||
if po.Type == "role" { | ||
if r, ok := rolesMap[po.ID]; ok && r.Position < highest { | ||
if err = ctx.GetSession().ChannelPermissionSet( | ||
target.ID, po.ID, "role", po.Allow&allowMask, po.Deny|discordgo.PermissionSendMessages); err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
if po.Type == "member" && ctx.GetUser().ID != po.ID && ctx.GetSession().State.User.ID != po.ID { | ||
if err = ctx.GetSession().ChannelPermissionSet( | ||
target.ID, po.ID, "member", po.Allow&allowMask, po.Deny|discordgo.PermissionSendMessages); err != nil { | ||
return err | ||
} | ||
if po.ID == target.GuildID { | ||
hasSetEveryone = true | ||
} | ||
} | ||
} | ||
|
||
if err = ctx.GetSession().ChannelPermissionSet( | ||
target.ID, ctx.GetSession().State.User.ID, "member", discordgo.PermissionSendMessages&discordgo.PermissionReadMessages, 0); err != nil { | ||
return err | ||
} | ||
|
||
if !hasSetEveryone { | ||
if err = ctx.GetSession().ChannelPermissionSet( | ||
target.ID, target.GuildID, "role", 0, discordgo.PermissionSendMessages); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
if err = db.SetLockChan(target.ID, target.GuildID, ctx.GetUser().ID, encodedPerms); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *CmdLock) unlock(target *discordgo.Channel, ctx shireikan.Context, db database.Database, executorID, encodedPerms string) error { | ||
permissionOverrides, err := c.decodePermissionOverrrides(encodedPerms) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
failed := 0 | ||
for _, po := range permissionOverrides { | ||
if err = ctx.GetSession().ChannelPermissionSet(target.ID, po.ID, po.Type, po.Allow, po.Deny); err != nil { | ||
failed++ | ||
} | ||
} | ||
|
||
if err = db.DeleteLockChan(target.ID); err != nil { | ||
return err | ||
} | ||
|
||
if failed > 0 { | ||
return util.SendEmbed(ctx.GetSession(), target.ID, | ||
fmt.Sprintf("This channel is now unlocked. You can now chat here again.\n*(Unlocked by %s)*\n\n"+ | ||
"**Attention:** %d permission actions failed on reset!", ctx.GetUser().Mention(), failed), | ||
"", static.ColorEmbedOrange). | ||
Error() | ||
} | ||
|
||
return util.SendEmbed(ctx.GetSession(), target.ID, | ||
fmt.Sprintf("This channel is now unlocked. You can now chat here again.\n*(Unlocked by %s)*", ctx.GetUser().Mention()), | ||
"", static.ColorEmbedGreen). | ||
Error() | ||
} | ||
|
||
func (c *CmdLock) encodePermissionOverrides(po []*discordgo.PermissionOverwrite) (res string, err error) { | ||
buff := bytes.NewBuffer([]byte{}) | ||
|
||
if err = json.NewEncoder(buff).Encode(po); err != nil { | ||
return | ||
} | ||
|
||
res = base64.StdEncoding.EncodeToString(buff.Bytes()) | ||
|
||
return | ||
} | ||
|
||
func (c *CmdLock) decodePermissionOverrrides(data string) (po []*discordgo.PermissionOverwrite, err error) { | ||
po = make([]*discordgo.PermissionOverwrite, 0) | ||
|
||
dataBytes, err := base64.StdEncoding.DecodeString(data) | ||
if err != nil { | ||
return | ||
} | ||
|
||
err = json.NewDecoder(bytes.NewBuffer(dataBytes)).Decode(&po) | ||
|
||
return | ||
} |
Oops, something went wrong.