Skip to content

Commit

Permalink
Merge "tools.py: add file_mode_checker()"
Browse files Browse the repository at this point in the history
  • Loading branch information
jenkins-bot authored and Gerrit Code Review committed Sep 14, 2016
2 parents 8200a24 + 35095fa commit 2d2d51b
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 23 deletions.
17 changes: 2 additions & 15 deletions pywikibot/comms/http.py
Expand Up @@ -23,8 +23,6 @@
__docformat__ = 'epytext'

import atexit
import os
import stat
import sys

from distutils.version import StrictVersion
Expand Down Expand Up @@ -56,6 +54,7 @@
from pywikibot.logging import critical, debug, error, log, warning
from pywikibot.tools import (
deprecate_arg,
file_mode_checker,
issue_deprecation_warning,
PY2,
StringTypes,
Expand All @@ -77,18 +76,6 @@
config.socket_timeout = min(config.socket_timeout)


def mode_check(filename):
"""Check if filename has mode 600 and, if not, set it."""
mode_600 = stat.S_IRUSR | stat.S_IWUSR
warn_str = 'File {0} had no {1:o} mode; converted to {1:o} mode'
st_mode = os.stat(filename).st_mode
if stat.S_ISREG(st_mode) and (st_mode - stat.S_IFREG != mode_600):
os.chmod(filename, mode_600)
# re-read and check changes
if os.stat(filename).st_mode != st_mode:
pywikibot.warning(warn_str.format(filename, mode_600))


def mode_check_decorator(func):
"""Decorate load()/save() CookieJar methods."""
def wrapper(cls, **kwargs):
Expand All @@ -97,7 +84,7 @@ def wrapper(cls, **kwargs):
except KeyError:
filename = cls.filename
res = func(cls, **kwargs)
mode_check(filename)
file_mode_checker(filename, mode=0o600)
return res
return wrapper

Expand Down
13 changes: 5 additions & 8 deletions pywikibot/login.py
Expand Up @@ -3,7 +3,7 @@
"""Library to log the bot in to a wiki account."""
#
# (C) Rob W.W. Hooft, 2003
# (C) Pywikibot team, 2003-2015
# (C) Pywikibot team, 2003-2016
#
# Distributed under the terms of the MIT license.
#
Expand All @@ -13,9 +13,10 @@
#
import codecs
import os
import stat
import webbrowser

from pywikibot.tools import file_mode_checker

from warnings import warn

try:
Expand Down Expand Up @@ -236,12 +237,8 @@ def readPassword(self):
if not os.path.isfile(password_file):
password_file = config.password_file

# We fix password file permission first,
# lift upper permission (regular file) from st_mode
# to compare it with private_files_permission.
if os.stat(password_file).st_mode - stat.S_IFREG \
!= config.private_files_permission:
os.chmod(password_file, config.private_files_permission)
# We fix password file permission first.
file_mode_checker(password_file, mode=config.private_files_permission)

password_f = codecs.open(password_file, encoding='utf-8')
for line_nr, line in enumerate(password_f):
Expand Down
21 changes: 21 additions & 0 deletions pywikibot/tools/__init__.py
Expand Up @@ -12,7 +12,9 @@
import gzip
import inspect
import itertools
import os
import re
import stat
import subprocess
import sys
import threading
Expand Down Expand Up @@ -168,6 +170,7 @@ def py2_encode_utf_8(func):


class UnicodeMixin(object):

"""Mixin class to add __str__ method in Python 2 or 3."""

@py2_encode_utf_8
Expand Down Expand Up @@ -1666,3 +1669,21 @@ def __getattr__(self, attr):
def open_compressed(filename, use_extension=False):
"""DEPRECATED: Open a file and uncompress it if needed."""
return open_archive(filename, use_extension=use_extension)


def file_mode_checker(filename, mode=0o600):
"""Check file mode and update it, if needed.
@param filename: filename path
@type filename: basestring
@param mode: requested file mode
@type mode: int
"""
warn_str = 'File {0} had {1:o} mode; converted to {2:o} mode.'
st_mode = os.stat(filename).st_mode
if stat.S_ISREG(st_mode) and (st_mode - stat.S_IFREG != mode):
os.chmod(filename, mode)
# re-read and check changes
if os.stat(filename).st_mode != st_mode:
warn(warn_str.format(filename, st_mode - stat.S_IFREG, mode))
49 changes: 49 additions & 0 deletions tests/tools_tests.py
Expand Up @@ -17,12 +17,19 @@
import tempfile
import warnings

try:
import mock
except ImportError as e:
mock = e

from pywikibot import tools

from tests import join_xml_data_path

from tests.aspects import (
unittest, require_modules, DeprecationTestCase, TestCase, MetaTestCaseClass
)

from tests.utils import expected_failure_if, add_metaclass


Expand Down Expand Up @@ -675,6 +682,48 @@ def getargspec(self, method):
return inspect.getargspec(method)


@require_modules('mock')
class TestFileModeChecker(TestCase):

"""Test parsing password files."""

net = False

def patch(self, name):
"""Patch up <name> in self.setUp."""
patcher = mock.patch(name)
self.addCleanup(patcher.stop)
return patcher.start()

def setUp(self):
"""Patch a variety of dependencies."""
super(TestFileModeChecker, self).setUp()
self.stat = self.patch('os.stat')
self.chmod = self.patch('os.chmod')
self.file = '~FakeFile'

def test_auto_chmod_for_dir(self):
"""Do not chmod files that have mode private_files_permission."""
self.stat.return_value.st_mode = 0o040600 # dir
tools.file_mode_checker(self.file, mode=0o600)
self.stat.assert_called_with(self.file)
self.assertFalse(self.chmod.called)

def test_auto_chmod_OK(self):
"""Do not chmod files that have mode private_files_permission."""
self.stat.return_value.st_mode = 0o100600 # regular file
tools.file_mode_checker(self.file, mode=0o600)
self.stat.assert_called_with(self.file)
self.assertFalse(self.chmod.called)

def test_auto_chmod_not_OK(self):
"""Chmod files that do not have mode private_files_permission."""
self.stat.return_value.st_mode = 0o100644 # regular file
tools.file_mode_checker(self.file, mode=0o600)
self.stat.assert_called_with(self.file)
self.chmod.assert_called_once_with(self.file, 0o600)


if __name__ == '__main__': # pragma: no cover
try:
unittest.main()
Expand Down

0 comments on commit 2d2d51b

Please sign in to comment.