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]:[/\\]}
DOT_ENTRIES =
[".", ".."].freeze

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)


45
46
47
48
49
50
51
52
53
54
55
# File 'lib/capsium/packager.rb', line 45

def compress_package(package, cap_file)
  entries = Dir.glob(File.join(package.path, "**", "**"), File::FNM_DOTMATCH).reject do |file|
    File.expand_path(file) == File.expand_path(cap_file) ||
      DOT_ENTRIES.include?(File.basename(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)


21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/capsium/packager.rb', line 21

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

  Dir.mktmpdir do |dir|
    build_cap(package, dir, output_file_name, options)
    FileUtils.mv(File.join(dir, output_file_name), 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)


82
83
84
# File 'lib/capsium/packager.rb', line 82

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)


70
71
72
73
74
75
76
77
78
79
80
# File 'lib/capsium/packager.rb', line 70

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)


34
35
36
37
38
39
40
41
42
43
# File 'lib/capsium/packager.rb', line 34

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)


59
60
61
62
63
64
# File 'lib/capsium/packager.rb', line 59

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