NAME

Archive::Asar - list and extract Electron ASAR (Atom Shell Archive) files

SYNOPSIS

use Archive::Asar;

my $asar = Archive::Asar->new_from_file('app.asar');
# or
my $asar = Archive::Asar->new_from_string($blob);
# or
my $asar = Archive::Asar->new_from_fh('(stdin)', \*STDIN);

my $index_structure = $asar->index_raw;

my $info = $asar->get_entry('file/foo.txt');

$asar->extract_to($target_directory);

DESCRIPTION

Archive::Asar provides an object-oriented interface for handling Electron .asar files ("Atom Shell Archive").

Constructors

new_from_fh

Usage: my $asar = Archive::Asar->new_from_fh($name, $handle);

$name is the name of the archive (used in error messages). $handle is the filehandle to read from (must be seekable, i.e. not a pipe, terminal, socket, etc).

$handle need not be a built-in Perl filehandle; it can be any object that responds to the required methods binmode, seek, tell, and read.

Returns the initialized object or throws an exception on error.

new_from_file

Usage: my $asar = Archive::Asar->new_from_file($file);

Like "new_from_fh", but opens $file first (and automatically uses $file as the name of the archive in error messages).

new_from_string

Usage: my $asar = Archive::Asar->new_from_string($blob);

Like "new_from_fh", but reads the archive data directly from a scalar, not a filehandle.

Methods

index_raw

Usage: my $index = $asar->index_raw;

Returns the parsed index data structure stored as JSON in the ASAR file.

The returned data structure must not be modified.

get_entry

Usage: my $entry = $asar->get_entry($path);

Returns information about the archive member stored at $path.

$path is either a reference to an array of path components (e.g. ['foo', 'bar', 'hello.txt']) or a string with path components separated by / (e.g. 'foo/bar/hello.txt') or (for Windows compatibility) by \ (e.g. 'foo\\bar\\hello.txt').

Use an empty path ([] or '') to get information about the root level of the archive, which should be of type directory.

If the specified path doesn't exist or anything else goes wrong, an exception is thrown.

The return value is a hash reference with a type field. There are three possible types:

directory

{ type => 'directory', entries => [...], unpacked? => true }

An entry of type directory has an entries field (an arrayref of strings) listing the entries in that directory. It may also have an unpacked field (normally set to true if present).

{ type => 'link', target => '...', unpacked? => true }

An entry of type link has a target field (a string) specifying the target of the symbolic link.

Beware: The target field is not validated! It may be any string provided by the archive. It may refer to a file outside of the archive or it may not be a valid filename at all.

file

{ type => 'file', unpacked => true }

{ type => 'file', contents => '...', executable? => true, integrity? => {...} }

An entry of type file has either a true unpacked field, indicating that the file is stored externally (outside of the packed archive), or a contents field giving the contents of the file as a string.

In the latter case, it may also have an executable field, which (if true) indicates that the file is executable, and/or an integrity field, which contains checksum information in the following format:

{
    algorithm => 'SHA256',
    hash      => '...', # lowercase hex
    blockSize => ...,
    blocks    => [...],
}

algorithm is the hashing algorithm to use (currently always SHA256; see Digest::SHA). hash is the result of hashing the file contents (in lowercase hex format, two hex digits per byte).

blockSize is an integer. The blocks field is an array of the results of splitting the file contents into chunks of (at most) blockSize bytes and hashing each chunk separately, in the same format as hash.

For example, an empty file may appear as:

{
    type      => 'file',
    contents  => '',
    integrity => {
        algorithm => 'SHA256',
        hash      => 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
        blockSize => 0x400000,
        blocks    => ['e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'],
    },
}
extract_to

Usage: $asar->extract_to($target_directory, $options = {});

Extracts the contents of the archive into the given $target_directory, which is automatically created if it doesn't exist yet.

The $options argument is optional, but must be a hash reference if given. Currently only one option is supported:

unpacked_dir

If unpacked_dir is set to a defined value, files marked unpacked in the archive will be read from this directory (and copied to $target_directory).

Otherwise unpacked files will be skipped when extracting.

BUGS AND LIMITATIONS

  • Creating and modifying archives is not supported.

  • Support for "unpacked" archive members is rudimentary.

  • Tests are incomplete.

AUTHOR

Lukas Mai, <lmai at web.de>

COPYRIGHT & LICENSE

Copyright 2026 Lukas Mai.

This module is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.