uploads_controller_spec.rb 18.3 KB
Newer Older
1
require 'spec_helper'
2
3
4
5
6
shared_examples 'content not cached without revalidation' do
  it 'ensures content will not be cached without revalidation' do
    expect(subject['Cache-Control']).to eq('max-age=0, private, must-revalidate')
  end
end
7
8

describe UploadsController do
9
  let!(:user) { create(:user, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
10

11
12
13
  describe 'POST create' do
    let(:model)   { 'personal_snippet' }
    let(:snippet) { create(:personal_snippet, :public) }
14
15
    let(:jpg)     { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
    let(:txt)     { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
16
17
18
19
20

    context 'when a user does not have permissions to upload a file' do
      it "returns 401 when the user is not logged in" do
        post :create, model: model, id: snippet.id, format: :json

21
        expect(response).to have_gitlab_http_status(401)
22
23
24
25
26
27
28
29
      end

      it "returns 404 when user can't comment on a snippet" do
        private_snippet = create(:personal_snippet, :private)

        sign_in(user)
        post :create, model: model, id: private_snippet.id, format: :json

30
        expect(response).to have_gitlab_http_status(404)
31
32
33
34
35
36
37
38
39
40
41
      end
    end

    context 'when a user is logged in' do
      before do
        sign_in(user)
      end

      it "returns an error without file" do
        post :create, model: model, id: snippet.id, format: :json

42
        expect(response).to have_gitlab_http_status(422)
43
44
45
46
47
48
49
50
51
52
      end

      it "returns an error with invalid model" do
        expect { post :create, model: 'invalid', id: snippet.id, format: :json }
        .to raise_error(ActionController::UrlGenerationError)
      end

      it "returns 404 status when object not found" do
        post :create, model: model, id: 9999, format: :json

53
        expect(response).to have_gitlab_http_status(404)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
      end

      context 'with valid image' do
        before do
          post :create, model: 'personal_snippet', id: snippet.id, file: jpg, format: :json
        end

        it 'returns a content with original filename, new link, and correct type.' do
          expect(response.body).to match '\"alt\":\"rails_sample\"'
          expect(response.body).to match "\"url\":\"/uploads"
        end

        it 'creates a corresponding Upload record' do
          upload = Upload.last

          aggregate_failures do
            expect(upload).to exist
            expect(upload.model).to eq snippet
          end
        end
      end

      context 'with valid non-image file' do
        before do
          post :create, model: 'personal_snippet', id: snippet.id, file: txt, format: :json
        end

        it 'returns a content with original filename, new link, and correct type.' do
          expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
          expect(response.body).to match "\"url\":\"/uploads"
        end

        it 'creates a corresponding Upload record' do
          upload = Upload.last

          aggregate_failures do
            expect(upload).to exist
            expect(upload.model).to eq snippet
          end
        end
      end
95
96
97
98
99
100
101
102
103
104

      context 'temporal with valid image' do
        subject do
          post :create, model: 'personal_snippet', file: jpg, format: :json
        end

        it 'returns a content with original filename, new link, and correct type.' do
          subject

          expect(response.body).to match '\"alt\":\"rails_sample\"'
105
          expect(response.body).to match "\"url\":\"/uploads/-/system/temp"
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
        end

        it 'does not create an Upload record' do
          expect { subject }.not_to change { Upload.count }
        end
      end

      context 'temporal with valid non-image file' do
        subject do
          post :create, model: 'personal_snippet', file: txt, format: :json
        end

        it 'returns a content with original filename, new link, and correct type.' do
          subject

          expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
122
          expect(response.body).to match "\"url\":\"/uploads/-/system/temp"
123
124
125
126
127
128
        end

        it 'does not create an Upload record' do
          expect { subject }.not_to change { Upload.count }
        end
      end
129
130
131
    end
  end

132
  describe "GET show" do
133
    context 'Content-Disposition security measures' do
134
      let(:project) { create(:project, :public) }
135
136
137
138

      context 'for PNG files' do
        it 'returns Content-Disposition: inline' do
          note = create(:note, :with_attachment, project: project)
139
          get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png'
140
141
142
143
144
145
146
147

          expect(response['Content-Disposition']).to start_with('inline;')
        end
      end

      context 'for SVG files' do
        it 'returns Content-Disposition: attachment' do
          note = create(:note, :with_svg_attachment, project: project)
148
          get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'unsanitized.svg'
149
150
151
152
153
154

          expect(response['Content-Disposition']).to start_with('attachment;')
        end
      end
    end

155
156
157
158
159
160
161
162
163
164
165
166
    context "when viewing a user avatar" do
      context "when signed in" do
        before do
          sign_in(user)
        end

        context "when the user is blocked" do
          before do
            user.block
          end

          it "redirects to the sign in page" do
167
            get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png"
168
169
170
171
172
173
174

            expect(response).to redirect_to(new_user_session_path)
          end
        end

        context "when the user isn't blocked" do
          it "responds with status 200" do
175
            get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png"
176

177
            expect(response).to have_gitlab_http_status(200)
178
          end
179
180
181

          it_behaves_like 'content not cached without revalidation' do
            subject do
182
              get :show, model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png'
183

184
185
186
              response
            end
          end
187
188
        end
      end
Felipe Artur's avatar
Felipe Artur committed
189

190
191
      context "when not signed in" do
        it "responds with status 200" do
192
          get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png"
193

194
          expect(response).to have_gitlab_http_status(200)
195
        end
196
197
198

        it_behaves_like 'content not cached without revalidation' do
          subject do
199
            get :show, model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png'
200

201
202
203
            response
          end
        end
204
205
206
207
      end
    end

    context "when viewing a project avatar" do
208
      let!(:project) { create(:project, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
209
210
211
212
213
214
215
216

      context "when the project is public" do
        before do
          project.update_attribute(:visibility_level, Project::PUBLIC)
        end

        context "when not signed in" do
          it "responds with status 200" do
217
            get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png"
218

219
            expect(response).to have_gitlab_http_status(200)
220
          end
221
222
223

          it_behaves_like 'content not cached without revalidation' do
            subject do
224
              get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'dk.png'
225

226
227
228
              response
            end
          end
229
230
231
232
233
234
235
236
        end

        context "when signed in" do
          before do
            sign_in(user)
          end

          it "responds with status 200" do
237
            get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png"
238

239
            expect(response).to have_gitlab_http_status(200)
240
          end
241
242
243

          it_behaves_like 'content not cached without revalidation' do
            subject do
244
              get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'dk.png'
245

246
247
248
              response
            end
          end
249
250
251
252
253
254
255
256
257
258
        end
      end

      context "when the project is private" do
        before do
          project.update_attribute(:visibility_level, Project::PRIVATE)
        end

        context "when not signed in" do
          it "redirects to the sign in page" do
259
            get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png"
260
261
262
263
264
265
266
267
268
269
270
271

            expect(response).to redirect_to(new_user_session_path)
          end
        end

        context "when signed in" do
          before do
            sign_in(user)
          end

          context "when the user has access to the project" do
            before do
272
              project.add_maintainer(user)
273
274
275
276
277
            end

            context "when the user is blocked" do
              before do
                user.block
278
                project.add_maintainer(user)
279
280
281
              end

              it "redirects to the sign in page" do
282
                get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png"
283
284
285
286
287
288
289

                expect(response).to redirect_to(new_user_session_path)
              end
            end

            context "when the user isn't blocked" do
              it "responds with status 200" do
290
                get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png"
291

292
                expect(response).to have_gitlab_http_status(200)
293
              end
294
295
296

              it_behaves_like 'content not cached without revalidation' do
                subject do
297
                  get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'dk.png'
298

299
300
301
                  response
                end
              end
302
303
304
305
306
            end
          end

          context "when the user doesn't have access to the project" do
            it "responds with status 404" do
307
              get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png"
308

309
              expect(response).to have_gitlab_http_status(404)
310
311
312
313
314
315
316
            end
          end
        end
      end
    end

    context "when viewing a group avatar" do
317
      let!(:group)   { create(:group, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
318

Douwe Maan's avatar
Douwe Maan committed
319
      context "when the group is public" do
320
321
        context "when not signed in" do
          it "responds with status 200" do
322
            get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png"
323

324
            expect(response).to have_gitlab_http_status(200)
325
          end
326
327
328

          it_behaves_like 'content not cached without revalidation' do
            subject do
329
              get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'dk.png'
330

331
332
333
              response
            end
          end
334
335
336
337
338
339
340
341
        end

        context "when signed in" do
          before do
            sign_in(user)
          end

          it "responds with status 200" do
342
            get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png"
343

344
            expect(response).to have_gitlab_http_status(200)
345
          end
346
347
348

          it_behaves_like 'content not cached without revalidation' do
            subject do
349
              get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'dk.png'
350

351
352
353
              response
            end
          end
354
355
356
        end
      end

Douwe Maan's avatar
Douwe Maan committed
357
      context "when the group is private" do
Douwe Maan's avatar
Douwe Maan committed
358
359
360
361
        before do
          group.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
        end

362
363
364
365
366
367
368
        context "when signed in" do
          before do
            sign_in(user)
          end

          context "when the user has access to the project" do
            before do
Douwe Maan's avatar
Douwe Maan committed
369
              group.add_developer(user)
370
371
372
373
374
375
376
377
            end

            context "when the user is blocked" do
              before do
                user.block
              end

              it "redirects to the sign in page" do
378
                get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png"
379
380
381
382
383
384
385

                expect(response).to redirect_to(new_user_session_path)
              end
            end

            context "when the user isn't blocked" do
              it "responds with status 200" do
386
                get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png"
387

388
                expect(response).to have_gitlab_http_status(200)
389
              end
390
391
392

              it_behaves_like 'content not cached without revalidation' do
                subject do
393
                  get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'dk.png'
394

395
396
397
                  response
                end
              end
398
399
400
401
402
            end
          end

          context "when the user doesn't have access to the project" do
            it "responds with status 404" do
403
              get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png"
404

405
              expect(response).to have_gitlab_http_status(404)
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
            end
          end
        end
      end
    end

    context "when viewing a note attachment" do
      let!(:note) { create(:note, :with_attachment) }
      let(:project) { note.project }

      context "when the project is public" do
        before do
          project.update_attribute(:visibility_level, Project::PUBLIC)
        end

        context "when not signed in" do
          it "responds with status 200" do
423
            get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png"
424

425
            expect(response).to have_gitlab_http_status(200)
426
          end
427
428
429

          it_behaves_like 'content not cached without revalidation' do
            subject do
430
              get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png'
431

432
433
434
              response
            end
          end
435
436
437
438
439
440
441
442
        end

        context "when signed in" do
          before do
            sign_in(user)
          end

          it "responds with status 200" do
443
            get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png"
444

445
            expect(response).to have_gitlab_http_status(200)
446
          end
447
448
449

          it_behaves_like 'content not cached without revalidation' do
            subject do
450
              get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png'
451

452
453
454
              response
            end
          end
455
456
457
458
459
460
461
462
463
464
        end
      end

      context "when the project is private" do
        before do
          project.update_attribute(:visibility_level, Project::PRIVATE)
        end

        context "when not signed in" do
          it "redirects to the sign in page" do
465
            get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png"
466
467
468
469
470
471
472
473
474
475
476
477

            expect(response).to redirect_to(new_user_session_path)
          end
        end

        context "when signed in" do
          before do
            sign_in(user)
          end

          context "when the user has access to the project" do
            before do
478
              project.add_maintainer(user)
479
480
481
482
483
            end

            context "when the user is blocked" do
              before do
                user.block
484
                project.add_maintainer(user)
485
486
487
              end

              it "redirects to the sign in page" do
488
                get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png"
489
490
491
492
493
494
495

                expect(response).to redirect_to(new_user_session_path)
              end
            end

            context "when the user isn't blocked" do
              it "responds with status 200" do
496
                get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png"
497

498
                expect(response).to have_gitlab_http_status(200)
499
              end
500
501
502

              it_behaves_like 'content not cached without revalidation' do
                subject do
503
                  get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png'
504

505
506
507
                  response
                end
              end
508
509
510
511
512
            end
          end

          context "when the user doesn't have access to the project" do
            it "responds with status 404" do
513
              get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png"
514

515
              expect(response).to have_gitlab_http_status(404)
516
517
518
519
520
            end
          end
        end
      end
    end
521
522
523

    context 'Appearance' do
      context 'when viewing a custom header logo' do
524
        let!(:appearance) { create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png', 'image/png') }
525
526
527
528
529

        context 'when not signed in' do
          it 'responds with status 200' do
            get :show, model: 'appearance', mounted_as: 'header_logo', id: appearance.id, filename: 'dk.png'

530
            expect(response).to have_gitlab_http_status(200)
531
532
533
534
535
          end

          it_behaves_like 'content not cached without revalidation' do
            subject do
              get :show, model: 'appearance', mounted_as: 'header_logo', id: appearance.id, filename: 'dk.png'
536

537
538
539
540
541
542
543
              response
            end
          end
        end
      end

      context 'when viewing a custom logo' do
544
        let!(:appearance) { create :appearance, logo: fixture_file_upload('spec/fixtures/dk.png', 'image/png') }
545
546
547
548
549

        context 'when not signed in' do
          it 'responds with status 200' do
            get :show, model: 'appearance', mounted_as: 'logo', id: appearance.id, filename: 'dk.png'

550
            expect(response).to have_gitlab_http_status(200)
551
552
553
554
555
          end

          it_behaves_like 'content not cached without revalidation' do
            subject do
              get :show, model: 'appearance', mounted_as: 'logo', id: appearance.id, filename: 'dk.png'
556

557
558
559
560
561
562
              response
            end
          end
        end
      end
    end
563

564
    context 'original filename or a version filename must match' do
565
      let!(:appearance) { create :appearance, favicon: fixture_file_upload('spec/fixtures/dk.png', 'image/png') }
566

567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
      context 'has a valid filename on the original file' do
        it 'successfully returns the file' do
          get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'dk.png'

          expect(response).to have_gitlab_http_status(200)
          expect(response.header['Content-Disposition']).to end_with 'filename="dk.png"'
        end
      end

      context 'has an invalid filename on the original file' do
        it 'returns a 404' do
          get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'bogus.png'

          expect(response).to have_gitlab_http_status(404)
        end
      end
583
    end
584
585
  end
end