summaryrefslogtreecommitdiff
path: root/chromium/extensions/browser/url_request_util.cc
blob: 4ceb9e377fc8905ed1fa12a93238f8c3b500d9b5 (plain)
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
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/browser/url_request_util.h"

#include <string>

#include "base/strings/string_piece.h"
#include "extensions/browser/extension_navigation_ui_data.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
#include "extensions/browser/process_map.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
#include "extensions/common/manifest_handlers/webview_info.h"
#include "services/network/public/cpp/resource_request.h"
#include "third_party/blink/public/common/loader/resource_type_util.h"

namespace extensions {
namespace url_request_util {

bool AllowCrossRendererResourceLoad(
    const network::ResourceRequest& request,
    network::mojom::RequestDestination destination,
    ui::PageTransition page_transition,
    int child_id,
    bool is_incognito,
    const Extension* extension,
    const ExtensionSet& extensions,
    const ProcessMap& process_map,
    bool* allowed) {
  const GURL& url = request.url;
  base::StringPiece resource_path = url.path_piece();

  // This logic is performed for main frame requests in
  // ExtensionNavigationThrottle::WillStartRequest.
  if (child_id != -1 ||
      destination != network::mojom::RequestDestination::kDocument) {
    // Extensions with webview: allow loading certain resources by guest
    // renderers with privileged partition IDs as specified in owner's extension
    // the manifest file.
    std::string owner_extension_id;
    int owner_process_id;
    WebViewRendererState::GetInstance()->GetOwnerInfo(
        child_id, &owner_process_id, &owner_extension_id);
    const Extension* owner_extension = extensions.GetByID(owner_extension_id);
    std::string partition_id;
    bool is_guest = WebViewRendererState::GetInstance()->GetPartitionID(
        child_id, &partition_id);

    if (AllowCrossRendererResourceLoadHelper(
            is_guest, extension, owner_extension, partition_id, resource_path,
            page_transition, allowed)) {
      return true;
    }
  }

  // The following checks require that we have an actual extension object. If we
  // don't have it, allow the request handling to continue with the rest of the
  // checks.
  if (!extension) {
    *allowed = true;
    return true;
  }

  // Disallow loading of packaged resources for hosted apps. We don't allow
  // hybrid hosted/packaged apps. The one exception is access to icons, since
  // some extensions want to be able to do things like create their own
  // launchers.
  base::StringPiece resource_root_relative_path =
      url.path_piece().empty() ? base::StringPiece()
                               : url.path_piece().substr(1);
  if (extension->is_hosted_app() &&
      !IconsInfo::GetIcons(extension)
           .ContainsPath(resource_root_relative_path)) {
    LOG(ERROR) << "Denying load of " << url.spec() << " from hosted app.";
    *allowed = false;
    return true;
  }

  DCHECK_EQ(extension->url(), url.GetWithEmptyPath());

  // Navigating the main frame to an extension URL is allowed, even if not
  // explicitly listed as web_accessible_resource.
  if (destination == network::mojom::RequestDestination::kDocument) {
    *allowed = true;
    return true;
  }

  // When navigating in subframe, allow if it is the same origin
  // as the top-level frame. This can only be the case if the subframe
  // request is coming from the extension process.
  if ((destination == network::mojom::RequestDestination::kIframe ||
       destination == network::mojom::RequestDestination::kFrame) &&
      process_map.Contains(child_id)) {
    *allowed = true;
    return true;
  }

  // Allow web accessible extension resources to be loaded as
  // subresources/sub-frames.
  if (WebAccessibleResourcesInfo::IsResourceWebAccessible(
          extension, std::string(resource_path), request.request_initiator)) {
    *allowed = true;
    return true;
  }

  if (!ui::PageTransitionIsWebTriggerable(page_transition)) {
    *allowed = false;
    return true;
  }

  // Couldn't determine if the resource is allowed or not.
  return false;
}

bool AllowCrossRendererResourceLoadHelper(bool is_guest,
                                          const Extension* extension,
                                          const Extension* owner_extension,
                                          const std::string& partition_id,
                                          base::StringPiece resource_path,
                                          ui::PageTransition page_transition,
                                          bool* allowed) {
  if (is_guest) {
    if (AllowSpecialCaseExtensionURLInGuest(extension, resource_path)) {
      *allowed = true;
      return true;
    }

    // An extension's resources should only be accessible to WebViews owned by
    // that extension.
    if (owner_extension != extension) {
      *allowed = false;
      return true;
    }

    *allowed = WebviewInfo::IsResourceWebviewAccessible(
        extension, partition_id, std::string(resource_path));
    return true;
  }

  return false;
}

bool AllowSpecialCaseExtensionURLInGuest(
    const Extension* extension,
    absl::optional<base::StringPiece> resource_path) {
  // Allow mobile setup web UI (chrome://mobilesetup) to embed resources from
  // the component mobile activation extension in a webview. This is needed
  // because the activation web UI relies on the activation extension to
  // provide parts of its UI, and to redirect POST requests to the network
  // payment URL during mobile device initialization.
  //
  // TODO(http://crbug.com/778021): Fix mobile activation UI not to require
  // this workaround.
  bool is_mobile_activation_extension =
      extension && extension->id() == "iadeocfgjdjdmpenejdbfeaocpbikmab";
  if (is_mobile_activation_extension) {
    if (!resource_path.has_value())
      return true;
    if (resource_path.value() == "/activation.html" ||
        resource_path.value() == "/portal_offline.html" ||
        resource_path.value() == "/invalid_device_info.html") {
      return true;
    }
  }

  // Otherwise this isn't a special case, and the normal logic should apply.
  return false;
}

}  // namespace url_request_util
}  // namespace extensions