Constellation-crxmake 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/README.rdoc +76 -0
  2. data/Rakefile +95 -0
  3. data/bin/crxmake +68 -0
  4. data/lib/crxmake.rb +190 -0
  5. data/test/crxmake_test.rb +35 -0
  6. metadata +71 -0
data/README.rdoc ADDED
@@ -0,0 +1,76 @@
1
+ = crxmake
2
+
3
+ * http://github.com/Constellation/crxmake
4
+
5
+ == DESCRIPTION:
6
+
7
+ make chromium extensions
8
+
9
+ == SYNOPSIS:
10
+ ruby code
11
+ require 'crxmake'
12
+ CrxMake.make(
13
+ :ex_dir => "./src",
14
+ :pkey => "./test.pem",
15
+ :crx_output => "./package/test.crx",
16
+ :verbose => true,
17
+ :ignorefile => /\.swp/,
18
+ :ignoredir => /\.(?:svn|git|cvs)/
19
+ )
20
+
21
+ command line
22
+ $ crxmake --pack-extension=<extension dir> --extension-output=<extension output path> --pack-extension-key=<pem path>
23
+
24
+ required opt
25
+ --pack-extension=<extension dir>
26
+ extension source directory
27
+
28
+ optional opt
29
+ --extension-output=<extension output path>
30
+ crx output path (default: ./<extension dirname>.crx)
31
+ --pack-extension-key=<pem path>
32
+ pem key path
33
+ --key-output=<key path>
34
+ pem key output path if you generate key (default: ./<extension
35
+ dirname>.pem)
36
+ --ignore-file=<pattern>
37
+ pattern to ignore files
38
+ pattern is compiled by Regexp.new(<pattern>)
39
+ --ignore-dir=<pattern>
40
+ pattern to ignore directories
41
+ pattern is compiled by Regexp.new(<pattern>)
42
+
43
+ == REQUIREMENTS:
44
+
45
+ * openssl
46
+ * zipruby
47
+
48
+ == INSTALL:
49
+
50
+ gem source -a http://gems.github.com
51
+ sudo gem install Constellation-crxmake
52
+
53
+ == LICENSE:
54
+
55
+ (The MIT License)
56
+
57
+ Copyright (c) 2009 Constellation
58
+
59
+ Permission is hereby granted, free of charge, to any person obtaining
60
+ a copy of this software and associated documentation files (the
61
+ 'Software'), to deal in the Software without restriction, including
62
+ without limitation the rights to use, copy, modify, merge, publish,
63
+ distribute, sublicense, and/or sell copies of the Software, and to
64
+ permit persons to whom the Software is furnished to do so, subject to
65
+ the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be
68
+ included in all copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
71
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
72
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
73
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
74
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
75
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
76
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,95 @@
1
+ # vim: fileencoding=utf-8
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+ require 'rake/packagetask'
7
+ require 'rake/gempackagetask'
8
+ require 'rake/rdoctask'
9
+ require 'rake/contrib/rubyforgepublisher'
10
+ require 'rake/contrib/sshpublisher'
11
+ require 'fileutils'
12
+ require 'lib/crxmake'
13
+ include FileUtils
14
+
15
+ $version = CrxMake::VERSION
16
+ $readme = 'README.rdoc'
17
+ $rdoc_opts = %W(--main #{$readme} --charset utf-8 --line-numbers --inline-source)
18
+ $name = 'crxmake'
19
+ $summary = 'make chromium extension'
20
+ $author = 'Constellation'
21
+ $email = 'utatane.tea@gmail.com'
22
+ $page = 'http://github.com/Constellation/crxmake/tree/master'
23
+ $exec = %W(crxmake)
24
+ $rubyforge_project = 'crxmake'
25
+
26
+
27
+ task :default => [:test]
28
+ task :package => [:clean]
29
+
30
+ Rake::TestTask.new("test") do |t|
31
+ t.libs << "test"
32
+ t.pattern = "test/**/*_test.rb"
33
+ t.verbose = true
34
+ end
35
+
36
+ spec = Gem::Specification.new do |s|
37
+ s.name = $name
38
+ s.version = $version
39
+ s.platform = Gem::Platform::RUBY
40
+ s.has_rdoc = true
41
+ s.extra_rdoc_files = [$readme]
42
+ s.rdoc_options += $rdoc_opts
43
+ s.summary = $summary
44
+ s.description = $summary
45
+ s.author = $author
46
+ s.email = $email
47
+ s.homepage = $page
48
+ s.executables = $exec
49
+ s.rubyforge_project = $rubyforge_project
50
+ s.bindir = 'bin'
51
+ s.require_path = 'lib'
52
+ s.test_files = Dir["test/*_test.rb"]
53
+ {
54
+ "zipruby" => ">=0.3.2",
55
+ # "openssl" => ">=1.0.0"
56
+ }.each do |dep, ver|
57
+ s.add_dependency(dep, ver)
58
+ end
59
+ s.files = %w(README.rdoc Rakefile) + Dir["{bin,test,lib}/**/*"]
60
+ end
61
+
62
+ Rake::GemPackageTask.new(spec) do |p|
63
+ p.need_tar = true
64
+ p.gem_spec = spec
65
+ end
66
+
67
+ Rake::RDocTask.new do |rdoc|
68
+ rdoc.rdoc_dir = 'doc'
69
+ rdoc.options += $rdoc_opts
70
+ # rdoc.template = 'resh'
71
+ rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb", "ext/**/*.c")
72
+ end
73
+
74
+ desc "gem spec"
75
+ task :gemspec do
76
+ File.open("#{$name}.gemspec", "wb") do |f|
77
+ f << spec.to_ruby
78
+ end
79
+ end
80
+
81
+ desc "gem build"
82
+ task :build => [:gemspec] do
83
+ sh "gem build #{$name}.gemspec"
84
+ end
85
+
86
+ desc "gem install"
87
+ task :install => [:build] do
88
+ sh "sudo gem install #{$name}-#{$version}.gem --local"
89
+ end
90
+
91
+ desc "gem uninstall"
92
+ task :uninstall do
93
+ sh "sudo gem uninstall #{$name}"
94
+ end
95
+ # vim: syntax=ruby
data/bin/crxmake ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/ruby
2
+ # vim: fileencoding=utf-8
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'crxmake'
6
+
7
+ data = {}
8
+ usage = <<-EOS
9
+ option not valid
10
+
11
+ [usage]
12
+ required opt
13
+ --pack-extension=<extension dir>
14
+ extension source directory
15
+
16
+ optional opt
17
+ --extension-output=<extension output path>
18
+ crx output path (default: ./<extension dirname>.crx)
19
+ --pack-extension-key=<pem path>
20
+ pem key path
21
+ --key-output=<key path>
22
+ pem key output path if you generate key (default: ./<extension
23
+ dirname>.pem)
24
+ --ignore-file=<pattern>
25
+ pattern to ignore files
26
+ pattern is compiled by Regexp.new(<pattern>)
27
+ --ignore-dir=<pattern>
28
+ pattern to ignore directories
29
+ pattern is compiled by Regexp.new(<pattern>)
30
+ EOS
31
+
32
+ OptionParser.new('Packaging Chromium Extension') do |opt|
33
+ opt.version = '2'
34
+ opt.on('--pack-extension DIR') do |val|
35
+ data[:ex_dir] = val
36
+ end
37
+ opt.on('--pack-extension-key KEY') do |key|
38
+ data[:pkey] = key
39
+ end
40
+ opt.on('--key-output OKEY') do |okey|
41
+ data[:pkey_output] = okey
42
+ end
43
+ opt.on('--extension-output CRX') do |crx|
44
+ data[:crx_output] = crx
45
+ end
46
+ opt.on('--ignore-file FILE') do |file|
47
+ data[:ignorefile] = Regexp.new file
48
+ end
49
+ opt.on('--ignore-dir DIR') do |dir|
50
+ data[:ignoredir] = Regexp.new dir
51
+ end
52
+ opt.on('-v', '--verbose') do
53
+ data[:verbose] = true
54
+ end
55
+ begin
56
+ opt.parse!(ARGV)
57
+ rescue
58
+ puts usage
59
+ end
60
+ end
61
+
62
+ begin
63
+ CrxMake.make(data)
64
+ rescue => e
65
+ puts e.message
66
+ puts usage
67
+ end
68
+
data/lib/crxmake.rb ADDED
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/ruby
2
+ # vim: fileencoding=utf-8
3
+ require 'rubygems'
4
+ require 'zipruby'
5
+ require 'openssl'
6
+ require 'digest/sha1'
7
+ require 'fileutils'
8
+ require 'find'
9
+
10
+ class CrxMake < Object
11
+ VERSION = '1.0.0'
12
+ @@magic = [?C, ?r, ?2, ?4].pack('C*')
13
+ # this is chromium extension version
14
+ @@version = [2].pack('L')
15
+
16
+ # CERT_PUBLIC_KEY_INFO struct
17
+ @@key_algo = %w(30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 81 8D 00 30 81 89 02 81 81).map{|s| s.hex}.pack('C*')
18
+ @@key_foot = %w(02 03 01 00 01).map{|s| s.hex}.pack('C*')
19
+ @@key_size = 1024
20
+ def initialize opt
21
+ check_valid_option(opt)
22
+ if @pkey
23
+ read_key
24
+ else
25
+ generate_key
26
+ end
27
+ create_zip
28
+ sign_zip
29
+ write_crx
30
+ ensure
31
+ final
32
+ end
33
+
34
+ private
35
+ def check_valid_option o
36
+ @exdir, @pkey, @pkey_o, @crx, @verbose, @ignorefile, @ignoredir = o[:ex_dir], o[:pkey], o[:pkey_output], o[:crx_output], o[:verbose], o[:ignorefile], o[:ignoredir]
37
+ @exdir = File.expand_path(@exdir) if @exdir
38
+ raise "extension dir not exist" if !@exdir || !File.exist?(@exdir) || !File.directory?(@exdir)
39
+ @pkey = File.expand_path(@pkey) if @pkey
40
+ raise "private key not exist" if @pkey && (!File.exist?(@pkey) || !File.file?(@pkey))
41
+ if @pkey_o
42
+ @pkey_o = File.expand_path(@pkey_o)
43
+ raise "private key output path is directory" if File.directory?(@pkey_o)
44
+ else
45
+ count = 0
46
+ loop do
47
+ if count.zero?
48
+ @pkey_o = File.expand_path("./#{File.basename(@exdir)}.pem")
49
+ else
50
+ @pkey_o = File.expand_path("./#{File.basename(@exdir)}-#{count+=1}.pem")
51
+ end
52
+ break unless File.directory?(@pkey_o)
53
+ end
54
+ end
55
+ if @crx
56
+ @crx = File.expand_path(@crx)
57
+ raise "crx path is directory" if File.directory?(@crx)
58
+ else
59
+ count = 0
60
+ loop do
61
+ if count.zero?
62
+ @crx = File.expand_path("./#{File.basename(@exdir)}.crx")
63
+ else
64
+ @crx = File.expand_path("./#{File.basename(@exdir)}-#{count+=1}.crx")
65
+ end
66
+ break unless File.directory?(@crx)
67
+ end
68
+ end
69
+ @crx_dir = File.dirname(@crx)
70
+ puts <<-EOS if @verbose
71
+ crx output dir: #{@crxdir}
72
+ ext dir: #{@exdir}
73
+ EOS
74
+ @zip = File.join(@crx_dir, 'extension.zip')
75
+ end
76
+
77
+ def read_key
78
+ puts "read pemkey, \"#{@pkey}\"" if @verbose
79
+ File.open(@pkey, 'rb') do |io|
80
+ @key = OpenSSL::PKey::RSA.new(io)
81
+ end
82
+ end
83
+
84
+ def generate_key
85
+ puts "generate pemkey to \"#{@pkey_o}\"" if @verbose
86
+ @key = OpenSSL::PKey::RSA.generate(@@key_size)
87
+ # save key
88
+ File.open(@pkey_o, 'wb') do |file|
89
+ file << @key.export()
90
+ end
91
+ end
92
+
93
+ def create_zip
94
+ puts "create zip" if @verbose
95
+ Zip::Archive.open(@zip, Zip::CREATE | Zip::TRUNC) do |zip|
96
+ Find.find(@exdir) do |path|
97
+ unless path == @exdir
98
+ if File.directory?(path)
99
+ if @ignoredir && File.basename(path) =~ @ignoredir
100
+ puts "ignore dir: \"#{path}\"" if @verbose
101
+ Find.prune
102
+ else
103
+ puts "include dir: \"#{path}\"" if @verbose
104
+ zip.add_dir(get_relative(@exdir, path))
105
+ end
106
+ else
107
+ if @ignorefile && File.basename(path) =~ @ignorefile
108
+ puts "ignore file: \"#{path}\"" if @verbose
109
+ else
110
+ puts "include file: \"#{path}\"" if @verbose
111
+ zip.add_file(get_relative(@exdir, path), path)
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ puts <<-EOS if @verbose
118
+ create zip...done
119
+ zip file at #{@zip}
120
+ EOS
121
+ end
122
+
123
+ def get_relative base, target
124
+ if base == target
125
+ return '.'
126
+ end
127
+ if base[base.size - 1] != ?/
128
+ base += '/'
129
+ end
130
+ target.sub(Regexp.escape(base), '')
131
+ end
132
+
133
+ def sign_zip
134
+ puts "sign zip" if @verbose
135
+ plain = nil
136
+ File.open(@zip, 'rb') do |file|
137
+ plain = file.read
138
+ end
139
+ @sig = @key.sign(OpenSSL::Digest::SHA1.new, plain)
140
+ end
141
+
142
+ def write_crx
143
+ print "write crx..." if @verbose
144
+ key = @@key_algo + key_data + @@key_foot
145
+ File.open(@crx, 'wb') do |file|
146
+ file << @@magic
147
+ file << @@version
148
+ file << to_sizet(key.size)
149
+ file << to_sizet(@sig.size)
150
+ file << key
151
+ file << @sig
152
+ File.open(@zip, 'rb') do |zip|
153
+ file << zip.read
154
+ end
155
+ end
156
+ puts "done" if @verbose
157
+ end
158
+
159
+ def key_data
160
+ pubkey = @key.public_key
161
+ memo = pubkey.to_text.split(/\r|\n|\n\r/).inject({:flag => false, :data => []}){|memo, line|
162
+ if memo[:flag]
163
+ if line =~ /^\s+/
164
+ memo[:data].push(*line.strip.split(':'))
165
+ else
166
+ memo[:flag] = false
167
+ end
168
+ elsif /^Modulus/ =~ line
169
+ memo[:flag] = true
170
+ end
171
+ memo
172
+ }
173
+ data = memo[:data].map{|s| s.hex}.pack('C*')
174
+ return data
175
+ end
176
+
177
+ def to_sizet num
178
+ return [num].pack('L')
179
+ end
180
+
181
+ def final
182
+ FileUtils.rm_rf(@zip) if @zip && File.exist?(@zip)
183
+ end
184
+
185
+ class << self
186
+ alias make new
187
+ end
188
+ end
189
+
190
+
@@ -0,0 +1,35 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/crxmake'
3
+ require 'fileutils'
4
+ require 'pp'
5
+ require 'open-uri'
6
+
7
+ class CrxMakeTest < Test::Unit::TestCase
8
+ def setup
9
+ @dir = File.expand_path('tmp')
10
+ FileUtils.mkdir @dir
11
+ # chromefullfeed compile
12
+ open("http://chromefullfeed.googlecode.com/files/package.tar") do |file|
13
+ File.open(File.join(@dir, 'package.tar'), 'wb') do |f|
14
+ f << file.read
15
+ end
16
+ end
17
+ system("tar -xf #{File.join(@dir, "package.tar")} -C #{@dir}")
18
+ end
19
+ def teardown
20
+ FileUtils.rm_rf @dir
21
+ end
22
+ def test_create_crx
23
+ CrxMake.make(
24
+ :ex_dir => File.join(@dir, 'src'),
25
+ :pkey_output => File.join(@dir, 'test.pem'),
26
+ :crx_output => File.join(@dir, 'test.crx'),
27
+ :verbose => true,
28
+ :ignorefile => /\.swp$/,
29
+ :ignoredir => /^\.(?:svn|git|cvs)$/
30
+ )
31
+ assert(File.exist?(File.join(@dir, 'test.crx')))
32
+ assert(File.exist?(File.join(@dir, 'test.pem')))
33
+ end
34
+ end
35
+
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: Constellation-crxmake
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Constellation
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-11 00:00:00 -07:00
13
+ default_executable: crxmake
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: zipruby
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.3.2
24
+ version:
25
+ description: make chromium extension
26
+ email: utatane.tea@gmail.com
27
+ executables:
28
+ - crxmake
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - README.rdoc
35
+ - Rakefile
36
+ - bin/crxmake
37
+ - test/crxmake_test.rb
38
+ - lib/crxmake.rb
39
+ has_rdoc: false
40
+ homepage: http://github.com/Constellation/crxmake/tree/master
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --main
44
+ - README.rdoc
45
+ - --charset
46
+ - utf-8
47
+ - --line-numbers
48
+ - --inline-source
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project: crxmake
66
+ rubygems_version: 1.2.0
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: make chromium extension
70
+ test_files:
71
+ - test/crxmake_test.rb