Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: allow paths to asar archives to contain the .asar extension in directories #20342

Merged
merged 1 commit into from
Oct 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 1 addition & 18 deletions lib/common/asar.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@
return newArchive
}

const ASAR_EXTENSION = '.asar'

// Separate asar package's path from full path.
const splitPath = archivePathOrBuffer => {
// Shortcut for disabled asar.
Expand All @@ -54,22 +52,7 @@
}
if (typeof archivePath !== 'string') return { isAsar: false }

if (archivePath.endsWith(ASAR_EXTENSION)) {
return { isAsar: true, asarPath: archivePath, filePath: '' }
}

archivePath = path.normalize(archivePath)
const index = archivePath.lastIndexOf(`${ASAR_EXTENSION}${path.sep}`)
if (index === -1) return { isAsar: false }

// E.g. for "//some/path/to/archive.asar/then/internal.file"...
return {
isAsar: true,
// "//some/path/to/archive.asar"
asarPath: archivePath.substr(0, index + ASAR_EXTENSION.length),
// "then/internal.file" (with a path separator excluded)
filePath: archivePath.substr(index + ASAR_EXTENSION.length + 1)
}
return asar.splitPath(path.normalize(archivePath))
}

// Convert asar archive's Stats object to fs's Stats object.
Expand Down
17 changes: 17 additions & 0 deletions shell/common/api/atom_api_asar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
#include <vector>

#include "native_mate/arguments.h"
#include "native_mate/dictionary.h"
#include "native_mate/object_template_builder_deprecated.h"
#include "native_mate/wrappable.h"
#include "shell/common/asar/archive.h"
#include "shell/common/asar/asar_util.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/native_mate_converters/file_path_converter.h"
Expand Down Expand Up @@ -127,12 +129,27 @@ void InitAsarSupport(v8::Isolate* isolate, v8::Local<v8::Value> require) {
&asar_init_params, &asar_init_args, nullptr);
}

v8::Local<v8::Value> SplitPath(v8::Isolate* isolate,
const base::FilePath& path) {
mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate);
base::FilePath asar_path, file_path;
if (asar::GetAsarArchivePath(path, &asar_path, &file_path, true)) {
dict.Set("isAsar", true);
dict.Set("asarPath", asar_path);
dict.Set("filePath", file_path);
} else {
dict.Set("isAsar", false);
}
return dict.GetHandle();
}

void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
gin_helper::Dictionary dict(context->GetIsolate(), exports);
dict.SetMethod("createArchive", &Archive::Create);
dict.SetMethod("splitPath", &SplitPath);
dict.SetMethod("initAsarSupport", &InitAsarSupport);
}

Expand Down
20 changes: 17 additions & 3 deletions shell/common/asar/asar_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "base/lazy_instance.h"
#include "base/stl_util.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
#include "shell/common/asar/archive.h"

namespace asar {
Expand All @@ -25,6 +26,17 @@ base::LazyInstance<base::ThreadLocalPointer<ArchiveMap>>::Leaky

const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar");

std::map<base::FilePath, bool> g_is_directory_cache;

bool IsDirectoryCached(const base::FilePath& path) {
auto it = g_is_directory_cache.find(path);
if (it != g_is_directory_cache.end()) {
return it->second;
}
base::ThreadRestrictions::ScopedAllowIO allow_io;
return g_is_directory_cache[path] = base::DirectoryExists(path);
}

} // namespace

std::shared_ptr<Archive> GetOrCreateAsarArchive(const base::FilePath& path) {
Expand Down Expand Up @@ -55,19 +67,21 @@ void ClearArchives() {

bool GetAsarArchivePath(const base::FilePath& full_path,
base::FilePath* asar_path,
base::FilePath* relative_path) {
base::FilePath* relative_path,
bool allow_root) {
base::FilePath iter = full_path;
while (true) {
base::FilePath dirname = iter.DirName();
if (iter.MatchesExtension(kAsarExtension))
if (iter.MatchesExtension(kAsarExtension) && !IsDirectoryCached(iter))
break;
else if (iter == dirname)
return false;
iter = dirname;
}

base::FilePath tail;
if (!iter.AppendRelativePath(full_path, &tail))
if (!((allow_root && iter == full_path) ||
iter.AppendRelativePath(full_path, &tail)))
return false;

*asar_path = iter;
Expand Down
3 changes: 2 additions & 1 deletion shell/common/asar/asar_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ void ClearArchives();
// Separates the path to Archive out.
bool GetAsarArchivePath(const base::FilePath& full_path,
base::FilePath* asar_path,
base::FilePath* relative_path);
base::FilePath* relative_path,
bool allow_root = false);

// Same with base::ReadFileToString but supports asar Archive.
bool ReadFileToString(const base::FilePath& path, std::string* contents);
Expand Down
4 changes: 2 additions & 2 deletions spec-main/api-protocol-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ describe('protocol module', () => {
})

describe('protocol.registerFileProtocol', () => {
const filePath = path.join(fixturesPath, 'asar', 'a.asar', 'file1')
const filePath = path.join(fixturesPath, 'test.asar', 'a.asar', 'file1')
const fileContent = fs.readFileSync(filePath)
const normalPath = path.join(fixturesPath, 'pages', 'a.html')
const normalContent = fs.readFileSync(normalPath)
Expand Down Expand Up @@ -248,7 +248,7 @@ describe('protocol module', () => {
})

it('fails when sending unexist-file', async () => {
const fakeFilePath = path.join(fixturesPath, 'asar', 'a.asar', 'not-exist')
const fakeFilePath = path.join(fixturesPath, 'test.asar', 'a.asar', 'not-exist')
await registerFileProtocol(protocolName, (request, callback) => callback(fakeFilePath))
await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404')
})
Expand Down