Class: Omnibus::Packager::WindowsBase

Inherits:
Base
  • Object
show all
Defined in:
lib/omnibus/packagers/windows_base.rb

Direct Known Subclasses

APPX, MSI

Constant Summary

Constants included from Util

Util::SHELLOUT_OPTIONS

Constants included from NullArgumentable

NullArgumentable::NULL

Instance Attribute Summary

Attributes inherited from Base

#project

Instance Method Summary collapse

Methods inherited from Base

build, #exclusions, id, #id, #initialize, #install_dir, #package_name, #package_path, #resource_path, #resources_path, #run!, setup, #skip_packager, #staging_dir, #staging_dir_path

Methods included from Util

#compiler_safe_path, #copy_file, #create_directory, #create_file, #create_link, included, #path_key, #remove_directory, #remove_file, #retry_block, #shellout, #shellout!, #windows_safe_path

Methods included from Templating

included, #render_template, #render_template_content

Methods included from Sugarable

extended, included, #node

Methods included from NullArgumentable

included, #null?

Methods included from Logging

included

Methods included from Instrumentation

#measure

Methods included from Digestable

#digest, #digest_directory, included

Constructor Details

This class inherits a constructor from Omnibus::Packager::Base

Instance Method Details

#algorithmObject



98
99
100
# File 'lib/omnibus/packagers/windows_base.rb', line 98

def algorithm
  signing_identity[:algorithm]
end

#cert_store_nameObject



102
103
104
# File 'lib/omnibus/packagers/windows_base.rb', line 102

def cert_store_name
  signing_identity[:store]
end

#certificate_subjectString

Get the certificate subject of the signing identity

Returns:

  • (String)


165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/omnibus/packagers/windows_base.rb', line 165

def certificate_subject
  return "CN=#{project.package_name}" unless signing_identity

  store = machine_store? ? "LocalMachine" : "CurrentUser"
  cmd = [].tap do |arr|
    arr << "powershell.exe"
    arr << "-ExecutionPolicy Bypass"
    arr << "-NoProfile"
    arr << "-Command (Get-Item Cert:/#{store}/#{cert_store_name}/#{thumbprint}).Subject"
  end.join(" ")

  shellout!(cmd).stdout.strip
end

#is_signed?(package_file) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/omnibus/packagers/windows_base.rb', line 123

def is_signed?(package_file)
  cmd = [].tap do |arr|
    arr << "smctl.exe"
    arr << "sign"
    arr << "--fingerprint #{thumbprint}"
    arr << "--input #{package_file}"
  end.join(" ")

  status = shellout(cmd)

  log.debug(log_key) { "#{self.class}##{__method__} - package_file: #{package_file}" }
  log.debug(log_key) { "#{self.class}##{__method__} - cmd: #{cmd}" }
  log.debug(log_key) { "#{self.class}##{__method__} - status: #{status}" }
  log.debug(log_key) { "#{self.class}##{__method__} - status.exitstatus: #{status.exitstatus}" }
  log.debug(log_key) { "#{self.class}##{__method__} - status.stdout: #{status.stdout}" }
  log.debug(log_key) { "#{self.class}##{__method__} - status.stderr: #{status.stderr}" }

  # log the error if the signing failed
  if status.exitstatus != 0
    log.warn(log_key) do
      <<-EOH.strip
            Failed to verify signature of #{package_file}

            STDOUT
            ------
            #{status.stdout}

            STDERR
            ------
            #{status.stderr}
      EOH
    end
  end

  status.exitstatus == 0
end

#keypair_aliasObject



110
111
112
# File 'lib/omnibus/packagers/windows_base.rb', line 110

def keypair_alias
  signing_identity[:keypair_alias]
end

#machine_store?Boolean

Returns:

  • (Boolean)


114
115
116
# File 'lib/omnibus/packagers/windows_base.rb', line 114

def machine_store?
  signing_identity[:machine_store]
end

#sign_package(package_file) ⇒ Object

signs the package with the given certificate



119
120
121
# File 'lib/omnibus/packagers/windows_base.rb', line 119

def sign_package(package_file)
  raise FailedToSignWindowsPackage.new unless is_signed?(package_file)
end

#signing_identity(thumbprint = NULL, params = NULL) ⇒ Hash{:thumbprint => String, :store => String, :timestamp_servers => Array[String]}

Set the signing certificate name

Examples:

signing_identity 'FooCert'
signing_identity 'FooCert', store: 'BarStore'

Parameters:

  • thumbprint (String) (defaults to: NULL)

    the thumbprint of the certificate in the certificate store

  • params (Hash<Symbol, String>) (defaults to: NULL)

    an optional hash that defines the parameters for the singing identity

Options Hash (params):

  • :store (String) — default: My

    The name of the certificate store which contains the certificate

  • :timestamp_servers (Array<String>, String)

    A trusted timestamp server or a list of truested timestamp servers to be tried. They are tried in the order provided.

  • :machine_store (TrueClass, FalseClass) — default: false

    If set to true, the local machine store will be searched for a valid certificate. Otherwise, the current user store is used

    Setting nothing will default to trying [‘timestamp.digicert.com’, ‘timestamp.verisign.com/scripts/timestamp.dll’]

Returns:

  • (Hash{:thumbprint => String, :store => String, :timestamp_servers => Array[String]})


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
# File 'lib/omnibus/packagers/windows_base.rb', line 45

def signing_identity(thumbprint = NULL, params = NULL)
  unless null?(thumbprint)
    @signing_identity = {}
    unless thumbprint.is_a?(String)
      raise InvalidValue.new(:signing_identity, "be a String")
    end

    @signing_identity[:thumbprint] = thumbprint

    if !null?(params)
      unless params.is_a?(Hash)
        raise InvalidValue.new(:params, "be a Hash")
      end

      valid_keys = %i{store machine_store algorithm keypair_alias}
      invalid_keys = params.keys - valid_keys
      unless invalid_keys.empty?

        # log a deprecated warning if timestamp_server is used
        if invalid_keys.include?(:timestamp_servers)
          log.deprecated(log_key) do
            "The signing_identity is updated to use smctl.exe. which does not require timestamp_servers" \
            "Please remove timestamp_servers from your signing_identity"
          end
        end

        raise InvalidValue.new(:params, "contain keys from [#{valid_keys.join(", ")}]. "\
                               "Found invalid keys [#{invalid_keys.join(", ")}]")
      end

      if !params[:machine_store].nil? && !(
         params[:machine_store].is_a?(TrueClass) ||
         params[:machine_store].is_a?(FalseClass))
        raise InvalidValue.new(:params, "contain key :machine_store of type TrueClass or FalseClass")
      end
    else
      params = {}
    end

    @signing_identity[:store] = params[:store] || "My"
    @signing_identity[:algorithm] = params[:algorithm] || "SHA256"
    @signing_identity[:machine_store] = params[:machine_store] || false
    @signing_identity[:keypair_alias] = params[:keypair_alias]
  end

  @signing_identity
end

#thumbprintObject



94
95
96
# File 'lib/omnibus/packagers/windows_base.rb', line 94

def thumbprint
  signing_identity[:thumbprint]
end

#timestamp_serversObject



106
107
108
# File 'lib/omnibus/packagers/windows_base.rb', line 106

def timestamp_servers
  signing_identity[:timestamp_servers]
end

#windows_package_versionString

Parse and return the version from the Omnibus::Project#build_version.

A project’s build_version looks something like:

dev builds => 11.14.0-alpha.1+20140501194641.git.94.561b564
           => 0.0.0+20140506165802.1

rel builds => 11.14.0.alpha.1 || 11.14.0

The appx and msi version specs expects a version that looks like X.Y.Z.W where X, Y, Z & W are all 32 bit integers.

Returns:

  • (String)


194
195
196
197
# File 'lib/omnibus/packagers/windows_base.rb', line 194

def windows_package_version
  major, minor, patch = project.build_version.split(/[.+-]/)
  [major, minor, patch, project.build_iteration].join(".")
end