owncast/controllers/admin/emoji.go
Philipp dc54dfe363
Feature: emoji editor (#2411)
* Custom emoji editor: implement backend

This reuses the logo upload code

* Implement emoji edit admin interface

Again reuse base64 logic from the logo upload

* Allow toggling between uploaded and default emojis

* Add route that always serves uploaded emojis

This is needed for the admin emoji interface,
as otherwise the emojis will 404 if custom emojis are disabled

* Fix linter warnings

* Remove custom/uploaded emoji logic

* Reset timer after emoji deletion

* Setup: copy built-in emojis to emoji directory
2022-12-12 08:40:43 -08:00

93 lines
2.2 KiB
Go

package admin
import (
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/controllers"
"github.com/owncast/owncast/utils"
)
// UploadCustomEmoji allows POSTing a new custom emoji to the server.
func UploadCustomEmoji(w http.ResponseWriter, r *http.Request) {
if !requirePOST(w, r) {
return
}
type postEmoji struct {
Name string `json:"name"`
Data string `json:"data"`
}
emoji := new(postEmoji)
if err := json.NewDecoder(r.Body).Decode(emoji); err != nil {
controllers.WriteSimpleResponse(w, false, err.Error())
return
}
bytes, _, err := utils.DecodeBase64Image(emoji.Data)
if err != nil {
controllers.WriteSimpleResponse(w, false, err.Error())
return
}
// Prevent path traversal attacks
var emojiFileName = filepath.Base(emoji.Name)
var targetPath = filepath.Join(config.CustomEmojiPath, emojiFileName)
err = os.MkdirAll(config.CustomEmojiPath, 0700)
if err != nil {
controllers.WriteSimpleResponse(w, false, err.Error())
return
}
if utils.DoesFileExists(targetPath) {
controllers.WriteSimpleResponse(w, false, fmt.Sprintf("An emoji with the name %q already exists", emojiFileName))
return
}
if err = os.WriteFile(targetPath, bytes, 0o600); err != nil {
controllers.WriteSimpleResponse(w, false, err.Error())
return
}
controllers.WriteSimpleResponse(w, true, fmt.Sprintf("Emoji %q has been uploaded", emojiFileName))
}
// DeleteCustomEmoji deletes a custom emoji.
func DeleteCustomEmoji(w http.ResponseWriter, r *http.Request) {
if !requirePOST(w, r) {
return
}
type deleteEmoji struct {
Name string `json:"name"`
}
emoji := new(deleteEmoji)
if err := json.NewDecoder(r.Body).Decode(emoji); err != nil {
controllers.WriteSimpleResponse(w, false, err.Error())
return
}
var emojiFileName = filepath.Base(emoji.Name)
var targetPath = filepath.Join(config.CustomEmojiPath, emojiFileName)
if err := os.Remove(targetPath); err != nil {
if os.IsNotExist(err) {
controllers.WriteSimpleResponse(w, false, fmt.Sprintf("Emoji %q doesn't exist", emojiFileName))
} else {
controllers.WriteSimpleResponse(w, false, err.Error())
}
return
}
controllers.WriteSimpleResponse(w, true, fmt.Sprintf("Emoji %q has been deleted", emojiFileName))
}