diff --git a/lib/cask.rb b/lib/cask.rb index 27cac12a540a..e47d8bd95ea7 100644 --- a/lib/cask.rb +++ b/lib/cask.rb @@ -21,6 +21,7 @@ class Cask; end require 'cask/dsl' require 'cask/exceptions' require 'cask/fetcher' +require 'cask/gpg' require 'cask/installer' require 'cask/link_checker' require 'cask/locations' diff --git a/lib/cask/dsl.rb b/lib/cask/dsl.rb index 1159a00f1ca2..cb8a62df6609 100644 --- a/lib/cask/dsl.rb +++ b/lib/cask/dsl.rb @@ -12,6 +12,8 @@ def url; self.class.url; end def appcast; self.class.appcast; end + def gpg; self.class.gpg; end + def version; self.class.version; end def depends_on_formula; self.class.depends_on_formula; end @@ -50,6 +52,17 @@ def appcast(*args) end end + def gpg(*args) + if @gpg and !args.empty? + raise CaskInvalidError.new(self.title, "'gpg' stanza may only appear once") + end + @gpg ||= begin + Cask::Gpg.new(*args) unless args.empty? + rescue StandardError => e + raise CaskInvalidError.new(self.title, e) + end + end + def container_type(type=nil) if @container_type and !type.nil? raise CaskInvalidError.new(self.title, "'container_type' stanza may only appear once") diff --git a/lib/cask/gpg.rb b/lib/cask/gpg.rb new file mode 100644 index 000000000000..286513e8c876 --- /dev/null +++ b/lib/cask/gpg.rb @@ -0,0 +1,40 @@ +class Cask::Gpg + + VALID_TYPES = Set.new [ + :id, # first one is the default + :url, + ] + + REQUIRED_PARAMETERS = [ + :signature + ] + + attr_reader :key, :parameters, :type, :signature + + def initialize(key, parameters={}) + @parameters = parameters + REQUIRED_PARAMETERS.each do |param| + unless @parameters.key?(param) and not @parameters[param].nil? + raise "gpg #{param.inspect} parameter is required" + end + end + @key = key + @signature = Cask::UnderscoreSupportingURI.parse(@parameters[:signature]) + @type = @parameters[:type] + @type = VALID_TYPES.first if @type.nil? + unless VALID_TYPES.include?(@type) + raise "invalid gpg type: '#{@type.inspect}'" + end + if @type == :url + @key = Cask::UnderscoreSupportingURI.parse(@key) + end + end + + def to_yaml + [@key, @parameters].to_yaml + end + + def to_s + @key.to_s + end +end diff --git a/lib/cask/utils.rb b/lib/cask/utils.rb index 26d4ff1d7c9a..1178a3811407 100644 --- a/lib/cask/utils.rb +++ b/lib/cask/utils.rb @@ -82,6 +82,7 @@ def dumpcask :caveats, :depends_on_formula, :container_type, + :gpg, ].each do |method| odebug "Cask instance method '#{method}':", self.send(method).to_yaml end diff --git a/test/cask/dsl_test.rb b/test/cask/dsl_test.rb index 33fd2bec6a7a..1eba1d12be7f 100644 --- a/test/cask/dsl_test.rb +++ b/test/cask/dsl_test.rb @@ -112,4 +112,36 @@ def caveats; <<-EOS.undent }.must_raise(CaskInvalidError) err.message.must_include "'version' stanza may only appear once" end + + describe "gpg stanza" do + it "allows gpg stanza to be specified" do + cask = Cask.load('with-gpg') + cask.gpg.to_s.must_match %r{\S} + end + + it "prevents specifying gpg multiple times" do + err = lambda { + invalid_cask = Cask.load('invalid/invalid-gpg-multiple') + }.must_raise(CaskInvalidError) + err.message.must_include "'gpg' stanza may only appear once" + end + + it "refuses to load invalid gpg signature URLs" do + err = lambda { + invalid_cask = Cask.load('invalid/invalid-gpg-signature-url') + }.must_raise(CaskInvalidError) + end + + it "refuses to load invalid gpg key URLs" do + err = lambda { + invalid_cask = Cask.load('invalid/invalid-gpg-key-url') + }.must_raise(CaskInvalidError) + end + + it "refuses to load if gpg :type is invalid" do + err = lambda { + invalid_cask = Cask.load('invalid/invalid-gpg-type') + }.must_raise(CaskInvalidError) + end + end end diff --git a/test/support/Casks/invalid/invalid-gpg-key-url.rb b/test/support/Casks/invalid/invalid-gpg-key-url.rb new file mode 100644 index 000000000000..ccf3828be649 --- /dev/null +++ b/test/support/Casks/invalid/invalid-gpg-key-url.rb @@ -0,0 +1,9 @@ +class InvalidGpgKeyUrl < TestCask + url TestHelper.local_binary('caffeine.zip') + homepage 'http://example.com/invalid-gpg-key-url' + gpg 1, :type => :url, + :signature => 'http://example.com/gpg-signature.asc' + sha256 '9203c30951f9aab41ac294bbeb1dcef7bed401ff0b353dcb34d68af32ea51853' + version '1.2.3' + link 'Caffeine.app' +end diff --git a/test/support/Casks/invalid/invalid-gpg-multiple.rb b/test/support/Casks/invalid/invalid-gpg-multiple.rb new file mode 100644 index 000000000000..5985179b7ed6 --- /dev/null +++ b/test/support/Casks/invalid/invalid-gpg-multiple.rb @@ -0,0 +1,11 @@ +class InvalidGpgMultiple < TestCask + url TestHelper.local_binary('caffeine.zip') + homepage 'http://example.com/invalid-gpg-multiple' + gpg 'ID', :type => :id, + :signature => 'http://example.com/gpg-signature.asc' + gpg 'ID', :type => :id, + :signature => 'http://example.com/gpg-signature.asc' + sha256 '9203c30951f9aab41ac294bbeb1dcef7bed401ff0b353dcb34d68af32ea51853' + version '1.2.3' + link 'Caffeine.app' +end diff --git a/test/support/Casks/invalid/invalid-gpg-signature-url.rb b/test/support/Casks/invalid/invalid-gpg-signature-url.rb new file mode 100644 index 000000000000..707421ed8c89 --- /dev/null +++ b/test/support/Casks/invalid/invalid-gpg-signature-url.rb @@ -0,0 +1,9 @@ +class InvalidGpgSignatureUrl < TestCask + url TestHelper.local_binary('caffeine.zip') + homepage 'http://example.com/invalid-gpg-signature-url' + gpg 'ID', :type => :id, + :signature => 1 + sha256 '9203c30951f9aab41ac294bbeb1dcef7bed401ff0b353dcb34d68af32ea51853' + version '1.2.3' + link 'Caffeine.app' +end diff --git a/test/support/Casks/invalid/invalid-gpg-type.rb b/test/support/Casks/invalid/invalid-gpg-type.rb new file mode 100644 index 000000000000..e3ebff89ba52 --- /dev/null +++ b/test/support/Casks/invalid/invalid-gpg-type.rb @@ -0,0 +1,9 @@ +class InvalidGpgType < TestCask + url TestHelper.local_binary('caffeine.zip') + homepage 'http://example.com/invalid-gpg-type' + gpg 'ID', :type => :no_such_type, + :signature => 'http://example.com/gpg-signature.asc' + sha256 '9203c30951f9aab41ac294bbeb1dcef7bed401ff0b353dcb34d68af32ea51853' + version '1.2.3' + link 'Caffeine.app' +end diff --git a/test/support/Casks/with-gpg.rb b/test/support/Casks/with-gpg.rb new file mode 100644 index 000000000000..afae2900ce41 --- /dev/null +++ b/test/support/Casks/with-gpg.rb @@ -0,0 +1,9 @@ +class WithGpg < TestCask + url TestHelper.local_binary('caffeine.zip') + homepage 'http://example.com/with-gpg' + gpg 'ID', :type => :id, + :signature => 'http://example.com/gpg-signature.asc' + sha256 '9203c30951f9aab41ac294bbeb1dcef7bed401ff0b353dcb34d68af32ea51853' + version '1.2.3' + link 'Caffeine.app' +end