Passed
Push — master ( a70b7c...7d482a )
by James
21:49 queued 11:38
created

app/Http/Controllers/AttachmentController.php (1 issue)

Severity
1
<?php
2
/**
3
 * AttachmentController.php
4
 * Copyright (c) 2017 [email protected]
5
 *
6
 * This file is part of Firefly III.
7
 *
8
 * Firefly III is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * Firefly III is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
20
 */
21
declare(strict_types=1);
22
23
namespace FireflyIII\Http\Controllers;
24
25
use FireflyIII\Exceptions\FireflyException;
26
use FireflyIII\Http\Requests\AttachmentFormRequest;
27
use FireflyIII\Models\Attachment;
28
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
29
use Illuminate\Http\RedirectResponse;
30
use Illuminate\Http\Request;
31
use Illuminate\Http\Response as LaravelResponse;
32
33
/**
34
 * Class AttachmentController.
35
 *
36
 */
37
class AttachmentController extends Controller
38
{
39
    /** @var AttachmentRepositoryInterface Attachment repository */
40
    private $repository;
41
42
    /**
43
     * AttachmentController constructor.
44
     */
45
    public function __construct()
46
    {
47
        parent::__construct();
48
49
        // translations:
50
        $this->middleware(
51
            function ($request, $next) {
52
                app('view')->share('mainTitleIcon', 'fa-paperclip');
53
                app('view')->share('title', (string)trans('firefly.attachments'));
54
                $this->repository = app(AttachmentRepositoryInterface::class);
55
56
                return $next($request);
57
            }
58
        );
59
    }
60
61
    /**
62
     * Form to delete an attachment.
63
     *
64
     * @param Attachment $attachment
65
     *
66
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
67
     */
68
    public function delete(Attachment $attachment)
69
    {
70
        $subTitle = (string)trans('firefly.delete_attachment', ['name' => $attachment->filename]);
71
72
        // put previous url in session
73
        $this->rememberPreviousUri('attachments.delete.uri');
74
75
        return view('attachments.delete', compact('attachment', 'subTitle'));
76
    }
77
78
    /**
79
     * Destroy attachment.
80
     *
81
     * @param Request $request
82
     * @param Attachment $attachment
83
     *
84
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
85
     */
86
    public function destroy(Request $request, Attachment $attachment)
87
    {
88
        $name = $attachment->filename;
89
90
        $this->repository->destroy($attachment);
91
92
        $request->session()->flash('success', (string)trans('firefly.attachment_deleted', ['name' => $name]));
93
        app('preferences')->mark();
94
95
        return redirect($this->getPreviousUri('attachments.delete.uri'));
96
    }
97
98
    /**
99
     * Download attachment to PC.
100
     *
101
     * @param Attachment $attachment
102
     *
103
     * @return mixed
104
     *
105
     * @throws FireflyException
106
     */
107
    public function download(Attachment $attachment)
108
    {
109
        if ($this->repository->exists($attachment)) {
110
            $content = $this->repository->getContent($attachment);
111
            $quoted  = sprintf('"%s"', addcslashes(basename($attachment->filename), '"\\'));
112
113
            /** @var LaravelResponse $response */
114
            $response = response($content);
115
            $response
116
                ->header('Content-Description', 'File Transfer')
117
                ->header('Content-Type', 'application/octet-stream')
118
                ->header('Content-Disposition', 'attachment; filename=' . $quoted)
119
                ->header('Content-Transfer-Encoding', 'binary')
120
                ->header('Connection', 'Keep-Alive')
121
                ->header('Expires', '0')
122
                ->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
123
                ->header('Pragma', 'public')
124
                ->header('Content-Length', \strlen($content));
125
126
            return $response;
127
        }
128
        throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
129
    }
130
131
    /**
132
     * Edit an attachment.
133
     *
134
     * @param Request $request
135
     * @param Attachment $attachment
136
     *
137
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
138
     */
139
    public function edit(Request $request, Attachment $attachment)
140
    {
141
        $subTitleIcon = 'fa-pencil';
142
        $subTitle     = (string)trans('firefly.edit_attachment', ['name' => $attachment->filename]);
143
144
        // put previous url in session if not redirect from store (not "return_to_edit").
145
        if (true !== session('attachments.edit.fromUpdate')) {
146
            $this->rememberPreviousUri('attachments.edit.uri');
147
        }
148
        $request->session()->forget('attachments.edit.fromUpdate');
149
        $preFilled = [
150
            'notes' => $this->repository->getNoteText($attachment),
151
        ];
152
        $request->session()->flash('preFilled', $preFilled);
153
154
        return view('attachments.edit', compact('attachment', 'subTitleIcon', 'subTitle'));
155
    }
156
157
    /**
158
     * Index of all attachments.
159
     *
160
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
161
     */
162
    public function index()
163
    {
164
        $set = $this->repository->get()->reverse();
165
        $set = $set->each(
166
            function (Attachment $attachment) {
167
                $attachment->file_exists = $this->repository->exists($attachment);
168
169
                return $attachment;
170
            }
171
        );
172
173
174
        return view('attachments.index', compact('set'));
175
    }
176
177
    /**
178
     * Update attachment.
179
     *
180
     * @param AttachmentFormRequest $request
181
     * @param Attachment $attachment
182
     *
183
     * @return RedirectResponse
184
     */
185
    public function update(AttachmentFormRequest $request, Attachment $attachment): RedirectResponse
186
    {
187
        $data = $request->getAttachmentData();
188
        $this->repository->update($attachment, $data);
189
190
        $request->session()->flash('success', (string)trans('firefly.attachment_updated', ['name' => $attachment->filename]));
191
        app('preferences')->mark();
192
193
        $redirect = redirect($this->getPreviousUri('attachments.edit.uri'));
194
        if (1 === (int)$request->get('return_to_edit')) {
195
            // @codeCoverageIgnoreStart
196
            $request->session()->put('attachments.edit.fromUpdate', true);
197
198
            $redirect = redirect(route('attachments.edit', [$attachment->id]))->withInput(['return_to_edit' => 1]);
199
            // @codeCoverageIgnoreEnd
200
        }
201
202
        // redirect to previous URL.
203
        return $redirect;
204
    }
205
206
    /**
207
     * View attachment in browser.
208
     *
209
     * @param Attachment $attachment
210
     *
211
     * @return LaravelResponse
212
     * @throws FireflyException
213
     */
214
    public function view(Request $request, Attachment $attachment): LaravelResponse
0 ignored issues
show
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

214
    public function view(/** @scrutinizer ignore-unused */ Request $request, Attachment $attachment): LaravelResponse

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
215
    {
216
        if ($this->repository->exists($attachment)) {
217
            $content = $this->repository->getContent($attachment);
218
219
            // prevent XSS by adding a new secure header.
220
            $csp = [
221
                "default-src 'none'",
222
                "object-src 'none'",
223
                "script-src 'none'",
224
                "style-src 'none'",
225
                "base-uri 'none'",
226
                "font-src 'none'",
227
                "connect-src 'none'",
228
                "img-src 'none'",
229
                "manifest-src 'none'",
230
            ];
231
232
            return response()->make(
233
                $content, 200, [
234
                            'Content-Security-Policy' => implode('; ', $csp),
235
                            'Content-Type'        => $attachment->mime,
236
                            'Content-Disposition' => 'inline; filename="' . $attachment->filename . '"',
237
                        ]
238
            );
239
        }
240
        throw new FireflyException('Could not find the indicated attachment. The file is no longer there.');
241
    }
242
}
243