Class: Capsium::Packager

Inherits:
Object
  • Object
show all
Defined in:
sig/capsium/packager.rbs,
lib/capsium/packager.rb

Overview

Packs a package directory into a .cap file (generating security.json) and unpacks .cap files with zip-slip protection.

Defined Under Namespace

Classes: FileAlreadyExistsError, UnsafeEntryError

Constant Summary collapse

DRIVE_LETTER_PATTERN =

Returns:

  • (Regexp)
%r{\A[A-Za-z]:[/\\]}

Instance Method Summary collapse

Instance Method Details

#compress_package(package, cap_file) ⇒ void

This method returns an undefined value.

Parameters:

  • package (Package)
  • cap_file (String)


60
61
62
63
64
65
66
67
68
69
# File 'lib/capsium/packager.rb', line 60

def compress_package(package, cap_file)
  entries = Dir[File.join(package.path, "**", "**")].reject do |file|
    File.expand_path(file) == File.expand_path(cap_file)
  end
  Zip::File.open(cap_file, create: true) do |zipfile|
    entries.each do |file|
      zipfile.add(file.sub("#{package.path}/", ""), file)
    end
  end
end

#pack(package, options = {}) ⇒ String

Parameters:

  • package (Package)
  • options (Hash[Symbol, untyped]) (defaults to: {})

Returns:

  • (String)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/capsium/packager.rb', line 20

def pack(package, options = {})
  directory = package.path
  output_file_name = "#{package..name}-#{package..version}.cap"
  output_directory = File.dirname(directory)
  cap_file_path = File.join(output_directory, output_file_name)

  if File.exist?(cap_file_path) && !options[:force]
    raise FileAlreadyExistsError,
          "Package target already exists, aborting: `#{relative_path_current(cap_file_path)}`"
  elsif File.exist?(cap_file_path)
    puts "Package target already exists, overwriting: `#{relative_path_current(cap_file_path)}`"
    FileUtils.rm_f(cap_file_path)
  end

  Dir.mktmpdir do |dir|
    FileUtils.cp_r("#{directory}/.", dir)
    strip_security_artifacts(dir)
    new_package = Package.new(dir)
    new_package.solidify
    generate_security(new_package)
    new_cap_file_path = File.join(dir, output_file_name)
    compress_package(new_package, new_cap_file_path)
    puts "Package built at: #{new_cap_file_path}"
    FileUtils.mv(new_cap_file_path, cap_file_path)
    puts "Package created: #{relative_path_current(cap_file_path)}"
    return cap_file_path
  end
end

#relative_path_current(absolute_path) ⇒ String

Parameters:

  • absolute_path (String)

Returns:

  • (String)


96
97
98
# File 'lib/capsium/packager.rb', line 96

def relative_path_current(absolute_path)
  Pathname.new(absolute_path).relative_path_from(Dir.pwd).to_s
end

#transform_cap(cap_path) {|dir| ... } ⇒ String

Unpacks a .cap into a temporary directory, yields it for modification, then recompresses the result back over cap_path. Returns cap_path.

Parameters:

  • cap_path (String)

Yields:

Yield Parameters:

  • dir (String)

Yield Returns:

  • (Object)

Returns:

  • (String)


84
85
86
87
88
89
90
91
92
93
94
# File 'lib/capsium/packager.rb', line 84

def transform_cap(cap_path)
  with_unpacked_cap(cap_path) do |dir|
    yield dir
    Dir.mktmpdir do |tmp|
      tmp_cap = File.join(tmp, File.basename(cap_path))
      compress_package(Package.new(dir), tmp_cap)
      FileUtils.mv(tmp_cap, cap_path)
    end
  end
  cap_path
end

#unpack(cap_file_path, destination) ⇒ void

This method returns an undefined value.

Parameters:

  • cap_file_path (String)
  • destination (String)


49
50
51
52
53
54
55
56
57
58
# File 'lib/capsium/packager.rb', line 49

def unpack(cap_file_path, destination)
  destination = File.expand_path(destination)
  Zip::File.open(cap_file_path) do |zip_file|
    zip_file.each do |entry|
      entry_path = safe_entry_path(destination, entry.name)
      FileUtils.mkdir_p(File.dirname(entry_path))
      entry.extract(entry_path)
    end
  end
end

#with_unpacked_cap(cap_path) {|dir| ... } ⇒ Object

Unpacks a .cap into a temporary directory, yields it for read-only inspection and returns the block's value.

Parameters:

  • cap_path (String)

Yields:

Yield Parameters:

  • dir (String)

Yield Returns:

  • (Object)

Returns:

  • (Object)


73
74
75
76
77
78
# File 'lib/capsium/packager.rb', line 73

def with_unpacked_cap(cap_path)
  Dir.mktmpdir do |dir|
    unpack(cap_path, dir)
    yield dir
  end
end