What is @electron/asar?
@electron/asar is a Node.js library used to create, manipulate, and extract ASAR (Atom Shell Archive) files. ASAR files are essentially archives used by Electron applications to package their resources. This package provides functionalities to pack files into an ASAR archive, extract files from an ASAR archive, and manipulate the contents of an ASAR archive.
What are @electron/asar's main functionalities?
Packing files into an ASAR archive
This feature allows you to pack a directory of files into an ASAR archive. The `createPackage` function takes the source directory and the output file path as arguments and creates the ASAR archive.
const asar = require('@electron/asar');
asar.createPackage('path/to/source', 'path/to/output.asar', function() {
console.log('ASAR archive created successfully!');
});
Extracting files from an ASAR archive
This feature allows you to extract all files from an ASAR archive to a specified directory. The `extractAll` function takes the ASAR archive path and the destination directory as arguments and extracts the contents.
const asar = require('@electron/asar');
asar.extractAll('path/to/archive.asar', 'path/to/destination', function() {
console.log('ASAR archive extracted successfully!');
});
Listing files in an ASAR archive
This feature allows you to list all files contained in an ASAR archive. The `listPackage` function takes the ASAR archive path as an argument and returns an array of file paths contained in the archive.
const asar = require('@electron/asar');
const files = asar.listPackage('path/to/archive.asar');
console.log(files);
Other packages similar to @electron/asar
tar
The `tar` package is used for reading and writing tar archives. It provides functionalities to create, extract, and list files in tar archives. Unlike ASAR, tar archives are more commonly used and supported across different platforms and tools.
zip
The `zip` package is used for creating and extracting zip archives. It provides functionalities to compress files into a zip archive and extract files from a zip archive. Zip archives are widely used and supported by many applications and operating systems.
node-7z
The `node-7z` package is a Node.js wrapper for the 7-Zip compression tool. It allows you to create and extract 7z archives, which offer high compression ratios. This package provides similar functionalities to ASAR but uses the 7z format instead.
@electron/asar - Electron Archive
Asar is a simple extensive archive format, it works like tar
that concatenates
all files together without compression, while having random access support.
Features
- Support random access
- Use JSON to store files' information
- Very easy to write a parser
Command line utility
Install
This module requires Node 10 or later.
$ npm install --engine-strict @electron/asar
Usage
$ asar --help
Usage: asar [options] [command]
Commands:
pack|p <dir> <output>
create asar archive
list|l <archive>
list files of asar archive
extract-file|ef <archive> <filename>
extract one file from archive
extract|e <archive> <dest>
extract archive
Options:
-h, --help output usage information
-V, --version output the version number
Excluding multiple resources from being packed
Given:
app
(a) ├── x1
(b) ├── x2
(c) ├── y3
(d) │ ├── x1
(e) │ └── z1
(f) │ └── x2
(g) └── z4
(h) └── w1
Exclude: a, b
$ asar pack app app.asar --unpack-dir "{x1,x2}"
Exclude: a, b, d, f
$ asar pack app app.asar --unpack-dir "**/{x1,x2}"
Exclude: a, b, d, f, h
$ asar pack app app.asar --unpack-dir "{**/x1,**/x2,z4/w1}"
Using programmatically
Example
const asar = require('@electron/asar');
const src = 'some/path/';
const dest = 'name.asar';
await asar.createPackage(src, dest);
console.log('done.');
Please note that there is currently no error handling provided!
Transform
You can pass in a transform
option, that is a function, which either returns
nothing, or a stream.Transform
. The latter will be used on files that will be
in the .asar
file to transform them (e.g. compress).
const asar = require('@electron/asar');
const src = 'some/path/';
const dest = 'name.asar';
function transform (filename) {
return new CustomTransformStream()
}
await asar.createPackageWithOptions(src, dest, { transform: transform });
console.log('done.');
Using with grunt
There is also an unofficial grunt plugin to generate asar archives at bwin/grunt-asar.
Format
Asar uses Pickle to safely serialize binary value to file.
The format of asar is very flat:
| UInt32: header_size | String: header | Bytes: file1 | ... | Bytes: file42 |
The header_size
and header
are serialized with Pickle class, and
header_size
's Pickle object is 8 bytes.
The header
is a JSON string, and the header_size
is the size of header
's
Pickle
object.
Structure of header
is something like this:
{
"files": {
"tmp": {
"files": {}
},
"usr" : {
"files": {
"bin": {
"files": {
"ls": {
"offset": "0",
"size": 100,
"executable": true,
"integrity": {
"algorithm": "SHA256",
"hash": "...",
"blockSize": 1024,
"blocks": ["...", "..."]
}
},
"cd": {
"offset": "100",
"size": 100,
"executable": true,
"integrity": {
"algorithm": "SHA256",
"hash": "...",
"blockSize": 1024,
"blocks": ["...", "..."]
}
}
}
}
}
},
"etc": {
"files": {
"hosts": {
"offset": "200",
"size": 32,
"integrity": {
"algorithm": "SHA256",
"hash": "...",
"blockSize": 1024,
"blocks": ["...", "..."]
}
}
}
}
}
}
offset
and size
records the information to read the file from archive, the
offset
starts from 0 so you have to manually add the size of header_size
and
header
to the offset
to get the real offset of the file.
offset
is a UINT64 number represented in string, because there is no way to
precisely represent UINT64 in JavaScript Number
. size
is a JavaScript
Number
that is no larger than Number.MAX_SAFE_INTEGER
, which has a value of
9007199254740991
and is about 8PB in size. We didn't store size
in UINT64
because file size in Node.js is represented as Number
and it is not safe to
convert Number
to UINT64.
integrity
is an object consisting of a few keys:
- A hashing
algorithm
, currently only SHA256
is supported. - A hex encoded
hash
value representing the hash of the entire file. - An array of hex encoded hashes for the
blocks
of the file. i.e. for a blockSize of 4KB this array contains the hash of every block if you split the file into N 4KB blocks. - A integer value
blockSize
representing the size in bytes of each block in the blocks
hashes above