Projet

Général

Profil

0003-actesweb-use-atomic_write-32413.patch

Benjamin Dauvergne, 18 avril 2019 12:13

Télécharger (4,79 ko)

Voir les différences:

Subject: [PATCH 3/3] actesweb: use atomic_write (#32413)

 passerelle/apps/actesweb/models.py | 41 ++++++++++++++----------------
 tests/test_actesweb.py             |  9 ++++---
 2 files changed, 24 insertions(+), 26 deletions(-)
passerelle/apps/actesweb/models.py
20 20
import stat
21 21
import tempfile
22 22
import contextlib
23
import errno
23 24

  
25
from django.conf import settings
24 26
from django.core.files.storage import default_storage
25 27
from django.template.loader import get_template
26 28
from django.utils import six
......
32 34
from passerelle.utils.api import endpoint
33 35
from passerelle.utils.jsonresponse import APIError
34 36
from passerelle.utils.conversion import ensure_encoding
37
from passerelle.utils.files import atomic_write
35 38

  
36 39

  
37 40
@contextlib.contextmanager
......
51 54

  
52 55
    @property
53 56
    def basepath(self):
54
        return os.path.join(
57
        path = os.path.join(
55 58
            default_storage.path('actesweb'), self.slug)
59
        if not os.path.exists(path):
60
            try:
61
                os.makedirs(path)
62
            except OSError as e:
63
                if e.errno != errno.EEXIST:
64
                    raise
65
            if settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS:
66
                # user and group must be able to delete/move files, others can read/access
67
                os.chmod(path, 0o775)
68
        return path
56 69

  
57 70
    @endpoint(perm='can_access', methods=['post'], description=_('Create demand'))
58 71
    def create(self, request, *args, **kwargs):
......
67 80
        template_name = 'actesweb/demand.txt'
68 81
        demand_content = get_template(template_name).render(payload)
69 82
        application_id = payload['application_id']
70
        # create tmp dir
71
        tmp_dir = os.path.join(self.basepath, 'tmp')
72
        if not os.path.exists(tmp_dir):
73
            if default_storage.directory_permissions_mode:
74
                d_umask = os.umask(0)
75
                try:
76
                    os.makedirs(tmp_dir, mode=default_storage.directory_permissions_mode)
77
                except OSError:
78
                    pass
79
                finally:
80
                    os.umask(d_umask)
81
            else:
82
                os.makedirs(tmp_dir)
83 83

  
84 84
        # ensure demand_content can be encoded to latin15
85 85
        demand_content = ensure_encoding(demand_content, 'iso-8859-15')
86 86

  
87 87
        filename = '%s.DEM' % now().strftime('%Y-%m-%d_%H-%M-%S_%f')
88 88
        filepath = os.path.join(self.basepath, filename)
89
        with named_tempfile(dir=tmp_dir, suffix='.DEM', delete=False) as tpf:
90
            tpf.write(demand_content)
91
            tpf.flush()
92
            os.fsync(tpf.file.fileno())
93
            tempfile_name = tpf.name
94
        os.rename(tempfile_name, filepath)
95
        # set read only permission for owner and group
96
        os.chmod(filepath, stat.S_IRUSR|stat.S_IRGRP|stat.S_IWGRP)
89
        tmp_dir = os.path.join(self.basepath, 'tmp')
90
        with atomic_write(filepath, dir=tmp_dir) as fd:
91
            fd.write(demand_content.encode('iso-8859-15'))
92
        # user can read/write, group can read, others can't
93
        os.chmod(filepath, 0o640)
97 94
        demand_id = '%s_%s' % (application_id, os.path.basename(filepath))
98 95
        return {'data': {'demand_id': demand_id}}
tests/test_actesweb.py
158 158
        response = app.post_json(url, params=payload['death'])
159 159
        demand_id = response.json['data']['demand_id']
160 160
        demfile = get_demand_filepath(actesweb, demand_id)
161
        # make sure only owner can read file
161
        # make sure only owner and group can read file, others can't
162 162
        assert bool(os.stat(demfile).st_mode & stat.S_IRUSR)
163
        # make sure group can read and write (move) file
164 163
        assert bool(os.stat(demfile).st_mode & stat.S_IRGRP)
165
        assert bool(os.stat(demfile).st_mode & stat.S_IWGRP)
166
        # and no others
167 164
        assert not bool(os.stat(demfile).st_mode & stat.S_IRWXO)
165
        # make sure group can delete/move file
166
        assert bool(os.stat(os.path.dirname(demfile)).st_mode & stat.S_IWGRP)
167
        # and no others
168
        assert not bool(os.stat(os.path.dirname(demfile)).st_mode & stat.S_IWOTH)
168 169
        assert_file_content_values(
169 170
            demfile, dict(
170 171
                DEMANDEUR_CIVILITE="Madame",
171
-