Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/toolkit/mozapps/extensions/AddonManagerWebAPI.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "AddonManagerWebAPI.h"
8
9
#include "mozilla/dom/Navigator.h"
10
#include "mozilla/dom/NavigatorBinding.h"
11
12
#include "mozilla/Preferences.h"
13
#include "nsGlobalWindow.h"
14
#include "xpcpublic.h"
15
16
#include "nsIDocShell.h"
17
#include "nsIScriptObjectPrincipal.h"
18
19
namespace mozilla {
20
using namespace mozilla::dom;
21
22
static bool
23
0
IsValidHost(const nsACString& host) {
24
0
  // This hidden pref allows users to disable mozAddonManager entirely if they want
25
0
  // for fingerprinting resistance. Someone like Tor browser will use this pref.
26
0
  if (Preferences::GetBool("privacy.resistFingerprinting.block_mozAddonManager")) {
27
0
    return false;
28
0
  }
29
0
30
0
  // This is ugly, but Preferences.h doesn't have support
31
0
  // for default prefs or locked prefs
32
0
  nsCOMPtr<nsIPrefService> prefService (do_GetService(NS_PREFSERVICE_CONTRACTID));
33
0
  nsCOMPtr<nsIPrefBranch> prefs;
34
0
  if (prefService) {
35
0
    prefService->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
36
0
    bool isEnabled;
37
0
    if (NS_SUCCEEDED(prefs->GetBoolPref("xpinstall.enabled", &isEnabled)) && !isEnabled) {
38
0
      bool isLocked;
39
0
      prefs->PrefIsLocked("xpinstall.enabled", &isLocked);
40
0
      if (isLocked) {
41
0
        return false;
42
0
      }
43
0
    }
44
0
  }
45
0
46
0
  if (host.EqualsLiteral("addons.mozilla.org") ||
47
0
      host.EqualsLiteral("discovery.addons.mozilla.org") ||
48
0
      host.EqualsLiteral("testpilot.firefox.com")) {
49
0
    return true;
50
0
  }
51
0
52
0
  // When testing allow access to the developer sites.
53
0
  if (Preferences::GetBool("extensions.webapi.testing", false)) {
54
0
    if (host.LowerCaseEqualsLiteral("addons.allizom.org") ||
55
0
        host.LowerCaseEqualsLiteral("discovery.addons.allizom.org") ||
56
0
        host.LowerCaseEqualsLiteral("addons-dev.allizom.org") ||
57
0
        host.LowerCaseEqualsLiteral("discovery.addons-dev.allizom.org") ||
58
0
        host.LowerCaseEqualsLiteral("testpilot.stage.mozaws.net") ||
59
0
        host.LowerCaseEqualsLiteral("testpilot.dev.mozaws.net") ||
60
0
        host.LowerCaseEqualsLiteral("example.com")) {
61
0
      return true;
62
0
    }
63
0
  }
64
0
65
0
  return false;
66
0
}
67
68
// Checks if the given uri is secure and matches one of the hosts allowed to
69
// access the API.
70
bool
71
AddonManagerWebAPI::IsValidSite(nsIURI* uri)
72
0
{
73
0
  if (!uri) {
74
0
    return false;
75
0
  }
76
0
77
0
  bool isSecure;
78
0
  nsresult rv = uri->SchemeIs("https", &isSecure);
79
0
  if (NS_FAILED(rv) || !isSecure) {
80
0
    if (!(xpc::IsInAutomation() && Preferences::GetBool("extensions.webapi.testing.http", false))) {
81
0
      return false;
82
0
    }
83
0
  }
84
0
85
0
  nsAutoCString host;
86
0
  rv = uri->GetHost(host);
87
0
  if (NS_FAILED(rv)) {
88
0
    return false;
89
0
  }
90
0
91
0
  return IsValidHost(host);
92
0
}
93
94
bool
95
AddonManagerWebAPI::IsAPIEnabled(JSContext* aCx, JSObject* aGlobal)
96
0
{
97
0
  MOZ_DIAGNOSTIC_ASSERT(JS_IsGlobalObject(aGlobal));
98
0
  nsGlobalWindowInner* global = xpc::WindowOrNull(aGlobal);
99
0
  if (!global) {
100
0
    return false;
101
0
  }
102
0
103
0
  nsCOMPtr<nsPIDOMWindowInner> win = global->AsInner();
104
0
  if (!win) {
105
0
    return false;
106
0
  }
107
0
108
0
  // Check that the current window and all parent frames are allowed access to
109
0
  // the API.
110
0
  while (win) {
111
0
    nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(win);
112
0
    if (!sop) {
113
0
      return false;
114
0
    }
115
0
116
0
    nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
117
0
    if (!principal) {
118
0
      return false;
119
0
    }
120
0
121
0
    // Reaching a window with a system principal means we have reached
122
0
    // privileged UI of some kind so stop at this point and allow access.
123
0
    if (principal->GetIsSystemPrincipal()) {
124
0
      return true;
125
0
    }
126
0
127
0
    nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
128
0
    if (!docShell) {
129
0
      // This window has been torn down so don't allow access to the API.
130
0
      return false;
131
0
    }
132
0
133
0
    if (!IsValidSite(win->GetDocumentURI())) {
134
0
      return false;
135
0
    }
136
0
137
0
    // Checks whether there is a parent frame of the same type. This won't cross
138
0
    // mozbrowser or chrome boundaries.
139
0
    nsCOMPtr<nsIDocShellTreeItem> parent;
140
0
    nsresult rv = docShell->GetSameTypeParent(getter_AddRefs(parent));
141
0
    if (NS_FAILED(rv)) {
142
0
      return false;
143
0
    }
144
0
145
0
    if (!parent) {
146
0
      // No parent means we've hit a mozbrowser or chrome boundary so allow
147
0
      // access to the API.
148
0
      return true;
149
0
    }
150
0
151
0
    nsIDocument* doc = win->GetDoc();
152
0
    if (!doc) {
153
0
      return false;
154
0
    }
155
0
156
0
    doc = doc->GetParentDocument();
157
0
    if (!doc) {
158
0
      // Getting here means something has been torn down so fail safe.
159
0
      return false;
160
0
    }
161
0
162
0
163
0
    win = doc->GetInnerWindow();
164
0
  }
165
0
166
0
  // Found a document with no inner window, don't grant access to the API.
167
0
  return false;
168
0
}
169
170
namespace dom {
171
172
bool
173
AddonManagerPermissions::IsHostPermitted(const GlobalObject& /*unused*/, const nsAString& host)
174
0
{
175
0
  return IsValidHost(NS_ConvertUTF16toUTF8(host));
176
0
}
177
178
} // namespace mozilla::dom
179
180
181
} // namespace mozilla