ocran 1.3.17 → 1.3.18

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b9a3cbb0a7f0f5d9eecc89b8f14d8c538abf146f9e95e982ece04a0fe1e58278
4
- data.tar.gz: acd0b94387b943c42ca1bbbd336faaacddaf209768e69bd446baff44995ac3cd
3
+ metadata.gz: 816bbf710efb38734ee1955a19ff5bd418b83ff1a5cf21b7a4d0bfe100b2c439
4
+ data.tar.gz: 95173c8a2bd36ea959f4dfe5ddafba5a96b891ced56e9026653e4c1b3aba32a3
5
5
  SHA512:
6
- metadata.gz: 6ce6b73b6a11d76d91c9ba09ce79e71c09de420f68d0ac52a8d6636c95167b669a6ccea3ad3ae171232db80b6335479240363d9e38042c52b3c0fa806b539a41
7
- data.tar.gz: 36334319b2735ff7498cd03f49b85810c2e2a7ea902ec7a9a14a4378e4ec52af56507c551f8d92ee6139883388c91542f1e8c8da0269c0fff4b23660b6472703
6
+ metadata.gz: ae9bd0453f9219098542daa6e1842004cc8efa29422cd80c52a0b936065f790c994139f775a1c2dd42fe9e3ed274e60741ecfc8721692d4293ee1c9fde70a34f
7
+ data.tar.gz: e422b2ed09f116891ff82cee0d5ec29125b71c6ead67964249cdcc4ad375aacced7802f07b91ef6d9419986af4ec49c7c3c56f0e22fcf85aa6cd55a62fd238e6
data/CHANGELOG.txt CHANGED
@@ -1,3 +1,23 @@
1
+ === 1.3.18
2
+ - Support shipping IRB as .exe File
3
+ - Fix SxS error 14001 when loading native extensions (e.g. openssl.so, date_core.so) at runtime. Each .so file may have a companion *.so-assembly.manifest in archdir defining its private SxS assembly; these manifests are now included alongside the .so files. All files in ruby_builtin_dlls/ (DLLs and manifest) are now included rather than the manifest alone.
4
+ - Support for Ruby 4.0.
5
+ - Include cacert.pem in the exe file to avoid SSL certificate verification issues.
6
+ - Use wide (UTF-16) Win32 APIs throughout system_utils.c (CreateFileW, CreateDirectoryW, DeleteFileW, FindFirstFileW/FindNextFileW, RemoveDirectoryW, GetFileAttributesW, MoveFileExW, GetTempPathW, CreateProcessW) to correctly handle multibyte (UTF-8) file and directory paths in the stub.
7
+ - Add Windows Authenticode code signing support. The stub now detects and skips PE security directory entries when searching for the OCRAN signature, so signed executables unpack correctly. Build time clears invalid security directory entries from PE headers to allow subsequent signing.
8
+ - Fix incorrect buffer size passed to GetModuleFileNameW in LibraryDetector (passed bytesize instead of character count).
9
+ - Fix pointer subtraction underflow in stub unpacker when a tampered offset places head past tail.
10
+ - Add bounds checking for icon file entries in edicon to prevent out-of-bounds reads from malformed .ico files.
11
+ - Support for Ruby 3.2 and above. Drop ruby 3.0 and 3.1 support.
12
+ - Suppress user notifications during stub cleanup and log errors to DEBUG output
13
+ - Fixes issue where two MessageBox dialogs appeared in GUI mode when a signature was not found.
14
+ - No longer create a marker file when the stub fails to delete the installation directory during cleanup.
15
+ - stub: During cleanup, switch to a safer working directory before removing the extraction directory.
16
+ - stub: Truncate error messages originating from the stub to a fixed maximum length.
17
+ - stub: Changed the name of the extraction directory to follow the mkdtemp style. The name is now generated using secure random numbers.
18
+ - stub: Disabled path expansion of template characters for additional options passed to the script.
19
+ - stub: Changed the script’s working directory switch to use Ruby’s `-C` option.
20
+
1
21
  === 1.3.17
2
22
  - Modified `rake test` to no longer build stubs during test execution. Use `rake build_stub` when stub generation is necessary.
3
23
  - New `rake build` task as a unified build entry point, delegating to `build_stub`.
data/README.md CHANGED
@@ -12,7 +12,7 @@ executable that contains the Ruby interpreter, your source code and
12
12
  any additionally needed ruby libraries or DLL.
13
13
 
14
14
  OCRAN is a fork of Ocra (https://github.com/larsch/ocra) in order to
15
- maintain compatibility with newer Ruby versions after 3.0
15
+ maintain compatibility with newer Ruby versions after 3.2
16
16
 
17
17
  ## Recommended usage
18
18
  Most commonly you will needs this, when you want to ship your program to windows servers / users that don't have Ruby installed.
@@ -35,9 +35,11 @@ the issue tracker on GitHub (http://github.com/largo/ocran/issues).
35
35
 
36
36
  ## Safety
37
37
 
38
- As this gem comes with binaries, we have taken actions to insure your safety.
39
- The gem releases are built on Github Actions. Feel free verify that it matches the version on rubygems.
40
- It ships with seb.exe and LZMA.exe in this repository, which come from official sources.
38
+ As this gem comes with binary blobs, we have taken actions to insure your safety.
39
+ The gem releases are securely built on Github Actions. Feel free verify that it matches the version on rubygems.
40
+ This repository ships with LZMA.exe from [The official release of ip7z/7zip](https://github.com/ip7z/7zip/releases): Version 22.01 from lzma2201.7z
41
+ The LZMA.exe is used to compress the executable.
42
+ Other files such as stub.exe, stubw.exe and edicon.exe are built from source code in the repository.
41
43
 
42
44
  ## Installation
43
45
 
@@ -144,10 +144,36 @@ module Ocran
144
144
  end
145
145
  end
146
146
 
147
- # Add external manifest files
147
+ # Add external manifest and builtin DLLs
148
148
  if (manifest = ruby_builtin_manifest)
149
- say "Adding external manifest #{manifest}"
150
- builder.duplicate_to_exec_prefix(manifest)
149
+ manifest.dirname.each_child do |path|
150
+ next if path.directory?
151
+ say "Adding builtin DLL/manifest #{path}"
152
+ builder.duplicate_to_exec_prefix(path)
153
+ end
154
+ end
155
+
156
+ # Include SxS assembly manifests for native extensions.
157
+ # Each .so file may have an embedded manifest referencing a companion
158
+ # *.so-assembly.manifest file in the same directory. Without these
159
+ # manifests the SxS activation context fails (error 14001) at runtime.
160
+ # Scan archdir and the extension dirs of all loaded gems.
161
+ sxs_manifest_dirs = []
162
+ archdir = Pathname(RbConfig::CONFIG["archdir"])
163
+ sxs_manifest_dirs << archdir if archdir.exist? && archdir.subpath?(exec_prefix)
164
+ if defined?(Gem)
165
+ Gem.loaded_specs.each_value do |spec|
166
+ next if spec.extensions.empty?
167
+ ext_dir = Pathname(spec.extension_dir)
168
+ sxs_manifest_dirs << ext_dir if ext_dir.exist? && ext_dir.subpath?(exec_prefix)
169
+ end
170
+ end
171
+ sxs_manifest_dirs.each do |dir|
172
+ dir.each_child do |path|
173
+ next unless path.extname == ".manifest"
174
+ say "Adding native extension assembly manifest #{path}"
175
+ builder.duplicate_to_exec_prefix(path)
176
+ end
151
177
  end
152
178
 
153
179
  # Add extra DLLs specified on the command line
@@ -209,15 +235,15 @@ module Ocran
209
235
  # If requested, add all ruby standard libraries
210
236
  if @option.add_all_core?
211
237
  say "Will include all ruby core libraries"
212
- @pre_env.load_path.each do |load_path|
213
- path = Pathname.new(load_path)
238
+ all_core_dir.each do |path|
214
239
  # Match the load path against standard library, site_ruby, and vendor_ruby paths
215
- path.to_posix.match(RUBY_LIBRARY_PATH_REGEX) do |m|
216
- subdir = m[1]
217
- path.find.each do |src|
218
- next if src.directory?
219
- builder.copy_to_lib(src, Pathname(subdir) / src.relative_path_from(path))
220
- end
240
+ unless (subdir = path.to_posix.match(RUBY_LIBRARY_PATH_REGEX)&.[](1))
241
+ raise "Unexpected library path format (does not match core dirs): #{path}"
242
+ end
243
+ path.find.each do |src|
244
+ next if src.directory?
245
+ a = Pathname(subdir) / src.relative_path_from(path)
246
+ builder.copy_to_lib(src, Pathname(subdir) / src.relative_path_from(path))
221
247
  end
222
248
  end
223
249
  end
@@ -312,6 +338,52 @@ module Ocran
312
338
  end
313
339
  end
314
340
 
341
+ # Bundle SSL certificates if OpenSSL was loaded (e.g. via net/http HTTPS)
342
+ if defined?(OpenSSL)
343
+ cert_file = Pathname(OpenSSL::X509::DEFAULT_CERT_FILE)
344
+ if cert_file.file? && cert_file.subpath?(exec_prefix)
345
+ say "Adding SSL certificate file #{cert_file}"
346
+ builder.duplicate_to_exec_prefix(cert_file)
347
+ builder.export("SSL_CERT_FILE", File.join(EXTRACT_ROOT, cert_file.relative_path_from(exec_prefix).to_posix))
348
+ end
349
+
350
+ cert_dir = Pathname(OpenSSL::X509::DEFAULT_CERT_DIR)
351
+ if cert_dir.directory? && cert_dir.subpath?(exec_prefix)
352
+ say "Adding SSL certificate directory #{cert_dir}"
353
+ cert_dir.find.each do |path|
354
+ next if path.directory?
355
+ builder.duplicate_to_exec_prefix(path)
356
+ end
357
+ builder.export("SSL_CERT_DIR", File.join(EXTRACT_ROOT, cert_dir.relative_path_from(exec_prefix).to_posix))
358
+ end
359
+ end
360
+
361
+ # Bundle Tcl/Tk library scripts if the Tk extension is loaded.
362
+ # tcl86.dll and tk86.dll are auto-detected by DLL scanning, but the
363
+ # Tcl/Tk script libraries (init.tcl etc.) must also be bundled so
364
+ # that Tcl can find them relative to the DLL at runtime.
365
+ if defined?(TclTkLib)
366
+ exec_prefix.glob("**/lib/tcl[0-9]*/init.tcl").each do |init_tcl|
367
+ tcl_lib_dir = init_tcl.dirname
368
+ next unless tcl_lib_dir.subpath?(exec_prefix)
369
+ say "Adding Tcl library files #{tcl_lib_dir}"
370
+ tcl_lib_dir.find.each do |path|
371
+ next if path.directory?
372
+ builder.duplicate_to_exec_prefix(path)
373
+ end
374
+ end
375
+
376
+ exec_prefix.glob("**/lib/tk[0-9]*/pkgIndex.tcl").each do |pkg_index|
377
+ tk_lib_dir = pkg_index.dirname
378
+ next unless tk_lib_dir.subpath?(exec_prefix)
379
+ say "Adding Tk library files #{tk_lib_dir}"
380
+ tk_lib_dir.find.each do |path|
381
+ next if path.directory?
382
+ builder.duplicate_to_exec_prefix(path)
383
+ end
384
+ end
385
+ end
386
+
315
387
  # Set environment variable
316
388
  builder.export("RUBYOPT", rubyopt)
317
389
  # Add the load path that are required with the correct path after
@@ -33,5 +33,12 @@ module Ocran
33
33
  def ruby_exe
34
34
  @ruby_exe ||= (RbConfig::CONFIG["ruby_install_name"] || "ruby") + exe_extname
35
35
  end
36
+
37
+ def all_core_dir
38
+ RbConfig::CONFIG
39
+ .slice("rubylibdir", "sitelibdir", "vendorlibdir")
40
+ .values
41
+ .map { |path| Pathname.new(path) }
42
+ end
36
43
  end
37
44
  end
@@ -49,7 +49,7 @@ module Ocran
49
49
  end
50
50
  str = "\x00".encode("UTF-16LE") * MAX_PATH
51
51
  handles.map do |handle|
52
- length = GetModuleFileNameW(handle, str, str.bytesize)
52
+ length = GetModuleFileNameW(handle, str, str.bytesize / 2)
53
53
  if length == 0
54
54
  raise "GetModuleFileNameW failed with error code #{GetLastError()}"
55
55
  end
@@ -8,7 +8,7 @@ module Ocran
8
8
  # instance of OcranBuilder.
9
9
  class StubBuilder
10
10
  Signature = [0x41, 0xb6, 0xba, 0x4e].freeze
11
- OP_END = 0
11
+
12
12
  OP_CREATE_DIRECTORY = 1
13
13
  OP_CREATE_FILE = 2
14
14
  OP_SETENV = 3
@@ -28,6 +28,34 @@ module Ocran
28
28
 
29
29
  attr_reader :data_size
30
30
 
31
+ # Clear invalid security directory entries from PE executables
32
+ # This is necessary because some linkers may set non-zero values in the
33
+ # security directory even when there is no actual digital signature
34
+ def self.clear_invalid_security_entry(file_path)
35
+ data = File.binread(file_path)
36
+ return unless data.size > 64 # Minimum PE header size
37
+
38
+ # Read DOS header to find PE header offset
39
+ e_lfanew_offset = 60
40
+ pe_offset = data[e_lfanew_offset, 4].unpack1("L")
41
+ return if pe_offset + 160 > data.size # Not enough room for headers
42
+
43
+ # Calculate security directory offset
44
+ # PE signature (4) + FILE_HEADER (20) + partial OPTIONAL_HEADER to DataDirectory
45
+ security_entry_offset = pe_offset + 4 + 20 + 128
46
+
47
+ # Read security directory entry (VirtualAddress and Size)
48
+ sec_addr = data[security_entry_offset, 4].unpack1("L")
49
+ sec_size = data[security_entry_offset + 4, 4].unpack1("L")
50
+
51
+ # Check if security entry is invalid (points beyond file or size is 0)
52
+ if sec_size != 0 && (sec_addr == 0 || sec_addr >= data.size || sec_addr + sec_size > data.size)
53
+ # Clear the invalid security entry
54
+ data[security_entry_offset, 8] = "\x00" * 8
55
+ File.binwrite(file_path, data)
56
+ end
57
+ end
58
+
31
59
  # chdir_before:
32
60
  # When set to true, the working directory is changed to the application's
33
61
  # deployment location at runtime.
@@ -65,6 +93,9 @@ module Ocran
65
93
  IO.copy_stream(gui_mode ? STUBW_PATH : STUB_PATH, stub)
66
94
  stub.close
67
95
 
96
+ # Clear any invalid security directory entries from the stub
97
+ self.class.clear_invalid_security_entry(stub.path)
98
+
68
99
  if icon_path
69
100
  system(EDICON_PATH, stub.path, icon_path.to_s, exception: true)
70
101
  end
@@ -77,7 +108,6 @@ module Ocran
77
108
 
78
109
  b = proc {
79
110
  yield(self)
80
- write_opcode(OP_END)
81
111
  }
82
112
 
83
113
  if enable_compression
@@ -184,13 +214,23 @@ module Ocran
184
214
  raise ArgumentError, "String length #{len} is too large: must be less than or equal to 65535 bytes including null terminator"
185
215
  end
186
216
 
187
- @of << [len, str].pack("vZ*")
188
- @data_size += 2 + len
217
+ write_size(len)
218
+ @of << [str].pack("Z*")
219
+ @data_size += len
189
220
  end
190
221
  private :write_string
191
222
 
192
223
  def write_string_array(*str_array)
193
224
  ary = str_array.map(&:to_s)
225
+
226
+ if ary.any?(&:empty?)
227
+ raise ArgumentError, "Argument list must not contain empty strings"
228
+ end
229
+
230
+ # Append an empty string so that when joined with "\0", the final buffer
231
+ # ends in two consecutive NUL bytes (double–NUL terminator) to mark end-of-list.
232
+ ary << ""
233
+
194
234
  size = ary.sum(0) { |s| s.bytesize + 1 }
195
235
  write_size(size)
196
236
  ary.each_slice(1) { |a| @of << a.pack("Z*") }
data/lib/ocran/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ocran
4
- VERSION = "1.3.17"
4
+ VERSION = "1.3.18"
5
5
  end
Binary file
data/share/ocran/stub.exe CHANGED
Binary file
Binary file
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ocran
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.17
4
+ version: 1.3.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andi Idogawa
8
8
  - Lars Christensen
9
- autorequire:
10
9
  bindir: exe
11
10
  cert_chain: []
12
- date: 2025-05-02 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: fiddle
@@ -29,7 +28,7 @@ description: "OCRAN (One-Click Ruby Application Next) builds Windows executables
29
28
  Ruby source code. \n The executable is a self-extracting, self-running executable
30
29
  that contains the Ruby interpreter, your source code and any additionally needed
31
30
  ruby libraries or DLL.\n \n This is a fork of OCRA that is compatible with ruby
32
- version after 3.0.\n Migration guide: make sure to write ocran instead of ocra
31
+ version after 3.2.\n Migration guide: make sure to write ocran instead of ocra
33
32
  in your code. For instance: OCRAN_EXECUTABLE\n\n usage: \n ocra helloworld.rb\n
34
33
  \ helloworld.exe\n\n See readme at https://github.com/largo/ocran\n Report problems
35
34
  in the github issues. Contributions welcome.\n This gem contains executables. We
@@ -76,7 +75,6 @@ metadata:
76
75
  homepage_uri: https://github.com/largo/ocran
77
76
  source_code_uri: https://github.com/largo/ocran
78
77
  changelog_uri: https://github.com/largo/ocran/CHANGELOG.txt
79
- post_install_message:
80
78
  rdoc_options: []
81
79
  require_paths:
82
80
  - lib
@@ -84,15 +82,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
84
82
  requirements:
85
83
  - - ">="
86
84
  - !ruby/object:Gem::Version
87
- version: 3.0.0
85
+ version: 3.2.0
88
86
  required_rubygems_version: !ruby/object:Gem::Requirement
89
87
  requirements:
90
88
  - - ">="
91
89
  - !ruby/object:Gem::Version
92
90
  version: '0'
93
91
  requirements: []
94
- rubygems_version: 3.5.3
95
- signing_key:
92
+ rubygems_version: 4.0.3
96
93
  specification_version: 4
97
94
  summary: OCRAN (One-Click Ruby Application Next) builds Windows executables from Ruby
98
95
  source code.