Constellation-crxmake 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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