owlet 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ spec/fixtures/*.alulaextz
6
+ spec/fixtures/*.alulathmz
7
+ /spec/reports/
8
+ /spec/fixtures/fixture.alulaextz
9
+ /spec/fixtures/fixture.alulathmz
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in owlet.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec', :version => 2, :cli => "--color --format documentation" do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch(%r{^lib/(.+)/(.+)\.rb$}) { |m| "spec/#{m[1]}/#{m[2]}_spec.rb" }
5
+ watch('spec/spec_helper.rb') { "spec" }
6
+ end
data/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Owlet
2
+
3
+ Owlet is a package system for Alula extensions and themes. Using custom packages for extensions
4
+ gives benefits of easier distribution, downloading and management. Using single file packages
5
+ it is easy to upload required extensions and themes directly to the server from your computer.
6
+
7
+ In addition, all Owlets are digitally signed to make sure that package is not altered in any ways.
8
+
9
+ ## Technical
10
+
11
+ Basically Owlets are simple ZIP files which as `_Signature` file as addition.
12
+ Signature file is simple YAML file, which contains signatures in base64 encoded
13
+ for all files that are in package, as well public certificate that was used
14
+ in signing process.
15
+
16
+ Owlets can be signed more than once, every additional signing round adds more signatures and
17
+ public key. While verifying packages, all signatures must match to public keys.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec) do |spec|
5
+ spec.pattern = FileList['spec/**/*_spec.rb']
6
+ end
7
+
8
+ require 'rubygems'
9
+ require 'ci/reporter/rake/rspec'
data/bin/owlet ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'owlet/cli'
5
+
6
+ Owlet::CLI.start
data/lib/owlet/cli.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'thor'
2
+ require 'owlet'
3
+
4
+ module Owlet
5
+ class CLI < Thor
6
+ # Signing operations
7
+ desc "sign PACKAGE", "Signs Owlet package with supplied key."
8
+ method_option :key, :required => true, :description => "Private and public key to be used for signing. Must be in PKCS12 format."
9
+ def sign(package)
10
+ Owlet::Signer.sign_package(package, options[:key])
11
+ end
12
+
13
+ desc "verify PACKAGE", "Verifies Alula extension or theme"
14
+ def verify(package)
15
+ begin
16
+ Owlet::Signer.verify_package(package)
17
+ puts "Verify OK."
18
+ rescue
19
+ puts "Verify FAILED."
20
+ end
21
+ end
22
+
23
+ # Packaking operations
24
+ desc "package DIRECTORY", "Create owlet package from given directory."
25
+ method_option :key
26
+ def package(dir)
27
+ pkg = Owlet::Package.create_from_dir(dir)
28
+ if (options[:key] and pkg)
29
+ Owlet::Signer.sign_package(pkg, options[:key])
30
+ end
31
+ end
32
+
33
+ desc "extract PACKAGE [DIR]", "Extracts contents of given package, optionally to given directory"
34
+ def extract(package, dir = ".")
35
+ Owlet::Package.extract(package, dir)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ require 'zip/zip'
2
+
3
+ module Owlet
4
+ class Package
5
+
6
+ def self.create(args = {})
7
+ source = args[:source]
8
+
9
+ # Validate source
10
+ unless File.directory?(source)
11
+ raise "Invalid source directory."
12
+ end
13
+
14
+ ext = File.extname(source)
15
+ dest_ext = case ext[1..-1]
16
+ when "alulaextension"
17
+ "alulaextz"
18
+ when "alulatheme"
19
+ "alulathmz"
20
+ else
21
+ raise "Unknown owlet type."
22
+ end
23
+ destination = args[:destination] || File.join(File.dirname(source), "#{File.basename(source, ext)}.#{dest_ext}")
24
+
25
+ Zip::ZipFile.open(destination, Zip::ZipFile::CREATE) do |zip|
26
+ Dir.glob("#{source}/**/*").each do |entry|
27
+ zip.add(entry.gsub("#{source}/", ''), entry)
28
+ end
29
+ end
30
+
31
+ # All done
32
+ return destination
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,104 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module Owlet
5
+ class Signer
6
+ # Sign arbitary data using private_key
7
+ # Return Base 64 (RFC 4648) encoded signature
8
+ def self.sign(data, private_key)
9
+ Base64.encode64(private_key.sign(OpenSSL::Digest::SHA256.new, data)).gsub(/\n/, '')
10
+ end
11
+
12
+ # Verify arbitary data against given signature and public key.
13
+ # Signature must be Base64 encoded, RFC 4648 compliat.
14
+ def self.verify(data, signature, public_key)
15
+ public_key.verify(OpenSSL::Digest::SHA256.new, Base64.decode64(signature).gsub(/\n/, ''), data)
16
+ end
17
+
18
+ def self.list_certificates(package)
19
+ # Check that package exists.
20
+ raise "Cannot file package #{package}" unless File.exists?(package)
21
+
22
+ sig_data = Zip::ZipFile.open(package) do |zip|
23
+ entry = zip.find_entry("_Signature")
24
+ unless entry.nil?
25
+ YAML.load(entry.get_input_stream.read)
26
+ else
27
+ {:certificates => []}
28
+ end
29
+ end
30
+
31
+ sig_data[:certificates]
32
+ end
33
+
34
+ # Signs given package with PKCS12 file
35
+ # p12 is either OpenSSL::PKCS!@ or file
36
+ def self.sign_package(package, p12)
37
+ # Get private key
38
+ unless p12.kind_of? OpenSSL::PKCS12
39
+ p12 = OpenSSL::PKCS12.new(File.read(p12))
40
+ end
41
+
42
+ raise "Cannot find package #{package}" unless File.exists?(package)
43
+
44
+ # Initialize signature data
45
+ sig_data = { :signatures => {}, :certificates => []}
46
+
47
+ # Open and sign files
48
+ Zip::ZipFile.open(package) do |zip|
49
+ sig_meta = zip.find_entry("_Signature")
50
+ unless sig_meta.nil?
51
+ sig_data = YAML.load(sig_meta.get_input_stream.read)
52
+ end
53
+
54
+ zip.each do |entry|
55
+ data = entry.get_input_stream.read
56
+ next if data.nil?
57
+
58
+ sig_data[:signatures][entry.name] ||= []
59
+ sig_data[:signatures][entry.name].push sign(data, p12.key)
60
+ end
61
+
62
+ sig_data[:certificates].push p12.certificate.to_pem
63
+
64
+ zip.get_output_stream("_Signature") do |io|
65
+ io.puts sig_data.to_yaml
66
+ end
67
+ end
68
+
69
+ true
70
+ end
71
+
72
+ def self.verify_package(package)
73
+ raise "Cannot find package #{package}" unless File.exists?(package)
74
+
75
+ Zip::ZipFile.open(package) do |zip|
76
+ entry = zip.find_entry("_Signature")
77
+ raise "Package not signed." if entry.nil?
78
+
79
+ sig_data = YAML.load(entry.get_input_stream.read)
80
+ sig_data[:certificates].map! { |c| OpenSSL::X509::Certificate.new(c) }
81
+
82
+ zip.each do |entry|
83
+ next if entry.name == "_Signature"
84
+
85
+ # Check for all certificates
86
+ sig_data[:certificates].each_index do |i|
87
+ data = entry.get_input_stream.read
88
+ next if data.nil?
89
+
90
+ if sig_data[:signatures][entry.name].nil? or sig_data[:signatures][entry.name][i].nil?
91
+ raise "Cannot find signature for #{entry.name}"
92
+ end
93
+
94
+ unless verify(data, sig_data[:signatures][entry.name][i], sig_data[:certificates][i].public_key)
95
+ raise "Signature for #{entry.name} for certicate #{sig_data[:certificates][i].subject} failed."
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ return true
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,3 @@
1
+ module Owlet
2
+ VERSION = "0.1.1"
3
+ end
data/lib/owlet.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "owlet/version"
2
+
3
+ module Owlet
4
+ autoload :Package, 'owlet/package'
5
+ autoload :Signer, 'owlet/signer'
6
+ end
data/owlet.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "owlet/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "owlet"
7
+ s.version = Owlet::VERSION
8
+ s.authors = ["Mikko Kokkonen"]
9
+ s.email = ["mikko@mikian.com"]
10
+ s.homepage = "http://alula.in/owlet"
11
+ s.summary = %q{Owlet is a packaging system for distributing extensions and themes for Alula Engine}
12
+ s.description = %q{Use Owlet library to create and alter and gather information about owlets.}
13
+
14
+ s.rubyforge_project = "owlet"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'thor'
22
+ s.add_dependency 'rubyzip'
23
+
24
+ s.add_development_dependency 'rake'
25
+ s.add_development_dependency 'rspec'
26
+ s.add_development_dependency 'guard-rspec'
27
+ s.add_development_dependency 'ci_reporter'
28
+ end
Binary file
@@ -0,0 +1,25 @@
1
+ extension "GoSquared"
2
+
3
+ description "GoSquared - real-time web analytics"
4
+
5
+ configuration do
6
+ desc "Site Token for your site"
7
+ option :token, :type => String
8
+ end
9
+
10
+ analytics :position => :body_bottom, do |c|
11
+ <<<-EOD
12
+ <script type="text/javascript">
13
+ var GoSquared={};
14
+ GoSquared.acct = "#{c.token}";
15
+ (function(w){
16
+ function gs(){
17
+ w._gstc_lt=+(new Date); var d=document;
18
+ var g = d.createElement("script"); g.type = "text/javascript"; g.async = true; g.src = "//d1l6p2sc9645hc.cloudfront.net/tracker.js";
19
+ var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(g, s);
20
+ }
21
+ w.addEventListener?w.addEventListener("load",gs,false):w.attachEvent("onload",gs);
22
+ })(window);
23
+ </script>
24
+ EOD
25
+ end
@@ -0,0 +1,8 @@
1
+ theme "fixture"
2
+
3
+ description "Fixture theme for Alula"
4
+
5
+ configuration do
6
+ desc "Header logo"
7
+ option :header, :type => :image, :size => [960, 80]
8
+ end
@@ -0,0 +1,5 @@
1
+ $background: #efefef;
2
+
3
+ body {
4
+ background-color: $background;
5
+ }
Binary file
File without changes
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Owlet::Package do
4
+ let(:fixture_path) { fixture_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "fixtures")) }
5
+
6
+ before(:all) do
7
+ %w{fixture.alulaextz fixture.alulathmz}.each do |fixture|
8
+ File.unlink(File.join(fixture_path, fixture)) if File.exists?(File.join(fixture_path, fixture))
9
+ end
10
+ end
11
+
12
+ it "should raise error for invalid source path" do
13
+ lambda { Owlet::Package.create(:source => File.join(fixture_path, "missing_path")) }.should raise_error("Invalid source directory.")
14
+ end
15
+
16
+ it "should create a package from extension" do
17
+ pkg = Owlet::Package.create(:source => File.join(fixture_path, "fixture.alulaextension"))
18
+ pkg.should eq(File.join(fixture_path, "fixture.alulaextz"))
19
+ end
20
+
21
+ it "should create package from theme" do
22
+ pkg = Owlet::Package.create(:source => File.join(fixture_path, "fixture.alulatheme"))
23
+ pkg.should eq(File.join(fixture_path, "fixture.alulathmz"))
24
+ end
25
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe Owlet::Signer do
4
+ let(:fixture_path) { fixture_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "fixtures")) }
5
+
6
+ context "Helper Methods" do
7
+ let(:first_p12) { OpenSSL::PKCS12.new(File.read(File.join(fixture_path, "first.p12"))) }
8
+ let(:pleco_p12) { OpenSSL::PKCS12.new(File.read(File.join(fixture_path, "pleco.p12"))) }
9
+ let(:first_signature) { "lu2zFctrv7ssmcudjTVNoj9xS47GpMsYBxF8tQVhXnpOBXIM/7TuY+ZpHkxUqzgWssJdrUqLpC6t9OoUyLbUOU2HI4aNdmwOHv3XmpuIazmELEz/aCbwuCnwIAw6YtQiF14GQhUqR2A/6LE9ZB3+bKBDuxSMRY9WbRHELjoeXyg=" }
10
+
11
+ it "should sign data" do
12
+ # Load private key
13
+ data = "aaaa/bbbb/cccc"
14
+ signature = Owlet::Signer.sign(data, first_p12.key)
15
+
16
+ signature.should == first_signature
17
+ end
18
+
19
+ it "should verify data" do
20
+ data = "aaaa/bbbb/cccc"
21
+
22
+ Owlet::Signer.verify(data, first_signature, first_p12.certificate.public_key).should be_true
23
+ end
24
+
25
+ it "should not verify invalid data" do
26
+ data = "aaaa/bbbb/cccc/dddd"
27
+
28
+ Owlet::Signer.verify(data, first_signature, first_p12.certificate.public_key).should be_false
29
+ end
30
+
31
+ it "should not verify with wrong public key" do
32
+ data = "aaaa/bbbb/cccc"
33
+
34
+ Owlet::Signer.verify(data, first_signature, pleco_p12.certificate.public_key).should be_false
35
+ end
36
+ end
37
+
38
+ context "Package" do
39
+ let(:first_p12) { OpenSSL::PKCS12.new(File.read(File.join(fixture_path, "first.p12"))) }
40
+ let(:pleco_p12) { OpenSSL::PKCS12.new(File.read(File.join(fixture_path, "pleco.p12"))) }
41
+
42
+ before(:each) do
43
+ # Create package
44
+ File.unlink(File.join(fixture_path, "fixture.alulaextz")) if File.exists?(File.join(fixture_path, "fixture.alulaextz"))
45
+ @pkg = Owlet::Package.create(:source => File.join(fixture_path, "fixture.alulaextension"))
46
+ end
47
+
48
+ it "should have no certificates" do
49
+ signatures = Owlet::Signer.list_certificates(@pkg)
50
+ signatures.should be_empty
51
+ end
52
+
53
+ it "should be signed succesfully" do
54
+ Owlet::Signer.sign_package(@pkg, first_p12).should be_true
55
+ end
56
+
57
+ it "should have one certificate" do
58
+ Owlet::Signer.sign_package(@pkg, first_p12).should be_true
59
+ signatures = Owlet::Signer.list_certificates(@pkg)
60
+ signatures[0].should_not be_nil
61
+ cert = OpenSSL::X509::Certificate.new(signatures[0])
62
+ cert.subject.to_s.should == "/O=Owl Forestry/CN=Alula Extension"
63
+ signatures[1].should be_nil
64
+ end
65
+
66
+ it "should verify signed package" do
67
+ Owlet::Signer.sign_package(@pkg, first_p12).should be_true
68
+ Owlet::Signer.verify_package(@pkg).should be_true
69
+ end
70
+
71
+ it "should signed twice" do
72
+ Owlet::Signer.sign_package(@pkg, first_p12).should be_true
73
+ Owlet::Signer.sign_package(@pkg, pleco_p12).should be_true
74
+ signatures = Owlet::Signer.list_certificates(@pkg)
75
+ signatures[1].should_not be_nil
76
+ cert = OpenSSL::X509::Certificate.new(signatures[1])
77
+ cert.subject.to_s.should == "/O=Owl Forestry/CN=Alula Pleco - Extension"
78
+ end
79
+
80
+ it "should fail with modified package" do
81
+ Owlet::Signer.sign_package(@pkg, first_p12).should be_true
82
+ Zip::ZipFile.open(@pkg) do |zip|
83
+ zip.get_output_stream("init.rb") do |io|
84
+ io.puts "# Fail this thanks."
85
+ end
86
+ end
87
+
88
+ lambda { Owlet::Signer.verify_package(@pkg)}.should raise_error "Signature for init.rb for certicate /O=Owl Forestry/CN=Alula Extension failed."
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'owlet'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: owlet
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mikko Kokkonen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &70162863022180 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70162863022180
25
+ - !ruby/object:Gem::Dependency
26
+ name: rubyzip
27
+ requirement: &70162863021740 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70162863021740
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70162863021240 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70162863021240
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &70162863020600 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70162863020600
58
+ - !ruby/object:Gem::Dependency
59
+ name: guard-rspec
60
+ requirement: &70162863019940 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70162863019940
69
+ - !ruby/object:Gem::Dependency
70
+ name: ci_reporter
71
+ requirement: &70162863019520 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70162863019520
80
+ description: Use Owlet library to create and alter and gather information about owlets.
81
+ email:
82
+ - mikko@mikian.com
83
+ executables:
84
+ - owlet
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - .gitignore
89
+ - Gemfile
90
+ - Guardfile
91
+ - README.md
92
+ - Rakefile
93
+ - bin/owlet
94
+ - lib/owlet.rb
95
+ - lib/owlet/cli.rb
96
+ - lib/owlet/package.rb
97
+ - lib/owlet/signer.rb
98
+ - lib/owlet/version.rb
99
+ - owlet.gemspec
100
+ - spec/fixtures/first.p12
101
+ - spec/fixtures/fixture.alulaextension/init.rb
102
+ - spec/fixtures/fixture.alulatheme/init.rb
103
+ - spec/fixtures/fixture.alulatheme/javascripts/application.js.coffeescript
104
+ - spec/fixtures/fixture.alulatheme/stylesheets/application.css.scss
105
+ - spec/fixtures/pleco.p12
106
+ - spec/owlet/cli_spec.rb
107
+ - spec/owlet/package_spec.rb
108
+ - spec/owlet/signer_spec.rb
109
+ - spec/spec_helper.rb
110
+ homepage: http://alula.in/owlet
111
+ licenses: []
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubyforge_project: owlet
130
+ rubygems_version: 1.8.6
131
+ signing_key:
132
+ specification_version: 3
133
+ summary: Owlet is a packaging system for distributing extensions and themes for Alula
134
+ Engine
135
+ test_files:
136
+ - spec/fixtures/first.p12
137
+ - spec/fixtures/fixture.alulaextension/init.rb
138
+ - spec/fixtures/fixture.alulatheme/init.rb
139
+ - spec/fixtures/fixture.alulatheme/javascripts/application.js.coffeescript
140
+ - spec/fixtures/fixture.alulatheme/stylesheets/application.css.scss
141
+ - spec/fixtures/pleco.p12
142
+ - spec/owlet/cli_spec.rb
143
+ - spec/owlet/package_spec.rb
144
+ - spec/owlet/signer_spec.rb
145
+ - spec/spec_helper.rb