File: scripting_utils.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (256 lines) | stat: -rw-r--r-- 10,632 bytes parent folder | download | duplicates (5)
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_BROWSER_SCRIPTING_UTILS_H_
#define EXTENSIONS_BROWSER_SCRIPTING_UTILS_H_

#include <string>

#include "base/containers/contains.h"
#include "base/functional/callback_forward.h"
#include "base/strings/utf_string_conversions.h"
#include "extensions/browser/extension_user_script_loader.h"
#include "extensions/browser/script_executor.h"
#include "extensions/common/api/scripts_internal.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/extension_resource.h"
#include "extensions/common/url_pattern_set.h"
#include "extensions/common/user_script.h"
#include "extensions/common/utils/content_script_utils.h"

namespace content {
class BrowserContext;
}  // namespace content

namespace extensions::scripting {

// Details specifying the target into which to inject the script.
struct InjectionTarget {
  InjectionTarget();
  InjectionTarget(InjectionTarget&& other);
  ~InjectionTarget();

  // Whether the script should inject into all frames within the tab.
  std::optional<bool> all_frames;
  // The IDs of specific documentIds to inject into.
  std::optional<std::vector<std::string>> document_ids;
  // The IDs of specific frames to inject into.
  std::optional<std::vector<int>> frame_ids;
  // The ID of the tab into which to inject.
  int tab_id;
};

// Details specifying the read file (either CSS or JS) for the script to be
// injected.
struct InjectedFileSource {
  InjectedFileSource(std::string file_name, std::unique_ptr<std::string> data);
  InjectedFileSource(InjectedFileSource&&);
  ~InjectedFileSource();

  std::string file_name;
  std::unique_ptr<std::string> data;
};

using ResourcesLoadedCallback =
    base::OnceCallback<void(std::vector<InjectedFileSource>,
                            std::optional<std::string>)>;

// Appends the prefix corresponding to the dynamic script `source` to
// `script_id`.
std::string AddPrefixToDynamicScriptId(const std::string& script_id,
                                       UserScript::Source source);

// Returns whether the extension provided `script_id` (without an internal
// prefix) is valid. Populates `error` if invalid.
bool IsScriptIdValid(const std::string& script_id, std::string* error);

// Returns whether new scripts added for the extension with the given
// `extension_id` should be allowed in incognito contexts.
bool ScriptsShouldBeAllowedInIncognito(
    const ExtensionId& extension_id,
    content::BrowserContext* browser_context);

// Returns a set of unique dynamic script IDs (with an added prefix
// corresponding to `source`) for all given `scripts`. If the script is invalid
// or duplicated in `existing_script_ids` or the new ids, populates error and
// returns an empty set.
template <typename Script>
std::set<std::string> CreateDynamicScriptIds(
    std::vector<Script>& scripts,
    UserScript::Source source,
    const std::set<std::string>& existing_script_ids,
    std::string* error) {
  std::set<std::string> new_script_ids;

  for (auto& script : scripts) {
    if (!IsScriptIdValid(script.id, error)) {
      return std::set<std::string>();
    }

    std::string new_script_id =
        scripting::AddPrefixToDynamicScriptId(script.id, source);
    if (base::Contains(existing_script_ids, new_script_id) ||
        base::Contains(new_script_ids, new_script_id)) {
      *error = ErrorUtils::FormatErrorMessage("Duplicate script ID '*'",
                                              script.id.c_str());
      return std::set<std::string>();
    }

    script.id = new_script_id;
    new_script_ids.insert(script.id);
  }

  return new_script_ids;
}

// Returns a list of UserScript objects for each `scripts_to_update` by
// retrieving the metadata of all loaded scripts with `source` using
// `create_script_callback` and updating them with the given delta using
// `apply_update_callback`. If any of the `scripts_to_update` hasn't been
// previously loaded or parsing fails, populates error and returns nullptr.
template <typename Script>
UserScriptList UpdateScripts(
    std::vector<Script>& scripts_to_update,
    UserScript::Source source,
    ExtensionUserScriptLoader& loader,
    base::RepeatingCallback<Script(const UserScript& script)>
        create_script_metadata_callback,
    base::RepeatingCallback<std::unique_ptr<UserScript>(
        Script& new_script,
        Script& existent_script,
        std::u16string* parse_error)> apply_update_callback,
    std::string* error) {
  // Retrieve the metadata of all loaded scripts with `source`.
  std::map<std::string, Script> loaded_scripts_metadata;
  const UserScriptList& dynamic_scripts = loader.GetLoadedDynamicScripts();
  for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
    if (script->GetSource() != source) {
      continue;
    }

    Script script_metadata = create_script_metadata_callback.Run(*script);
    loaded_scripts_metadata.emplace(script->id(), std::move(script_metadata));
  }

  // Verify scripts to update have previously been loaded.
  for (const auto& script : scripts_to_update) {
    if (!loaded_scripts_metadata.contains(script.id)) {
      *error = ErrorUtils::FormatErrorMessage(
          "Script with ID '*' does not exist or is not fully registered",
          UserScript::TrimPrefixFromScriptID(script.id));
      return {};
    }
  }

  // Update the scripts.
  std::u16string parse_error;
  UserScriptList parsed_scripts;
  parsed_scripts.reserve(scripts_to_update.size());
  for (Script& new_script : scripts_to_update) {
    CHECK(base::Contains(loaded_scripts_metadata, new_script.id));
    Script& existent_script = loaded_scripts_metadata[new_script.id];

    // Note: `new_script` and `existent_script` may be unsafe to use after this.
    std::unique_ptr<UserScript> script =
        apply_update_callback.Run(new_script, existent_script, &parse_error);
    if (!script) {
      CHECK(!parse_error.empty());
      *error = base::UTF16ToASCII(parse_error);
      return {};
    }

    parsed_scripts.push_back(std::move(script));
  }

  return parsed_scripts;
}

// Removes all scripts with `ids` of `extension_id`. If `ids` has no value,
// clears all scripts with `source` and `extension_id`. If any of the `ids`
// provided is invalid, populates `error` and returns false. Otherwise, returns
// true and removes the script from the UserScriptLoader invoking
// `remove_callback` on completion.
bool RemoveScripts(
    const std::optional<std::vector<std::string>>& ids,
    UserScript::Source source,
    content::BrowserContext* browser_context,
    const ExtensionId& extension_id,
    ExtensionUserScriptLoader::DynamicScriptsModifiedCallback remove_callback,
    std::string* error);

// Returns the set of URL patterns from persistent dynamic content scripts.
// Patterns are stored in prefs so UserScriptListener can access them
// synchronously as the persistent scripts themselves are stored in a
// StateStore.
URLPatternSet GetPersistentScriptURLPatterns(
    content::BrowserContext* browser_context,
    const ExtensionId& extension_id);

// Updates the set of URL patterns from persistent dynamic content scripts. This
// preference gets cleared on extension update.
void SetPersistentScriptURLPatterns(content::BrowserContext* browser_context,
                                    const ExtensionId& extension_id,
                                    const URLPatternSet& patterns);

// Clears the set of URL patterns from persistent dynamic content scripts.
void ClearPersistentScriptURLPatterns(content::BrowserContext* browser_context,
                                      const ExtensionId& extension_id);

// Holds a list of user scripts as the first item, or an error string as the
// second item when the user scripts are invalid.
using ValidateScriptsResult =
    std::pair<UserScriptList, std::optional<std::string>>;

// Validates that `scripts` resources exist and are properly encoded.
ValidateScriptsResult ValidateParsedScriptsOnFileThread(
    ExtensionResource::SymlinkPolicy symlink_policy,
    UserScriptList scripts);

// Returns whether the `target` can be accessed with the given `permissions`.
// If the target can be accessed, populates `script_executor_out`,
// `frame_scope_out`, and `frame_ids_out` with the appropriate values;
// if the target cannot be accessed, populates `error_out`.
bool CanAccessTarget(const PermissionsData& permissions,
                     const scripting::InjectionTarget& target,
                     content::BrowserContext* browser_context,
                     bool include_incognito_information,
                     ScriptExecutor** script_executor_out,
                     ScriptExecutor::FrameScope* frame_scope_out,
                     std::set<int>* frame_ids_out,
                     std::string* error_out);

// Checks the specified `files` for validity, and attempts to load and localize
// them, invoking `callback` with the result. Returns true on success; on
// failure, populates `error_out`.
bool CheckAndLoadFiles(std::vector<std::string> files,
                       script_parsing::ContentScriptType resources_type,
                       const Extension& extension,
                       bool requires_localization,
                       ResourcesLoadedCallback callback,
                       std::string* error_out);

// Checks `files` and populates `resources_out` with the appropriate extension
// resource. Returns true on success; on failure, populates `error_out`.
bool GetFileResources(const std::vector<std::string>& files,
                      script_parsing::ContentScriptType resources_type,
                      const Extension& extension,
                      std::vector<ExtensionResource>* resources_out,
                      std::string* error_out);

// Executes script with `sources` in the frames identified by `frame_ids`
void ExecuteScript(const ExtensionId& extension_id,
                   std::vector<mojom::JSSourcePtr> sources,
                   mojom::ExecutionWorld execution_world,
                   const std::optional<std::string>& world_id,
                   ScriptExecutor* script_executor,
                   ScriptExecutor::FrameScope frame_scope,
                   std::set<int> frame_ids,
                   bool inject_immediately,
                   bool user_gesture,
                   ScriptExecutor::ScriptFinishedCallback callback);

}  // namespace extensions::scripting

#endif  // EXTENSIONS_BROWSER_SCRIPTING_UTILS_H_