1
0
mirror of https://github.com/Tygs/0bin.git synced 2023-08-10 21:13:00 +03:00
0bin/zerobin/utils.py

173 lines
4.7 KiB
Python
Raw Normal View History

2012-05-14 19:17:49 +04:00
import time
import os
import glob
import tempfile
2015-05-10 20:19:02 +03:00
import codecs
import unicodedata
2020-08-12 10:19:38 +03:00
import hashlib
import secrets
2015-05-10 20:19:02 +03:00
from functools import partial
2012-05-14 19:17:49 +04:00
2015-05-10 20:19:02 +03:00
from zerobin import default_settings
2012-05-14 19:17:49 +04:00
try:
2015-05-10 20:19:02 +03:00
from zerobin.privilege import drop_privileges_permanently, coerce_user, coerce_group
2012-05-14 19:17:49 +04:00
except (AttributeError):
2020-08-12 10:19:38 +03:00
pass # privilege does't work on several plateforms
2012-05-14 19:17:49 +04:00
2020-08-12 10:19:38 +03:00
from runpy import run_path
2012-05-14 19:17:49 +04:00
def drop_privileges(user=None, group=None, wait=5):
"""
Try to set the process user and group to another one.
If no group is provided, it's set to the same as the user.
You can wait for a certain time before doing so.
"""
if wait:
time.sleep(wait)
if user:
group = group or user
try:
user = coerce_user(user)
group = coerce_group(group)
2020-08-11 17:37:03 +03:00
lock_files = glob.glob(os.path.join(tempfile.gettempdir(), "bottle.*.lock"))
2012-05-14 19:17:49 +04:00
for lock_file in lock_files:
os.chown(lock_file, user, group)
drop_privileges_permanently(user, group, ())
except Exception:
2015-05-10 20:19:02 +03:00
print("Failed to drop privileges. Running with current user.")
2012-05-14 19:17:49 +04:00
2015-05-10 20:19:02 +03:00
class SettingsValidationError(Exception):
pass
2012-05-14 19:17:49 +04:00
class SettingsContainer(object):
"""
Singleton containing the settings for the whole app
"""
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
2020-08-11 17:37:03 +03:00
cls._instance = super(SettingsContainer, cls).__new__(cls, *args, **kwargs)
2012-05-14 19:17:49 +04:00
cls._instance.update_with_module(default_settings)
return cls._instance
def update_with_dict(self, dict):
2012-05-14 19:17:49 +04:00
"""
Update settings with values from the given mapping object.
2012-05-14 19:17:49 +04:00
(Taking only variable with uppercased name)
"""
2015-05-10 20:19:02 +03:00
for name, value in dict.items():
2012-05-14 19:17:49 +04:00
if name.isupper():
setattr(self, name, value)
return self
def update_with_module(self, module):
"""
Update settings with values from the given module.
Uses update_with_dict() behind the scenes.
"""
return self.update_with_dict(module.__dict__)
2012-05-14 19:17:49 +04:00
@classmethod
def from_module(cls, module):
"""
Create an instance of SettingsContainer with values based
on the one in the passed module.
"""
settings = cls()
settings.update_with_module(module)
return settings
def update_with_file(self, filepath):
"""
Update settings with values from the given module file.
Uses update_with_dict() behind the scenes.
2012-05-14 19:17:49 +04:00
"""
settings = run_path(filepath)
return self.update_with_dict(settings)
2012-05-14 19:17:49 +04:00
settings = SettingsContainer()
2015-05-10 20:19:02 +03:00
def to_ascii(utext):
""" Take a unicode string and return ascii bytes.
Try to replace non ASCII char by similar ASCII char. If it can't,
replace it with "?".
"""
2020-08-11 17:37:03 +03:00
return unicodedata.normalize("NFKD", utext).encode("ascii", "replace")
2015-05-10 20:19:02 +03:00
# Make sure to always specify encoding when using open in Python 2 or 3
safe_open = partial(codecs.open, encoding="utf8")
def as_unicode(obj):
""" Return the unicode representation of an object """
try:
return unicode(obj)
except NameError:
return str(obj)
2020-08-12 10:19:38 +03:00
def ensure_var_env():
""" Ensure all the variable things we generate are available.
This will make sure we have:
- a var dir
- a content dir
- a secret key
- an admin URL
"""
settings.VAR_DIR.mkdir(exist_ok=True, parents=True)
2020-08-12 16:21:49 +03:00
settings.PASTE_FILES_ROOT = settings.VAR_DIR / "content"
2020-08-12 10:19:38 +03:00
settings.PASTE_FILES_ROOT.mkdir(exist_ok=True)
2020-08-12 16:21:49 +03:00
settings.SESSIONS_DIR = settings.VAR_DIR / "sessions"
2020-08-12 10:19:38 +03:00
settings.SESSIONS_DIR.mkdir(exist_ok=True)
secret_key_file = settings.VAR_DIR / "secret_key"
if not secret_key_file.is_file():
secret_key_file.write_text(secrets.token_urlsafe(64))
settings.SECRET_KEY = secret_key_file.read_text()
admin_password_file = settings.VAR_DIR / "admin_password"
if not secret_key_file.is_file():
admin_password_file.write_text(
"No password set. Use the set_admin_passord command. Don't write this file by hand."
)
settings.ADMIN_PASSWORD_FILE = admin_password_file
payload = ("admin" + settings.SECRET_KEY).encode("ascii")
2020-08-12 16:21:49 +03:00
settings.ADMIN_URL = "/admin/" + hashlib.sha256(payload).hexdigest() + "/"
2020-08-12 10:19:38 +03:00
def hash_password(password):
return hashlib.scrypt(
password.encode("utf8"),
salt=settings.SECRET_KEY.encode("ascii"),
n=16384,
r=8,
p=1,
dklen=32,
)
def check_password(password):
try:
2020-08-12 16:21:49 +03:00
return settings.ADMIN_PASSWORD_FILE.read_bytes() == hash_password(password)
2020-08-12 10:19:38 +03:00
except (FileNotFoundError, AttributeError):
return False