azure-storage-common-2.0.1/0000755000177000017700000000000013753762266014651 5ustar avronavronazure-storage-common-2.0.1/azure-storage-common.gemspec0000644000177000017700000001270113753762266022275 0ustar avronavron######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: azure-storage-common 2.0.1 ruby lib Gem::Specification.new do |s| s.name = "azure-storage-common".freeze s.version = "2.0.1" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Microsoft Corporation".freeze] s.date = "2020-03-10" s.description = "Microsoft Azure Storage Common Client Library for Ruby".freeze s.email = "ascl@microsoft.com".freeze s.files = ["./lib/azure/core.rb".freeze, "./lib/azure/http_response_helper.rb".freeze, "./lib/azure/storage/common.rb".freeze, "lib/azure/core/auth/authorizer.rb".freeze, "lib/azure/core/auth/shared_key.rb".freeze, "lib/azure/core/auth/shared_key_lite.rb".freeze, "lib/azure/core/auth/signer.rb".freeze, "lib/azure/core/default.rb".freeze, "lib/azure/core/error.rb".freeze, "lib/azure/core/filtered_service.rb".freeze, "lib/azure/core/http/debug_filter.rb".freeze, "lib/azure/core/http/http_error.rb".freeze, "lib/azure/core/http/http_filter.rb".freeze, "lib/azure/core/http/http_request.rb".freeze, "lib/azure/core/http/http_response.rb".freeze, "lib/azure/core/http/retry_policy.rb".freeze, "lib/azure/core/http/signer_filter.rb".freeze, "lib/azure/core/service.rb".freeze, "lib/azure/core/signed_service.rb".freeze, "lib/azure/core/utility.rb".freeze, "lib/azure/core/version.rb".freeze, "lib/azure/storage/common/autoload.rb".freeze, "lib/azure/storage/common/client.rb".freeze, "lib/azure/storage/common/client_options.rb".freeze, "lib/azure/storage/common/client_options_error.rb".freeze, "lib/azure/storage/common/configurable.rb".freeze, "lib/azure/storage/common/core.rb".freeze, "lib/azure/storage/common/core/auth/anonymous_signer.rb".freeze, "lib/azure/storage/common/core/auth/shared_access_signature.rb".freeze, "lib/azure/storage/common/core/auth/shared_access_signature_generator.rb".freeze, "lib/azure/storage/common/core/auth/shared_access_signature_signer.rb".freeze, "lib/azure/storage/common/core/auth/shared_key.rb".freeze, "lib/azure/storage/common/core/auth/token_signer.rb".freeze, "lib/azure/storage/common/core/autoload.rb".freeze, "lib/azure/storage/common/core/error.rb".freeze, "lib/azure/storage/common/core/filter/exponential_retry_filter.rb".freeze, "lib/azure/storage/common/core/filter/linear_retry_filter.rb".freeze, "lib/azure/storage/common/core/filter/retry_filter.rb".freeze, "lib/azure/storage/common/core/http_client.rb".freeze, "lib/azure/storage/common/core/sr.rb".freeze, "lib/azure/storage/common/core/token_credential.rb".freeze, "lib/azure/storage/common/core/utility.rb".freeze, "lib/azure/storage/common/default.rb".freeze, "lib/azure/storage/common/service/access_policy.rb".freeze, "lib/azure/storage/common/service/cors.rb".freeze, "lib/azure/storage/common/service/cors_rule.rb".freeze, "lib/azure/storage/common/service/enumeration_results.rb".freeze, "lib/azure/storage/common/service/geo_replication.rb".freeze, "lib/azure/storage/common/service/logging.rb".freeze, "lib/azure/storage/common/service/metrics.rb".freeze, "lib/azure/storage/common/service/retention_policy.rb".freeze, "lib/azure/storage/common/service/serialization.rb".freeze, "lib/azure/storage/common/service/signed_identifier.rb".freeze, "lib/azure/storage/common/service/storage_service.rb".freeze, "lib/azure/storage/common/service/storage_service_properties.rb".freeze, "lib/azure/storage/common/service/storage_service_stats.rb".freeze, "lib/azure/storage/common/service/user_delegation_key.rb".freeze, "lib/azure/storage/common/version.rb".freeze] s.homepage = "http://github.com/azure/azure-storage-ruby".freeze s.licenses = ["MIT".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) s.rubygems_version = "3.2.0.rc.1".freeze s.summary = "Official Ruby client library to consume Azure Storage Common service".freeze if s.respond_to? :specification_version then s.specification_version = 4 end if s.respond_to? :add_runtime_dependency then s.add_development_dependency(%q.freeze, ["~> 1.11"]) s.add_development_dependency(%q.freeze, ["~> 2.0"]) s.add_runtime_dependency(%q.freeze, ["~> 1.0"]) s.add_runtime_dependency(%q.freeze, ["~> 1.0.0.rc1"]) s.add_development_dependency(%q.freeze, ["~> 5"]) s.add_development_dependency(%q.freeze, ["~> 1"]) s.add_development_dependency(%q.freeze, ["~> 1.0"]) s.add_runtime_dependency(%q.freeze, ["~> 1.10.4"]) s.add_development_dependency(%q.freeze, ["~> 13.0"]) s.add_development_dependency(%q.freeze, ["~> 0.7"]) s.add_development_dependency(%q.freeze, ["~> 0.9", ">= 0.9.11"]) else s.add_dependency(%q.freeze, ["~> 1.11"]) s.add_dependency(%q.freeze, ["~> 2.0"]) s.add_dependency(%q.freeze, ["~> 1.0"]) s.add_dependency(%q.freeze, ["~> 1.0.0.rc1"]) s.add_dependency(%q.freeze, ["~> 5"]) s.add_dependency(%q.freeze, ["~> 1"]) s.add_dependency(%q.freeze, ["~> 1.0"]) s.add_dependency(%q.freeze, ["~> 1.10.4"]) s.add_dependency(%q.freeze, ["~> 13.0"]) s.add_dependency(%q.freeze, ["~> 0.7"]) s.add_dependency(%q.freeze, ["~> 0.9", ">= 0.9.11"]) end end azure-storage-common-2.0.1/lib/0000755000177000017700000000000013753762266015417 5ustar avronavronazure-storage-common-2.0.1/lib/azure/0000755000177000017700000000000013753762266016545 5ustar avronavronazure-storage-common-2.0.1/lib/azure/core/0000755000177000017700000000000013753762266017475 5ustar avronavronazure-storage-common-2.0.1/lib/azure/core/default.rb0000644000177000017700000000167213753762266021454 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module Core module Default # Default User Agent header string USER_AGENT = "Azure-Core/#{Azure::Core::Version}".freeze end end end azure-storage-common-2.0.1/lib/azure/core/error.rb0000644000177000017700000000171713753762266021161 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module Core # Superclass for errors generated from this library, so people can # just rescue this for generic error handling class Error < StandardError;end end end azure-storage-common-2.0.1/lib/azure/core/auth/0000755000177000017700000000000013753762266020436 5ustar avronavronazure-storage-common-2.0.1/lib/azure/core/auth/signer.rb0000644000177000017700000000332513753762266022255 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'openssl' require 'base64' module Azure module Core module Auth # Utility class to sign strings with HMAC-256 and then encode the # signed string using Base64. class Signer # The access key for the account attr :access_key # Initialize the Signer. # # @param access_key [String] The access_key encoded in Base64. def initialize(access_key) if access_key.nil? raise ArgumentError, 'Signing key must be provided' end @access_key = Base64.decode64(access_key) end # Generate an HMAC signature. # # @param body [String] The string to sign. # # @return [String] a Base64 String signed with HMAC. def sign(body) signed = OpenSSL::HMAC.digest('sha256', access_key, body) Base64.strict_encode64(signed) end end end end end azure-storage-common-2.0.1/lib/azure/core/auth/authorizer.rb0000644000177000017700000000266113753762266023164 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/configuration" module Azure module Core module Auth class Authorizer # Public: Signs an HTTP request before it's made, by adding the # Authorization header # # request - An Azure::Core::HttpRequest that hasn't been signed # signer - A signing strategy, such as Azure::Table::Auth::SharedKey # # Returns the modified request def sign(request, signer) signature = signer.sign(request.method, request.uri, request.headers) request.headers['Authorization'] = "#{signer.name} #{signature}" request end end end end end azure-storage-common-2.0.1/lib/azure/core/auth/shared_key_lite.rb0000644000177000017700000000335613753762266024125 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/auth/shared_key" module Azure module Core module Auth class SharedKeyLite < SharedKey # The name of the strategy. # # @return [String] def name 'SharedKeyLite' end # Generate the string to sign. # # @param method [Symbol] The HTTP request method. # @param uri [URI] The URI of the request we're signing. # @param headers [Hash] A Hash of HTTP request headers. # # Returns a plain text string. def signable_string(method, uri, headers) [ method.to_s.upcase, headers.fetch('Content-MD5', ''), headers.fetch('Content-Type', ''), headers.fetch('Date') { raise IndexError, 'Headers must include Date' }, canonicalized_headers(headers), canonicalized_resource(uri) ].join("\n") end end end end end azure-storage-common-2.0.1/lib/azure/core/auth/shared_key.rb0000644000177000017700000001153413753762266023105 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'cgi' require 'azure/core/auth/signer' module Azure module Core module Auth class SharedKey < Signer # The Azure account's name. attr :account_name # Initialize the Signer. # # @param account_name [String] The account name. Defaults to the one in the # global configuration. # @param access_key [String] The access_key encoded in Base64. Defaults to the # one in the global configuration. def initialize(account_name=Azure.storage_account_name, access_key=Azure.storage_access_key) @account_name = account_name super(access_key) end # The name of the strategy. # # @return [String] def name 'SharedKey' end # Create the signature for the request parameters # # @param method [Symbol] HTTP request method. # @param uri [URI] URI of the request we're signing. # @param headers [Hash] HTTP request headers. # # @return [String] base64 encoded signature def sign(method, uri, headers) "#{account_name}:#{super(signable_string(method, uri, headers))}" end # Sign the request # # @param req [Azure::Core::Http::HttpRequest] HTTP request to sign # # @return [Azure::Core::Http::HttpRequest] def sign_request(req) # Need to make sure Content-Length is correctly set. if ((!req.body.nil?)) then if (req.body.respond_to? :bytesize) then req.headers['Content-Length'] = req.body.bytesize.to_s elsif (req.body.respond_to? :size) req.headers['Content-Length'] = req.body.size.to_s end end req.headers['Authorization'] = "#{name} #{sign(req.method, req.uri, req.headers)}" req end # Generate the string to sign. # # @param method [Symbol] HTTP request method. # @param uri [URI] URI of the request we're signing. # @param headers [Hash] HTTP request headers. # # @return [String] def signable_string(method, uri, headers) [ method.to_s.upcase, headers.fetch('Content-Encoding', ''), headers.fetch('Content-Language', ''), headers.fetch('Content-Length', ''), headers.fetch('Content-MD5', ''), headers.fetch('Content-Type', ''), headers.fetch('Date', ''), headers.fetch('If-Modified-Since', ''), headers.fetch('If-Match', ''), headers.fetch('If-None-Match', ''), headers.fetch('If-Unmodified-Since', ''), headers.fetch('Range', ''), canonicalized_headers(headers), canonicalized_resource(uri) ].join("\n") end # Calculate the Canonicalized Headers string for a request. # # @param headers [Hash] HTTP request headers. # # @return [String] a string with the canonicalized headers. def canonicalized_headers(headers) headers = headers.map { |k,v| [k.to_s.downcase, v] } headers.select! { |k,_| k =~ /^x-ms-/ } headers.sort_by! { |(k,_)| k } headers.map! { |k,v| '%s:%s' % [k, v] }.join("\n") end # Calculate the Canonicalized Resource string for a request. # # @param uri [URI] URI of the request we're signing. # # @return [String] a string with the canonicalized resource. def canonicalized_resource(uri) resource = '/' + account_name + (uri.path.empty? ? '/' : uri.path) params = CGI.parse(uri.query.to_s).map { |k,v| [k.downcase, v] } params.sort_by! { |k,_| k } params.map! { |k,v| '%s:%s' % [k, v.map(&:strip).sort.join(',')] } [resource, *params].join("\n") end end end end end azure-storage-common-2.0.1/lib/azure/core/signed_service.rb0000644000177000017700000000370413753762266023017 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/filtered_service' require 'azure/core/http/signer_filter' require 'azure/core/auth/shared_key' module Azure module Core # A base class for Service implementations class SignedService < FilteredService # Create a new instance of the SignedService # # @param signer [Azure::Core::Auth::Signer]. An implementation of Signer used for signing requests. (optional, Default=Azure::Core::Auth::SharedKey.new) # @param account_name [String] The account name (optional, Default=Azure.config.storage_account_name) # @param options [Hash] options def initialize(signer=nil, account_name=nil, options={}) super('', options) signer ||= Core::Auth::SharedKey.new(client.storage_account_name, client.storage_access_key) @account_name = account_name || client.storage_account_name @signer = signer filters.unshift Core::Http::SignerFilter.new(signer) if signer end attr_accessor :account_name attr_accessor :signer def call(method, uri, body=nil, headers=nil, options={}) super(method, uri, body, headers, options) end end end endazure-storage-common-2.0.1/lib/azure/core/utility.rb0000644000177000017700000001370313753762266021531 0ustar avronavron#------------------------------------------------------------------------- # Copyright 2013 Microsoft Open Technologies, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'ipaddr' if RUBY_VERSION.to_f < 2.0 begin require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32|mingw32/ rescue LoadError puts 'WARNING: Output will look weird on Windows unless'\ ' you install the "win32console" gem.' end end module Azure module Error # Azure Error class Error < Azure::Core::Error attr_reader :description attr_reader :status_code attr_reader :type def initialize(type, status, description) @type = type @status_code = status @description = description super("#{type} (#{status_code}): #{description}") end end end module Core module Utility def random_string(str = 'azure', no_of_char = 5) str + (0...no_of_char).map { ('a'..'z').to_a[rand(26)] }.join end def xml_content(xml, key, default = '') content = default node = xml.at_css(key) content = node.text if node content end def locate_file(name) if File.exist? name name elsif File.exist?(File.join(ENV['HOME'], name)) File.join(ENV['HOME'], name) else Azure::Loggerx.error_with_exit "Unable to find #{name} file " end end def export_der(cert, key, pass = nil, name = nil) pkcs12 = OpenSSL::PKCS12.create(pass, name, key, cert) Base64.encode64(pkcs12.to_der) rescue Exception => e puts e.message abort end def export_fingerprint(certificate) Digest::SHA1.hexdigest(certificate.to_der) end def enable_winrm?(winrm_transport) (!winrm_transport.nil? && (winrm_transport.select { |x| x.downcase == 'http' || x.downcase == 'https' }.size > 0)) end def get_certificate(private_key_file) rsa = OpenSSL::PKey.read File.read(private_key_file) cert = OpenSSL::X509::Certificate.new cert.version = 2 cert.serial = 0 name = OpenSSL::X509::Name.new([['CN', 'Azure Management Certificate']]) cert.subject = cert.issuer = name cert.not_before = Time.now cert.not_after = cert.not_before + (60*60*24*365) cert.public_key = rsa.public_key cert.sign(rsa, OpenSSL::Digest::SHA1.new) cert end def initialize_external_logger(logger) Loggerx.initialize_external_logger(logger) end end # Logger module Logger class << self attr_accessor :logger def info(msg) if logger.nil? puts msg.bold.white else logger.info(msg) end end def error_with_exit(msg) if logger.nil? puts msg.bold.red else logger.error(msg) end raise msg.bold.red end def warn(msg) if logger.nil? puts msg.yellow else logger.warn(msg) end msg end def error(msg) if logger.nil? puts msg.bold.red else logger.error(msg) end msg end def exception_message(msg) if logger.nil? puts msg.bold.red else logger.warn(msg) end raise msg.bold.red end def success(msg) msg_with_new_line = msg + "\n" if logger.nil? print msg_with_new_line.green else logger.info(msg) end end def initialize_external_logger(logger) @logger = logger end end end end end class String { reset: 0, bold: 1, dark: 2, underline: 4, blink: 5, orange: 6, negative: 7, black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37, }.each do |key, value| define_method key do "\e[#{value}m" + self + "\e[0m" end end end # Code validate private/public IP acceptable ranges. class IPAddr PRIVATE_RANGES = [ IPAddr.new('10.0.0.0/8'), IPAddr.new('172.16.0.0/12'), IPAddr.new('192.168.0.0/16') ] def private? return false unless self.ipv4? PRIVATE_RANGES.each do |ipr| return true if ipr.include?(self) end false end def public? !private? end class << self def validate_ip_and_prefix(ip, cidr) if cidr.to_s.empty? raise "Cidr is missing for IP '#{ip}'." elsif valid?(ip) raise "Ip address '#{ip}' is invalid." elsif !IPAddr.new(ip).private? raise "Ip Address #{ip} must be private." end end def validate_address_space(ip) if ip.split('/').size != 2 raise "Cidr is invalid for IP #{ip}." elsif valid?(ip) raise "Address space '#{ip}' is invalid." end end def address_prefix(ip, cidr) ip + '/' + cidr.to_s end def valid?(ip) (IPAddr.new(ip) rescue nil).nil? end end end Azure::Loggerx = Azure::Core::Logger azure-storage-common-2.0.1/lib/azure/core/service.rb0000644000177000017700000000331313753762266021462 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/http/http_request' module Azure module Core # A base class for Service implementations class Service # Create a new instance of the Service # # @param host [String] The hostname. (optional, Default empty) # @param options [Hash] options including {:client} (optional, Default {}) def initialize(host='', options = {}) @host = host @client = options[:client] || Azure end attr_accessor :host, :client def call(method, uri, body=nil, headers={}) request = Core::Http::HttpRequest.new(method, uri, body: body, headers: headers, client: @client) yield request if block_given? request.call end def generate_uri(path='', query={}) uri = URI.parse(File.join(host, path)) uri.query = URI.encode_www_form(query) unless query == nil or query.empty? uri end end end endazure-storage-common-2.0.1/lib/azure/core/http/0000755000177000017700000000000013753762266020454 5ustar avronavronazure-storage-common-2.0.1/lib/azure/core/http/http_filter.rb0000644000177000017700000000431713753762266023332 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module Core module Http # A filter which can modify the HTTP pipeline both before and # after requests/responses. Multiple filters can be nested in a # "Russian Doll" model to create a compound HTTP pipeline class HttpFilter # Initialize a HttpFilter # # &block - An inline block which implements the filter. # # The inline block should take parameters |request, _next| where # request is a HttpRequest and _next is an object that implements # a method .call which returns an HttpResponse. The block passed # to the constructor should also return HttpResponse, either as # the result of calling _next.call or by customized logic. # def initialize(&block) @block = block end # Executes the filter # # request - HttpRequest. The request # _next - An object that implements .call (no params) # # NOTE: _next is a either a subsequent HttpFilter wrapped in a # closure, or the HttpRequest object's call method. Either way, # it must have it's .call method executed within each filter to # complete the pipeline. _next.call should return an HttpResponse # and so should this Filter. def call(request, _next) @block ? @block.call(request, _next) : _next.call end end end end endazure-storage-common-2.0.1/lib/azure/core/http/retry_policy.rb0000644000177000017700000000627513753762266023537 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/http/http_filter" module Azure module Core module Http # A HttpFilter implementation that handles retrying based on a # specific policy when HTTP layer errors occur class RetryPolicy < HttpFilter def initialize(&block) @block = block @retry_data = {} end attr_accessor :retry_data # Overrides the base class implementation of call to implement # a retry loop that uses should_retry? to determine when to # break the loop # # req - HttpRequest. The HTTP request # _next - HttpFilter. The next filter in the pipeline def call(req, _next) response = nil retry_data = @retry_data.dup begin # URI could change in the retry, e.g. secondary endpoint unless retry_data[:uri].nil? req.uri = retry_data[:uri] end retry_data[:error] = nil response = _next.call rescue retry_data[:error] = $! end while should_retry?(response, retry_data) # Assign the error when HTTP error is not thrown from the previous filter retry_data[:error] = response.error if response && !response.success? if retry_data[:error].nil? response else raise retry_data[:error] end end # Determines if the HTTP request should continue retrying # # response - HttpResponse. The response from the active request # retry_data - Hash. Stores stateful retry data # # The retry_data is a Hash which can be used to store # stateful data about the request execution context (such as an # incrementing counter, timestamp, etc). The retry_data object # will be the same instance throughout the lifetime of the request. # # If an inline block was passed to the constructor, that block # will be used here and should return true to retry the job, or # false to stop exit. If an inline block was not passed to the # constructor the method returns false. # # Alternatively, a subclass could override this method. def should_retry?(response, retry_data) @block ? @block.call(response, retry_data) : false end end end end end azure-storage-common-2.0.1/lib/azure/core/http/http_error.rb0000644000177000017700000001163413753762266023176 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/error' require 'nokogiri' require 'json' module Azure module Core module Http # Public: Class for handling all HTTP response errors class HTTPError < Azure::Core::Error # Public: Detail of the response # # Returns an Azure::Core::Http::HttpResponse object attr :http_response # Public: The request URI # # Returns a String attr :uri # Public: The HTTP status code of this error # # Returns a Fixnum attr :status_code # Public: The type of error # # http://msdn.microsoft.com/en-us/library/azure/dd179357 # # Returns a String attr :type # Public: Description of the error # # Returns a String attr :description # Public: Detail of the error # # Returns a String attr :detail # Public: The header name whose value is invalid # # Returns a String attr :header # Public: The invalid header value # # Returns a String attr :header_value # Public: Initialize an error # # http_response - An Azure::Core::HttpResponse def initialize(http_response) @http_response = http_response @uri = http_response.uri @status_code = http_response.status_code parse_response # Use reason phrase as the description if description is empty @description = http_response.reason_phrase if (@description.nil? || @description.empty?) && http_response.reason_phrase super("#{type} (#{status_code}): #{description}") end # Extract the relevant information from the response's body. If the response # body is not an XML, we return an 'Unknown' error with the entire body as # the description # # Returns nothing def parse_response if @http_response.body && @http_response.respond_to?(:headers) && @http_response.headers['Content-Type'] if @http_response.headers['Content-Type'].include?('xml') parse_xml_response elsif @http_response.headers['Content-Type'].include?('json') parse_json_response end else parse_unknown_response end end def parse_xml_response document = Nokogiri.Slop(@http_response.body) @type = document.css('code').first.text if document.css('code').any? @type = document.css('Code').first.text if document.css('Code').any? @description = document.css('message').first.text if document.css('message').any? @description = document.css('Message').first.text if document.css('Message').any? @header = document.css('headername').first.text if document.css('headername').any? @header = document.css('HeaderName').first.text if document.css('HeaderName').any? @header_value = document.css('headervalue').first.text if document.css('headervalue').any? @header_value = document.css('HeaderValue').first.text if document.css('HeaderValue').any? # service bus uses detail instead of message @detail = document.css('detail').first.text if document.css('detail').any? @detail = document.css('Detail').first.text if document.css('Detail').any? end def parse_json_response odata_error = JSON.parse(@http_response.body)['odata.error'] @type = odata_error['code'] @description = odata_error['message']['value'] end def parse_unknown_response @type = 'Unknown' if @http_response.body @description = "#{@http_response.body.strip}" end end def inspect string = "#<#{self.class.name}:#{self.object_id} " fields = self.instance_variables.map{|field| "#{field}: #{self.send(field.to_s.delete("@")).inspect}"} string << fields.join(", ") << ">" end end end end end azure-storage-common-2.0.1/lib/azure/core/http/http_request.rb0000644000177000017700000001605113753762266023533 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'digest/md5' require 'base64' require 'net/http' require 'time' require 'azure/core/version' require 'azure/core/http/http_response' require 'azure/core/http/retry_policy' require 'azure/core/default' require 'azure/http_response_helper' module Azure module Core module Http # Represents a HTTP request can perform synchronous queries to a # HTTP server, returning a HttpResponse class HttpRequest include Azure::HttpResponseHelper alias_method :_method, :method # The HTTP method to use (:get, :post, :put, :delete, etc...) attr_accessor :method # The URI of the HTTP endpoint to query attr_accessor :uri # The header values as a Hash attr_accessor :headers # The body of the request (IO or String) attr_accessor :body # Azure client which contains configuration context and http agents # @return [Azure::Client] attr_accessor :client # The http filter attr_accessor :has_retry_filter # Public: Create the HttpRequest # # @param method [Symbol] The HTTP method to use (:get, :post, :put, :del, etc...) # @param uri [URI] The URI of the HTTP endpoint to query # @param options_or_body [Hash|IO|String] The request options including {:client, :body} or raw body only def initialize(method, uri, options_or_body = {}) options ||= unless options_or_body.is_a?(Hash) {body: options_or_body} end || options_or_body || {} @method = method @uri = if uri.is_a?(String) URI.parse(uri) else uri end @client = options[:client] || Azure self.headers = default_headers(options[:current_time] || Time.now.httpdate).merge(options[:headers] || {}) self.body = options[:body] end # Public: Applies a HttpFilter to the HTTP Pipeline # # filter - Any object that responds to .call(req, _next) and # returns a HttpResponse eg. HttpFilter, Proc, # lambda, etc. (optional) # # options - The options that are used when call Azure::Core::FilteredService.call. # It can be used by retry policies to determine changes in the retry. # # &block - An inline block may be used instead of a filter # # example: # # request.with_filter do |req, _next| # _next.call # end # # NOTE: # # The code block provided must call _next or the filter pipeline # will not complete and the HTTP request will never execute # def with_filter(filter=nil, options={}, &block) filter = filter || block if filter is_retry_policy = filter.is_a?(Azure::Core::Http::RetryPolicy) filter.retry_data[:request_options] = options if is_retry_policy @has_retry_filter ||= is_retry_policy original_call = self._method(:call) # support 1.8.7 (define_singleton_method doesn't exist until 1.9.1) filter_call = Proc.new do filter.call(self, original_call) end k = class << self; self; end if k.method_defined? :define_singleton_method self.define_singleton_method(:call, filter_call) else k.send(:define_method, :call, filter_call) end end end # Build a default headers Hash def default_headers(current_time) {}.tap do |def_headers| def_headers['User-Agent'] = Azure::Core::Default::USER_AGENT def_headers['x-ms-date'] = current_time def_headers['x-ms-version'] = '2014-02-14' def_headers['DataServiceVersion'] = '1.0;NetFx' def_headers['MaxDataServiceVersion'] = '3.0;NetFx' def_headers['Content-Type'] = 'application/atom+xml; charset=utf-8' end end def http_setup @client.agents(uri) end def body=(body) @body = body apply_body_headers end # Sends request to HTTP server and returns a HttpResponse # # @return [HttpResponse] def call conn = http_setup res = set_up_response(method.to_sym, uri, conn, headers ,body) response = HttpResponse.new(res) response.uri = uri raise response.error if !response.success? && !@has_retry_filter response end private def apply_body_headers return headers['Content-Length'] = '0' unless body return apply_io_headers if IO === body || Tempfile === body return apply_string_io_headers if StringIO === body return apply_miscellaneous_headers end def apply_io_headers headers['Content-Length'] = body.size.to_s if body.respond_to?('size') if headers['Content-Length'].nil? raise ArgumentError, '\'Content-Length\' must be defined if size cannot be obtained from body IO.' end headers['Content-MD5'] = Digest::MD5.file(body.path).base64digest unless headers['Content-MD5'] end def apply_string_io_headers headers['Content-Length'] = body.size.to_s unless headers['Content-MD5'] headers['Content-MD5'] = Digest::MD5.new.tap do |checksum| while chunk = body.read(5242880) checksum << chunk end body.rewind end.base64digest end end def apply_miscellaneous_headers headers['Content-Length'] = body.size.to_s headers['Content-MD5'] = Base64.strict_encode64(Digest::MD5.digest(body.to_s)) unless headers['Content-MD5'] end end end end end azure-storage-common-2.0.1/lib/azure/core/http/debug_filter.rb0000644000177000017700000000301413753762266023432 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require "azure/core/http/http_filter" module Azure module Core module Http # A HttpFilter implementation that displays information about the request and response for debugging class DebugFilter < HttpFilter def call(req, _next) puts "--REQUEST-BEGIN---------------------------" puts "method:", req.method, "uri:", req.uri, "headers:", req.headers, "body:", req.body puts "--REQUEST-END---------------------------" r = _next.call puts "--RESPONSE-BEGIN---------------------------" puts "status_code:", r.status_code, "headers:", r.headers, "body:", r.body puts "--RESPONSE-END---------------------------" r end end end end endazure-storage-common-2.0.1/lib/azure/core/http/signer_filter.rb0000644000177000017700000000230713753762266023637 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/http/http_filter' module Azure module Core module Http # A HttpFilter implementation that creates a authorization signature which is added to the request headers class SignerFilter < HttpFilter def initialize(signer) @signer = signer end def call(req, _next) @signer.sign_request(req) _next.call end end end end end azure-storage-common-2.0.1/lib/azure/core/http/http_response.rb0000644000177000017700000000637613753762266023712 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/http/http_error' module Azure module Core module Http # A small proxy to clean up the API of Net::HTTPResponse. class HttpResponse # Public: Initialize a new response. # # http_response - A Net::HTTPResponse. def initialize(http_response, uri='') @http_response = http_response @uri = uri end attr_accessor :uri # Public: Get the response body. # # Returns a String. def body @http_response.body end # Public: Get the response status code. # # Returns a Fixnum. def status_code @http_response.status end # Public: Get the response reason phrase. # # Returns a String. def reason_phrase @http_response.reason_phrase end # Public: Check if this response was successful. A request is considered # successful if the response is in the 200 - 399 range. # # Returns nil|false. def success? @http_response.success? end # Public: Get all the response headers as a Hash. # # Returns a Hash. def headers @http_response.headers end # Public: Get an error that wraps this HTTP response, as long as this # response was unsuccessful. This method will return nil if the # response was successful. # # Returns an Azure::Core::Http::HTTPError. def exception HTTPError.new(self) unless success? end alias_method :error, :exception # TODO: This needs to be deleted and HttpError needs to be refactored to not rely on HttpResponse. # The dependency on knowing the internal structure of HttpResponse breaks good design principles. # The only reason this class exists is because the HttpError parses the HttpResponse to produce an error msg. class MockResponse def initialize(code, body, headers) @status = code @body = body @headers = headers @headers.each { |k,v| @headers[k] = [v] unless v.respond_to? 'first' } end attr_accessor :status attr_accessor :body attr_accessor :headers def to_hash @headers end end end end end end azure-storage-common-2.0.1/lib/azure/core/version.rb0000644000177000017700000000222213753762266021505 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module Core class Version MAJOR = 0 unless defined? MAJOR MINOR = 2 unless defined? MINOR UPDATE = 0 unless defined? UPDATE PRE = nil unless defined? PRE class << self # @return [String] def to_s [MAJOR, MINOR, UPDATE].join('.') + (PRE.nil? ? '' : "-#{PRE}") end end end end end azure-storage-common-2.0.1/lib/azure/core/filtered_service.rb0000644000177000017700000000316413753762266023344 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'azure/core/service' module Azure module Core # A base class for Service implementations class FilteredService < Service # Create a new instance of the FilteredService # # @param host [String] The hostname. (optional, Default empty) # @param options [Hash] options including {:client} (optional, Default {}) def initialize(host='', options={}) super @filters = [] end attr_accessor :filters def call(method, uri, body=nil, headers=nil, options={}) super(method, uri, body, headers) do |request| filters.reverse.each { |filter| request.with_filter filter, options } if filters end end def with_filter(filter=nil, &block) filter = filter || block filters.push filter if filter end end end endazure-storage-common-2.0.1/lib/azure/core.rb0000644000177000017700000000437613753762266020034 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- require 'rubygems' require 'nokogiri' require 'faraday' require 'faraday_middleware' module Azure module Core autoload :Utility, 'azure/core/utility' autoload :Logger, 'azure/core/utility' autoload :Error, 'azure/core/error' autoload :Service, 'azure/core/service' autoload :FilteredService, 'azure/core/filtered_service' autoload :SignedService, 'azure/core/signed_service' autoload :Default, 'azure/core/default' module Auth autoload :SharedKey, 'azure/core/auth/shared_key' autoload :Signer, 'azure/core/auth/signer' autoload :Authorizer, 'azure/core/auth/authorizer' autoload :SharedKeyLite, 'azure/core/auth/shared_key_lite' end module Http autoload :DebugFilter, 'azure/core/http/debug_filter' autoload :HTTPError, 'azure/core/http/http_error' autoload :HttpFilter, 'azure/core/http/http_filter' autoload :HttpRequest, 'azure/core/http/http_request' autoload :HttpResponse, 'azure/core/http/http_response' autoload :RetryPolicy, 'azure/core/http/retry_policy' autoload :SignerFilter, 'azure/core/http/signer_filter' end end end azure-storage-common-2.0.1/lib/azure/storage/0000755000177000017700000000000013753762266020211 5ustar avronavronazure-storage-common-2.0.1/lib/azure/storage/common.rb0000644000177000017700000000256313753762266022034 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/autoload" azure-storage-common-2.0.1/lib/azure/storage/common/0000755000177000017700000000000013753762266021501 5ustar avronavronazure-storage-common-2.0.1/lib/azure/storage/common/default.rb0000644000177000017700000007134413753762266023463 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "rbconfig" require "azure/storage/common/version" module Azure::Storage::Common module Default # Default REST service (STG) version number. This is used only for SAS generator. STG_VERSION = "2018-11-09" # The number of default concurrent requests for parallel operation. DEFAULT_PARALLEL_OPERATION_THREAD_COUNT = 1 # Constant representing a kilobyte (Non-SI version). KB = 1024 # Constant representing a megabyte (Non-SI version). MB = 1024 * 1024 # Constant representing a gigabyte (Non-SI version). GB = 1024 * 1024 * 1024 # Specifies HTTP. HTTP = "http" # Specifies HTTPS. HTTPS = "https" # Default HTTP port. DEFAULT_HTTP_PORT = 80 # Default HTTPS port. DEFAULT_HTTPS_PORT = 443 # Marker for atom metadata. XML_METADATA_MARKER = "$" # Marker for atom value. XML_VALUE_MARKER = "_" def os host_os = RbConfig::CONFIG["host_os"] case host_os when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ "Windows #{host_os}" when /darwin|mac os/ "MacOS #{host_os}" when /linux/ "Linux #{host_os}" when /solaris|bsd/ "Unix #{host_os}" else "Unknown #{host_os}" end end module_function :os class << self def options Hash[Azure::Storage::Common::Configurable.keys.map { |key| [key, send(key)] }] end # Default storage access key # @return [String] def storage_access_key ENV["AZURE_STORAGE_ACCESS_KEY"] end # Default storage account name # @return [String] def storage_account_name ENV["AZURE_STORAGE_ACCOUNT"] end # Default storage connection string # @return [String] def storage_connection_string ENV["AZURE_STORAGE_CONNECTION_STRING"] end # Default storage shared access signature token # @return [String] def storage_sas_token ENV["AZURE_STORAGE_SAS_TOKEN"] end # Default storage table host # @return [String] def storage_table_host ENV["AZURE_STORAGE_TABLE_HOST"] end # Default storage blob host # @return [String] def storage_blob_host ENV["AZURE_STORAGE_BLOB_HOST"] end # Default storage queue host # @return [String] def storage_queue_host ENV["AZURE_STORAGE_QUEUE_HOST"] end # Default storage file host # @return [String] def storage_file_host ENV["AZURE_STORAGE_FILE_HOST"] end # A placeholder to map with the Azure::Storage::Common::Configurable.keys # @return nil def signer end end end # Service Types module ServiceType BLOB = "blob" QUEUE = "queue" TABLE = "table" FILE = "file" end # Specifies the location mode used to decide which location the request should be sent to. module LocationMode PRIMARY_ONLY = 0 PRIMARY_THEN_SECONDARY = 1 SECONDARY_ONLY = 2 SECONDARY_THEN_PRIMARY = 3 end # Specifies the location used to indicate which location the operation (REST API) can be performed against. # This is determined by the API and cannot be specified by the users. module RequestLocationMode PRIMARY_ONLY = 0 SECONDARY_ONLY = 1 PRIMARY_OR_SECONDARY = 2 end # Represents a storage service location. module StorageLocation PRIMARY = 0 SECONDARY = 1 end # Defines constants for use with shared access policies. module AclConstants # XML element for an access policy. ACCESS_POLICY = "AccessPolicy" # XML element for the end time of an access policy. EXPIRY = "Expiry" # XML attribute for IDs. ID = "Id" # XML element for the permission of an access policy. PERMISSION = "Permission" # XML element for a signed identifier. SIGNED_IDENTIFIER_ELEMENT = "SignedIdentifier" # XML element for signed identifiers. SIGNED_IDENTIFIERS_ELEMENT = "SignedIdentifiers" # XML element for the start time of an access policy. START = "Start" end # Defines constants for use with service properties. module ServicePropertiesConstants # XML element for storage service properties. STORAGE_SERVICE_PROPERTIES_ELEMENT = "StorageServiceProperties" # Default analytics version to send for logging, hour metrics and minute metrics. DEFAULT_ANALYTICS_VERSION = "1.0" # XML element for logging. LOGGING_ELEMENT = "Logging" # XML element for version. VERSION_ELEMENT = "Version" # XML element for delete. DELETE_ELEMENT = "Delete" # XML element for read. READ_ELEMENT = "Read" # XML element for write. WRITE_ELEMENT = "Write" # XML element for retention policy. RETENTION_POLICY_ELEMENT = "RetentionPolicy" # XML element for enabled. ENABLED_ELEMENT = "Enabled" # XML element for days. DAYS_ELEMENT = "Days" # XML element for HourMetrics. HOUR_METRICS_ELEMENT = "HourMetrics" # XML element for MinuteMetrics. MINUTE_METRICS_ELEMENT = "MinuteMetrics" # XML element for Cors. CORS_ELEMENT = "Cors" # XML element for CorsRule. CORS_RULE_ELEMENT = "CorsRule" # XML element for AllowedOrigins. ALLOWED_ORIGINS_ELEMENT = "AllowedOrigins" # XML element for AllowedMethods. ALLOWED_METHODS_ELEMENT = "AllowedMethods" # XML element for MaxAgeInSeconds. MAX_AGE_IN_SECONDS_ELEMENT = "MaxAgeInSeconds" # XML element for ExposedHeaders. EXPOSED_HEADERS_ELEMENT = "ExposedHeaders" # XML element for AllowedHeaders. ALLOWED_HEADERS_ELEMENT = "AllowedHeaders" # XML element for IncludeAPIs. INCLUDE_APIS_ELEMENT = "IncludeAPIs" # XML element for DefaultServiceVersion. DEFAULT_SERVICE_VERSION_ELEMENT = "DefaultServiceVersion" end # Defines constants for use with HTTP headers. module HeaderConstants # The accept ranges header. ACCEPT_RANGES = "accept_ranges" # The content transfer encoding header. CONTENT_TRANSFER_ENCODING = "content-transfer-encoding" # The transfer encoding header. TRANSFER_ENCODING = "transfer-encoding" # The server header. SERVER = "server" # The location header. LOCATION = "location" # The Last-Modified header LAST_MODIFIED = "Last-Modified" # The data service version. DATA_SERVICE_VERSION = "DataServiceVersion" # The maximum data service version. MAX_DATA_SERVICE_VERSION = "maxdataserviceversion" # The master Windows Azure Storage header prefix. PREFIX_FOR_STORAGE = "x-ms-" # The client request Id header. CLIENT_REQUEST_ID = "x-ms-client-request-id" # The header that specifies the approximate message count of a queue. APPROXIMATE_MESSAGES_COUNT = "x-ms-approximate-messages-count" # The Authorization header. AUTHORIZATION = "authorization" # The header that specifies public access to blobs. BLOB_PUBLIC_ACCESS = "x-ms-blob-public-access" # The header for the blob type. BLOB_TYPE = "x-ms-blob-type" # The header for the type. TYPE = "x-ms-type" # Specifies the block blob type. BLOCK_BLOB = "blockblob" # The CacheControl header. CACHE_CONTROL = "cache-control" # The header that specifies blob caching control. BLOB_CACHE_CONTROL = "x-ms-blob-cache-control" # The header that specifies caching control. FILE_CACHE_CONTROL = "x-ms-cache-control" # The copy status. COPY_STATUS = "x-ms-copy-status" # The copy completion time COPY_COMPLETION_TIME = "x-ms-copy-completion-time" # The copy status message COPY_STATUS_DESCRIPTION = "x-ms-copy-status-description" # The copy identifier. COPY_ID = "x-ms-copy-id" # Progress of any copy operation COPY_PROGRESS = "x-ms-copy-progress" # The copy action. COPY_ACTION = "x-ms-copy-action" # The ContentID header. CONTENT_ID = "content-id" # The ContentEncoding header. CONTENT_ENCODING = "content-encoding" # The header that specifies blob content encoding. BLOB_CONTENT_ENCODING = "x-ms-blob-content-encoding" # The header that specifies content encoding. FILE_CONTENT_ENCODING = "x-ms-content-encoding" # The ContentLangauge header. CONTENT_LANGUAGE = "content-language" # The header that specifies blob content language. BLOB_CONTENT_LANGUAGE = "x-ms-blob-content-language" # The header that specifies content language. FILE_CONTENT_LANGUAGE = "x-ms-content-language" # The ContentLength header. CONTENT_LENGTH = "content-length" # The header that specifies blob content length. BLOB_CONTENT_LENGTH = "x-ms-blob-content-length" # The header that specifies content length. FILE_CONTENT_LENGTH = "x-ms-content-length" # The ContentDisposition header. CONTENT_DISPOSITION = "content-disposition" # The header that specifies blob content disposition. BLOB_CONTENT_DISPOSITION = "x-ms-blob-content-disposition" # The header that specifies content disposition. FILE_CONTENT_DISPOSITION = "x-ms-content-disposition" # The ContentMD5 header. CONTENT_MD5 = "content-md5" # The header that specifies blob content MD5. BLOB_CONTENT_MD5 = "x-ms-blob-content-md5" # The header that specifies content MD5. FILE_CONTENT_MD5 = "x-ms-content-md5" # The ContentRange header. CONTENT_RANGE = "cache-range" # The ContentType header. CONTENT_TYPE = "Content-Type" # The header that specifies blob content type. BLOB_CONTENT_TYPE = "x-ms-blob-content-type" # The header that specifies content type. FILE_CONTENT_TYPE = "x-ms-content-type" # The header for copy source. COPY_SOURCE = "x-ms-copy-source" # The header that specifies the date. DATE = "date" # The header that specifies the date. MS_DATE = "x-ms-date" # The header to delete snapshots. DELETE_SNAPSHOT = "x-ms-delete-snapshots" # The ETag header. ETAG = "etag" # The IfMatch header. IF_MATCH = "if-match" # The IfModifiedSince header. IF_MODIFIED_SINCE = "if-modified-since" # The IfNoneMatch header. IF_NONE_MATCH = "if-none-match" # The IfUnmodifiedSince header. IF_UNMODIFIED_SINCE = "if-unmodified-since" # Specifies snapshots are to be included. INCLUDE_SNAPSHOTS_VALUE = "include" # Specifies that the content-type is JSON. JSON_CONTENT_TYPE_VALUE = "application/json" # The header that specifies lease ID. LEASE_ID = "x-ms-lease-id" # The header that specifies the lease break period. LEASE_BREAK_PERIOD = "x-ms-lease-break-period" # The header that specifies the proposed lease identifier. PROPOSED_LEASE_ID = "x-ms-proposed-lease-id" # The header that specifies the lease duration. LEASE_DURATION = "x-ms-lease-duration" # The header that specifies the source lease ID. SOURCE_LEASE_ID = "x-ms-source-lease-id" # The header that specifies lease time. LEASE_TIME = "x-ms-lease-time" # The header that specifies lease status. LEASE_STATUS = "x-ms-lease-status" # The header that specifies lease state. LEASE_STATE = "x-ms-lease-state" # Specifies the page blob type. PAGE_BLOB = "PageBlob" # The header that specifies page write mode. PAGE_WRITE = "x-ms-page-write" # The header that specifies file range write mode. FILE_WRITE = "x-ms-write" # The header that specifies whether the response should include the inserted entity. PREFER = "Prefer" # The header value which specifies that the response should include the inserted entity. PREFER_CONTENT = "return-content" # The header value which specifies that the response should not include the inserted entity. PREFER_NO_CONTENT = "return-no-content" # The header prefix for metadata. PREFIX_FOR_STORAGE_METADATA = "x-ms-meta-" # The header prefix for properties. PREFIX_FOR_STORAGE_PROPERTIES = "x-ms-prop-" # The Range header. RANGE = "Range" # The header that specifies if the request will populate the ContentMD5 header for range gets. RANGE_GET_CONTENT_MD5 = "x-ms-range-get-content-md5" # The format string for specifying ranges. RANGE_HEADER_FORMAT = "bytes:%d-%d" # The header that indicates the request ID. REQUEST_ID = "x-ms-request-id" # The header for specifying the sequence number. SEQUENCE_NUMBER = "x-ms-blob-sequence-number" # The header for specifying the If-Sequence-Number-EQ condition. SEQUENCE_NUMBER_EQUAL = "x-ms-if-sequence-number-eq" # The header for specifying the If-Sequence-Number-LT condition. SEQUENCE_NUMBER_LESS_THAN = "x-ms-if-sequence-number-lt" # The header for specifying the If-Sequence-Number-LE condition. SEQUENCE_NUMBER_LESS_THAN_OR_EQUAL = "x-ms-if-sequence-number-le" # The header that specifies sequence number action. SEQUENCE_NUMBER_ACTION = "x-ms-sequence-number-action" # The header for the blob content length. SIZE = "x-ms-blob-content-length" # The header for snapshots. SNAPSHOT = "x-ms-snapshot" # Specifies only snapshots are to be included. SNAPSHOTS_ONLY_VALUE = "only" # The header for the If-Match condition. SOURCE_IF_MATCH = "x-ms-source-if-match" # The header for the If-Modified-Since condition. SOURCE_IF_MODIFIED_SINCE = "x-ms-source-if-modified-since" # The header for the If-None-Match condition. SOURCE_IF_NONE_MATCH = "x-ms-source-if-none-match" # The header for the If-Unmodified-Since condition. SOURCE_IF_UNMODIFIED_SINCE = "x-ms-source-if-unmodified-since" # The header for data ranges. STORAGE_RANGE = "x-ms-range" # The header for storage version. STORAGE_VERSION = "x-ms-version" # The UserAgent header. USER_AGENT = "user-agent" # The pop receipt header. POP_RECEIPT = "x-ms-popreceipt" # The time next visibile header. TIME_NEXT_VISIBLE = "x-ms-time-next-visible" # The approximate message counter header. APPROXIMATE_MESSAGE_COUNT = "x-ms-approximate-message-count" # The lease action header. LEASE_ACTION = "x-ms-lease-action" # The accept header. ACCEPT = "Accept" # The accept charset header. ACCEPT_CHARSET = "Accept-Charset" # The host header. HOST = "host" # The correlation identifier header. CORRELATION_ID = "x-ms-correlation-id" # The group identifier header. GROUP_ID = "x-ms-group-id" # The share quota header. SHARE_QUOTA = "x-ms-share-quota" # The max blob size header. BLOB_CONDITION_MAX_SIZE = "x-ms-blob-condition-maxsize" # The append blob position header. BLOB_CONDITION_APPEND_POSITION = "x-ms-blob-condition-appendpos" # The append blob append offset header. BLOB_APPEND_OFFSET = "x-ms-blob-append-offset" # The append blob committed block header. BLOB_COMMITTED_BLOCK_COUNT = "x-ms-blob-committed-block-count" # The returned response payload should be with no metadata. ODATA_NO_META = "application/json;odata=nometadata" # The returned response payload should be with minimal metadata. ODATA_MIN_META = "application/json;odata=minimalmetadata" # The returned response payload should be with full metadata. ODATA_FULL_META = "application/json;odata=fullmetadata" # The header for if request has been encrypted at server side. REQUEST_SERVER_ENCRYPTED = "x-ms-request-server-encrypted" # The header for if blob data and application metadata has been encrypted at server side. SERVER_ENCRYPTED = "x-ms-server-encrypted" end module QueryStringConstants # Query component for SAS API version. API_VERSION = "api-version" # The Comp value. COMP = "comp" # The Res Type. RESTYPE = "restype" # The copy Id. COPY_ID = "copyid" # The Snapshot value. SNAPSHOT = "snapshot" # The timeout value. TIMEOUT = "timeout" # The signed start time query string argument for shared access signature. SIGNED_START = "st" # The signed expiry time query string argument for shared access signature. SIGNED_EXPIRY = "se" # The signed resource query string argument for shared access signature. SIGNED_RESOURCE = "sr" # The signed permissions query string argument for shared access signature. SIGNED_PERMISSIONS = "sp" # The signed identifier query string argument for shared access signature. SIGNED_IDENTIFIER = "si" # The signature query string argument for shared access signature. SIGNATURE = "sig" # The signed version argument for shared access signature. SIGNED_VERSION = "sv" # The cache control argument for shared access signature. CACHE_CONTROL = "rscc" # The content type argument for shared access signature. CONTENT_TYPE = "rsct" # The content encoding argument for shared access signature. CONTENT_ENCODING = "rsce" # The content language argument for shared access signature. CONTENT_LANGUAGE = "rscl" # The content disposition argument for shared access signature. CONTENT_DISPOSITION = "rscd" # The block identifier query string argument for blob service. BLOCK_ID = "blockid" # The block list type query string argument for blob service. BLOCK_LIST_TYPE = "blocklisttype" # The prefix query string argument for listing operations. PREFIX = "prefix" # The marker query string argument for listing operations. MARKER = "marker" # The maxresults query string argument for listing operations. MAX_RESULTS = "maxresults" # The delimiter query string argument for listing operations. DELIMITER = "delimiter" # The include query string argument for listing operations. INCLUDE = "include" # The peekonly query string argument for queue service. PEEK_ONLY = "peekonly" # The numofmessages query string argument for queue service. NUM_OF_MESSAGES = "numofmessages" # The popreceipt query string argument for queue service. POP_RECEIPT = "popreceipt" # The visibilitytimeout query string argument for queue service. VISIBILITY_TIMEOUT = "visibilitytimeout" # The messagettl query string argument for queue service. MESSAGE_TTL = "messagettl" # The select query string argument. SELECT = "$select" # The filter query string argument. FILTER = "$filter" # The top query string argument. TOP = "$top" # The skip query string argument. SKIP = "$skip" # The next partition key query string argument for table service. NEXT_PARTITION_KEY = "NextPartitionKey" # The next row key query string argument for table service. NEXT_ROW_KEY = "NextRowKey" # The lock identifier for service bus messages. LOCK_ID = "lockid" # The table name for table SAS URI's. TABLENAME = "tn" # The starting Partition Key for tableSAS URI's. STARTPK = "spk" # The starting Partition Key for tableSAS URI's. STARTRK = "srk" # The ending Partition Key for tableSAS URI's. ENDPK = "epk" # The ending Partition Key for tableSAS URI's. ENDRK = "erk" # ACL ACL = "acl" # Incremental Copy INCREMENTAL_COPY = "incrementalcopy" end module StorageServiceClientConstants # The default protocol. DEFAULT_PROTOCOL = "https" # Default credentials. DEVSTORE_STORAGE_ACCOUNT = "devstoreaccount1" DEVSTORE_STORAGE_ACCESS_KEY = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==" # The development store URI. DEV_STORE_URI = "http://127.0.0.1" # Development ServiceClient URLs. DEVSTORE_BLOB_HOST_PORT = "10000" DEVSTORE_QUEUE_HOST_PORT = "10001" DEVSTORE_TABLE_HOST_PORT = "10002" DEVSTORE_FILE_HOST_PORT = "10003" DEFAULT_ENDPOINT_SUFFIX = "core.windows.net" end module HttpConstants # Http Verbs module HttpVerbs PUT = "PUT" GET = "GET" DELETE = "DELETE" POST = "POST" MERGE = "MERGE" HEAD = "HEAD" end # Response codes. module HttpResponseCodes Ok = 200 Created = 201 Accepted = 202 NoContent = 204 PartialContent = 206 BadRequest = 400 Unauthorized = 401 Forbidden = 403 NotFound = 404 Conflict = 409 LengthRequired = 411 PreconditionFailed = 412 end end # Constants for storage error strings # More details are at = http://msdn.microsoft.com/en-us/library/azure/dd179357.aspx module StorageErrorCodeStrings # Not Modified (304) = The condition specified in the conditional header(s) was not met for a read operation. # Precondition Failed (412) = The condition specified in the conditional header(s) was not met for a write operation. CONDITION_NOT_MET = "ConditionNotMet" # Bad Request (400) = A required HTTP header was not specified. MISSING_REQUIRED_HEADER = "MissingRequiredHeader" # Bad Request (400) = A required XML node was not specified in the request body. MISSING_REQUIRED_XML_NODE = "MissingRequiredXmlNode" # Bad Request (400) = One of the HTTP headers specified in the request is not supported. UNSUPPORTED_HEADER = "UnsupportedHeader" # Bad Request (400) = One of the XML nodes specified in the request body is not supported. UNSUPPORTED_XML_NODE = "UnsupportedXmlNode" # Bad Request (400) = The value provided for one of the HTTP headers was not in the correct format. INVALID_HEADER_VALUE = "InvalidHeaderValue" # Bad Request (400) = The value provided for one of the XML nodes in the request body was not in the correct format. INVALID_XML_NODE_VALUE = "InvalidXmlNodeValue" # Bad Request (400) = A required query parameter was not specified for this request. MISSING_REQUIRED_QUERY_PARAMETER = "MissingRequiredQueryParameter" # Bad Request (400) = One of the query parameters specified in the request URI is not supported. UNSUPPORTED_QUERY_PARAMETER = "UnsupportedQueryParameter" # Bad Request (400) = An invalid value was specified for one of the query parameters in the request URI. INVALID_QUERY_PARAMETER_VALUE = "InvalidQueryParameterValue" # Bad Request (400) = A query parameter specified in the request URI is outside the permissible range. OUT_OF_RANGE_QUERY_PARAMETER_VALUE = "OutOfRangeQueryParameterValue" # Bad Request (400) = The url in the request could not be parsed. REQUEST_URL_FAILED_TO_PARSE = "RequestUrlFailedToParse" # Bad Request (400) = The requested URI does not represent any resource on the server. INVALID_URI = "InvalidUri" # Bad Request (400) = The HTTP verb specified was not recognized by the server. INVALID_HTTP_VERB = "InvalidHttpVerb" # Bad Request (400) = The key for one of the metadata key-value pairs is empty. EMPTY_METADATA_KEY = "EmptyMetadataKey" # Bad Request (400) = The specified XML is not syntactically valid. INVALID_XML_DOCUMENT = "InvalidXmlDocument" # Bad Request (400) = The MD5 value specified in the request did not match the MD5 value calculated by the server. MD5_MISMATCH = "Md5Mismatch" # Bad Request (400) = The MD5 value specified in the request is invalid. The MD5 value must be 128 bits and Base64-encoded. INVALID_MD5 = "InvalidMd5" # Bad Request (400) = One of the request inputs is out of range. OUT_OF_RANGE_INPUT = "OutOfRangeInput" # Bad Request (400) = The authentication information was not provided in the correct format. Verify the value of Authorization header. INVALID_AUTHENTICATION_INFO = "InvalidAuthenticationInfo" # Bad Request (400) = One of the request inputs is not valid. INVALID_INPUT = "InvalidInput" # Bad Request (400) = The specified metadata is invalid. It includes characters that are not permitted. INVALID_METADATA = "InvalidMetadata" # Bad Request (400) = The specifed resource name contains invalid characters. INVALID_RESOURCE_NAME = "InvalidResourceName" # Bad Request (400) = The size of the specified metadata exceeds the maximum size permitted. METADATA_TOO_LARGE = "MetadataTooLarge" # Bad Request (400) = Condition headers are not supported. CONDITION_HEADER_NOT_SUPPORTED = "ConditionHeadersNotSupported" # Bad Request (400) = Multiple condition headers are not supported. MULTIPLE_CONDITION_HEADER_NOT_SUPPORTED = "MultipleConditionHeadersNotSupported" # Forbidden (403) = Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature. AUTHENTICATION_FAILED = "AuthenticationFailed" # Forbidden (403) = Read-access geo-redundant replication is not enabled for the account. # Forbidden (403) = Write operations to the secondary location are not allowed. # Forbidden (403) = The account being accessed does not have sufficient permissions to execute this operation. INSUFFICIENT_ACCOUNT_PERMISSIONS = "InsufficientAccountPermissions" # Not Found (404) = The specified resource does not exist. RESOURCE_NOT_FOUND = "ResourceNotFound" # Forbidden (403) = The specified account is disabled. ACCOUNT_IS_DISABLED = "AccountIsDisabled" # Method Not Allowed (405) = The resource doesn't support the specified HTTP verb. UNSUPPORTED_HTTP_VERB = "UnsupportedHttpVerb" # Conflict (409) = The specified account already exists. ACCOUNT_ALREADY_EXISTS = "AccountAlreadyExists" # Conflict (409) = The specified account is in the process of being created. ACCOUNT_BEING_CREATED = "AccountBeingCreated" # Conflict (409) = The specified resource already exists. RESOURCE_ALREADY_EXISTS = "ResourceAlreadyExists" # Conflict (409) = The specified resource type does not match the type of the existing resource. RESOURCE_TYPE_MISMATCH = "ResourceTypeMismatch" # Length Required (411) = The Content-Length header was not specified. MISSING_CONTENT_LENGTH_HEADER = "MissingContentLengthHeader" # Request Entity Too Large (413) = The size of the request body exceeds the maximum size permitted. REQUEST_BODY_TOO_LARGE = "RequestBodyTooLarge" # Requested Range Not Satisfiable (416) = The range specified is invalid for the current size of the resource. INVALID_RANGE = "InvalidRange" # Internal Server Error (500) = The server encountered an internal error. Please retry the request. INTERNAL_ERROR = "InternalError" # Internal Server Error (500) = The operation could not be completed within the permitted time. OPERATION_TIMED_OUT = "OperationTimedOut" # Service Unavailable (503) = The server is currently unable to receive requests. Please retry your request. SERVER_BUSY = "ServerBusy" # Legacy error code strings UPDATE_CONDITION_NOT_SATISFIED = "UpdateConditionNotSatisfied" CONTAINER_NOT_FOUND = "ContainerNotFound" CONTAINER_ALREADY_EXISTS = "ContainerAlreadyExists" CONTAINER_DISABLED = "ContainerDisabled" CONTAINER_BEING_DELETED = "ContainerBeingDeleted" end end azure-storage-common-2.0.1/lib/azure/storage/common/client_options_error.rb0000644000177000017700000000340513753762266026272 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/core" module Azure::Storage::Common class InvalidConnectionStringError < Core::StorageError def initialize(message = Azure::Storage::Common::Core::SR::INVALID_CONNECTION_STRING) super(message) end end class InvalidOptionsError < Core::StorageError def initialize(message = Azure::Storage::Common::Core::SR::INVALID_CLIENT_OPTIONS) super(message) end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/0000755000177000017700000000000013753762266022431 5ustar avronavronazure-storage-common-2.0.1/lib/azure/storage/common/core/error.rb0000644000177000017700000000353313753762266024113 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/core" module Azure::Storage::Common::Core # Superclass for errors generated from this library, so people can # just rescue this for generic error handling class StorageError < StandardError # attr_reader :description # attr_reader :status_code # attr_reader :type # def initialize(description, type, status) # @type = type # @status_code = status # @description = description # super("#{type} (#{status_code}): #{description}") # end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/auth/0000755000177000017700000000000013753762266023372 5ustar avronavronazure-storage-common-2.0.1/lib/azure/storage/common/core/auth/anonymous_signer.rb0000644000177000017700000000333313753762266027320 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "base64" module Azure::Storage::Common::Core module Auth class AnonymousSigner < Azure::Core::Auth::Signer # Public: Initialize the Anonymous Signer def initialize() # Use mock key to initialize super class super(Base64.strict_encode64("accesskey")) end def sign_request(req) # Do nothing. end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/auth/token_signer.rb0000644000177000017700000000346513753762266026416 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common::Core module Auth class TokenSigner < Azure::Core::Auth::Signer # Public: Initialize the Token Signer def initialize(token_credential) @credential = token_credential # Use mock key to initialize super class super(Base64.strict_encode64("accesstoken")) end def sign_request(req) req.headers['Authorization'] = "Bearer #{@credential.token}" req end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/auth/shared_access_signature_generator.rb0000644000177000017700000004736213753762266032651 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/core" require "azure/storage/common/client_options_error" require "azure/core/auth/signer" require "time" require "uri" # @see https://msdn.microsoft.com/library/azure/dn140255.aspx for more information on construction module Azure::Storage::Common::Core module Auth class SharedAccessSignature DEFAULTS = { permissions: "r", version: Azure::Storage::Common::Default::STG_VERSION } SERVICE_TYPE_MAPPING = { b: Azure::Storage::Common::ServiceType::BLOB, t: Azure::Storage::Common::ServiceType::TABLE, q: Azure::Storage::Common::ServiceType::QUEUE, f: Azure::Storage::Common::ServiceType::FILE } ACCOUNT_KEY_MAPPINGS = { version: :sv, service: :ss, resource: :srt, permissions: :sp, start: :st, expiry: :se, protocol: :spr, ip_range: :sip } SERVICE_KEY_MAPPINGS = { version: :sv, permissions: :sp, start: :st, expiry: :se, identifier: :si, protocol: :spr, ip_range: :sip } USER_DELEGATION_KEY_MAPPINGS = { signed_oid: :skoid, signed_tid: :sktid, signed_start: :skt, signed_expiry: :ske, signed_service: :sks, signed_version: :skv } BLOB_KEY_MAPPINGS = { resource: :sr, timestamp: :snapshot, cache_control: :rscc, content_disposition: :rscd, content_encoding: :rsce, content_language: :rscl, content_type: :rsct } TABLE_KEY_MAPPINGS = { table_name: :tn, startpk: :spk, endpk: :epk, startrk: :srk, endrk: :erk } FILE_KEY_MAPPINGS = { resource: :sr, cache_control: :rscc, content_disposition: :rscd, content_encoding: :rsce, content_language: :rscl, content_type: :rsct } SERVICE_OPTIONAL_QUERY_PARAMS = [:sp, :si, :sip, :spr, :rscc, :rscd, :rsce, :rscl, :rsct, :spk, :srk, :epk, :erk] ACCOUNT_OPTIONAL_QUERY_PARAMS = [:st, :sip, :spr] attr :account_name # Public: Initialize the SharedAccessSignature generator # # @param account_name [String] The account name. Defaults to the one in the global configuration. # @param access_key [String] The access_key encoded in Base64. Defaults to the one in the global configuration. # @param user_delegation_key [Azure::Storage::Common::UserDelegationKey] The user delegation key obtained from # calling get_user_delegation_key after authenticating with an Azure Active Directory entity. If present, the # SAS is signed with the user delegation key instead of the access key. def initialize(account_name = "", access_key = "", user_delegation_key = nil) if access_key.empty? && !user_delegation_key.nil? access_key = user_delegation_key.value end if account_name.empty? || access_key.empty? client = Azure::Storage::Common::Client.create_from_env account_name = client.storage_account_name if account_name.empty? access_key = client.storage_access_key if access_key.empty? end @account_name = account_name @user_delegation_key = user_delegation_key @signer = Azure::Core::Auth::Signer.new(access_key) end # Service Shared Access Signature Token for the given path and options # @param path [String] Path of the URI or the table name # @param options [Hash] # # ==== Options # # * +:service+ - String. Required. Service type. 'b' (blob) or 'q' (queue) or 't' (table) or 'f' (file). # * +:resource+ - String. Required. Resource type, 'b' (blob) or 'c' (container) or 'f' (file) or 's' (share). # * +:permissions+ - String. Optional. Combination of 'r', 'a', 'c', w','d','l' in this order for a container. # Combination of 'r', 'a', 'c', 'w', 'd' in this order for a blob. # Combination of 'r', 'c', 'w', 'd', 'l' in this order for a share. # Combination of 'r', 'c', 'w', 'd' in this order for a file. # Combination of 'r', 'a', 'u', 'p' in this order for a queue. # Combination of 'r', 'a', 'u', 'd' in this order for a table. # This option must be omitted if it has been specified in an associated stored access policy. # * +:start+ - String. Optional. UTC Date/Time in ISO8601 format. # * +:expiry+ - String. Optional. UTC Date/Time in ISO8601 format. Default now + 30 minutes. # * +:identifier+ - String. Optional. Identifier for stored access policy. # This option must be omitted if a user delegation key has been provided. # * +:protocol+ - String. Optional. Permitted protocols. # * +:ip_range+ - String. Optional. An IP address or a range of IP addresses from which to accept requests. # # Below options for blob serivce only # * +:snapshot+ - String. Optional. UTC Date/Time in ISO8601 format. The blob snapshot to grant permission. # * +:cache_control+ - String. Optional. Response header override. # * +:content_disposition+ - String. Optional. Response header override. # * +:content_encoding+ - String. Optional. Response header override. # * +:content_language+ - String. Optional. Response header override. # * +:content_type+ - String. Optional. Response header override. # # Below options for table service only # * +:startpk+ - String. Optional but must accompany startrk. The start partition key of a specified partition key range. # * +:endpk+ - String. Optional but must accompany endrk. The end partition key of a specified partition key range. # * +:startrk+ - String. Optional. The start row key of a specified row key range. # * +:endrk+ - String. Optional. The end row key of a specified row key range. def generate_service_sas_token(path, options = {}) if options.key?(:service) service_type = SERVICE_TYPE_MAPPING[options[:service].to_sym] options.delete(:service) end raise Azure::Storage::Common::InvalidOptionsError, "SAS version cannot be set" if options[:version] options = DEFAULTS.merge(options) valid_mappings = SERVICE_KEY_MAPPINGS if service_type == Azure::Storage::Common::ServiceType::BLOB if options[:resource] options.merge!(resource: options[:resource]) else options.merge!(resource: "b") end valid_mappings.merge!(BLOB_KEY_MAPPINGS) elsif service_type == Azure::Storage::Common::ServiceType::TABLE options.merge!(table_name: path) valid_mappings.merge!(TABLE_KEY_MAPPINGS) elsif service_type == Azure::Storage::Common::ServiceType::FILE if options[:resource] options.merge!(resource: options[:resource]) else options.merge!(resource: "f") end valid_mappings.merge!(FILE_KEY_MAPPINGS) end service_key_mappings = SERVICE_KEY_MAPPINGS unless @user_delegation_key.nil? valid_mappings.delete(:identifier) USER_DELEGATION_KEY_MAPPINGS.each { |k, _| options[k] = @user_delegation_key.send(k) } valid_mappings.merge!(USER_DELEGATION_KEY_MAPPINGS) service_key_mappings = service_key_mappings.merge(USER_DELEGATION_KEY_MAPPINGS) end invalid_options = options.reject { |k, _| valid_mappings.key?(k) } raise Azure::Storage::Common::InvalidOptionsError, "invalid options #{invalid_options} provided for SAS token generate" if invalid_options.length > 0 canonicalize_time(options) query_hash = Hash[options.map { |k, v| [service_key_mappings[k], v] }] .reject { |k, v| SERVICE_OPTIONAL_QUERY_PARAMS.include?(k) && v.to_s == "" } .merge(sig: @signer.sign(signable_string_for_service(service_type, path, options))) URI.encode_www_form(query_hash) end # Construct the plaintext to the spec required for signatures # @return [String] def signable_string_for_service(service_type, path, options) # Order is significant # The newlines from empty strings here are required signable_fields = [ options[:permissions], options[:start], options[:expiry], canonicalized_resource(service_type, path) ] if @user_delegation_key.nil? signable_fields.push(options[:identifier]) else signable_fields.concat [ @user_delegation_key.signed_oid, @user_delegation_key.signed_tid, @user_delegation_key.signed_start, @user_delegation_key.signed_expiry, @user_delegation_key.signed_service, @user_delegation_key.signed_version ] end signable_fields.concat [ options[:ip_range], options[:protocol], Azure::Storage::Common::Default::STG_VERSION ] signable_fields.concat [ options[:resource], options[:timestamp] ] if service_type == Azure::Storage::Common::ServiceType::BLOB signable_fields.concat [ options[:cache_control], options[:content_disposition], options[:content_encoding], options[:content_language], options[:content_type] ] if service_type == Azure::Storage::Common::ServiceType::BLOB || service_type == Azure::Storage::Common::ServiceType::FILE signable_fields.concat [ options[:startpk], options[:startrk], options[:endpk], options[:endrk] ] if service_type == Azure::Storage::Common::ServiceType::TABLE signable_fields.join "\n" end # Account Shared Access Signature Token for the given options # @param account_name [String] storage account name # @param options [Hash] # # ==== Options # # * +:service+ - String. Required. Accessible services. Combination of 'b' (blob), 'q' (queue), 't' (table), 'f' (file). # * +:resource+ - String. Required. Accessible resource types. Combination of 's' (service), 'c' (container-level), 'o'(object-level). # * +:permissions+ - String. Required. Permissions. Combination of 'r' (read), 'w' (write), 'd'(delete), 'l'(list), 'a'(add), # 'c'(create), 'u'(update), 'p'(process). Permissions are only valid if they match # the specified signed resource type; otherwise they are ignored. # * +:start+ - String. Optional. UTC Date/Time in ISO8601 format. # * +:expiry+ - String. Optional. UTC Date/Time in ISO8601 format. Default now + 30 minutes. # * +:protocol+ - String. Optional. Permitted protocols. # * +:ip_range+ - String. Optional. An IP address or a range of IP addresses from which to accept requests. # When specifying a range, note that the range is inclusive. def generate_account_sas_token(options = {}) raise Azure::Storage::Common::InvalidOptionsError, "SAS version cannot be set" if options[:version] options = DEFAULTS.merge(options) valid_mappings = ACCOUNT_KEY_MAPPINGS invalid_options = options.reject { |k, _| valid_mappings.key?(k) } raise Azure::Storage::Common::InvalidOptionsError, "invalid options #{invalid_options} provided for SAS token generate" if invalid_options.length > 0 canonicalize_time(options) query_hash = Hash[options.map { |k, v| [ACCOUNT_KEY_MAPPINGS[k], v] }] .reject { |k, v| ACCOUNT_OPTIONAL_QUERY_PARAMS.include?(k) && v.to_s == "" } .merge(sig: @signer.sign(signable_string_for_account(options))) URI.encode_www_form(query_hash) end # Construct the plaintext to the spec required for signatures # @return [String] def signable_string_for_account(options) # Order is significant # The newlines from empty strings here are required [ @account_name, options[:permissions], options[:service], options[:resource], options[:start], options[:expiry], options[:ip_range], options[:protocol], Azure::Storage::Common::Default::STG_VERSION, "" ].join("\n") end # Return the cononicalized resource representation of the blob resource # @return [String] def canonicalized_resource(service_type, path) "/#{service_type}/#{account_name}#{path.start_with?('/') ? '' : '/'}#{path}" end def canonicalize_time(options) options[:start] = Time.parse(options[:start]).utc.iso8601 if options[:start] options[:expiry] = Time.parse(options[:expiry]).utc.iso8601 if options[:expiry] options[:expiry] ||= (Time.now + 60 * 30).utc.iso8601 end # A customised URI reflecting options for the resource signed with Shared Access Signature # @param uri [URI] uri to resource including query options # @param use_account_sas [Boolean] Whether uses account SAS # @param options [Hash] # # ==== Options # # * +:start+ - String. Optional. UTC Date/Time in ISO8601 format. # * +:expiry+ - String. Optional. UTC Date/Time in ISO8601 format. Default now + 30 minutes. # * +:protocol+ - String. Optional. Permitted protocols. # * +:ip_range+ - String. Optional. An IP address or a range of IP addresses from which to accept requests. # When specifying a range, note that the range is inclusive. # # Below options for account SAS only # * +:service+ - String. Required. Accessible services. Combination of 'b' (blob), 'q' (queue), 't' (table), 'f' (file). # * +:resource+ - String. Required. Accessible resource types. Combination of 's' (service), 'c' (container-level), 'o'(object-level). # * +:permissions+ - String. Required. Permissions. Combination of 'r' (read), 'w' (write), 'd'(delete), 'l'(list), 'a'(add), # 'c'(create), 'u'(update), 'p'(process). Permissions are only valid if they match # the specified signed resource type; otherwise they are ignored. # # Below options for service SAS only # * +:service+ - String. Required. Service type. 'b' (blob) or 'q' (queue) or 't' (table) or 'f' (file). # * +:resource+ - String. Required. Resource type, 'b' (blob) or 'c' (container) or 'f' (file) or 's' (share). # * +:identifier+ - String. Optional. Identifier for stored access policy. # * +:permissions+ - String. Optional. Combination of 'r', 'a', 'c', w','d','l' in this order for a container. # Combination of 'r', 'a', 'c', 'w', 'd' in this order for a blob. # Combination of 'r', 'c', 'w', 'd', 'l' in this order for a share. # Combination of 'r', 'c', 'w', 'd' in this order for a file. # Combination of 'r', 'a', 'u', 'p' in this order for a queue. # Combination of 'r', 'a', 'u', 'd' in this order for a table. # # Below options for Blob service only # * +:cache_control+ - String. Optional. Response header override. # * +:content_disposition+ - String. Optional. Response header override. # * +:content_encoding+ - String. Optional. Response header override. # * +:content_language+ - String. Optional. Response header override. # * +:content_type+ - String. Optional. Response header override. # # Below options for Table service only # * +:table_name+ - String. Required. Table name for SAS. # * +:startpk+ - String. Optional but must accompany startrk. The start partition key of a specified partition key range. # * +:endpk+ - String. Optional but must accompany endrk. The end partition key of a specified partition key range. # * +:startrk+ - String. Optional. The start row key of a specified row key range. # * +:endrk+ - String. Optional. The end row key of a specified row key range. def signed_uri(uri, use_account_sas, options) CGI::parse(uri.query || "").inject({}) { |memo, (k, v)| memo[k.to_sym] = v; memo } if options[:service] == (nil) && uri.host != (nil) host_splits = uri.host.split(".") options[:service] = host_splits[1].chr if host_splits.length > 1 && host_splits[0] == @account_name end sas_params = if use_account_sas generate_account_sas_token(options) else generate_service_sas_token(uri.path, options) end URI.parse(uri.to_s + (uri.query.nil? ? "?" : "&") + sas_params) end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/auth/shared_access_signature_signer.rb0000644000177000017700000000501213753762266032134 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/core/auth/signer" module Azure::Storage::Common::Core module Auth class SharedAccessSignatureSigner < Azure::Core::Auth::Signer attr :account_name, :sas_token attr_accessor :api_ver # Public: Initialize the Signer with a SharedAccessSignature # # @param api_ver [String] The api version of the service. # @param account_name [String] The account name. Defaults to the one in the global configuration. # @param sas_token [String] The sas token to be used for signing def initialize(api_ver, account_name = "", sas_token = "") if account_name.empty? || sas_token.empty? client = Azure::Storage::Common::Client.create_from_env account_name = client.storage_account_name if account_name.empty? sas_token = client.storage_sas_token if sas_token.empty? end @api_ver = api_ver @account_name = account_name @sas_token = sas_token end def sign_request(req) req.uri = URI.parse(req.uri.to_s + (req.uri.query.nil? ? "?" : "&") + sas_token.sub(/^\?/, "") + "&api-version=" + @api_ver) req end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/auth/shared_key.rb0000644000177000017700000000507613753762266026045 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "cgi" require "azure/core/auth/signer" require "azure/core/auth/shared_key" module Azure::Storage::Common::Core module Auth class SharedKey < Azure::Core::Auth::SharedKey # Generate the string to sign. # # @param method [Symbol] HTTP request method. # @param uri [URI] URI of the request we're signing. # @param headers [Hash] HTTP request headers. # # @return [String] def signable_string(method, uri, headers) [ method.to_s.upcase, headers.fetch("Content-Encoding", ""), headers.fetch("Content-Language", ""), headers.fetch("Content-Length", "").sub(/^0+/, ""), # from 2015-02-21, if Content-Length == 0, it won't be signed headers.fetch("Content-MD5", ""), headers.fetch("Content-Type", ""), headers.fetch("Date", ""), headers.fetch("If-Modified-Since", ""), headers.fetch("If-Match", ""), headers.fetch("If-None-Match", ""), headers.fetch("If-Unmodified-Since", ""), headers.fetch("Range", ""), canonicalized_headers(headers), canonicalized_resource(uri) ].join("\n") end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/auth/shared_access_signature.rb0000644000177000017700000000301713753762266030570 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/core/auth/shared_access_signature_generator" require "azure/storage/common/core/auth/shared_access_signature_signer" include Azure::Storage::Common::Core::Auth azure-storage-common-2.0.1/lib/azure/storage/common/core/http_client.rb0000644000177000017700000000607413753762266025302 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common::Core module HttpClient # Returns the http agent based on uri # @param uri [URI|String] the base uri (scheme, host, port) of the http endpoint # @return [Net::HTTP] http agent for a given uri def agents(uri) uri = URI(uri) unless uri.is_a? URI key = uri.host @agents ||= {} unless @agents.key?(key) @agents[key] = build_http(uri) else reuse_agent!(@agents[key]) end @agents[key] end # Empties all the http agents def reset_agents! @agents = nil end private # Empties all information that cannot be reused. def reuse_agent!(agent) agent.params.clear agent.headers.clear end def build_http(uri) ssl_options = {} if uri.is_a?(URI) && uri.scheme.downcase == "https" ssl_options[:version] = self.ssl_version if self.ssl_version # min_version and max_version only supported in ruby 2.5 ssl_options[:min_version] = self.ssl_min_version if self.ssl_min_version ssl_options[:max_version] = self.ssl_max_version if self.ssl_max_version ssl_options[:ca_file] = self.ca_file if self.ca_file ssl_options[:verify] = true end proxy_options = if ENV["HTTP_PROXY"] URI::parse(ENV["HTTP_PROXY"]) elsif ENV["HTTPS_PROXY"] URI::parse(ENV["HTTPS_PROXY"]) end || nil Faraday.new(uri, ssl: ssl_options, proxy: proxy_options) do |conn| conn.use FaradayMiddleware::FollowRedirects conn.adapter Faraday.default_adapter end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/filter/0000755000177000017700000000000013753762266023716 5ustar avronavronazure-storage-common-2.0.1/lib/azure/storage/common/core/filter/linear_retry_filter.rb0000644000177000017700000000472513753762266030317 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/core" require "azure/core/http/retry_policy" module Azure::Storage::Common::Core::Filter class LinearRetryPolicyFilter < RetryPolicyFilter def initialize(retry_count = nil, retry_interval = nil) @retry_count = retry_count || LinearRetryPolicyFilter::DEFAULT_RETRY_COUNT @retry_interval = retry_interval || LinearRetryPolicyFilter::DEFAULT_RETRY_INTERVAL super @retry_count, @retry_interval end DEFAULT_RETRY_COUNT = 3 DEFAULT_RETRY_INTERVAL = 30 # Overrides the base class implementation of call to determine # how the HTTP request should continue retrying # # retry_data - Hash. Stores stateful retry data # # The retry_data is a Hash which can be used to store # stateful data about the request execution context (such as an # incrementing counter, timestamp, etc). The retry_data object # will be the same instance throughout the lifetime of the request def apply_retry_policy(retry_data) retry_data[:count] = retry_data[:count] == nil ? 1 : retry_data[:count] + 1 retry_data[:interval] = @retry_interval end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/filter/retry_filter.rb0000644000177000017700000003032213753762266026755 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/core" require "azure/core/http/retry_policy" module Azure::Storage::Common::Core::Filter class RetryPolicyFilter < Azure::Core::Http::RetryPolicy def initialize(retry_count = nil, retry_interval = nil) @retry_count = retry_count @retry_interval = retry_interval @request_options = {} super &:should_retry? end attr_reader :retry_count, :retry_interval # Overrides the base class implementation of call to determine # whether to retry the operation # # response - HttpResponse. The response from the active request # retry_data - Hash. Stores stateful retry data def should_retry?(response, retry_data) # Fill necessary information init_retry_data retry_data # Applies the logic when there is subclass overrides it apply_retry_policy retry_data # Checks the result and count limit if retry_data[:retryable].nil? retry_data[:retryable] = true else retry_data[:retryable] &&= retry_data[:count] <= @retry_count end return false unless retry_data[:retryable] # Checks whether there is a local error # Cannot retry immediately when it returns true, as it need check other errors should_retry_on_local_error? retry_data return false unless should_retry_on_error? response, retry_data # Determined that it needs to retry. adjust_retry_request retry_data wait_for_retry retry_data[:retryable] end # Apply the retry policy to determine how the HTTP request should continue retrying # # retry_data - Hash. Stores stateful retry data # # The retry_data is a Hash which can be used to store # stateful data about the request execution context (such as an # incrementing counter, timestamp, etc). The retry_data object # will be the same instance throughout the lifetime of the request # # Alternatively, a subclass could override this method. def apply_retry_policy(retry_data) end # Determines if the HTTP request should continue retrying # # retry_data - Hash. Stores stateful retry data # # The retry_data is a Hash which can be used to store # stateful data about the request execution context (such as an # incrementing counter, timestamp, etc). The retry_data object # will be the same instance throughout the lifetime of the request. def should_retry_on_local_error?(retry_data) unless retry_data[:error] retry_data[:retryable] = true; return true end error_message = retry_data[:error].inspect if error_message.include?("SocketError: Hostname not known") # Retry on local DNS resolving # When uses resolv-replace.rb to replace the libc resolver # Reference: # https://makandracards.com/ninjaconcept/30815-fixing-socketerror-getaddrinfo-name-or-service-not-known-with-ruby-s-resolv-replace-rb # http://www.subelsky.com/2014/05/fixing-socketerror-getaddrinfo-name-or.html retry_data[:retryable] = true; elsif error_message.include?("getaddrinfo: Name or service not known") # When uses the default resolver retry_data[:retryable] = true; elsif error_message.downcase.include?("timeout") retry_data[:retryable] = true; elsif error_message.include?("Errno::ECONNRESET") retry_data[:retryable] = true; elsif error_message.include?("Errno::EACCES") retry_data[:retryable] = false; elsif error_message.include?("NOSUPPORT") retry_data[:retryable] = false; end retry_data[:retryable] end # Determines if the HTTP request should continue retrying # # response - Azure::Core::Http::HttpResponse. The response from the active request # retry_data - Hash. Stores stateful retry data # # The retry_data is a Hash which can be used to store # stateful data about the request execution context (such as an # incrementing counter, timestamp, etc). The retry_data object # will be the same instance throughout the lifetime of the request. def should_retry_on_error?(response, retry_data) response = response || retry_data[:error].http_response if retry_data[:error] && retry_data[:error].respond_to?("http_response") unless response retry_data[:retryable] = false unless retry_data[:error] return retry_data[:retryable] end check_location(response, retry_data) check_status_code(retry_data) retry_data[:retryable] end # Adjust the retry parameter and wait for retry def wait_for_retry sleep @retry_interval if @retry_interval > 0 end # Adjust the retry request # # retry_data - Hash. Stores stateful retry data def adjust_retry_request(retry_data) # Adjust the location first next_location = @request_options[:target_location].nil? ? get_next_location(retry_data) : @request_options[:target_location] retry_data[:current_location] = next_location retry_data[:uri] = if next_location == Azure::Storage::Common::StorageLocation::PRIMARY @request_options[:primary_uri] else @request_options[:secondary_uri] end # Now is the time to calculate the exact retry interval. ShouldRetry call above already # returned back how long two requests to the same location should be apart from each other. # However, for the reasons explained above, the time spent between the last attempt to # the target location and current time must be subtracted from the total retry interval # that ShouldRetry returned. lastAttemptTime = if retry_data[:current_location] == Azure::Storage::Common::StorageLocation::PRIMARY retry_data[:last_primary_attempt] else retry_data[:last_secondary_attempt] end @retry_interval = if lastAttemptTime.nil? 0 else since_last_attempt = Time.now - lastAttemptTime remainder = retry_data[:interval] - since_last_attempt remainder > 0 ? remainder : 0 end end # Initialize the retry data # # retry_data - Hash. Stores stateful retry data def init_retry_data(retry_data) @request_options = retry_data[:request_options] unless retry_data[:request_options].nil? if retry_data[:current_location].nil? retry_data[:current_location] = Azure::Storage::Common::Service::StorageService.get_location(@request_options[:location_mode], @request_options[:request_location_mode]) end if retry_data[:current_location] == Azure::Storage::Common::StorageLocation::PRIMARY retry_data[:last_primary_attempt] = Time.now else retry_data[:last_secondary_attempt] = Time.now end end # Check the location # # retry_data - Hash. Stores stateful retry data def check_location(response, retry_data) # If a request sent to the secondary location fails with 404 (Not Found), it is possible # that the resource replication is not finished yet. So, in case of 404 only in the secondary # location, the failure should still be retryable. retry_data[:secondary_not_found] = ((retry_data[:current_location] === Azure::Storage::Common::StorageLocation::SECONDARY) && response.status_code === 404); if retry_data[:secondary_not_found] retry_data[:status_code] = 500 else if (response.status_code) retry_data[:status_code] = response.status_code else retry_data[:status_code] = nil end end end # Check the status code # # retry_data - Hash. Stores stateful retry data def check_status_code(retry_data) if (retry_data[:status_code] < 400) retry_data[:retryable] = false; # Non-timeout Cases elsif (retry_data[:status_code] != 408) # Always no retry on "not implemented" and "version not supported" if (retry_data[:status_code] == 501 || retry_data[:status_code] == 505) retry_data[:retryable] = false; end # When absorb_conditional_errors_on_retry is set (for append blob) if (@request_options[:absorb_conditional_errors_on_retry]) if (retry_data[:status_code] == 412) # When appending block with precondition failure and their was a server error before, we ignore the error. if (retry_data[:last_server_error]) retry_data[:error] = nil; retry_data[:retryable] = true; else retry_data[:retryable] = false; end elsif (retry_data[:retryable] && retry_data[:status_code] >= 500 && retry_data[:status_code] < 600) # Retry on the server error retry_data[:retryable] = true; retry_data[:last_server_error] = true; end elsif (retry_data[:status_code] < 500) # No retry on the client error retry_data[:retryable] = false; end end end # Get retry request destination # # retry_data - Hash. Stores stateful retry data def get_next_location(retry_data) # In case of 404 when trying the secondary location, instead of retrying on the # secondary, further requests should be sent only to the primary location, as it most # probably has a higher chance of succeeding there. if retry_data[:secondary_not_found] && @request_options[:location_mode] != Azure::Storage::Common::LocationMode::SECONDARY_ONLY @request_options[:location_mode] = Azure::Storage::Common::LocationMode::PRIMARY_ONLY; return Azure::Storage::Common::StorageLocation::PRIMARY end case @request_options[:location_mode] when Azure::Storage::Common::LocationMode::PRIMARY_ONLY Azure::Storage::Common::StorageLocation::PRIMARY when Azure::Storage::Common::LocationMode::SECONDARY_ONLY Azure::Storage::Common::StorageLocation::SECONDARY else # request_location_mode cannot be SECONDARY_ONLY because it will be blocked at the first time if @request_options[:request_location_mode] == Azure::Storage::Common::RequestLocationMode::PRIMARY_ONLY Azure::Storage::Common::StorageLocation::PRIMARY elsif @request_options[:request_location_mode] == Azure::Storage::Common::RequestLocationMode::SECONDARY_ONLY Azure::Storage::Common::StorageLocation::SECONDARY else if retry_data[:current_location] === Azure::Storage::Common::StorageLocation::PRIMARY Azure::Storage::Common::StorageLocation::SECONDARY else Azure::Storage::Common::StorageLocation::PRIMARY end end end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/filter/exponential_retry_filter.rb0000644000177000017700000000603413753762266031366 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/core" require "azure/core/http/retry_policy" module Azure::Storage::Common::Core::Filter class ExponentialRetryPolicyFilter < RetryPolicyFilter def initialize(retry_count = nil, min_retry_interval = nil, max_retry_interval = nil) @retry_count = retry_count || ExponentialRetryPolicyFilter::DEFAULT_RETRY_COUNT @min_retry_interval = min_retry_interval || ExponentialRetryPolicyFilter::DEFAULT_MIN_RETRY_INTERVAL @max_retry_interval = max_retry_interval || ExponentialRetryPolicyFilter::DEFAULT_MAX_RETRY_INTERVAL super @retry_count, @min_retry_interval end attr_reader :min_retry_interval, :max_retry_interval DEFAULT_RETRY_COUNT = 3 DEFAULT_MIN_RETRY_INTERVAL = 10 DEFAULT_MAX_RETRY_INTERVAL = 90 # Overrides the base class implementation of call to determine # how the HTTP request should continue retrying # # retry_data - Hash. Stores stateful retry data # # The retry_data is a Hash which can be used to store # stateful data about the request execution context (such as an # incrementing counter, timestamp, etc). The retry_data object # will be the same instance throughout the lifetime of the request def apply_retry_policy(retry_data) # Adjust retry count retry_data[:count] = retry_data[:count] === nil ? 1 : retry_data[:count] + 1 # Adjust retry interval increment_delta = (@max_retry_interval - @min_retry_interval).fdiv(2**(@retry_count - 1)) * (2**(retry_data[:count] - 1)); retry_data[:interval] = retry_data[:interval] === nil ? @min_retry_interval : [@min_retry_interval + increment_delta, @max_retry_interval].min; end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/sr.rb0000644000177000017700000001527713753762266023416 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common::Core module SR ANONYMOUS_ACCESS_BLOBSERVICE_ONLY = "Anonymous access is only valid for the BlobService." ARGUMENT_NULL_OR_EMPTY = "The argument must not be null or an empty string. Argument name: %s." ARGUMENT_NULL_OR_UNDEFINED = "The argument must not be null or undefined. Argument name: %s." ARGUMENT_OUT_OF_RANGE_ERROR = "The argument is out of range. Argument name: %s, Value passed: %s." BATCH_ONE_PARTITION_KEY = "All entities in the batch must have the same PartitionKey value." BATCH_ONE_RETRIEVE = "If a retrieve operation is part of a batch, it must be the only operation in the batch." BATCH_TOO_LARGE = "Batches must not contain more than 100 operations." BLOB_INVALID_SEQUENCE_NUMBER = "The sequence number may not be specified for an increment operation." BLOB_TYPE_MISMATCH = 'Blob type of the blob reference doesn\'t match blob type of the blob.' CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY = "Cannot create Shared Access Signature unless the Account Name and Key are used to create the ServiceClient." CONTENT_LENGTH_MISMATCH = "An incorrect number of bytes was read from the connection. The connection may have been closed." CONTENT_TYPE_MISSING = "Content-Type response header is missing or invalid." EMPTY_BATCH = "Batch must not be empty." EXCEEDED_SIZE_LIMITATION = "Upload exceeds the size limitation. Max size is %s but the current size is %s" HASH_MISMATCH = "Hash mismatch (integrity check failed), Expected value is %s, retrieved %s." INCORRECT_ENTITY_KEYS = "PartitionKey and RowKey must be specified as strings in the entity object." INVALID_BLOB_LENGTH = "createBlockBlobFromText requires the size of text to be less than 64MB. Please use createBlockBlobFromLocalFile or createBlockBlobFromStream to upload large blobs." INVALID_CONNECTION_STRING = 'Connection strings must be of the form "key1=value1;key2=value2".' INVALID_CONNECTION_STRING_BAD_KEY = 'Connection string contains unrecognized key: "%s"' INVALID_CONNECTION_STRING_DUPLICATE_KEY = 'Connection string contains duplicate key: "%s"' INVALID_CONNECTION_STRING_EMPTY_KEY = "Connection strings must not contain empty keys." INVALID_CLIENT_OPTIONS = "Storage client options are invalid" INVALID_DELETE_SNAPSHOT_OPTION = "The deleteSnapshots option cannot be included when deleting a specific snapshot using the snapshotId option." INVALID_EDM_TYPE = 'The value \'%s\' does not match the type \'%s\'.' INVALID_FILE_LENGTH = "createFileFromText requires the size of text to be less than 4MB. Please use createFileFromLocalFile or createFileFromStream to upload large files." INVALID_FILE_RANGE_FOR_UPDATE = "Range size should be less than 4MB for a file range update operation." INVALID_HEADERS = "Headers are not supported in the 2012-02-12 version." INVALID_MESSAGE_ID = "Message ID cannot be null or undefined for deleteMessage and updateMessage operations." INVALID_PAGE_BLOB_LENGTH = "Page blob length must be multiple of 512." INVALID_PAGE_END_OFFSET = "Page end offset must be multiple of 512." INVALID_PAGE_RANGE_FOR_UPDATE = "Page range size should be less than 4MB for a page update operation." INVALID_PAGE_START_OFFSET = "Page start offset must be multiple of 512." INVALID_POP_RECEIPT = "Pop Receipt cannot be null or undefined for deleteMessage and updateMessage operations." INVALID_PROPERTY_RESOLVER = "The specified property resolver returned an invalid type. %s:{_:%s,$:%s }" INVALID_RANGE_FOR_MD5 = "The requested range should be less than 4MB when contentMD5 is expected from the server" INVALID_SAS_VERSION = "SAS Version ? is invalid. Valid versions include: ?." INVALID_SAS_TOKEN = "The SAS token should not contain api-version." INVALID_SIGNED_IDENTIFIERS = "Signed identifiers need to be an array." INVALID_STREAM_LENGTH = "The length of the provided stream is invalid." INVALID_STRING_ERROR = "Invalid string error." INVALID_TABLE_OPERATION = "Operation not found: %s" INVALID_TEXT_LENGTH = "The length of the provided text is invalid." MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION = "The client could not finish the operation within specified maximum execution timeout." MD5_NOT_PRESENT_ERROR = "MD5 does not exist. If you do not want to force validation, please disable useTransactionalMD5." METADATA_KEY_INVALID = "The key for one of the metadata key-value pairs is null, empty, or whitespace." METADATA_VALUE_INVALID = "The value for one of the metadata key-value pairs is null, empty, or whitespace." NO_CREDENTIALS_PROVIDED = "Credentials must be provided when creating a service client." PRIMARY_ONLY_COMMAND = "This operation can only be executed against the primary storage location." QUERY_OPERATOR_REQUIRES_WHERE = "%s operator needs to be used after where." SECONDARY_ONLY_COMMAND = "This operation can only be executed against the secondary storage location." STORAGE_HOST_LOCATION_REQUIRED = "The host for the storage service must be specified." STORAGE_HOST_MISSING_LOCATION = 'The host for the target storage location is not specified. Please consider changing the request\'s location mode.' TYPE_NOT_SUPPORTED = "Type not supported when sending data to the service: " MAX_BLOB_SIZE_CONDITION_NOT_MEET = "The max blob size condition specified was not met." end end azure-storage-common-2.0.1/lib/azure/storage/common/core/utility.rb0000644000177000017700000001540513753762266024466 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "ipaddr" require "azure/storage/common/core/error" if RUBY_VERSION.to_f < 2.0 begin require "Win32/Console/ANSI" if RUBY_PLATFORM =~ /win32|mingw32/ rescue LoadError puts "WARNING: Output will look weird on Windows unless"\ ' you install the "win32console" gem.' end end module Azure::Storage::Common module Error # Azure Error class Error < Azure::Core::Error attr_reader :description attr_reader :status_code attr_reader :type def initialize(type, status, description) @type = type @status_code = status @description = description super("#{type} (#{status_code}): #{description}") end end end module Core module Utility def random_string(str = "azure", no_of_char = 5) str + (0...no_of_char).map { ("a".."z").to_a[rand(26)] }.join end def xml_content(xml, key, default = "") content = default node = xml.at_css(key) content = node.text if node content end def locate_file(name) if File.exist? name name elsif File.exist?(File.join(ENV["HOME"], name)) File.join(ENV["HOME"], name) else Azure::Loggerx.error_with_exit "Unable to find #{name} file " end end def export_der(cert, key, pass = nil, name = nil) pkcs12 = OpenSSL::PKCS12.create(pass, name, key, cert) Base64.encode64(pkcs12.to_der) rescue Exception => e puts e.message abort end def export_fingerprint(certificate) Digest::SHA1.hexdigest(certificate.to_der) end def enable_winrm?(winrm_transport) (!winrm_transport.nil? && (winrm_transport.select { |x| x.downcase == "http" || x.downcase == "https" }.size > 0)) end def get_certificate(private_key_file) rsa = OpenSSL::PKey.read File.read(private_key_file) cert = OpenSSL::X509::Certificate.new cert.version = 2 cert.serial = 0 name = OpenSSL::X509::Name.new([["CN", "Azure Management Certificate"]]) cert.subject = cert.issuer = name cert.not_before = Time.now cert.not_after = cert.not_before + (60 * 60 * 24 * 365) cert.public_key = rsa.public_key cert.sign(rsa, OpenSSL::Digest::SHA1.new) cert end def initialize_external_logger(logger) Loggerx.initialize_external_logger(logger) end def parse_charset_from_content_type(content_type) if (content_type && content_type.length > 0) charset = content_type.split(";").delete_if { |attribute| !attribute.lstrip.start_with?("charset=") }.map { |x| x.lstrip }[0] charset["charset=".length...charset.length] if charset end end end # Logger module Logger class << self attr_accessor :logger def info(msg) if logger.nil? puts msg.bold.white else logger.info(msg) end end def error_with_exit(msg) if logger.nil? puts msg.bold.red else logger.error(msg) end raise msg.bold.red end def warn(msg) if logger.nil? puts msg.yellow else logger.warn(msg) end msg end def error(msg) if logger.nil? puts msg.bold.red else logger.error(msg) end msg end def exception_message(msg) if logger.nil? puts msg.bold.red else logger.warn(msg) end raise msg.bold.red end def success(msg) msg_with_new_line = msg + "\n" if logger.nil? print msg_with_new_line.green else logger.info(msg) end end def initialize_external_logger(logger) @logger = logger end end end end end class String { reset: 0, bold: 1, dark: 2, underline: 4, blink: 5, orange: 6, negative: 7, black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37, }.each do |key, value| define_method key do "\e[#{value}m" + self + "\e[0m" end end end # Code validate private/public IP acceptable ranges. class IPAddr def private? return false unless self.ipv4? PRIVATE_RANGES.each do |ipr| return true if ipr.include?(self) end false end def public? !private? end class << self def validate_ip_and_prefix(ip, cidr) if cidr.to_s.empty? raise "Cidr is missing for IP '#{ip}'." elsif valid?(ip) raise "Ip address '#{ip}' is invalid." elsif !IPAddr.new(ip).private? raise "Ip Address #{ip} must be private." end end def validate_address_space(ip) if ip.split("/").size != 2 raise "Cidr is invalid for IP #{ip}." elsif valid?(ip) raise "Address space '#{ip}' is invalid." end end def address_prefix(ip, cidr) ip + "/" + cidr.to_s end def valid?(ip) (IPAddr.new(ip) rescue nil).nil? end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/token_credential.rb0000644000177000017700000000425113753762266026272 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/core" module Azure::Storage::Common::Core class TokenCredential # Public: Initializes an instance of [Azure::Storage::Common::Core::TokenCredential] # # ==== Attributes # # * +token+ - String. The initial access token. # def initialize(token) @token = token @mutex = Mutex.new end # Public: Gets the access token # # Note: Providing this getter under the protect of a mutex # def token @mutex.synchronize do @token end end # Public: Renews the access token # # ==== Attributes # # * +new_token+ - String. The new access token. # def renew_token(new_token) @mutex.synchronize do @token = new_token end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core/autoload.rb0000644000177000017700000000542613753762266024575 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure module Storage module Common module Core autoload :HttpClient, "azure/storage/common/core/http_client" autoload :Utility, "azure/storage/common/core/utility" autoload :Logger, "azure/storage/common/core/utility" autoload :Error, "azure/storage/common/core/error" autoload :TokenCredential, "azure/storage/common/core/token_credential.rb" module Auth autoload :SharedKey, "azure/storage/common/core/auth/shared_key.rb" autoload :SharedAccessSignature, "azure/storage/common/core/auth/shared_access_signature_generator.rb" autoload :SharedAccessSignatureSigner, "azure/storage/common/core/auth/shared_access_signature_signer.rb" autoload :AnonymousSigner, "azure/storage/common/core/auth/anonymous_signer.rb" autoload :TokenSigner, "azure/storage/common/core/auth/token_signer.rb" end module Filter autoload :RetryPolicyFilter, "azure/storage/common/core/filter/retry_filter" autoload :LinearRetryPolicyFilter, "azure/storage/common/core/filter/linear_retry_filter" autoload :ExponentialRetryPolicyFilter, "azure/storage/common/core/filter/exponential_retry_filter" end end end end end azure-storage-common-2.0.1/lib/azure/storage/common/core.rb0000644000177000017700000000304213753762266022755 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure module Storage end end require "azure/storage/common/core/error" require "azure/storage/common/default" require "azure/storage/common/core/sr" require "azure/storage/common/core/utility" azure-storage-common-2.0.1/lib/azure/storage/common/service/0000755000177000017700000000000013753762266023141 5ustar avronavronazure-storage-common-2.0.1/lib/azure/storage/common/service/enumeration_results.rb0000644000177000017700000000273713753762266027606 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common module Service class EnumerationResults < Array attr_accessor :continuation_token end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/serialization.rb0000644000177000017700000003067613753762266026357 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "nokogiri" require "time" require "azure/storage/common/service/enumeration_results" require "azure/storage/common/service/signed_identifier" require "azure/storage/common/service/access_policy" require "azure/storage/common/service/storage_service_properties" require "azure/storage/common/service/logging" require "azure/storage/common/service/metrics" require "azure/storage/common/service/retention_policy" require "azure/storage/common/service/cors" require "azure/storage/common/service/cors_rule" require "azure/storage/common/service/storage_service_stats" module Azure::Storage::Common module Service module Serialization module ClassMethods def signed_identifiers_from_xml(xml) xml = slopify(xml) expect_node("SignedIdentifiers", xml) identifiers = [] return identifiers unless (xml > "SignedIdentifier").any? if xml.SignedIdentifier.count == 0 identifiers.push(signed_identifier_from_xml(xml.SignedIdentifier)) else xml.SignedIdentifier.each { |identifier_node| identifiers.push(signed_identifier_from_xml(identifier_node)) } end identifiers end def signed_identifiers_to_xml(signed_identifiers) builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml| xml.SignedIdentifiers { signed_identifiers.each do |identifier| xml.SignedIdentifier { xml.Id identifier.id xml.AccessPolicy { xml.Start identifier.access_policy.start xml.Expiry identifier.access_policy.expiry xml.Permission identifier.access_policy.permission } } end } end builder.to_xml end def signed_identifier_from_xml(xml) xml = slopify(xml) expect_node("SignedIdentifier", xml) SignedIdentifier.new do |identifier| identifier.id = xml.Id.text if (xml > "Id").any? identifier.access_policy = access_policy_from_xml(xml.AccessPolicy) if (xml > "AccessPolicy").any? end end def access_policy_from_xml(xml) xml = slopify(xml) expect_node("AccessPolicy", xml) AccessPolicy.new do |policy| policy.start = xml.Start.text if (xml > "Start").any? policy.expiry = xml.Expiry.text if (xml > "Expiry").any? policy.permission = xml.Permission.text if (xml > "Permission").any? end end def enumeration_results_from_xml(xml, results) xml = slopify(xml) expect_node("EnumerationResults", xml) results = results || Service::EnumerationResults.new; results.continuation_token = xml.NextMarker.text if (xml > "NextMarker").any? results end def metadata_from_xml(xml) xml = slopify(xml) expect_node("Metadata", xml) metadata = {} xml.children.each { |meta_node| key = meta_node.name.downcase if metadata.has_key? key metadata[key] = [metadata[key]] unless metadata[key].respond_to? :push metadata[key].push(meta_node.text) else metadata[key] = meta_node.text end } metadata end def metadata_from_headers(headers) metadata = {} headers.each { |k, v| if key = k[/^x-ms-meta-(.*)/, 1] if metadata.has_key? key metadata[key] = [metadata[key]] unless metadata[key].respond_to? :push metadata[key].push(v) else metadata[key] = v end end } metadata end def retention_policy_to_xml(retention_policy, xml) xml.RetentionPolicy { xml.Enabled retention_policy.enabled xml.Days retention_policy.days if retention_policy.enabled && retention_policy.days } if retention_policy end def retention_policy_from_xml(xml) xml = slopify(xml) expect_node("RetentionPolicy", xml) RetentionPolicy.new do |policy| policy.enabled = to_bool(xml.Enabled.text) if (xml > "Enabled").any? policy.days = xml.Days.text.to_i if (xml > "Days").any? end end def metrics_to_xml_children(metrics, xml) return unless metrics xml.Version metrics.version xml.Enabled metrics.enabled xml.IncludeAPIs metrics.include_apis if metrics.enabled retention_policy_to_xml(metrics.retention_policy, xml) if metrics.retention_policy end def hour_metrics_to_xml(metrics, xml) xml.HourMetrics { metrics_to_xml_children(metrics, xml) } if metrics end def minute_metrics_to_xml(metrics, xml) xml.MinuteMetrics { metrics_to_xml_children(metrics, xml) } if metrics end def metrics_from_xml(xml) xml = slopify(xml) Metrics.new do |metrics| metrics.version = xml.Version.text if (xml > "Version").any? metrics.enabled = to_bool(xml.Enabled.text) if (xml > "Enabled").any? metrics.include_apis = to_bool(xml.IncludeAPIs.text) if (xml > "IncludeAPIs").any? metrics.retention_policy = retention_policy_from_xml(xml.RetentionPolicy) end end def logging_to_xml(logging, xml) xml.Logging { xml.Version logging.version xml.Delete logging.delete xml.Read logging.read xml.Write logging.write retention_policy_to_xml(logging.retention_policy, xml) } if logging end def logging_from_xml(xml) xml = slopify(xml) expect_node("Logging", xml) Logging.new do |logging| logging.version = xml.Version.text if (xml > "Version").any? logging.delete = to_bool(xml.Delete.text) if (xml > "Delete").any? logging.read = to_bool(xml.Read.text) if (xml > "Read").any? logging.write = to_bool(xml.Write.text) if (xml > "Write").any? logging.retention_policy = retention_policy_from_xml(xml.RetentionPolicy) end end def cors_to_xml(cors, xml) xml.Cors { cors.cors_rules.to_a.each do |cors_rule| cors_rule_to_xml(cors_rule, xml) end } end def cors_rule_to_xml(cors_rule, xml) xml.CorsRule { xml.AllowedOrigins cors_rule.allowed_origins.join(",") if cors_rule.allowed_origins xml.AllowedMethods cors_rule.allowed_methods.join(",") if cors_rule.allowed_methods xml.MaxAgeInSeconds cors_rule.max_age_in_seconds if cors_rule.max_age_in_seconds xml.ExposedHeaders cors_rule.exposed_headers.join(",") if cors_rule.exposed_headers xml.AllowedHeaders cors_rule.allowed_headers.join(",") if cors_rule.allowed_headers } end def cors_from_xml(xml) xml = slopify(xml) expect_node("Cors", xml) Cors.new do |cors| cors.cors_rules = xml.children.to_a.map { |child| cors_rule_from_xml(child) } end end def cors_rule_from_xml(xml) xml = slopify(xml) expect_node("CorsRule", xml) CorsRule.new do |cors_rule| cors_rule.allowed_origins = ary_from_node(xml.AllowedOrigins) if (xml > "AllowedOrigins").any? cors_rule.allowed_methods = ary_from_node(xml.AllowedMethods) if (xml > "AllowedMethods").any? cors_rule.max_age_in_seconds = xml.MaxAgeInSeconds.text.to_i if (xml > "MaxAgeInSeconds").any? cors_rule.exposed_headers = ary_from_node(xml.ExposedHeaders) if (xml > "ExposedHeaders").any? cors_rule.allowed_headers = ary_from_node(xml.AllowedHeaders) if (xml > "AllowedHeaders").any? end end def geo_replication_from_xml(xml) xml = slopify(xml) expect_node("GeoReplication", xml) GeoReplication.new do |geo_replication| geo_replication.status = xml.Status.text if (xml > "Status").any? geo_replication.last_sync_time = begin Time.parse(xml.LastSyncTime.text) if (xml > "LastSyncTime").any? rescue nil end end end def ary_from_node(node) node.text.split(",").map { |s| s.strip } end def service_properties_to_xml(properties) builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml| xml.StorageServiceProperties { xml.DefaultServiceVersion(properties.default_service_version) if properties.default_service_version logging_to_xml(properties.logging, xml) if properties.logging hour_metrics_to_xml(properties.hour_metrics, xml) if properties.hour_metrics minute_metrics_to_xml(properties.minute_metrics, xml) if properties.minute_metrics cors_to_xml(properties.cors, xml) if properties.cors } end builder.to_xml end def service_properties_from_xml(xml) xml = slopify(xml) expect_node("StorageServiceProperties", xml) StorageServiceProperties.new do |props| props.default_service_version = xml.DefaultServiceVersion.text if (xml > "DefaultServiceVersion").any? props.logging = logging_from_xml(xml.Logging) if (xml > "Logging").any? props.hour_metrics = metrics_from_xml(xml.HourMetrics) if (xml > "HourMetrics").any? props.minute_metrics = metrics_from_xml(xml.MinuteMetrics) if (xml > "MinuteMetrics").any? props.cors = cors_from_xml(xml.Cors) if (xml > "Cors").any? end end def service_stats_from_xml(xml) xml = slopify(xml) expect_node("StorageServiceStats", xml) StorageServiceStats.new do |stats| stats.geo_replication = geo_replication_from_xml(xml.GeoReplication) end end def to_bool(s) (s || "").downcase == "true" end def slopify(xml) node = (xml.is_a? String) ? Nokogiri.Slop(xml).root : xml node.slop! if node.is_a? Nokogiri::XML::Document unless node.respond_to? :method_missing node = node.root if node.is_a? Nokogiri::XML::Document node end def expect_node(node_name, xml) raise "Xml is not a #{node_name} node. xml:\n#{xml}" unless xml.name == node_name end end extend ClassMethods def self.included(other) other.extend(ClassMethods) end end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/cors_rule.rb0000644000177000017700000000377613753762266025500 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common module Service class CorsRule def initialize # All CORS rule elements are required if the CorsRule element is specified. # The request will fail with error code 400 (Bad Request) if any element is missing. @allowed_origins = [] @allowed_methods = [] @exposed_headers = [] @allowed_headers = [] @max_age_in_seconds = 0 yield self if block_given? end attr_accessor :allowed_origins attr_accessor :allowed_methods attr_accessor :max_age_in_seconds attr_accessor :exposed_headers attr_accessor :allowed_headers end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/logging.rb0000644000177000017700000000352113753762266025115 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/service/retention_policy" module Azure::Storage::Common module Service class Logging def initialize @version = "1.0" @delete = false @read = false @write = false @retention_policy = RetentionPolicy.new yield self if block_given? end attr_accessor :version attr_accessor :delete attr_accessor :read attr_accessor :write attr_accessor :retention_policy end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/storage_service_properties.rb0000644000177000017700000000367713753762266031143 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/service/logging" require "azure/storage/common/service/metrics" require "azure/storage/common/service/cors" module Azure::Storage::Common module Service class StorageServiceProperties def initialize @logging = Logging.new @hour_metrics = Metrics.new @minute_metrics = Metrics.new @cors = Cors.new yield self if block_given? end attr_accessor :logging attr_accessor :hour_metrics attr_accessor :minute_metrics attr_accessor :cors attr_accessor :default_service_version end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/storage_service.rb0000644000177000017700000003435213753762266026661 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/core/signed_service" require "azure/storage/common/core" require "azure/storage/common/service/storage_service_properties" require "azure/storage/common/service/storage_service_stats" module Azure::Storage::Common module Service # A base class for StorageService implementations class StorageService < Azure::Core::SignedService # @!attribute storage_service_host # @return [Hash] Get or set the storage service host attr_accessor :storage_service_host # Create a new instance of the StorageService # # @param signer [Azure::Core::Auth::Signer] An implementation of Signer used for signing requests. # (optional, Default=Azure::Storage::CommonAuth::SharedKey.new) # @param account_name [String] The account name (optional, Default=Azure::Storage.storage_account_name) # @param options [Azure::Storage::CommonConfigurable] the client configuration context def initialize(signer = nil, account_name = nil, options = {}, &block) StorageService.register_request_callback(&block) if block_given? client_config = options[:client] signer = signer || Azure::Storage::Common::Core::Auth::SharedKey.new( client_config.storage_account_name, client_config.storage_access_key) if client_config.storage_access_key signer = signer || Azure::Storage::Common::Core::Auth::SharedAccessSignatureSigner.new( client_config.storage_account_name, client_config.storage_sas_token) @storage_service_host = { primary: "", secondary: "" }; super(signer, account_name, options) end def call(method, uri, body = nil, headers = {}, options = {}) super(method, uri, body, StorageService.common_headers(options, body).merge(headers), options) end # Public: Get Storage Service properties # # See http://msdn.microsoft.com/en-us/library/azure/hh452239 # See http://msdn.microsoft.com/en-us/library/azure/hh452243 # # ==== Options # # * +:timeout+ - Integer. A timeout in seconds. # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded # in the analytics logs when storage analytics logging is enabled. # # Returns a Hash with the service properties or nil if the operation failed def get_service_properties(options = {}) query = {} StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout] response = call(:get, service_properties_uri(query), nil, {}, options) Serialization.service_properties_from_xml response.body end # Public: Set Storage Service properties # # service_properties - An instance of Azure::Storage::CommonService::StorageServiceProperties # # See http://msdn.microsoft.com/en-us/library/azure/hh452235 # See http://msdn.microsoft.com/en-us/library/azure/hh452232 # # ==== Options # # * +:timeout+ - Integer. A timeout in seconds. # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded # in the analytics logs when storage analytics logging is enabled. # # Returns boolean indicating success. def set_service_properties(service_properties, options = {}) query = {} StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout] body = Serialization.service_properties_to_xml service_properties call(:put, service_properties_uri(query), body, {}, options) nil end # Public: Retrieves statistics related to replication for the service. # It is only available on the secondary location endpoint when read-access geo-redundant # replication is enabled for the storage account. # # See https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-service-stats # See https://docs.microsoft.com/en-us/rest/api/storageservices/get-queue-service-stats # See https://docs.microsoft.com/en-us/rest/api/storageservices/get-table-service-stats # # ==== Options # # * +:timeout+ - Integer. A timeout in seconds. # * +:request_id+ - String. Provides a client-generated, opaque value with a 1 KB character limit that is recorded # in the analytics logs when storage analytics logging is enabled. # # Returns a Hash with the service statistics or nil if the operation failed def get_service_stats(options = {}) query = {} StorageService.with_query query, "timeout", options[:timeout].to_s if options[:timeout] options.update( location_mode: LocationMode::SECONDARY_ONLY, request_location_mode: RequestLocationMode::SECONDARY_ONLY) response = call(:get, service_stats_uri(query, options), nil, {}, options) Serialization.service_stats_from_xml response.body end # Public: Generate the URI for the service properties # # * +:query+ - see Azure::Storage::CommonServices::GetServiceProperties#call documentation. # # Returns a URI. def service_properties_uri(query = {}) query.update(restype: "service", comp: "properties") generate_uri("", query) end # Public: Generate the URI for the service statistics # # * +:query+ - see Azure::Storage::CommonServices::GetServiceStats#call documentation. # # Returns a URI. def service_stats_uri(query = {}, options = {}) query.update(restype: "service", comp: "stats") generate_uri("", query, options) end # Overrides the base class implementation to determine the request uri # # path - String. the request path # query - Hash. the query parameters # # ==== Options # # * +:encode+ - bool. Specifies whether to encode the path. # * +:location_mode+ - LocationMode. Specifies the location mode used to decide # which location the request should be sent to. # * +:request_location_mode+ - RequestLocationMode. Specifies the location used to indicate # which location the operation (REST API) can be performed against. # This is determined by the API and cannot be specified by the users. # # Returns the uri hash def generate_uri(path = "", query = {}, options = {}) location_mode = if options[:location_mode].nil? LocationMode::PRIMARY_ONLY else options[:location_mode] end request_location_mode = if options[:request_location_mode].nil? RequestLocationMode::PRIMARY_ONLY else request_location_mode = options[:request_location_mode] end location = StorageService.get_location location_mode, request_location_mode if self.client.is_a?(Azure::Storage::Common::Client) && self.client.options[:use_path_style_uri] account_path = get_account_path location path = path.length > 0 ? account_path + "/" + path : account_path end @host = location == StorageLocation::PRIMARY ? @storage_service_host[:primary] : @storage_service_host[:secondary] encode = options[:encode].nil? ? false : options[:encode] if encode path = CGI.escape(path.encode("UTF-8")) # decode the forward slashes to match what the server expects. path = path.gsub(/%2F/, "/") # decode the backward slashes to match what the server expects. path = path.gsub(/%5C/, "/") # Re-encode the spaces (encoded as space) to the % encoding. path = path.gsub(/\+/, "%20") end @host = storage_service_host[:primary] options[:primary_uri] = super path, query @host = storage_service_host[:secondary] options[:secondary_uri] = super path, query if location == StorageLocation::PRIMARY @host = @storage_service_host[:primary] return options[:primary_uri] else @host = @storage_service_host[:secondary] return options[:secondary_uri] end end # Get account path according to the location settings. # # * +:location+ - StorageLocation. Specifies the request location. # # Returns the account path def get_account_path(location) if location == StorageLocation::PRIMARY self.client.options[:storage_account_name] else self.client.options[:storage_account_name] + "-secondary" end end class << self # @!attribute user_agent_prefix # @return [Proc] Get or set the user agent prefix attr_accessor :user_agent_prefix # @!attribute request_callback # @return [Proc] The callback before the request is signed and sent attr_reader :request_callback # Registers the callback when sending the request # The headers in the request can be viewed or changed in the code block def register_request_callback @request_callback = Proc.new end # Get the request location. # # * +:location_mode+ - LocationMode. Specifies the location mode used to decide # which location the request should be sent to. # * +:request_location_mode+ - RequestLocationMode. Specifies the location used to indicate # which location the operation (REST API) can be performed against. # This is determined by the API and cannot be specified by the users. # # Returns the reqeust location def get_location(location_mode, request_location_mode) if request_location_mode == RequestLocationMode::PRIMARY_ONLY && location_mode == LocationMode::SECONDARY_ONLY raise InvalidOptionsError, "This operation can only be executed against the primary storage location." end if request_location_mode == RequestLocationMode::SECONDARY_ONLY && location_mode == LocationMode::PRIMARY_ONLY raise InvalidOptionsError, "This operation can only be executed against the secondary storage location." end if request_location_mode == RequestLocationMode::PRIMARY_ONLY return StorageLocation::PRIMARY elsif request_location_mode == RequestLocationMode::SECONDARY_ONLY return StorageLocation::SECONDARY end if location_mode == LocationMode::PRIMARY_ONLY || location_mode == LocationMode::PRIMARY_THEN_SECONDARY StorageLocation::PRIMARY elsif location_mode == LocationMode::SECONDARY_ONLY || location_mode == LocationMode::SECONDARY_THEN_PRIMARY StorageLocation::SECONDARY end end # Adds metadata properties to header hash with required prefix # # * +:metadata+ - A Hash of metadata name/value pairs # * +:headers+ - A Hash of HTTP headers def add_metadata_to_headers(metadata, headers) if metadata metadata.each do |key, value| headers["x-ms-meta-#{key}"] = value end end end # Adds a value to the Hash object # # * +:object+ - A Hash object # * +:key+ - The key name # * +:value+ - The value def with_value(object, key, value) object[key] = value.to_s if value end # Adds a header with the value # # * +:headers+ - A Hash of HTTP headers # * +:name+ - The header name # * +:value+ - The value alias with_header with_value # Adds a query parameter # # * +:query+ - A Hash of HTTP query # * +:name+ - The parameter name # * +:value+ - The value alias with_query with_value # Declares a default hash object for request headers def common_headers(options = {}, body = nil) headers = {} headers.merge!("x-ms-client-request-id" => options[:request_id]) if options[:request_id] @request_callback.call(headers) if @request_callback headers end end end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/user_delegation_key.rb0000644000177000017700000000365213753762266027515 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common module Service class UserDelegationKey def initialize @signed_oid = nil @signed_tid = nil @signed_start = nil @signed_expiry = nil @signed_service = nil @signed_version = nil @value = nil yield self if block_given? end attr_accessor :signed_oid attr_accessor :signed_tid attr_accessor :signed_start attr_accessor :signed_expiry attr_accessor :signed_service attr_accessor :signed_version attr_accessor :value end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/cors.rb0000644000177000017700000000304413753762266024435 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common module Service class Cors def initialize @cors_rules = [] yield self if block_given? end attr_accessor :cors_rules end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/signed_identifier.rb0000644000177000017700000000322313753762266027141 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/service/access_policy" module Azure::Storage::Common module Service class SignedIdentifier def initialize @access_policy = AccessPolicy.new yield self if block_given? end attr_accessor :id attr_accessor :access_policy end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/retention_policy.rb0000644000177000017700000000310313753762266027051 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common module Service class RetentionPolicy def initialize @enabled = false yield self if block_given? end attr_accessor :enabled attr_accessor :days end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/storage_service_stats.rb0000644000177000017700000000320513753762266030070 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/service/geo_replication" module Azure::Storage::Common module Service class StorageServiceStats def initialize @geo_replication = GeoReplication.new yield self if block_given? end attr_accessor :geo_replication end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/metrics.rb0000644000177000017700000000345713753762266025145 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "azure/storage/common/service/retention_policy" module Azure::Storage::Common module Service class Metrics def initialize @version = "1.0" @enabled = false @include_apis = false @retention_policy = RetentionPolicy.new yield self if block_given? end attr_accessor :version attr_accessor :enabled attr_accessor :include_apis attr_accessor :retention_policy end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/access_policy.rb0000644000177000017700000000310713753762266026307 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common module Service class AccessPolicy def initialize yield self if block_given? end attr_accessor :start attr_accessor :expiry attr_accessor :permission end end end azure-storage-common-2.0.1/lib/azure/storage/common/service/geo_replication.rb0000644000177000017700000000315313753762266026633 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common module Service class GeoReplication def initialize @status = nil @last_sync_time = nil yield self if block_given? end attr_accessor :status attr_accessor :last_sync_time end end end azure-storage-common-2.0.1/lib/azure/storage/common/client.rb0000644000177000017700000002266213753762266023314 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common class Client include Azure::Storage::Common::Configurable include Azure::Storage::Common::ClientOptions include Azure::Storage::Common::Core::HttpClient # Public: Creates an instance of [Azure::Storage::Common::Client] # # ==== Attributes # # * +options+ - Hash. Optional parameters. # # ==== Options # # Accepted key/value pairs in options parameter are: # # * +:use_development_storage+ - TrueClass|FalseClass. Whether to use storage emulator. # * +:development_storage_proxy_uri+ - String. Used with +:use_development_storage+ if emulator is hosted other than localhost. # * +:storage_connection_string+ - String. The storage connection string. # * +:storage_account_name+ - String. The name of the storage account. # * +:storage_access_key+ - Base64 String. The access key of the storage account. # * +:storage_sas_token+ - String. The signed access signature for the storage account or one of its service. # * +:storage_blob_host+ - String. Specified Blob serivce endpoint or hostname # * +:storage_table_host+ - String. Specified Table serivce endpoint or hostname # * +:storage_queue_host+ - String. Specified Queue serivce endpoint or hostname # * +:storage_dns_suffix+ - String. The suffix of a regional Storage Serivce, to # * +:default_endpoints_protocol+ - String. http or https # * +:use_path_style_uri+ - String. Whether use path style URI for specified endpoints # * +:ca_file+ - String. File path of the CA file if having issue with SSL # * +:user_agent_prefix+ - String. The user agent prefix that can identify the application calls the library # # The valid set of options include: # * Storage Emulator: +:use_development_storage+ required, +:development_storage_proxy_uri+ optionally # * Storage account name and key: +:storage_account_name+ and +:storage_access_key+ required, set +:storage_dns_suffix+ necessarily # * Storage account name and SAS token: +:storage_account_name+ and +:storage_sas_token+ required, set +:storage_dns_suffix+ necessarily # * Specified hosts and SAS token: At least one of the service host and SAS token. It's up to user to ensure the SAS token is suitable for the serivce # * Anonymous Blob: only +:storage_blob_host+, if it is to only access blobs within a container # # Additional notes: # * Specified hosts can be set when use account name with access key or sas token # * +:default_endpoints_protocol+ can be set if the scheme is not specified in hosts # * Storage emulator always use path style URI # * +:ca_file+ is independent. # # When empty options are given, it will try to read settings from Environment Variables. Refer to [Azure::Storage::Common::ClientOptions.env_vars_mapping] for the mapping relationship # # @return [Azure::Storage::Common::Client] def initialize(options = {}, &block) if options.is_a?(Hash) && options.has_key?(:user_agent_prefix) Azure::Storage::Common::Service::StorageService.user_agent_prefix = options[:user_agent_prefix] options.delete :user_agent_prefix end Azure::Storage::Common::Service::StorageService.register_request_callback(&block) if block_given? reset!(options) end class << self # Public: Creates an instance of [Azure::Storage::Common::Client] # # ==== Attributes # # * +options+ - Hash. Optional parameters. # # ==== Options # # Accepted key/value pairs in options parameter are: # # * +:use_development_storage+ - TrueClass|FalseClass. Whether to use storage emulator. # * +:development_storage_proxy_uri+ - String. Used with +:use_development_storage+ if emulator is hosted other than localhost. # * +:storage_account_name+ - String. The name of the storage account. # * +:storage_access_key+ - Base64 String. The access key of the storage account. # * +:storage_sas_token+ - String. The signed access signature for the storage account or one of its service. # * +:storage_blob_host+ - String. Specified Blob service endpoint or hostname # * +:storage_table_host+ - String. Specified Table service endpoint or hostname # * +:storage_queue_host+ - String. Specified Queue service endpoint or hostname # * +:storage_dns_suffix+ - String. The suffix of a regional Storage Service, to # * +:default_endpoints_protocol+ - String. http or https # * +:use_path_style_uri+ - String. Whether use path style URI for specified endpoints # * +:ca_file+ - String. File path of the CA file if having issue with SSL # * +:ssl_version+ - Symbol. The ssl version to be used, sample: :TLSv1_1, :TLSv1_2, for the details, see https://github.com/ruby/openssl/blob/master/lib/openssl/ssl.rb # * +:ssl_min_version+ - Symbol. The min ssl version supported, only supported in Ruby 2.5+ # * +:ssl_max_version+ - Symbol. The max ssl version supported, only supported in Ruby 2.5+ # * +:user_agent_prefix+ - String. The user agent prefix that can identify the application calls the library # # The valid set of options include: # * Storage Emulator: +:use_development_storage+ required, +:development_storage_proxy_uri+ optionally # * Storage account name and key: +:storage_account_name+ and +:storage_access_key+ required, set +:storage_dns_suffix+ necessarily # * Storage account name and SAS token: +:storage_account_name+ and +:storage_sas_token+ required, set +:storage_dns_suffix+ necessarily # * Specified hosts and SAS token: At least one of the service host and SAS token. It's up to user to ensure the SAS token is suitable for the serivce # * Anonymous Blob: only +:storage_blob_host+, if it is to only access blobs within a container # # Additional notes: # * Specified hosts can be set when use account name with access key or sas token # * +:default_endpoints_protocol+ can be set if the scheme is not specified in hosts # * Storage emulator always use path style URI # * +:ca_file+ is independent. # # When empty options are given, it will try to read settings from Environment Variables. Refer to [Azure::Storage::Common::ClientOptions.env_vars_mapping] for the mapping relationship # # @return [Azure::Storage::Common::Client] def create(options = {}, &block) client = Client.new(options, &block) end # Public: Creates an instance of [Azure::Storage::Common::Client] with Storage Emulator # # ==== Attributes # # * +proxy_uri+ - String. Used with +:use_development_storage+ if emulator is hosted other than localhost. # # @return [Azure::Storage::Common::Client] def create_development(proxy_uri = nil, &block) proxy_uri ||= StorageServiceClientConstants::DEV_STORE_URI client = create(use_development_storage: true, development_storage_proxy_uri: proxy_uri, &block) end # Public: Creates an instance of [Azure::Storage::Common::Client] from Environment Variables # # @return [Azure::Storage::Client] def create_from_env(&block) client = create(&block) end # Public: Creates an instance of [Azure::Storage::Common::Client] from Environment Variables # # ==== Attributes # # * +connection_string+ - String. Please refer to https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/. # # @return [Azure::Storage::Common::Client] def create_from_connection_string(connection_string, &block) client = Client.new(connection_string, &block) end end end end azure-storage-common-2.0.1/lib/azure/storage/common/configurable.rb0000644000177000017700000001742613753762266024500 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure::Storage::Common # The Azure::Storage::Common::Configurable module provides basic configuration for Azure storage activities. module Configurable # @!attribute [w] storage_access_key # @return [String] Azure Storage access key. # @!attribute storage_account_name # @return [String] Azure Storage account name. # @!attribute storage_connection_string # @return [String] Azure Storage connection string. # @!attribute storage_blob_host # @return [String] Set the host for the Blob service. Only set this if you want # something custom (like, for example, to point this to a LocalStorage # emulator). This should be the complete host, including http:// at the # start. When using the emulator, make sure to include your account name at # the end. # @!attribute storage_table_host # @return [String] Set the host for the Table service. Only set this if you want # something custom (like, for example, to point this to a LocalStorage # emulator). This should be the complete host, including http:// at the # start. When using the emulator, make sure to include your account name at # the end. # @!attribute storage_queue_host # @return [String] Set the host for the Queue service. Only set this if you want # something custom (like, for example, to point this to a LocalStorage # emulator). This should be the complete host, including http:// at the # start. When using the emulator, make sure to include your account name at # the end. attr_accessor :storage_access_key, :storage_account_name, :storage_connection_string, :storage_sas_token attr_writer :storage_table_host, :storage_blob_host, :storage_queue_host, :storage_file_host, :storage_table_host_secondary, :storage_blob_host_secondary, :storage_queue_host_secondary, :storage_file_host_secondary attr_reader :signer class << self # List of configurable keys for {Azure::Client} # @return [Array] of option keys def keys @keys ||= [ :storage_access_key, :storage_account_name, :storage_connection_string, :storage_sas_token, :storage_table_host, :storage_blob_host, :storage_queue_host, :storage_file_host, :signer ] end end # Set configuration options using a block def configure yield self end def config self end # Reset configuration options to default values def reset_config!(options = {}) Azure::Storage::Common::Configurable.keys.each do |key| value = if self == Azure::Storage::Common Azure::Storage::Common::Default.options[key] else self.send(key) end instance_variable_set(:"@#{key}", options.fetch(key, value)) # Set the secondary endpoint if the primary one is given if key.to_s.include? "host" instance_variable_set(:"@#{key}_secondary", secondary_endpoint(options.fetch(key, value))) end end self.send(:reset_agents!) if self.respond_to?(:reset_agents!) setup_signer_for_service(options[:api_version]) self end alias setup reset_config! # Storage queue host # @return [String] def storage_queue_host(isSecondary = false) if isSecondary @storage_queue_host_secondary || default_host(:queue, true) else @storage_queue_host || default_host(:queue, false) end end # Storage blob host # @return [String] def storage_blob_host(isSecondary = false) if isSecondary @storage_blob_host_secondary || default_host(:blob, true) else @storage_blob_host || default_host(:blob, false) end end # Storage table host # @return [String] def storage_table_host(isSecondary = false) if isSecondary @storage_table_host_secondary || default_host(:table, true) else @storage_table_host || default_host(:table, false) end end # Storage file host # @return [String] def storage_file_host(isSecondary = false) if isSecondary @storage_file_host_secondary || default_host(:file, true) else @storage_file_host || default_host(:file, false) end end private def default_host(service, isSecondary = false) "https://#{storage_account_name}#{isSecondary ? "-secondary" : ""}.#{service}.core.windows.net" if storage_account_name end def setup_options opts = {} Azure::Storage::Common::Configurable.keys.map do |key| opts[key] = self.send(key) if self.send(key) end opts end def account_name_from_endpoint(endpoint) return nil if endpoint.nil? uri = URI::parse endpoint fields = uri.host.split "." fields[0] end def secondary_endpoint(primary_endpoint) return nil if primary_endpoint.nil? account_name = account_name_from_endpoint primary_endpoint primary_endpoint.sub account_name, account_name + "-secondary" end def determine_account_name if instance_variable_get(:@storage_account_name).nil? hosts = [@storage_blob_host, @storage_table_host, @storage_queue_host, @storage_file_host] account_name = nil; hosts.each do |host| parsed = account_name_from_endpoint host if account_name.nil? account_name = parsed elsif !account_name.nil? && !parsed.nil? && (account_name <=> parsed) != (0) raise InvalidOptionsError, "Ambiguous account name in service hosts." end end raise InvalidOptionsError, "Cannot identify account name." if account_name.nil? @storage_account_name = account_name end end def setup_signer_for_service(api_ver) if @storage_sas_token determine_account_name @signer = Azure::Storage::Common::Core::Auth::SharedAccessSignatureSigner.new api_ver, @storage_account_name, @storage_sas_token end end end end azure-storage-common-2.0.1/lib/azure/storage/common/version.rb0000644000177000017700000000354713753762266023524 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- module Azure module Storage module Common class Version # Fields represent the parts defined in http://semver.org/ MAJOR = 2 unless defined? MAJOR MINOR = 0 unless defined? MINOR UPDATE = 1 unless defined? UPDATE class << self # @return [String] def to_s [MAJOR, MINOR, UPDATE].compact.join(".") end def to_uas [MAJOR, MINOR, UPDATE].join(".") end end end end end end azure-storage-common-2.0.1/lib/azure/storage/common/client_options.rb0000644000177000017700000004311713753762266025065 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "uri" require "azure/storage/common/client_options_error" require "azure/storage/common/core/auth/anonymous_signer" module Azure::Storage::Common module ClientOptions attr_accessor :ca_file, :ssl_version, :ssl_min_version, :ssl_max_version # Public: Reset options for [Azure::Storage::Common::Client] # # ==== Attributes # # * +options+ - Hash | String. Optional parameters or storage connection string. # # ==== Options # # Accepted key/value pairs in options parameter are: # # * +:use_development_storage+ - TrueClass|FalseClass. Whether to use storage emulator. # * +:development_storage_proxy_uri+ - String. Used with +:use_development_storage+ if emulator is hosted other than localhost. # * +:storage_connection_string+ - String. The storage connection string. # * +:storage_account_name+ - String. The name of the storage account. # * +:storage_access_key+ - Base64 String. The access key of the storage account. # * +:storage_sas_token+ - String. The signed access signature for the storage account or one of its service. # * +:storage_blob_host+ - String. Specified Blob serivce endpoint or hostname # * +:storage_table_host+ - String. Specified Table serivce endpoint or hostname # * +:storage_queue_host+ - String. Specified Queue serivce endpoint or hostname # * +:storage_dns_suffix+ - String. The suffix of a regional Storage Serivce, to # * +:default_endpoints_protocol+ - String. http or https # * +:use_path_style_uri+ - String. Whether use path style URI for specified endpoints # * +:ca_file+ - String. File path of the CA file if having issue with SSL # * +:ssl_version+ - Symbol. The ssl version to be used, sample: :TLSv1_1, :TLSv1_2, for the details, see https://github.com/ruby/openssl/blob/master/lib/openssl/ssl.rb # * +:ssl_min_version+ - Symbol. The min ssl version supported, only supported in Ruby 2.5+ # * +:ssl_max_version+ - Symbol. The max ssl version supported, only supported in Ruby 2.5+ # # The valid set of options include: # * Storage Emulator: +:use_development_storage+ required, +:development_storage_proxy_uri+ optionally # * Storage account name and key: +:storage_account_name+ and +:storage_access_key+ required, set +:storage_dns_suffix+ necessarily # * Storage account name and SAS token: +:storage_account_name+ and +:storage_sas_token+ required, set +:storage_dns_suffix+ necessarily # * Specified hosts and SAS token: At least one of the service host and SAS token. It's up to user to ensure the SAS token is suitable for the serivce # * Anonymous Blob: only +:storage_blob_host+, if it is to only access blobs within a container # # Additional notes: # * Specified hosts can be set when use account name with access key or sas token # * +:default_endpoints_protocol+ can be set if the scheme is not specified in hosts # * Storage emulator always use path style URI # # When empty options are given, it will try to read settings from Environment Variables. Refer to [Azure::Storage::Common:ClientOptions.env_vars_mapping] for the mapping relationship # # @return [Azure::Storage::Common::Client] def reset!(options = {}) if options.is_a? String options = parse_connection_string(options) elsif options.is_a? Hash # When the options are provided via singleton setup: Azure::Storage.setup() options = setup_options if options.length == 0 options = parse_connection_string(options[:storage_connection_string]) if options[:storage_connection_string] end # Load from environment when no valid input options = load_env if options.length == 0 @ca_file = options.delete(:ca_file) @ssl_version = options.delete(:ssl_version) @ssl_min_version = options.delete(:ssl_min_version) @ssl_max_version = options.delete(:ssl_max_version) @options = filter(options) self.send(:reset_config!, @options) if self.respond_to?(:reset_config!) self end # Check if this client is configured with the same options def same_options?(opts) opts.length == 0 || opts.hash == options.hash end # The options after validated and normalized # # @return [Hash] def options @options ||= {} end # The valid options for the storage client # # @return [Array] def self.valid_options @valid_options ||= [ :use_development_storage, :development_storage_proxy_uri, :storage_account_name, :storage_access_key, :storage_connection_string, :storage_sas_token, :storage_blob_host, :storage_table_host, :storage_queue_host, :storage_file_host, :storage_dns_suffix, :default_endpoints_protocol, :use_path_style_uri ] end # The mapping between Storage Environment Variables and the options name # # @return [Hash] def self.env_vars_mapping @env_vars_mapping ||= { "EMULATED" => :use_development_storage, "AZURE_STORAGE_ACCOUNT" => :storage_account_name, "AZURE_STORAGE_ACCESS_KEY" => :storage_access_key, "AZURE_STORAGE_CONNECTION_STRING" => :storage_connection_string, "AZURE_STORAGE_BLOB_HOST" => :storage_blob_host, "AZURE_STORAGE_TABLE_HOST" => :storage_table_host, "AZURE_STORAGE_QUEUE_HOST" => :storage_queue_host, "AZURE_STORAGE_FILE_HOST" => :storage_file_host, "AZURE_STORAGE_SAS_TOKEN" => :storage_sas_token, "AZURE_STORAGE_DNS_SUFFIX" => :storage_dns_suffix } end # The mapping between Storage Connection String items and the options name # # @return [Hash] def self.connection_string_mapping @connection_string_mapping ||= { "UseDevelopmentStorage" => :use_development_storage, "DevelopmentStorageProxyUri" => :development_storage_proxy_uri, "DefaultEndpointsProtocol" => :default_endpoints_protocol, "AccountName" => :storage_account_name, "AccountKey" => :storage_access_key, "BlobEndpoint" => :storage_blob_host, "TableEndpoint" => :storage_table_host, "QueueEndpoint" => :storage_queue_host, "FileEndpoint" => :storage_file_host, "SharedAccessSignature" => :storage_sas_token, "EndpointSuffix" => :storage_dns_suffix } end private def method_missing(method_name, *args, &block) return super unless options.key? method_name options[method_name] end def filter(opts = {}) results = {} # P1 - develpoment storage begin results = validated_options(opts, required: [:use_development_storage], optional: [:development_storage_proxy_uri]) results[:use_development_storage] = true proxy_uri = results[:development_storage_proxy_uri] ||= StorageServiceClientConstants::DEV_STORE_URI results.merge!(storage_account_name: StorageServiceClientConstants::DEVSTORE_STORAGE_ACCOUNT, storage_access_key: StorageServiceClientConstants::DEVSTORE_STORAGE_ACCESS_KEY, storage_blob_host: "#{proxy_uri}:#{StorageServiceClientConstants::DEVSTORE_BLOB_HOST_PORT}", storage_table_host: "#{proxy_uri}:#{StorageServiceClientConstants::DEVSTORE_TABLE_HOST_PORT}", storage_queue_host: "#{proxy_uri}:#{StorageServiceClientConstants::DEVSTORE_QUEUE_HOST_PORT}", storage_file_host: "#{proxy_uri}:#{StorageServiceClientConstants::DEVSTORE_FILE_HOST_PORT}", use_path_style_uri: true) return results rescue InvalidOptionsError => e end # P2 - explicit hosts with account connection string begin results = validated_options(opts, required: [:storage_connection_string], optional: [:use_path_style_uri]) results[:use_path_style_uri] = results.key?(:use_path_style_uri) normalize_hosts(results) return results rescue InvalidOptionsError => e end # P3 - account name and key or sas with default hosts or an end suffix begin results = validated_options(opts, required: [:storage_account_name], only_one: [:storage_access_key, :storage_sas_token, :signer], optional: [:default_endpoints_protocol, :storage_dns_suffix]) protocol = results[:default_endpoints_protocol] ||= StorageServiceClientConstants::DEFAULT_PROTOCOL suffix = results[:storage_dns_suffix] ||= StorageServiceClientConstants::DEFAULT_ENDPOINT_SUFFIX account = results[:storage_account_name] results.merge!(storage_blob_host: "#{protocol}://#{account}.#{ServiceType::BLOB}.#{suffix}", storage_table_host: "#{protocol}://#{account}.#{ServiceType::TABLE}.#{suffix}", storage_queue_host: "#{protocol}://#{account}.#{ServiceType::QUEUE}.#{suffix}", storage_file_host: "#{protocol}://#{account}.#{ServiceType::FILE}.#{suffix}", use_path_style_uri: false) return results rescue InvalidOptionsError => e end # P4 - explicit hosts with account name and key begin results = validated_options(opts, required: [:storage_account_name, :storage_access_key], at_least_one: [:storage_blob_host, :storage_table_host, :storage_file_host, :storage_queue_host], optional: [:use_path_style_uri, :default_endpoints_protocol]) results[:use_path_style_uri] = results.key?(:use_path_style_uri) normalize_hosts(results) return results rescue InvalidOptionsError => e end # P5 - anonymous or sas only for one or more particular services, options with account name/key + hosts should be already validated in P4 begin results = validated_options(opts, at_least_one: [:storage_blob_host, :storage_table_host, :storage_file_host, :storage_queue_host], optional: [:use_path_style_uri, :default_endpoints_protocol, :storage_sas_token]) results[:use_path_style_uri] = results.key?(:use_path_style_uri) normalize_hosts(results) # Adds anonymous signer if no sas token results[:signer] = Azure::Storage::Common::Core::Auth::AnonymousSigner.new unless results.key?(:storage_sas_token) return results rescue InvalidOptionsError => e end # P6 - account name and key or sas with explicit hosts begin results = validated_options(opts, required: [:storage_account_name], only_one: [:storage_access_key, :storage_sas_token], at_least_one: [:storage_blob_host, :storage_table_host, :storage_file_host, :storage_queue_host]) results[:use_path_style_uri] = results.key?(:use_path_style_uri) normalize_hosts(results) return results rescue InvalidOptionsError => e end raise InvalidOptionsError, "options provided are not valid set: #{opts}" # wrong opts if move to this line end def normalize_hosts(options) if options[:default_endpoints_protocol] [:storage_blob_host, :storage_table_host, :storage_file_host, :storage_queue_host].each do |k| if options[k] raise InvalidOptionsError, "Explict host cannot contain scheme if default_endpoints_protocol is set." if options[k] =~ /^https?/ options[k] = "#{options[:default_endpoints_protocol]}://#{options[k]}" end end end end def is_base64_encoded Proc.new do |i| i.is_a?(String) && i =~ /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$/ end end def is_url Proc.new do |i| i = "http://" + i unless i =~ /\Ahttps?:\/\// i =~ URI.regexp(["http", "https"]) end end def is_true Proc.new { |i| i == true || (i.is_a?(String) && i.downcase == "true") } end def is_non_empty_string Proc.new { |i| i && i.is_a?(String) && i.strip.length } end def validated_options(opts, requirements = {}) raise InvalidOptionsError, 'nil is not allowed for option\'s value' if opts.values.any? { |v| v == nil } required = requirements[:required] || [] at_least_one = requirements[:at_least_one] || [] only_one = requirements[:only_one] || [] optional = requirements[:optional] || [] raise InvalidOptionsError, "Not all required keys are provided: #{required}" if required.any? { |k| !opts.key? k } raise InvalidOptionsError, "Only one of #{only_one} is required" unless only_one.length == 0 || only_one.count { |k| opts.key? k } == 1 raise InvalidOptionsError, "At least one of #{at_least_one} is required" unless at_least_one.length == 0 || at_least_one.any? { |k| opts.key? k } @@option_validators ||= { use_development_storage: is_true, development_storage_proxy_uri: is_url, storage_account_name: lambda { |i| i.is_a?(String) }, storage_access_key: is_base64_encoded, storage_sas_token: lambda { |i| i.is_a?(String) }, storage_blob_host: is_url, storage_table_host: is_url, storage_queue_host: is_url, storage_file_host: is_url, storage_dns_suffix: is_url, default_endpoints_protocol: lambda { |i| ["http", "https"].include? i.downcase }, use_path_style_uri: is_true, signer: lambda { |i| i.is_a? Azure::Core::Auth::Signer} } valid_options = required + at_least_one + only_one + optional results = {} opts.each do |k, v| raise InvalidOptionsError, "#{k} is not included in valid options" unless valid_options.length == 0 || valid_options.include?(k) unless @@option_validators.key?(k) && @@option_validators[k].call(v) raise InvalidOptionsError, "#{k} is invalid" end results[k] = v end results end def load_env cs = ENV["AZURE_STORAGE_CONNECTION_STRING"] return parse_connection_string(cs) if cs opts = {} ClientOptions.env_vars_mapping.each { |k, v| opts[v] = ENV[k] if ENV[k] } opts end def parse_connection_string(connection_string) opts = {} connection_string.split(";").each do |i| e = i.index("=") raise InvalidConnectionStringError, Azure::Storage::Common::Core::SR::INVALID_CONNECTION_STRING if e < 0 || e == i.length - 1 key, value = i[0..e - 1], i[e + 1..i.length - 1] raise InvalidConnectionStringError, Azure::Storage::Common::Core::SR::INVALID_CONNECTION_STRING_BAD_KEY % key unless ClientOptions.connection_string_mapping.key? key raise InvalidConnectionStringError, Azure::Storage::Common::Core::SR::INVALID_CONNECTION_STRING_EMPTY_KEY % key if value.length == 0 raise InvalidConnectionStringError, Azure::Storage::Common::Core::SR::INVALID_CONNECTION_STRING_DUPLICATE_KEY % key if opts.key? key opts[ClientOptions.connection_string_mapping[key]] = value end raise InvalidConnectionStringError, Azure::Storage::Common::Core::SR::INVALID_CONNECTION_STRING if opts.length == 0 opts end end end azure-storage-common-2.0.1/lib/azure/storage/common/autoload.rb0000644000177000017700000000545413753762266023646 0ustar avronavron# frozen_string_literal: true #------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # The MIT License(MIT) # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files(the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and / or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions : # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. #-------------------------------------------------------------------------- require "rubygems" require "nokogiri" require "base64" require "openssl" require "uri" require "faraday" require "faraday_middleware" require "azure/storage/common/core/autoload" require "azure/storage/common/default" module Azure module Storage autoload :Common, "azure/storage/common/core" module Common autoload :Default, "azure/storage/common/default" autoload :Configurable, "azure/storage/common/configurable" autoload :Client, "azure/storage/common/client" autoload :ClientOptions, "azure/storage/common/client_options" module Auth autoload :SharedAccessSignature, "azure/storage/common/core/auth/shared_access_signature" end module Service autoload :Serialization, "azure/storage/common/service/serialization" autoload :SignedIdentifier, "azure/storage/common/service/signed_identifier" autoload :AccessPolicy, "azure/storage/common/service/access_policy" autoload :StorageService, "azure/storage/common/service/storage_service" autoload :CorsRule, "azure/storage/common/service/cors_rule" autoload :EnumerationResults, "azure/storage/common/service/enumeration_results" autoload :UserDelegationKey, "azure/storage/common/service/user_delegation_key" end end end end azure-storage-common-2.0.1/lib/azure/http_response_helper.rb0000644000177000017700000000331613753762266023331 0ustar avronavron#------------------------------------------------------------------------- # # Copyright (c) Microsoft and contributors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #-------------------------------------------------------------------------- module Azure module HttpResponseHelper # Sends request to HTTP server and returns a Faraday::Response # @param method [Symbol] The HTTP method to use (:get, :post, :put, :del, etc...) # @param url [URI] The URI of the HTTP endpoint to query # @param conn [Net::HTTP] http agent for a given uri # @param headers [String] The request headers # @param body [String] The request body #returns Faraday::Response def set_up_response(method, url, conn, headers ,body) conn.run_request(method, url, nil, nil) do |req| req.body = body if body req.headers = headers if headers unless headers.nil? keep_alive = headers['Keep-Alive'] || headers['keep-alive'] req.options[:timeout] = keep_alive.split('=').last.to_i unless keep_alive.nil? end req.options[:open_timeout] ||= 60 end end end end