[Windows] Security model for files permissions - STEP 1 (#6893)

This PR is the first part of #6497 to ease the integration, following the new plan propose by @bmw here: #6497 (comment)

This step 1 refactor existing certbot.compat module into certbot.compat.misc, without any logic changed. Package certbot.compat will host the new modules that constitute the security model for Windows.

* Create the certbot.compat package. Move logic in certbot.compat.misc

* Add doc

* Fix lint

* Correct mypy

* Update client.py
This commit is contained in:
Adrien Ferrand
2019-03-28 15:51:48 -07:00
committed by Brad Warren
parent b0fb570c1c
commit 6ce6c67932
26 changed files with 123 additions and 136 deletions
+5 -7
View File
@@ -12,24 +12,22 @@ import zope.interface
from acme import challenges
from acme import crypto_util as acme_crypto_util
from acme.magic_typing import List, Dict, Set # pylint: disable=unused-import, no-name-in-module
from certbot import compat
from certbot import constants as core_constants
from certbot import crypto_util
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot.compat import misc
from certbot.plugins import common
from certbot_nginx import constants
from certbot_nginx import display_ops
from certbot_nginx import nginxparser
from certbot_nginx import parser
from certbot_nginx import http_01
from certbot_nginx import nginxparser
from certbot_nginx import obj # pylint: disable=unused-import
from acme.magic_typing import List, Dict, Set # pylint: disable=unused-import, no-name-in-module
from certbot_nginx import parser
NAME_RANK = 0
START_WILDCARD_RANK = 1
@@ -895,7 +893,7 @@ class NginxConfigurator(common.Installer):
have permissions of root.
"""
uid = compat.os_geteuid()
uid = misc.os_geteuid()
util.make_or_verify_dir(
self.config.work_dir, core_constants.CONFIG_DIRS_MODE, uid)
util.make_or_verify_dir(
+4 -5
View File
@@ -7,22 +7,21 @@ import os
import shutil
import socket
from cryptography.hazmat.primitives import serialization
import josepy as jose
import pyrfc3339
import pytz
import six
import zope.component
from cryptography.hazmat.primitives import serialization
from acme import fields as acme_fields
from acme import messages
from certbot import compat
from certbot import constants
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot.compat import misc
logger = logging.getLogger(__name__)
@@ -141,7 +140,7 @@ class AccountFileStorage(interfaces.AccountStorage):
"""
def __init__(self, config):
self.config = config
util.make_or_verify_dir(config.accounts_dir, 0o700, compat.os_geteuid(),
util.make_or_verify_dir(config.accounts_dir, 0o700, misc.os_geteuid(),
self.config.strict_permissions)
def _account_dir_path(self, account_id):
@@ -324,7 +323,7 @@ class AccountFileStorage(interfaces.AccountStorage):
def _save(self, account, acme, regr_only):
account_dir_path = self._account_dir_path(account.id)
util.make_or_verify_dir(account_dir_path, 0o700, compat.os_geteuid(),
util.make_or_verify_dir(account_dir_path, 0o700, misc.os_geteuid(),
self.config.strict_permissions)
try:
with open(self._regr_path(account_dir_path), "w") as regr_file:
+6 -5
View File
@@ -2,20 +2,21 @@
import datetime
import logging
import os
import pytz
import re
import traceback
import pytz
import zope.component
from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-module
from certbot import compat
from certbot import crypto_util
from certbot import errors
from certbot import interfaces
from certbot import ocsp
from certbot import storage
from certbot import util
from certbot.compat import misc
from certbot.display import util as display_util
logger = logging.getLogger(__name__)
@@ -105,7 +106,7 @@ def lineage_for_certname(cli_config, certname):
"""Find a lineage object with name certname."""
configs_dir = cli_config.renewal_configs_dir
# Verify the directory is there
util.make_or_verify_dir(configs_dir, mode=0o755, uid=compat.os_geteuid())
util.make_or_verify_dir(configs_dir, mode=0o755, uid=misc.os_geteuid())
try:
renewal_file = storage.renewal_file_for_certname(cli_config, certname)
except errors.CertStorageError:
@@ -375,7 +376,7 @@ def _search_lineages(cli_config, func, initial_rv, *args):
"""
configs_dir = cli_config.renewal_configs_dir
# Verify the directory is there
util.make_or_verify_dir(configs_dir, mode=0o755, uid=compat.os_geteuid())
util.make_or_verify_dir(configs_dir, mode=0o755, uid=misc.os_geteuid())
rv = initial_rv
for renewal_file in storage.renewal_conf_files(cli_config):
+6 -10
View File
@@ -4,14 +4,13 @@ import logging
import os
import platform
import OpenSSL
import josepy as jose
import zope.component
from cryptography.hazmat.backends import default_backend
# https://github.com/python/typeshed/blob/master/third_party/
# 2/cryptography/hazmat/primitives/asymmetric/rsa.pyi
from cryptography.hazmat.primitives.asymmetric.rsa import generate_private_key # type: ignore
import josepy as jose
import OpenSSL
import zope.component
from acme import client as acme_client
from acme import crypto_util as acme_crypto_util
@@ -20,11 +19,9 @@ from acme import messages
from acme.magic_typing import Optional # pylint: disable=unused-import,no-name-in-module
import certbot
from certbot import account
from certbot import auth_handler
from certbot import cli
from certbot import compat
from certbot import constants
from certbot import crypto_util
from certbot import eff
@@ -34,12 +31,11 @@ from certbot import interfaces
from certbot import reverter
from certbot import storage
from certbot import util
from certbot.display import ops as display_ops
from certbot.compat import misc
from certbot.display import enhancements
from certbot.display import ops as display_ops
from certbot.plugins import selection as plugin_selection
logger = logging.getLogger(__name__)
@@ -466,7 +462,7 @@ class Client(object):
"""
for path in cert_path, chain_path, fullchain_path:
util.make_or_verify_dir(
os.path.dirname(path), 0o755, compat.os_geteuid(),
os.path.dirname(path), 0o755, misc.os_geteuid(),
self.config.strict_permissions)
+6
View File
@@ -0,0 +1,6 @@
"""
Compatibility layer to run certbot both on Linux and Windows.
This package contains all logic that needs to be implemented specifically for Linux and for Windows.
Then the rest of certbot code relies on this module to be platform agnostic.
"""
+2 -4
View File
@@ -1,8 +1,6 @@
"""
Compatibility layer to run certbot both on Linux and Windows.
This module contains all required platform specific code,
allowing the rest of Certbot codebase to be platform agnostic.
This compat module handles various platform specific calls that do not fall into one
particular category.
"""
import os
import select
+3 -3
View File
@@ -2,14 +2,14 @@
import copy
import os
from six.moves.urllib import parse # pylint: disable=import-error
import zope.interface
from six.moves.urllib import parse # pylint: disable=import-error
from certbot import compat
from certbot import constants
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot.compat import misc
@zope.interface.implementer(interfaces.IConfig)
@@ -70,7 +70,7 @@ class NamespaceConfig(object):
def accounts_dir_for_server_path(self, server_path):
"""Path to accounts directory based on server_path"""
server_path = compat.underscores_for_unsupported_characters_in_path(server_path)
server_path = misc.underscores_for_unsupported_characters_in_path(server_path)
return os.path.join(
self.namespace.config_dir, constants.ACCOUNTS_DIR, server_path)
+7 -5
View File
@@ -1,10 +1,12 @@
"""Certbot constants."""
import logging
import os
import pkg_resources
from acme import challenges
from certbot import compat
from certbot.compat import misc
SETUPTOOLS_PLUGINS_ENTRY_POINT = "certbot.plugins"
"""Setuptools entry point group name for plugins."""
@@ -14,7 +16,7 @@ OLD_SETUPTOOLS_PLUGINS_ENTRY_POINT = "letsencrypt.plugins"
CLI_DEFAULTS = dict(
config_files=[
os.path.join(compat.get_default_folder('config'), 'cli.ini'),
os.path.join(misc.get_default_folder('config'), 'cli.ini'),
# http://freedesktop.org/wiki/Software/xdg-user-dirs/
os.path.join(os.environ.get("XDG_CONFIG_HOME", "~/.config"),
"letsencrypt", "cli.ini"),
@@ -87,9 +89,9 @@ CLI_DEFAULTS = dict(
auth_cert_path="./cert.pem",
auth_chain_path="./chain.pem",
key_path=None,
config_dir=compat.get_default_folder('config'),
work_dir=compat.get_default_folder('work'),
logs_dir=compat.get_default_folder('logs'),
config_dir=misc.get_default_folder('config'),
work_dir=misc.get_default_folder('work'),
logs_dir=misc.get_default_folder('logs'),
server="https://acme-v02.api.letsencrypt.org/directory",
# Plugins parsers
+8 -8
View File
@@ -12,24 +12,24 @@ import warnings
import pyrfc3339
import six
import zope.component
from OpenSSL import SSL # type: ignore
from OpenSSL import crypto
# https://github.com/python/typeshed/tree/master/third_party/2/cryptography
from cryptography import x509 # type: ignore
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric.ec import ECDSA
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
# https://github.com/python/typeshed/tree/master/third_party/2/cryptography
from cryptography import x509 # type: ignore
from OpenSSL import crypto
from OpenSSL import SSL # type: ignore
from acme import crypto_util as acme_crypto_util
from acme.magic_typing import IO # pylint: disable=unused-import, no-name-in-module
from certbot import compat
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot.compat import misc
logger = logging.getLogger(__name__)
@@ -61,7 +61,7 @@ def init_save_key(key_size, key_dir, keyname="key-certbot.pem"):
config = zope.component.getUtility(interfaces.IConfig)
# Save file
util.make_or_verify_dir(key_dir, 0o700, compat.os_geteuid(),
util.make_or_verify_dir(key_dir, 0o700, misc.os_geteuid(),
config.strict_permissions)
key_f, key_path = util.unique_file(
os.path.join(key_dir, keyname), 0o600, "wb")
@@ -92,7 +92,7 @@ def init_save_csr(privkey, names, path):
privkey.pem, names, must_staple=config.must_staple)
# Save CSR
util.make_or_verify_dir(path, 0o755, compat.os_geteuid(),
util.make_or_verify_dir(path, 0o755, misc.os_geteuid(),
config.strict_permissions)
csr_f, csr_filename = util.unique_file(
os.path.join(path, "csr-certbot.pem"), 0o644, "wb")
+2 -3
View File
@@ -4,11 +4,10 @@ import os
import zope.component
from certbot import compat
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot.compat import misc
from certbot.display import util as display_util
logger = logging.getLogger(__name__)
@@ -36,7 +35,7 @@ def get_email(invalid=False, optional=True):
"the client with --register-unsafely-without-email "
"but make sure you then backup your account key from "
"{0}\n\n".format(os.path.join(
compat.get_default_folder('config'), 'accounts')))
misc.get_default_folder('config'), 'accounts')))
if optional:
if invalid:
msg += unsafe_suggestion
+3 -3
View File
@@ -6,10 +6,10 @@ import textwrap
import zope.interface
from certbot import compat
from certbot import constants
from certbot import interfaces
from certbot import errors
from certbot import interfaces
from certbot.compat import misc
from certbot.display import completer
logger = logging.getLogger(__name__)
@@ -79,7 +79,7 @@ def input_with_timeout(prompt=None, timeout=36000.0):
sys.stdout.write(prompt)
sys.stdout.flush()
line = compat.readline_with_timeout(timeout, prompt)
line = misc.readline_with_timeout(timeout, prompt)
if not line:
raise EOFError
+3 -2
View File
@@ -13,6 +13,7 @@ and properly flushed before program exit.
"""
from __future__ import print_function
import functools
import logging
import logging.handlers
@@ -23,10 +24,10 @@ import traceback
from acme import messages
from certbot import compat
from certbot import constants
from certbot import errors
from certbot import util
from certbot.compat import misc
# Logging format
CLI_FMT = "%(message)s"
@@ -134,7 +135,7 @@ def setup_log_file_handler(config, logfile, fmt):
# TODO: logs might contain sensitive data such as contents of the
# private key! #525
util.set_up_core_dir(
config.logs_dir, 0o700, compat.os_geteuid(), config.strict_permissions)
config.logs_dir, 0o700, misc.os_geteuid(), config.strict_permissions)
log_file_path = os.path.join(config.logs_dir, logfile)
try:
handler = logging.handlers.RotatingFileHandler(
+7 -8
View File
@@ -1,6 +1,7 @@
"""Certbot main entry point."""
# pylint: disable=too-many-lines
from __future__ import print_function
import functools
import logging.handlers
import os
@@ -14,12 +15,10 @@ from acme import errors as acme_errors
from acme.magic_typing import Union # pylint: disable=unused-import, no-name-in-module
import certbot
from certbot import account
from certbot import cert_manager
from certbot import cli
from certbot import client
from certbot import compat
from certbot import configuration
from certbot import constants
from certbot import crypto_util
@@ -33,11 +32,11 @@ from certbot import reporter
from certbot import storage
from certbot import updater
from certbot import util
from certbot.compat import misc
from certbot.display import util as display_util, ops as display_ops
from certbot.plugins import disco as plugins_disco
from certbot.plugins import selection as plug_sel
from certbot.plugins import enhancements
from certbot.plugins import selection as plug_sel
USER_CANCELLED = ("User chose to cancel the operation and may "
"reinvoke the client.")
@@ -1285,16 +1284,16 @@ def make_or_verify_needed_dirs(config):
"""
util.set_up_core_dir(config.config_dir, constants.CONFIG_DIRS_MODE,
compat.os_geteuid(), config.strict_permissions)
misc.os_geteuid(), config.strict_permissions)
util.set_up_core_dir(config.work_dir, constants.CONFIG_DIRS_MODE,
compat.os_geteuid(), config.strict_permissions)
misc.os_geteuid(), config.strict_permissions)
hook_dirs = (config.renewal_pre_hooks_dir,
config.renewal_deploy_hooks_dir,
config.renewal_post_hooks_dir,)
for hook_dir in hook_dirs:
util.make_or_verify_dir(hook_dir,
uid=compat.os_geteuid(),
uid=misc.os_geteuid(),
strict=config.strict_permissions)
@@ -1345,7 +1344,7 @@ def main(cli_args=sys.argv[1:]):
# On windows, shell without administrative right cannot create symlinks required by certbot.
# So we check the rights before continuing.
compat.raise_for_non_administrative_windows_rights(config.verb)
misc.raise_for_non_administrative_windows_rights(config.verb)
try:
log.post_arg_parse_setup(config)
+3 -5
View File
@@ -17,14 +17,12 @@ import six
from acme import challenges
from certbot import achallenges
from certbot import compat
from certbot import errors
from certbot.compat import misc
from certbot.display import util as display_util
from certbot.tests import acme_util
from certbot.tests import util as test_util
KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem"))
@@ -171,14 +169,14 @@ class AuthenticatorTest(unittest.TestCase):
# Remove exec bit from permission check, so that it
# matches the file
self.auth.perform([self.achall])
self.assertTrue(compat.compare_file_modes(os.stat(self.validation_path).st_mode, 0o644))
self.assertTrue(misc.compare_file_modes(os.stat(self.validation_path).st_mode, 0o644))
# Check permissions of the directories
for dirpath, dirnames, _ in os.walk(self.path):
for directory in dirnames:
full_path = os.path.join(dirpath, directory)
self.assertTrue(compat.compare_file_modes(os.stat(full_path).st_mode, 0o755))
self.assertTrue(misc.compare_file_modes(os.stat(full_path).st_mode, 0o755))
parent_gid = os.stat(self.path).st_gid
parent_uid = os.stat(self.path).st_uid
+5 -6
View File
@@ -10,12 +10,11 @@ import traceback
import six
import zope.component
from certbot import compat
from certbot import constants
from certbot import errors
from certbot import interfaces
from certbot import util
from certbot.compat import misc
logger = logging.getLogger(__name__)
@@ -66,7 +65,7 @@ class Reverter(object):
self.config = config
util.make_or_verify_dir(
config.backup_dir, constants.CONFIG_DIRS_MODE, compat.os_geteuid(),
config.backup_dir, constants.CONFIG_DIRS_MODE, misc.os_geteuid(),
self.config.strict_permissions)
def revert_temporary_config(self):
@@ -220,7 +219,7 @@ class Reverter(object):
"""
util.make_or_verify_dir(
cp_dir, constants.CONFIG_DIRS_MODE, compat.os_geteuid(),
cp_dir, constants.CONFIG_DIRS_MODE, misc.os_geteuid(),
self.config.strict_permissions)
op_fd, existing_filepaths = self._read_and_append(
@@ -434,7 +433,7 @@ class Reverter(object):
cp_dir = self.config.in_progress_dir
util.make_or_verify_dir(
cp_dir, constants.CONFIG_DIRS_MODE, compat.os_geteuid(),
cp_dir, constants.CONFIG_DIRS_MODE, misc.os_geteuid(),
self.config.strict_permissions)
return cp_dir
@@ -576,7 +575,7 @@ class Reverter(object):
timestamp = self._checkpoint_timestamp()
final_dir = os.path.join(self.config.backup_dir, timestamp)
try:
compat.os_rename(self.config.in_progress_dir, final_dir)
misc.os_rename(self.config.in_progress_dir, final_dir)
return
except OSError:
logger.warning("Extreme, unexpected race condition, retrying (%s)", timestamp)
+4 -5
View File
@@ -4,23 +4,22 @@ import glob
import logging
import os
import re
import shutil
import stat
import configobj
import parsedatetime
import pytz
import shutil
import six
import certbot
from certbot import cli
from certbot import compat
from certbot import constants
from certbot import crypto_util
from certbot import errors
from certbot import error_handler
from certbot import errors
from certbot import util
from certbot.compat import misc
from certbot.plugins import common as plugins_common
from certbot.plugins import disco as plugins_disco
@@ -192,7 +191,7 @@ def update_configuration(lineagename, archive_dir, target, cli_config):
# Save only the config items that are relevant to renewal
values = relevant_values(vars(cli_config.namespace))
write_renewal_config(config_filename, temp_filename, archive_dir, target, values)
compat.os_rename(temp_filename, config_filename)
misc.os_rename(temp_filename, config_filename)
return configobj.ConfigObj(config_filename)
+3 -5
View File
@@ -12,11 +12,9 @@ import pytz
from acme import messages
from certbot import compat
from certbot import errors
import certbot.tests.util as test_util
from certbot import errors
from certbot.compat import misc
KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem"))
@@ -116,7 +114,7 @@ class AccountFileStorageTest(test_util.ConfigTestCase):
def test_init_creates_dir(self):
self.assertTrue(os.path.isdir(
compat.underscores_for_unsupported_characters_in_path(self.config.accounts_dir)))
misc.underscores_for_unsupported_characters_in_path(self.config.accounts_dir)))
@test_util.broken_on_windows
def test_save_and_restore(self):
+3 -2
View File
@@ -1,8 +1,9 @@
"""Tests for certbot.compat."""
import os
from certbot import compat
import certbot.tests.util as test_util
from certbot.compat import misc
class OsReplaceTest(test_util.TempDirTestCase):
"""Test to ensure consistent behavior of os_rename method"""
@@ -15,7 +16,7 @@ class OsReplaceTest(test_util.TempDirTestCase):
open(dst, 'w').close()
# On Windows, a direct call to os.rename will fail because dst already exists.
compat.os_rename(src, dst)
misc.os_rename(src, dst)
self.assertFalse(os.path.exists(src))
self.assertTrue(os.path.exists(dst))
+3 -3
View File
@@ -4,12 +4,12 @@ import unittest
import mock
from certbot import compat
from certbot import constants
from certbot import errors
from certbot.compat import misc
from certbot.tests import util as test_util
class NamespaceConfigTest(test_util.ConfigTestCase):
"""Tests for certbot.configuration.NamespaceConfig."""
@@ -48,7 +48,7 @@ class NamespaceConfigTest(test_util.ConfigTestCase):
mock_constants.KEY_DIR = 'keys'
mock_constants.TEMP_CHECKPOINT_DIR = 't'
ref_path = compat.underscores_for_unsupported_characters_in_path(
ref_path = misc.underscores_for_unsupported_characters_in_path(
'acc/acme-server.org:443/new')
self.assertEqual(
os.path.normpath(self.config.accounts_dir),
+2 -3
View File
@@ -4,14 +4,13 @@ import socket
import tempfile
import unittest
import six
import mock
import six
from certbot import errors
from certbot import interfaces
from certbot.display import util as display_util
CHOICES = [("First", "Description1"), ("Second", "Description2")]
TAGS = ["tag1", "tag2", "tag3"]
TAGS_CHOICES = [("1", "tag1"), ("2", "tag2"), ("3", "tag3")]
@@ -32,7 +31,7 @@ class InputWithTimeoutTest(unittest.TestCase):
def test_input(self, prompt=None):
expected = "foo bar"
stdin = six.StringIO(expected + "\n")
with mock.patch("certbot.compat.select.select") as mock_select:
with mock.patch("certbot.compat.misc.select.select") as mock_select:
mock_select.return_value = ([stdin], [], [],)
self.assertEqual(self._call(prompt), expected)
+2 -3
View File
@@ -8,14 +8,13 @@ import unittest
import mock
import six
from acme import messages
from acme.magic_typing import Optional # pylint: disable=unused-import, no-name-in-module
from certbot import compat
from certbot import constants
from certbot import errors
from certbot import util
from certbot.compat import misc
from certbot.tests import util as test_util
@@ -261,7 +260,7 @@ class TempHandlerTest(unittest.TestCase):
def test_permissions(self):
self.assertTrue(
util.check_permissions(self.handler.path, 0o600, compat.os_geteuid()))
util.check_permissions(self.handler.path, 0o600, misc.os_geteuid()))
def test_delete(self):
self.handler.close()
+11 -12
View File
@@ -3,42 +3,41 @@
# pylint: disable=too-many-lines
from __future__ import print_function
import datetime
import itertools
import json
import mock
import os
import shutil
import sys
import tempfile
import traceback
import unittest
import datetime
import pytz
import tempfile
import sys
import josepy as jose
import mock
import pytz
import six
from six.moves import reload_module # pylint: disable=import-error
from acme.magic_typing import List # pylint: disable=unused-import, no-name-in-module
import certbot.tests.util as test_util
from certbot import account
from certbot import cli
from certbot import compat
from certbot import constants
from certbot import configuration
from certbot import constants
from certbot import crypto_util
from certbot import errors
from certbot import interfaces # pylint: disable=unused-import
from certbot import main
from certbot import updater
from certbot import util
from certbot.compat import misc
from certbot.plugins import disco
from certbot.plugins import enhancements
from certbot.plugins import manual
from certbot.plugins import null
import certbot.tests.util as test_util
CERT_PATH = test_util.vector_path('cert_512.pem')
CERT = test_util.vector_path('cert_512.pem')
CSR = test_util.vector_path('csr_512.der')
@@ -1587,7 +1586,7 @@ class MakeOrVerifyNeededDirs(test_util.ConfigTestCase):
for core_dir in (self.config.config_dir, self.config.work_dir,):
mock_util.set_up_core_dir.assert_any_call(
core_dir, constants.CONFIG_DIRS_MODE,
compat.os_geteuid(), self.config.strict_permissions
misc.os_geteuid(), self.config.strict_permissions
)
hook_dirs = (self.config.renewal_pre_hooks_dir,
@@ -1596,7 +1595,7 @@ class MakeOrVerifyNeededDirs(test_util.ConfigTestCase):
for hook_dir in hook_dirs:
# default mode of 755 is used
mock_util.make_or_verify_dir.assert_any_call(
hook_dir, uid=compat.os_geteuid(),
hook_dir, uid=misc.os_geteuid(),
strict=self.config.strict_permissions)
+1 -2
View File
@@ -10,7 +10,6 @@ import mock
import six
from certbot import errors
from certbot.tests import util as test_util
@@ -356,7 +355,7 @@ class TestFullCheckpointsReverter(test_util.ConfigTestCase):
self.assertRaises(
errors.ReverterError, self.reverter.finalize_checkpoint, "Title")
@mock.patch("certbot.reverter.compat.os_rename")
@mock.patch("certbot.reverter.misc.os_rename")
def test_finalize_checkpoint_no_rename_directory(self, mock_rename):
self.reverter.add_to_checkpoint(self.sets[0], "perm save")
+8 -10
View File
@@ -12,12 +12,10 @@ import pytz
import six
import certbot
from certbot import compat
from certbot import errors
from certbot.storage import ALL_FOUR
import certbot.tests.util as test_util
from certbot import errors
from certbot.compat import misc
from certbot.storage import ALL_FOUR
CERT = test_util.load_cert('cert_512.pem')
@@ -572,21 +570,21 @@ class RenewableCertTests(BaseRenewableCertTest):
for kind in ALL_FOUR:
self._write_out_kind(kind, 1)
self.test_rc.update_all_links_to(1)
self.assertTrue(compat.compare_file_modes(
self.assertTrue(misc.compare_file_modes(
os.stat(self.test_rc.version("privkey", 1)).st_mode, 0o600))
os.chmod(self.test_rc.version("privkey", 1), 0o444)
# If no new key, permissions should be the same (we didn't write any keys)
self.test_rc.save_successor(1, b"newcert", None, b"new chain", self.config)
self.assertTrue(compat.compare_file_modes(
self.assertTrue(misc.compare_file_modes(
os.stat(self.test_rc.version("privkey", 2)).st_mode, 0o444))
# If new key, permissions should be kept as 644
self.test_rc.save_successor(2, b"newcert", b"new_privkey", b"new chain", self.config)
self.assertTrue(compat.compare_file_modes(
self.assertTrue(misc.compare_file_modes(
os.stat(self.test_rc.version("privkey", 3)).st_mode, 0o644))
# If permissions reverted, next renewal will also revert permissions of new key
os.chmod(self.test_rc.version("privkey", 3), 0o400)
self.test_rc.save_successor(3, b"newcert", b"new_privkey", b"new chain", self.config)
self.assertTrue(compat.compare_file_modes(
self.assertTrue(misc.compare_file_modes(
os.stat(self.test_rc.version("privkey", 4)).st_mode, 0o600))
@test_util.broken_on_windows
@@ -624,7 +622,7 @@ class RenewableCertTests(BaseRenewableCertTest):
self.config.live_dir, "README")))
self.assertTrue(os.path.exists(os.path.join(
self.config.live_dir, "the-lineage.com", "README")))
self.assertTrue(compat.compare_file_modes(os.stat(result.key_path).st_mode, 0o600))
self.assertTrue(misc.compare_file_modes(os.stat(result.key_path).st_mode, 0o600))
with open(result.fullchain, "rb") as f:
self.assertEqual(f.read(), b"cert" + b"chain")
# Let's do it again and make sure it makes a different lineage
+10 -10
View File
@@ -8,9 +8,9 @@ import mock
import six
from six.moves import reload_module # pylint: disable=import-error
from certbot import compat
from certbot import errors
import certbot.tests.util as test_util
from certbot import errors
from certbot.compat import misc
class RunScriptTest(unittest.TestCase):
@@ -119,7 +119,7 @@ class SetUpCoreDirTest(test_util.TempDirTestCase):
@mock.patch('certbot.util.lock_dir_until_exit')
def test_success(self, mock_lock):
new_dir = os.path.join(self.tempdir, 'new')
self._call(new_dir, 0o700, compat.os_geteuid(), False)
self._call(new_dir, 0o700, misc.os_geteuid(), False)
self.assertTrue(os.path.exists(new_dir))
self.assertEqual(mock_lock.call_count, 1)
@@ -127,7 +127,7 @@ class SetUpCoreDirTest(test_util.TempDirTestCase):
def test_failure(self, mock_make_or_verify):
mock_make_or_verify.side_effect = OSError
self.assertRaises(errors.Error, self._call,
self.tempdir, 0o700, compat.os_geteuid(), False)
self.tempdir, 0o700, misc.os_geteuid(), False)
class MakeOrVerifyDirTest(test_util.TempDirTestCase):
@@ -144,7 +144,7 @@ class MakeOrVerifyDirTest(test_util.TempDirTestCase):
self.path = os.path.join(self.tempdir, "foo")
os.mkdir(self.path, 0o600)
self.uid = compat.os_geteuid()
self.uid = misc.os_geteuid()
def _call(self, directory, mode):
from certbot.util import make_or_verify_dir
@@ -154,11 +154,11 @@ class MakeOrVerifyDirTest(test_util.TempDirTestCase):
path = os.path.join(self.tempdir, "bar")
self._call(path, 0o650)
self.assertTrue(os.path.isdir(path))
self.assertTrue(compat.compare_file_modes(os.stat(path).st_mode, 0o650))
self.assertTrue(misc.compare_file_modes(os.stat(path).st_mode, 0o650))
def test_existing_correct_mode_does_not_fail(self):
self._call(self.path, 0o600)
self.assertTrue(compat.compare_file_modes(os.stat(self.path).st_mode, 0o600))
self.assertTrue(misc.compare_file_modes(os.stat(self.path).st_mode, 0o600))
@test_util.skip_on_windows('Umask modes are mostly ignored on Windows.')
def test_existing_wrong_mode_fails(self):
@@ -181,7 +181,7 @@ class CheckPermissionsTest(test_util.TempDirTestCase):
def setUp(self):
super(CheckPermissionsTest, self).setUp()
self.uid = compat.os_geteuid()
self.uid = misc.os_geteuid()
def _call(self, mode):
from certbot.util import check_permissions
@@ -223,8 +223,8 @@ class UniqueFileTest(test_util.TempDirTestCase):
def test_right_mode(self):
fd1, name1 = self._call(0o700)
fd2, name2 = self._call(0o600)
self.assertTrue(compat.compare_file_modes(0o700, os.stat(name1).st_mode))
self.assertTrue(compat.compare_file_modes(0o600, os.stat(name2).st_mode))
self.assertTrue(misc.compare_file_modes(0o700, os.stat(name1).st_mode))
self.assertTrue(misc.compare_file_modes(0o600, os.stat(name2).st_mode))
fd1.close()
fd2.close()
+4 -5
View File
@@ -10,20 +10,19 @@ import logging
import os
import platform
import re
import six
import socket
import subprocess
from collections import OrderedDict
import configargparse
import six
from acme.magic_typing import Tuple, Union # pylint: disable=unused-import, no-name-in-module
from certbot import compat
from certbot import constants
from certbot import errors
from certbot import lock
from certbot.compat import misc
logger = logging.getLogger(__name__)
@@ -204,7 +203,7 @@ def check_permissions(filepath, mode, uid=0):
"""
file_stat = os.stat(filepath)
return compat.compare_file_modes(file_stat.st_mode, mode) and file_stat.st_uid == uid
return misc.compare_file_modes(file_stat.st_mode, mode) and file_stat.st_uid == uid
def safe_open(path, mode="w", chmod=None, buffering=None):