diff options
Diffstat (limited to 'app/services/packages/debian/generate_distribution_key_service.rb')
-rw-r--r-- | app/services/packages/debian/generate_distribution_key_service.rb | 106 |
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 |