Handle subdirectories of emoji in copying, fetching and deleting. For #1916
This commit is contained in:
parent
71be5e4b41
commit
0ebb968074
@ -37,10 +37,10 @@ func UploadCustomEmoji(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prevent path traversal attacks
|
// Prevent path traversal attacks
|
||||||
var emojiFileName = filepath.Base(emoji.Name)
|
emojiFileName := filepath.Base(emoji.Name)
|
||||||
var targetPath = filepath.Join(config.CustomEmojiPath, emojiFileName)
|
targetPath := filepath.Join(config.CustomEmojiPath, emojiFileName)
|
||||||
|
|
||||||
err = os.MkdirAll(config.CustomEmojiPath, 0700)
|
err = os.MkdirAll(config.CustomEmojiPath, 0o700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
controllers.WriteSimpleResponse(w, false, err.Error())
|
controllers.WriteSimpleResponse(w, false, err.Error())
|
||||||
return
|
return
|
||||||
@ -76,17 +76,17 @@ func DeleteCustomEmoji(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var emojiFileName = filepath.Base(emoji.Name)
|
// var emojiFileName = filepath.Base(emoji.Name)
|
||||||
var targetPath = filepath.Join(config.CustomEmojiPath, emojiFileName)
|
targetPath := filepath.Join(config.CustomEmojiPath, emoji.Name)
|
||||||
|
|
||||||
if err := os.Remove(targetPath); err != nil {
|
if err := os.Remove(targetPath); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
controllers.WriteSimpleResponse(w, false, fmt.Sprintf("Emoji %q doesn't exist", emojiFileName))
|
controllers.WriteSimpleResponse(w, false, fmt.Sprintf("Emoji %q doesn't exist", emoji.Name))
|
||||||
} else {
|
} else {
|
||||||
controllers.WriteSimpleResponse(w, false, err.Error())
|
controllers.WriteSimpleResponse(w, false, err.Error())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
controllers.WriteSimpleResponse(w, true, fmt.Sprintf("Emoji %q has been deleted", emojiFileName))
|
controllers.WriteSimpleResponse(w, true, fmt.Sprintf("Emoji %q has been deleted", emoji.Name))
|
||||||
}
|
}
|
||||||
|
@ -11,25 +11,30 @@ import (
|
|||||||
"github.com/owncast/owncast/models"
|
"github.com/owncast/owncast/models"
|
||||||
"github.com/owncast/owncast/static"
|
"github.com/owncast/owncast/static"
|
||||||
"github.com/owncast/owncast/utils"
|
"github.com/owncast/owncast/utils"
|
||||||
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetEmojiList returns a list of custom emoji from the emoji directory.
|
// GetEmojiList returns a list of custom emoji from the emoji directory.
|
||||||
func GetEmojiList() []models.CustomEmoji {
|
func GetEmojiList() []models.CustomEmoji {
|
||||||
var emojiFS = os.DirFS(config.CustomEmojiPath)
|
emojiFS := os.DirFS(config.CustomEmojiPath)
|
||||||
|
|
||||||
emojiResponse := make([]models.CustomEmoji, 0)
|
emojiResponse := make([]models.CustomEmoji, 0)
|
||||||
|
|
||||||
files, err := fs.Glob(emojiFS, "*")
|
walkFunction := func(path string, d os.DirEntry, err error) error {
|
||||||
if err != nil {
|
if d.IsDir() {
|
||||||
log.Errorln(err)
|
return nil
|
||||||
return emojiResponse
|
}
|
||||||
|
|
||||||
|
emojiPath := filepath.Join(config.EmojiDir, path)
|
||||||
|
singleEmoji := models.CustomEmoji{Name: d.Name(), URL: emojiPath}
|
||||||
|
emojiResponse = append(emojiResponse, singleEmoji)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range files {
|
if err := fs.WalkDir(emojiFS, ".", walkFunction); err != nil {
|
||||||
emojiPath := filepath.Join(config.EmojiDir, name)
|
log.Errorln("unable to fetch emojis: " + err.Error())
|
||||||
singleEmoji := models.CustomEmoji{Name: name, URL: emojiPath}
|
return emojiResponse
|
||||||
emojiResponse = append(emojiResponse, singleEmoji)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return emojiResponse
|
return emojiResponse
|
||||||
@ -38,6 +43,11 @@ func GetEmojiList() []models.CustomEmoji {
|
|||||||
// SetupEmojiDirectory sets up the custom emoji directory by copying all built-in
|
// SetupEmojiDirectory sets up the custom emoji directory by copying all built-in
|
||||||
// emojis if the directory does not yet exist.
|
// emojis if the directory does not yet exist.
|
||||||
func SetupEmojiDirectory() (err error) {
|
func SetupEmojiDirectory() (err error) {
|
||||||
|
type emojiDirectory struct {
|
||||||
|
path string
|
||||||
|
isDir bool
|
||||||
|
}
|
||||||
|
|
||||||
if utils.DoesFileExists(config.CustomEmojiPath) {
|
if utils.DoesFileExists(config.CustomEmojiPath) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -47,14 +57,42 @@ func SetupEmojiDirectory() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
staticFS := static.GetEmoji()
|
staticFS := static.GetEmoji()
|
||||||
files, err := fs.Glob(staticFS, "*")
|
files := []emojiDirectory{}
|
||||||
|
|
||||||
|
walkFunction := func(path string, d os.DirEntry, err error) error {
|
||||||
|
if path == "." {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Name() == "LICENSE.md" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
files = append(files, emojiDirectory{path: path, isDir: d.IsDir()})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := fs.WalkDir(staticFS, ".", walkFunction); err != nil {
|
||||||
|
log.Errorln("unable to fetch emojis: " + err.Error())
|
||||||
|
return errors.Wrap(err, "unable to fetch embedded emoji files")
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to read built-in emoji files: %w", err)
|
return fmt.Errorf("unable to read built-in emoji files: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now copy all built-in emojis to the custom emoji directory
|
// Now copy all built-in emojis to the custom emoji directory
|
||||||
for _, name := range files {
|
for _, path := range files {
|
||||||
emojiPath := filepath.Join(config.CustomEmojiPath, filepath.Base(name))
|
emojiPath := filepath.Join(config.CustomEmojiPath, path.path)
|
||||||
|
|
||||||
|
if path.isDir {
|
||||||
|
if err := os.Mkdir(emojiPath, 0o700); err != nil {
|
||||||
|
return errors.Wrap(err, "unable to create emoji directory, check permissions?: "+path.path)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
memFile, err := staticFS.Open(path.path)
|
||||||
|
|
||||||
// nolint:gosec
|
// nolint:gosec
|
||||||
diskFile, err := os.Create(emojiPath)
|
diskFile, err := os.Create(emojiPath)
|
||||||
@ -62,7 +100,6 @@ func SetupEmojiDirectory() (err error) {
|
|||||||
return fmt.Errorf("unable to create custom emoji file on disk: %w", err)
|
return fmt.Errorf("unable to create custom emoji file on disk: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
memFile, err := staticFS.Open(name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = diskFile.Close()
|
_ = diskFile.Close()
|
||||||
return fmt.Errorf("unable to open built-in emoji file: %w", err)
|
return fmt.Errorf("unable to open built-in emoji file: %w", err)
|
||||||
|
@ -51,7 +51,10 @@ const Emoji = () => {
|
|||||||
getEmojis();
|
getEmojis();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
async function handleDelete(name: string) {
|
async function handleDelete(fullPath: string) {
|
||||||
|
const name = `/${fullPath.split('/').slice(3).join('/')}`;
|
||||||
|
console.log(name);
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
setSubmitStatus(createInputStatus(STATUS_PROCESSING, 'Deleting emoji...'));
|
setSubmitStatus(createInputStatus(STATUS_PROCESSING, 'Deleting emoji...'));
|
||||||
@ -128,7 +131,7 @@ const Emoji = () => {
|
|||||||
key: 'delete',
|
key: 'delete',
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Space size="middle">
|
<Space size="middle">
|
||||||
<Button onClick={() => handleDelete(record.name)} icon={<DeleteOutlined />} />
|
<Button onClick={() => handleDelete(record.url)} icon={<DeleteOutlined />} />
|
||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user