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/packages/debian/generate_distribution_key_service.rb')
-rw-r--r--app/services/packages/debian/generate_distribution_key_service.rb106
1 files changed, 106 insertions, 0 deletions
diff --git a/app/services/packages/debian/generate_distribution_key_service.rb b/app/services/packages/debian/generate_distribution_key_service.rb
new file mode 100644
index 00000000000..28c97c7681e
--- /dev/null
+++ b/app/services/packages/debian/generate_distribution_key_service.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+module Packages
+ module Debian
+ class GenerateDistributionKeyService
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(current_user:, params: {})
+ @current_user = current_user
+ @params = params
+ end
+
+ def execute
+ raise ArgumentError, 'Please provide a user' unless current_user.is_a?(User)
+
+ generate_key
+ end
+
+ private
+
+ attr_reader :current_user, :params
+
+ def passphrase
+ strong_memoize(:passphrase) do
+ params[:passphrase] || ::User.random_password
+ end
+ end
+
+ def pinentry_script_content
+ escaped_passphrase = Shellwords.escape(passphrase)
+
+ <<~EOF
+ #!/bin/sh
+
+ echo OK Pleased to meet you
+
+ while read -r cmd; do
+ case "$cmd" in
+ GETPIN) echo D #{escaped_passphrase}; echo OK;;
+ *) echo OK;;
+ esac
+ done
+ EOF
+ end
+
+ def using_pinentry
+ Gitlab::Gpg.using_tmp_keychain do
+ home_dir = Gitlab::Gpg.current_home_dir
+
+ File.write("#{home_dir}/pinentry.sh", pinentry_script_content, mode: 'w', perm: 0755)
+
+ File.write("#{home_dir}/gpg-agent.conf", "pinentry-program #{home_dir}/pinentry.sh\n", mode: 'w')
+
+ GPGME::Ctx.new(armor: true, offline: true) do |ctx|
+ yield ctx
+ end
+ end
+ end
+
+ def generate_key_params
+ # https://www.gnupg.org/documentation/manuals/gnupg/Unattended-GPG-key-generation.html
+ '<GnupgKeyParms format="internal">' + "\n" +
+ {
+ 'Key-Type': params[:key_type] || 'RSA',
+ 'Key-Length': params[:key_length] || 4096,
+ 'Key-Usage': params[:key_usage] || 'sign',
+ 'Name-Real': params[:name_real] || 'GitLab Debian repository',
+ 'Name-Email': params[:name_email] || Gitlab.config.gitlab.email_reply_to,
+ 'Name-Comment': params[:name_comment] || 'GitLab Debian repository automatic signing key',
+ 'Expire-Date': params[:expire_date] || 0,
+ 'Passphrase': passphrase
+ }.map { |k, v| "#{k}: #{v}\n" }.join +
+ '</GnupgKeyParms>'
+ end
+
+ def generate_key
+ using_pinentry do |ctx|
+ # Generate key
+ ctx.generate_key generate_key_params
+
+ key = ctx.keys.first # rubocop:disable Gitlab/KeysFirstAndValuesFirst
+ fingerprint = key.fingerprint
+
+ # Export private key
+ data = GPGME::Data.new
+ ctx.export_keys fingerprint, data, GPGME::EXPORT_MODE_SECRET
+ data.seek 0
+ private_key = data.read
+
+ # Export public key
+ data = GPGME::Data.new
+ ctx.export_keys fingerprint, data
+ data.seek 0
+ public_key = data.read
+
+ {
+ private_key: private_key,
+ public_key: public_key,
+ passphrase: passphrase,
+ fingerprint: fingerprint
+ }
+ end
+ end
+ end
+ end
+end