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

generate_distribution_key_service.rb « debian « packages « services « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 28c97c7681e410d3fc9fde07520179c76d500782 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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