diff --git a/Containerfile b/Containerfile
index 55057d8..9ae9198 100644
--- a/Containerfile
+++ b/Containerfile
@@ -70,6 +70,7 @@ COPY container/root/ /
ENV \
# Docker-specific configuration
MALOJA_SKIP_SETUP=yes \
+ MALOJA_CONTAINER=yes \
PYTHONUNBUFFERED=1 \
# Prevents breaking change for previous container that ran maloja as root
# On linux hosts (non-podman rootless) these variables should be set to the
diff --git a/dev/releases/3.2.yml b/dev/releases/3.2.yml
index 75971c7..3c890e6 100644
--- a/dev/releases/3.2.yml
+++ b/dev/releases/3.2.yml
@@ -33,5 +33,7 @@ minor_release_name: "Nicole"
- "[Technical] Upgraded all third party modules to use requests module and send User Agent"
3.2.2:
notes:
+ - "[Security] Fixed XSS vulnerability in error page (Disclosed by https://github.com/NULLYUKI)"
+ - "[Architecture] Reworked the default directory selection"
- "[Feature] Added option to show scrobbles on tile charts"
- "[Bugfix] Fixed Last.fm authentication"
\ No newline at end of file
diff --git a/maloja/__pkginfo__.py b/maloja/__pkginfo__.py
index 47c8e25..6bd621b 100644
--- a/maloja/__pkginfo__.py
+++ b/maloja/__pkginfo__.py
@@ -4,7 +4,7 @@
# you know what f*ck it
# this is hardcoded for now because of that damn project / package name discrepancy
# i'll fix it one day
-VERSION = "3.2.1"
+VERSION = "3.2.2"
HOMEPAGE = "https://github.com/krateng/maloja"
diff --git a/maloja/data_files/config/rules/predefined/krateng_kpopgirlgroups.tsv b/maloja/data_files/config/rules/predefined/krateng_kpopgirlgroups.tsv
index 840bd84..ad205fb 100644
--- a/maloja/data_files/config/rules/predefined/krateng_kpopgirlgroups.tsv
+++ b/maloja/data_files/config/rules/predefined/krateng_kpopgirlgroups.tsv
@@ -160,8 +160,8 @@ replaceartist 여자친구 GFriend GFriend
# Girl's Generation
replaceartist 소녀시대 Girls' Generation
replaceartist SNSD Girls' Generation
-replaceartist Girls' Generation-TTS TaeTiSeo
-countas TaeTiSeo Girls' Generation
+replaceartist Girls' Generation-TTS TaeTiSeo
+countas TaeTiSeo Girls' Generation
# Apink
replaceartist A Pink Apink
@@ -217,6 +217,8 @@ countas Pristin V Pristin
# CLC
countas Sorn CLC
+countas Yeeun CLC
+countas Seungyeon CLC
# Popular Remixes
artistintitle Areia Remix Areia
diff --git a/maloja/pkg_global/conf.py b/maloja/pkg_global/conf.py
index be280fc..0d404fd 100644
--- a/maloja/pkg_global/conf.py
+++ b/maloja/pkg_global/conf.py
@@ -17,9 +17,11 @@ AUX_MODE = True
# DIRECRORY_CONFIG, DIRECRORY_STATE, DIRECTORY_LOGS and DIRECTORY_CACHE
# config can only be determined by environment variable, the others can be loaded
# from the config files
-# explicit settings will always be respected, fallback to default
-# if default isn't usable, and config writable, find alternative and fix it in settings
+# we don't specify 'default' values in the normal sense of the config object
+# the default is none, meaning the app should figure it out (depending on environment)
+# the actual 'default' values of our folders are simply in code since they are dependent on environment (container?)
+# and we need to actually distinguish them from the user having specified something
# USEFUL FUNCS
pthj = os.path.join
@@ -27,9 +29,7 @@ pthj = os.path.join
def is_dir_usable(pth):
try:
os.makedirs(pth,exist_ok=True)
- os.mknod(pthj(pth,".test"))
- os.remove(pthj(pth,".test"))
- return True
+ return os.access(pth,os.W_OK)
except Exception:
return False
@@ -41,6 +41,9 @@ def get_env_vars(key,pathsuffix=[]):
directory_info = {
"config":{
"sentinel":".maloja_config_sentinel",
+ "possible_folders_container":[
+ "/config/config"
+ ],
"possible_folders":[
"/etc/maloja",
os.path.expanduser("~/.local/share/maloja")
@@ -49,14 +52,21 @@ directory_info = {
},
"cache":{
"sentinel":".maloja_cache_sentinel",
+ "possible_folders_container":[
+ "/config/cache"
+ ],
"possible_folders":[
"/var/cache/maloja",
- os.path.expanduser("~/.local/share/maloja/cache")
+ os.path.expanduser("~/.local/share/maloja/cache"),
+ "/tmp/maloja"
],
"setting":"directory_cache"
},
"state":{
"sentinel":".maloja_state_sentinel",
+ "possible_folders_container":[
+ "/config/state"
+ ],
"possible_folders":[
"/var/lib/maloja",
os.path.expanduser("~/.local/share/maloja")
@@ -65,6 +75,9 @@ directory_info = {
},
"logs":{
"sentinel":".maloja_logs_sentinel",
+ "possible_folders_container":[
+ "/config/logs"
+ ],
"possible_folders":[
"/var/log/maloja",
os.path.expanduser("~/.local/share/maloja/logs")
@@ -77,25 +90,27 @@ directory_info = {
# checks if one has been in use before and writes it to dict/config
# if not, determines which to use and writes it to dict/config
# returns determined folder
-def find_good_folder(datatype,configobject):
+def find_good_folder(datatype):
info = directory_info[datatype]
+ possible_folders = info['possible_folders']
+ if os.environ.get("MALOJA_CONTAINER"):
+ possible_folders = info['possible_folders_container'] + possible_folders
+
# check each possible folder if its used
- for p in info['possible_folders']:
+ for p in possible_folders:
if os.path.exists(pthj(p,info['sentinel'])):
if is_dir_usable(p):
- print(p,"was apparently used as maloja's folder for",datatype,"- fixing in settings")
- configobject[info['setting']] = p
+ #print(p,"was apparently used as maloja's folder for",datatype,"- fixing in settings")
return p
else:
- raise PermissionError(f"Can no longer use previously used path {p}")
+ raise PermissionError(f"Can no longer use previously used {datatype} folder {p}")
#print("Could not find previous",datatype,"folder")
# check which one we can use
- for p in info['possible_folders']:
+ for p in possible_folders:
if is_dir_usable(p):
- print(p,"has been selected as maloja's folder for",datatype)
- configobject[info['setting']] = p
+ #print(p,"has been selected as maloja's folder for",datatype)
return p
#print("No folder can be used for",datatype)
#print("This should not happen!")
@@ -106,26 +121,20 @@ def find_good_folder(datatype,configobject):
### STEP 1 - find out where the settings file is
-# environment variables
+
maloja_dir_config = os.environ.get("MALOJA_DATA_DIRECTORY") or os.environ.get("MALOJA_DIRECTORY_CONFIG")
-
if maloja_dir_config is None:
- maloja_dir_config = find_good_folder('config',{})
- found_new_config_dir = True
+ # if nothing is set, we set our own
+ maloja_dir_config = find_good_folder('config')
else:
- found_new_config_dir = False
- # remember whether we had to find our config dir or it was user-specified
+ pass
+ # if there is an environment variable, this is 100% explicitly defined by the user, so we respect it
+ # the user might run more than one instances on the same machine, so we don't do any heuristics here
+ # if you define this, we believe it!
os.makedirs(maloja_dir_config,exist_ok=True)
-
-oldsettingsfile = pthj(maloja_dir_config,"settings","settings.ini")
-newsettingsfile = pthj(maloja_dir_config,"settings.ini")
-
-
-
-if os.path.exists(oldsettingsfile):
- os.rename(oldsettingsfile,newsettingsfile)
+settingsfile = pthj(maloja_dir_config,"settings.ini")
### STEP 2 - create settings object
@@ -135,10 +144,10 @@ malojaconfig = Configuration(
settings={
"Setup":{
"data_directory":(tp.String(), "Data Directory", None, "Folder for all user data. Overwrites all choices for specific directories."),
- "directory_config":(tp.String(), "Config Directory", "/etc/maloja", "Folder for config data. Only applied when global data directory is not set."),
- "directory_state":(tp.String(), "State Directory", "/var/lib/maloja", "Folder for state data. Only applied when global data directory is not set."),
- "directory_logs":(tp.String(), "Log Directory", "/var/log/maloja", "Folder for log data. Only applied when global data directory is not set."),
- "directory_cache":(tp.String(), "Cache Directory", "/var/cache/maloja", "Folder for cache data. Only applied when global data directory is not set."),
+ "directory_config":(tp.String(), "Config Directory", None, "Folder for config data. Only applied when global data directory is not set."),
+ "directory_state":(tp.String(), "State Directory", None, "Folder for state data. Only applied when global data directory is not set."),
+ "directory_logs":(tp.String(), "Log Directory", None, "Folder for log data. Only applied when global data directory is not set."),
+ "directory_cache":(tp.String(), "Cache Directory", None, "Folder for cache data. Only applied when global data directory is not set."),
"skip_setup":(tp.Boolean(), "Skip Setup", False, "Make server setup process non-interactive. Vital for Docker."),
"force_password":(tp.String(), "Force Password", None, "On startup, overwrite admin password with this one. This should usually only be done via environment variable in Docker."),
"clean_output":(tp.Boolean(), "Avoid Mutable Console Output", False, "Use if console output will be redirected e.g. to a web interface.")
@@ -214,18 +223,15 @@ malojaconfig = Configuration(
"theme":(tp.String(), "Theme", "maloja")
}
},
- configfile=newsettingsfile,
+ configfile=settingsfile,
save_endpoint="/apis/mlj_1/settings",
env_prefix="MALOJA_",
extra_files=["/run/secrets/maloja.yml","/run/secrets/maloja.ini"]
)
-if found_new_config_dir:
- try:
- malojaconfig["DIRECTORY_CONFIG"] = maloja_dir_config
- except PermissionError as e:
- pass
+if not malojaconfig.readonly:
+ malojaconfig["DIRECTORY_CONFIG"] = maloja_dir_config
# this really doesn't matter because when are we gonna load info about where
# the settings file is stored from the settings file
# but oh well
@@ -247,17 +253,17 @@ except PermissionError as e:
pass
-### STEP 3 - check all possible folders for files (old installation)
-
+### STEP 3 - now check the other directories
if not malojaconfig.readonly:
for datatype in ("state","cache","logs"):
- # obviously default values shouldn't trigger this
- # if user has nothing specified, we need to use this
- if malojaconfig.get_specified(directory_info[datatype]['setting']) is None and malojaconfig.get_specified('DATA_DIRECTORY') is None:
- find_good_folder(datatype,malojaconfig)
-
+ # if the setting is specified in the file or via a user environment variable, we accept it (we'll check later if it's usable)
+ if malojaconfig[directory_info[datatype]['setting']] or malojaconfig['DATA_DIRECTORY']:
+ pass
+ # otherwise, find a good one
+ else:
+ malojaconfig[directory_info[datatype]['setting']] = find_good_folder(datatype)
@@ -310,11 +316,11 @@ for identifier,path in data_directories.items():
# just move to the next one
if identifier in ['cache']:
print("Cannot use",path,"for cache, finding new folder...")
- find_good_folder('cache',malojaconfig)
- data_directories['cache'] = dir_settings['cache'] = malojaconfig['DIRECTORY_CACHE']
+ data_directories['cache'] = dir_settings['cache'] = malojaconfig['DIRECTORY_CACHE'] = find_good_folder('cache')
else:
print("Directory",path,"is not usable.")
print("Please change permissions or settings!")
+ print("Make sure Maloja has write and execute access to this directory.")
raise
diff --git a/maloja/web/jinja/abstracts/base.jinja b/maloja/web/jinja/abstracts/base.jinja
index be9c746..8934040 100644
--- a/maloja/web/jinja/abstracts/base.jinja
+++ b/maloja/web/jinja/abstracts/base.jinja
@@ -75,7 +75,7 @@