Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb')
-rw-r--r--app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb93
1 files changed, 93 insertions, 0 deletions
diff --git a/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb
new file mode 100644
index 00000000000..5cbca53582d
--- /dev/null
+++ b/app/services/import/gitlab_projects/file_acquisition_strategies/remote_file_s3.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+module Import
+ module GitlabProjects
+ module FileAcquisitionStrategies
+ class RemoteFileS3
+ include ActiveModel::Validations
+ include Gitlab::Utils::StrongMemoize
+
+ def self.allow_local_requests?
+ ::Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
+ end
+
+ validates_presence_of :region, :bucket_name, :file_key, :access_key_id, :secret_access_key
+ validates :file_url, addressable_url: {
+ schemes: %w(https),
+ allow_localhost: allow_local_requests?,
+ allow_local_network: allow_local_requests?,
+ dns_rebind_protection: true
+ }
+
+ validates_with RemoteFileValidator
+
+ # The import itself has a limit of 24h, since the URL is created before the import starts
+ # we add an expiration a bit longer to ensure it won't expire during the import.
+ URL_EXPIRATION = 28.hours.seconds
+
+ def initialize(current_user: nil, params:)
+ @params = params
+ end
+
+ def project_params
+ @project_parms ||= {
+ import_export_upload: ::ImportExportUpload.new(remote_import_url: file_url)
+ }
+ end
+
+ def file_url
+ @file_url ||= s3_object&.presigned_url(:get, expires_in: URL_EXPIRATION.to_i)
+ end
+
+ def content_type
+ @content_type ||= s3_object&.content_type
+ end
+
+ def content_length
+ @content_length ||= s3_object&.content_length.to_i
+ end
+
+ # Make the validated params/methods accessible
+ def read_attribute_for_validation(key)
+ return file_url if key == :file_url
+
+ params[key]
+ end
+
+ private
+
+ attr_reader :params
+
+ def s3_object
+ strong_memoize(:s3_object) do
+ build_s3_options
+ end
+ end
+
+ def build_s3_options
+ object = Aws::S3::Object.new(
+ params[:bucket_name],
+ params[:file_key],
+ client: Aws::S3::Client.new(
+ region: params[:region],
+ access_key_id: params[:access_key_id],
+ secret_access_key: params[:secret_access_key]
+ )
+ )
+
+ # Force validate if the object exists and is accessible
+ # Some exceptions are only raised when trying to access the object data
+ unless object.exists?
+ errors.add(:base, "File not found '#{params[:file_key]}' in '#{params[:bucket_name]}'")
+ return
+ end
+
+ object
+ rescue StandardError => e
+ errors.add(:base, "Failed to open '#{params[:file_key]}' in '#{params[:bucket_name]}': #{e.message}")
+ nil
+ end
+ end
+ end
+ end
+end