17
17
18
18
from mimetypes import guess_type
19
19
import re
20
+ import os .path
20
21
from os .path import isfile , getsize
21
22
22
23
from beets .plugins import BeetsPlugin
@@ -595,6 +596,24 @@ def single_resource(self, artist_id):
595
596
return self .single_resource_document (artist_resource )
596
597
597
598
599
+ def safe_filename (fn ):
600
+ """Check whether a string is a simple (non-path) filename.
601
+
602
+ For example, `foo.txt` is safe because it is a "plain" filename. But
603
+ `foo/bar.txt` and `../foo.txt` and `.` are all non-safe because they
604
+ can traverse to other directories other than the current one.
605
+ """
606
+ # Rule out any directories.
607
+ if os .path .basename (fn ) != fn :
608
+ return False
609
+
610
+ # In single names, rule out Unix directory traversal names.
611
+ if fn in ('.' , '..' ):
612
+ return False
613
+
614
+ return True
615
+
616
+
598
617
class ImageDocument (AURADocument ):
599
618
"""Class for building documents for /images/(id) endpoints."""
600
619
@@ -616,6 +635,8 @@ def get_image_path(image_id):
616
635
parent_type = id_split [0 ]
617
636
parent_id = id_split [1 ]
618
637
img_filename = "-" .join (id_split [2 :])
638
+ if not safe_filename (img_filename ):
639
+ return None
619
640
620
641
# Get the path to the directory parent's images are in
621
642
if parent_type == "album" :
@@ -631,7 +652,7 @@ def get_image_path(image_id):
631
652
# Images for other resource types are not supported
632
653
return None
633
654
634
- img_path = dir_path + "/" + img_filename
655
+ img_path = os . path . join ( dir_path , img_filename )
635
656
# Check the image actually exists
636
657
if isfile (img_path ):
637
658
return img_path
0 commit comments