1 class Arvados::V1::CollectionsController < ApplicationController
3 owner_uuid = resource_attrs.delete(:owner_uuid) || current_user.uuid
4 unless current_user.can? write: owner_uuid
5 logger.warn "User #{current_user.andand.uuid} tried to set collection owner_uuid to #{owner_uuid}"
6 raise ArvadosModel::PermissionDeniedError
9 # Check permissions on the collection manifest.
10 # If any signature cannot be verified, return 403 Permission denied.
11 api_token = current_api_client_authorization.andand.api_token
13 key: Rails.configuration.blob_signing_key,
15 ttl: Rails.configuration.blob_signing_ttl,
17 resource_attrs[:manifest_text].lines.each do |entry|
18 entry.split[1..-1].each do |tok|
19 if /^[[:digit:]]+:[[:digit:]]+:/.match tok
20 # This is a filename token, not a blob locator. Note that we
21 # keep checking tokens after this, even though manifest
22 # format dictates that all subsequent tokens will also be
23 # filenames. Safety first!
24 elsif Blob.verify_signature tok, signing_opts
26 elsif Locator.parse(tok).andand.signature
27 # Signature provided, but verify_signature did not like it.
28 logger.warn "Invalid signature on locator #{tok}"
29 raise ArvadosModel::PermissionDeniedError
30 elsif Rails.configuration.permit_create_collection_with_unsigned_manifest
31 # No signature provided, but we are running in insecure mode.
32 logger.debug "Missing signature on locator #{tok} ignored"
33 elsif Blob.new(tok).empty?
34 # No signature provided -- but no data to protect, either.
36 logger.warn "Missing signature on locator #{tok}"
37 raise ArvadosModel::PermissionDeniedError
42 # Remove any permission signatures from the manifest.
43 resource_attrs[:manifest_text]
44 .gsub!(/ [[:xdigit:]]{32}(\+[[:digit:]]+)?(\+\S+)/) { |word|
46 loc = Locator.parse(word)
48 " " + loc.without_signature.to_s
54 # Save the collection with the stripped manifest.
55 @object = model_class.new resource_attrs
61 if current_api_client_authorization
63 key: Rails.configuration.blob_signing_key,
64 api_token: current_api_client_authorization.api_token,
65 ttl: Rails.configuration.blob_signing_ttl,
67 @object[:manifest_text]
68 .gsub!(/ [[:xdigit:]]{32}(\+[[:digit:]]+)?(\+\S+)/) { |word|
70 loc = Locator.parse(word)
72 " " + Blob.sign_locator(word, signing_opts)
78 render json: @object.as_api_response(:with_data)
81 def script_param_edges(visited, sp)
85 script_param_edges(visited, v)
89 script_param_edges(visited, v)
93 m = stripped_portable_data_hash(sp)
95 generate_provenance_edges(visited, m)
100 def generate_provenance_edges(visited, uuid)
101 m = stripped_portable_data_hash(uuid)
104 if not uuid or uuid.empty? or visited[uuid]
108 logger.debug "visiting #{uuid}"
111 # uuid is a collection
112 Collection.readable_by(current_user).where(portable_data_hash: uuid).each do |c|
113 visited[uuid] = c.as_api_response
114 visited[uuid][:files] = []
116 visited[uuid][:files] << f
120 Job.readable_by(current_user).where(output: uuid).each do |job|
121 generate_provenance_edges(visited, job.uuid)
124 Job.readable_by(current_user).where(log: uuid).each do |job|
125 generate_provenance_edges(visited, job.uuid)
129 # uuid is something else
130 rsc = ArvadosModel::resource_class_for_uuid uuid
132 Job.readable_by(current_user).where(uuid: uuid).each do |job|
133 visited[uuid] = job.as_api_response
134 script_param_edges(visited, job.script_parameters)
137 rsc.where(uuid: uuid).each do |r|
138 visited[uuid] = r.as_api_response
143 Link.readable_by(current_user).
144 where(head_uuid: uuid, link_class: "provenance").
146 visited[link.uuid] = link.as_api_response
147 generate_provenance_edges(visited, link.tail_uuid)
153 generate_provenance_edges(visited, @object[:uuid])
157 def generate_used_by_edges(visited, uuid)
158 m = stripped_portable_data_hash(uuid)
161 if not uuid or uuid.empty? or visited[uuid]
165 logger.debug "visiting #{uuid}"
168 # uuid is a collection
169 Collection.readable_by(current_user).where(portable_data_hash: uuid).each do |c|
170 visited[uuid] = c.as_api_response
171 visited[uuid][:files] = []
173 visited[uuid][:files] << f
177 if uuid == "d41d8cd98f00b204e9800998ecf8427e+0"
178 # special case for empty collection
182 Job.readable_by(current_user).where(["jobs.script_parameters like ?", "%#{uuid}%"]).each do |job|
183 generate_used_by_edges(visited, job.uuid)
187 # uuid is something else
188 rsc = ArvadosModel::resource_class_for_uuid uuid
190 Job.readable_by(current_user).where(uuid: uuid).each do |job|
191 visited[uuid] = job.as_api_response
192 generate_used_by_edges(visited, job.output)
195 rsc.where(uuid: uuid).each do |r|
196 visited[uuid] = r.as_api_response
201 Link.readable_by(current_user).
202 where(tail_uuid: uuid, link_class: "provenance").
204 visited[link.uuid] = link.as_api_response
205 generate_used_by_edges(visited, link.head_uuid)
211 generate_used_by_edges(visited, @object[:uuid])