-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathmedia_controller.rb
182 lines (147 loc) · 4.49 KB
/
media_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# frozen_string_literal: true
class MediaController < ApplicationController
skip_before_action :authenticate_user!
before_action :set_token_payload
def download
if asset.replacement.present? && (!asset.replacement.draft? || requested_from_draft_assets_host?)
set_default_expiry
redirect_to_replacement_for(asset)
return
end
if redirect_to_draft_assets_host_for?(asset)
redirect_to_draft_assets_host
return
end
unless authorized_for_asset?(asset)
error_403
return
end
unless asset_servable?
error_404
return
end
unless filename_current?
redirect_to_current_filename
return
end
if asset.redirect_url.present?
redirect_to asset.redirect_url
return
end
if temporary_redirect?
perform_temporary_redirect
return
end
if requested_from_draft_assets_host? || requested_from_internal_host?
expires_now
else
set_default_expiry
end
add_link_header(asset)
add_frame_header
proxy_to_s3_via_nginx(asset)
rescue Mongoid::Errors::DocumentNotFound
if (requested_from_draft_assets_host? || requested_from_internal_host?) && !user_signed_in?
authenticate_user!
else
raise
end
end
protected
def has_bypass_id_for_asset?(asset)
return false if @token_payload.nil?
asset.valid_auth_bypass_token?(@token_payload["sub"])
end
def authorized_for_asset?(asset)
return true unless requested_from_draft_assets_host? || requested_from_internal_host?
return true if has_bypass_id_for_asset?(asset)
return true if draft_asset_manager_access? && !asset.access_limited?
authenticate_user!
asset.accessible_by?(current_user)
end
def requested_from_draft_assets_host?
request.host == AssetManager.govuk.draft_assets_host
end
def requested_from_internal_host?
request.host == URI.parse(Plek.find("asset-manager")).host
end
def draft_asset_manager_access?
return false if @token_payload.nil?
@token_payload["draft_asset_manager_access"] == true
end
def proxy_to_s3_via_nginx(asset)
headers["ETag"] = %("#{asset.etag}")
headers["Last-Modified"] = asset.last_modified.httpdate
headers["Content-Disposition"] = AssetManager.content_disposition.header_for(asset)
if request.fresh?(response)
head :not_modified
elsif AssetManager.s3.fake?
url = Services.cloud_storage.presigned_url_for(asset, http_method: request.request_method)
redirect_to url
else
url = Services.cloud_storage.presigned_url_for(asset, http_method: request.request_method)
headers["X-Accel-Redirect"] = "/cloud-storage-proxy/#{url}"
head :ok, content_type: content_type(asset)
end
end
def content_type(asset)
asset.content_type || asset.content_type_from_extension
end
def redirect_to_draft_assets_host_for?(asset)
asset.draft? && !requested_from_draft_assets_host? && !requested_from_internal_host?
end
def redirect_to_draft_assets_host
redirect_to host: AssetManager.govuk.draft_assets_host,
format: params[:format],
params: request.query_parameters
end
def redirect_to_replacement_for(asset)
# explicitly use the external asset host
target_host =
if asset.replacement.draft?
AssetManager.govuk.draft_assets_host
else
AssetManager.govuk.assets_host
end
redirect_to "//#{target_host}#{asset.replacement.public_url_path}",
status: :moved_permanently
end
def add_link_header(asset)
if asset.parent_document_url
headers["Link"] = %(<#{asset.parent_document_url}>; rel="up")
end
end
def add_frame_header
headers["X-Frame-Options"] = "DENY"
end
def filename_current?
asset.filename == params[:filename]
end
def asset_servable?
asset.filename_valid?(params[:filename]) &&
asset.uploaded?
end
def asset
@asset ||= Asset.undeleted.find(params[:id])
end
def redirect_to_current_filename
redirect_to(
action: :download,
id: params[:id],
filename: asset.filename,
only_path: true,
)
end
def temporary_redirect?
false
end
def set_token_payload
token = params.fetch(:token, cookies[:auth_bypass_token])
@token_payload = if token
secret = Rails.application.secrets.jwt_auth_secret
JWT.decode(token, secret, true, algorithm: "HS256").first
end
rescue JWT::DecodeError
@token_payload = nil
end
end