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 +4 -4
- data/CHANGELOG.txt +20 -0
- data/README.md +6 -4
- data/lib/ocran/direction.rb +83 -11
- data/lib/ocran/host_config_helper.rb +7 -0
- data/lib/ocran/library_detector.rb +1 -1
- data/lib/ocran/stub_builder.rb +44 -4
- data/lib/ocran/version.rb +1 -1
- data/share/ocran/edicon.exe +0 -0
- data/share/ocran/stub.exe +0 -0
- data/share/ocran/stubw.exe +0 -0
- metadata +5 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 816bbf710efb38734ee1955a19ff5bd418b83ff1a5cf21b7a4d0bfe100b2c439
|
|
4
|
+
data.tar.gz: 95173c8a2bd36ea959f4dfe5ddafba5a96b891ced56e9026653e4c1b3aba32a3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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
|
|
39
|
-
The gem releases are built on Github Actions. Feel free verify that it matches the version on rubygems.
|
|
40
|
-
|
|
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
|
|
data/lib/ocran/direction.rb
CHANGED
|
@@ -144,10 +144,36 @@ module Ocran
|
|
|
144
144
|
end
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
-
# Add external manifest
|
|
147
|
+
# Add external manifest and builtin DLLs
|
|
148
148
|
if (manifest = ruby_builtin_manifest)
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
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)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
data/lib/ocran/stub_builder.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Ocran
|
|
|
8
8
|
# instance of OcranBuilder.
|
|
9
9
|
class StubBuilder
|
|
10
10
|
Signature = [0x41, 0xb6, 0xba, 0x4e].freeze
|
|
11
|
-
|
|
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
|
-
|
|
188
|
-
@
|
|
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
data/share/ocran/edicon.exe
CHANGED
|
Binary file
|
data/share/ocran/stub.exe
CHANGED
|
Binary file
|
data/share/ocran/stubw.exe
CHANGED
|
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.
|
|
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:
|
|
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.
|
|
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.
|
|
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:
|
|
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.
|