1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "unpacked_extension_installer.h"
#include "base/files/file_util.h"
#include "base/rand_util.h"
#include "base/threading/scoped_blocking_call.h"
#include <algorithm>
#include <random>
namespace QtWebEngineCore {
namespace {
static constexpr const char *kCharSet =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
std::string generateRandomString(size_t length)
{
std::string str = std::string(kCharSet);
while (length > str.length())
str += str;
auto rng = std::default_random_engine{};
std::shuffle(str.begin(), str.end(), rng);
return str.substr(0, length);
}
bool generateDirNameOnFileThread(const base::FilePath &baseDir,
base::FilePath::StringPieceType prefix, base::FilePath *out)
{
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK);
base::FilePath outPath;
for (int count = 0; count < 50; ++count) {
base::FilePath::StringType newName;
newName.assign(prefix);
#if BUILDFLAG(IS_WIN)
// based on 'CreateTemporaryDirInDir' in chromium/base/file_util_win.cc
newName.append(base::AsWString(base::NumberToString16(base::GetCurrentProcId())));
newName.push_back('_');
newName.append(base::AsWString(
base::NumberToString16(base::RandInt(0, std::numeric_limits<int32_t>::max()))));
#else
// based on 'CreateTemporaryDirInDir' in chromium/base/file_util_posix.cc
newName.append(generateRandomString(6));
#endif
outPath = baseDir.Append(newName);
if (!base::PathExists(outPath)) {
*out = outPath;
return true;
}
}
return false;
}
} // namespace
UnpackedExtensionInstaller::UnpackedExtensionInstaller(
const scoped_refptr<base::SequencedTaskRunner> &taskRunner, DoneCallback doneCallback)
: m_taskRunner(taskRunner), m_doneCallback(std::move(doneCallback))
{
}
// static
scoped_refptr<UnpackedExtensionInstaller>
UnpackedExtensionInstaller::Create(const scoped_refptr<base::SequencedTaskRunner> &taskRunner,
DoneCallback doneCallback)
{
return base::WrapRefCounted(
new UnpackedExtensionInstaller(taskRunner, std::move(doneCallback)));
}
// static
UnpackedExtensionInstaller::InstallInfo
UnpackedExtensionInstaller::installUnpackedExtensionOnFileThread(const base::FilePath &src,
const base::FilePath &installDir)
{
InstallInfo installInfo;
if (!base::DirectoryExists(installDir)) {
if (!base::CreateDirectory(installDir)) {
installInfo.error = "Install directory does not exists";
return installInfo;
}
}
// The installed dir format is `dirName_XXXXXX` where `XXXXXX` is populated with
// mktemp() logic to match the output format of the zip installer.
base::FilePath extensionInstallPath;
base::FilePath::StringType dirName = src.BaseName().value() + FILE_PATH_LITERAL("_");
if (!generateDirNameOnFileThread(installDir, dirName, &extensionInstallPath)) {
installInfo.error = "Failed to create install directory for extension";
return installInfo;
}
installInfo.extensionInstallPath = extensionInstallPath;
// This performs a 'cp -r src installDir/', we need to rename the copied directory later.
if (!base::CopyDirectory(src, installDir, true)) {
installInfo.error = "Copy directory failed";
return installInfo;
}
auto copyPath = installDir.Append(src.BaseName());
CHECK(base::DirectoryExists(copyPath));
if (!base::Move(copyPath, extensionInstallPath))
installInfo.error = "Move directory failed";
return installInfo;
}
void UnpackedExtensionInstaller::install(const base::FilePath &src,
const base::FilePath &installDir)
{
// Verify the extension before doing any file operations by preloading it.
m_taskRunner->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&QtWebEngineCore::ExtensionLoader::loadExtensionOnFileThread, src),
base::BindOnce(&UnpackedExtensionInstaller::installInternal, this, src, installDir));
}
void UnpackedExtensionInstaller::installInternal(const base::FilePath &src,
const base::FilePath &installDir,
const ExtensionLoader::LoadingInfo &loadingInfo)
{
if (!loadingInfo.error.empty()) {
std::move(m_doneCallback).Run(src, installDir, loadingInfo.error);
return;
}
m_taskRunner->PostTaskAndReplyWithResult(
FROM_HERE, base::BindOnce(installUnpackedExtensionOnFileThread, src, installDir),
base::BindOnce(&UnpackedExtensionInstaller::installDone, this, src));
}
void UnpackedExtensionInstaller::installDone(const base::FilePath &src,
const InstallInfo &installInfo)
{
std::move(m_doneCallback).Run(src, installInfo.extensionInstallPath, installInfo.error);
}
} // namespace QtWebEngineCore
|