-require 'locator'
-
class Arvados::V1::CollectionsController < ApplicationController
def create
# Collections are owned by system_user. Creating a collection has
}
resource_attrs[:manifest_text].lines.each do |entry|
entry.split[1..-1].each do |tok|
- # TODO(twp): fail the request if this match fails.
- # Add in Phase 4 (see #2755)
+ # TODO(twp): in Phase 4, fail the request if the locator
+ # lacks a permission signature. (see #2755)
loc = Locator.parse(tok)
if loc and loc.signature
if !api_token
# Remove any permission signatures from the manifest.
resource_attrs[:manifest_text]
- .gsub!(/[[:xdigit:]]{32}(\+[[:digit:]]+)?(\+\S+)/) { |word|
+ .gsub!(/ [[:xdigit:]]{32}(\+[[:digit:]]+)?(\+\S+)/) { |word|
loc = Locator.parse(word)
if loc
- loc.without_signature.to_s
+ " " + loc.without_signature.to_s
else
word
end
ttl: Rails.configuration.blob_signing_ttl,
}
@object[:manifest_text]
- .gsub!(/[[:xdigit:]]{32}(\+[[:digit:]]+)?(\+\S+)/) { |word|
+ .gsub!(/ [[:xdigit:]]{32}(\+[[:digit:]]+)?(\+\S+)/) { |word|
loc = Locator.parse(word)
if loc
- Blob.sign_locator(word, signing_opts)
+ " " + Blob.sign_locator(word, signing_opts)
else
word
end
--- /dev/null
+# A Locator is used to parse and manipulate Keep locator strings.
+#
+# Locators obey the following syntax:
+#
+# locator ::= address hint*
+# address ::= digest size-hint
+# digest ::= <32 hexadecimal digits>
+# size-hint ::= "+" [0-9]+
+# hint ::= "+" hint-type hint-content
+# hint-type ::= [A-Z]
+# hint-content ::= [A-Za-z0-9@_-]+
+#
+# Individual hints may have their own required format:
+#
+# sign-hint ::= "+A" <40 lowercase hex digits> "@" sign-timestamp
+# sign-timestamp ::= <8 lowercase hex digits>
+
+class Locator
+ def initialize(hasharg, sizearg, hintarg)
+ @hash = hasharg
+ @size = sizearg
+ @hints = hintarg
+ end
+
+ # Locator.parse returns a Locator object parsed from the string tok.
+ # Returns nil if tok could not be parsed as a valid locator.
+ def self.parse(tok)
+ begin
+ Locator.parse!(tok)
+ rescue ArgumentError => e
+ nil
+ end
+ end
+
+ # Locator.parse! returns a Locator object parsed from the string tok,
+ # raising an ArgumentError if tok cannot be parsed.
+ def self.parse!(tok)
+ m = /^([[:xdigit:]]{32})(\+([[:digit:]]+))?(\+([[:upper:]][[:alnum:]+@_-]*))?$/.match(tok.strip)
+ unless m
+ raise ArgumentError.new "could not parse #{tok}"
+ end
+
+ tokhash, _, toksize, _, trailer = m[1..5]
+ tokhints = []
+ if trailer
+ trailer.split('+').each do |hint|
+ if hint =~ /^[[:upper:]][[:alnum:]@_-]+$/
+ tokhints.push(hint)
+ else
+ raise ArgumentError.new "unknown hint #{hint}"
+ end
+ end
+ end
+
+ Locator.new(tokhash, toksize, tokhints)
+ end
+
+ # Returns the signature hint supplied with this locator,
+ # or nil if the locator was not signed.
+ def signature
+ @hints.grep(/^A/).first
+ end
+
+ # Returns an unsigned Locator.
+ def without_signature
+ Locator.new(@hash, @size, @hints.reject { |o| o.start_with?("A") })
+ end
+
+ def hash
+ @hash
+ end
+
+ def size
+ @size
+ end
+
+ def hints
+ @hints
+ end
+
+ def to_s
+ [ @hash, @size, *@hints ].join('+')
+ end
+end
#git_repositories_dir: /var/cache/git
#git_internal_dir: /var/cache/arvados/internal.git
- # Amount of time (in seconds) for which a blob permission signature
- # remains valid. Default: 2 weeks (1209600 seconds)
- #blob_signing_ttl: 1209600
+++ /dev/null
-class Locator
- # This regex will match a word that appears to be a locator.
- @@pattern = %r![[:xdigit:]]{32}(\+[[:digit:]]+)?(\+\S+)?!
-
- def initialize(hasharg, sizearg, optarg)
- @hash = hasharg
- @size = sizearg
- @options = optarg
- end
-
- def self.parse(tok)
- Locator.parse!(tok) rescue nil
- end
-
- def self.parse!(tok)
- m = /^([[:xdigit:]]{32})(\+([[:digit:]]+))?(\+.*)?$/.match(tok)
- unless m
- raise ArgumentError.new "could not parse #{tok}"
- end
-
- tokhash, _, toksize, trailer = m[1..4]
- tokopts = []
- while m = /^\+[[:upper:]][^\s+]+/.match(trailer)
- opt = m.to_s
- if opt =~ /^\+A[[:xdigit:]]+@[[:xdigit:]]{8}$/ or
- opt =~ /\+K@[[:alnum:]]+$/
- tokopts.push(opt)
- trailer = m.post_match
- else
- raise ArgumentError.new "unknown option #{opt}"
- end
- end
- if trailer and !trailer.empty?
- raise ArgumentError.new "unrecognized trailing chars #{trailer}"
- end
-
- Locator.new(tokhash, toksize, tokopts)
- end
-
- def signature
- @options.grep(/^\+A/).first
- end
-
- def without_signature
- Locator.new(@hash, @size, @options.reject { |o| o.start_with?("+A") })
- end
-
- def hash
- @hash
- end
-
- def size
- @size
- end
-
- def options
- @options
- end
-
- def to_s
- [ @hash + "+", @size, *@options].join
- end
-end