Line data Source code
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 :
15 : #include "nsIDocShell.h"
16 : #include "nsIScriptObjectPrincipal.h"
17 :
18 : namespace mozilla {
19 : using namespace mozilla::dom;
20 :
21 : static bool
22 0 : IsValidHost(const nsACString& host) {
23 : // This is ugly, but Preferences.h doesn't have support
24 : // for default prefs or locked prefs
25 0 : nsCOMPtr<nsIPrefService> prefService (do_GetService(NS_PREFSERVICE_CONTRACTID));
26 0 : nsCOMPtr<nsIPrefBranch> prefs;
27 0 : if (prefService) {
28 0 : prefService->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
29 : bool isEnabled;
30 0 : if (NS_SUCCEEDED(prefs->GetBoolPref("xpinstall.enabled", &isEnabled)) && !isEnabled) {
31 : bool isLocked;
32 0 : prefs->PrefIsLocked("xpinstall.enabled", &isLocked);
33 0 : if (isLocked) {
34 0 : return false;
35 : }
36 : }
37 : }
38 :
39 0 : if (host.Equals("addons.mozilla.org") ||
40 0 : host.Equals("discovery.addons.mozilla.org") ||
41 0 : host.Equals("testpilot.firefox.com")) {
42 0 : return true;
43 : }
44 :
45 : // When testing allow access to the developer sites.
46 0 : if (Preferences::GetBool("extensions.webapi.testing", false)) {
47 0 : if (host.LowerCaseEqualsLiteral("addons.allizom.org") ||
48 0 : host.LowerCaseEqualsLiteral("discovery.addons.allizom.org") ||
49 0 : host.LowerCaseEqualsLiteral("addons-dev.allizom.org") ||
50 0 : host.LowerCaseEqualsLiteral("discovery.addons-dev.allizom.org") ||
51 0 : host.LowerCaseEqualsLiteral("testpilot.stage.mozaws.net") ||
52 0 : host.LowerCaseEqualsLiteral("testpilot.dev.mozaws.net") ||
53 0 : host.LowerCaseEqualsLiteral("example.com")) {
54 0 : return true;
55 : }
56 : }
57 :
58 0 : return false;
59 : }
60 :
61 : // Checks if the given uri is secure and matches one of the hosts allowed to
62 : // access the API.
63 : bool
64 0 : AddonManagerWebAPI::IsValidSite(nsIURI* uri)
65 : {
66 0 : if (!uri) {
67 0 : return false;
68 : }
69 :
70 : bool isSecure;
71 0 : nsresult rv = uri->SchemeIs("https", &isSecure);
72 0 : if (NS_FAILED(rv) || !isSecure) {
73 0 : return false;
74 : }
75 :
76 0 : nsAutoCString host;
77 0 : rv = uri->GetHost(host);
78 0 : if (NS_FAILED(rv)) {
79 0 : return false;
80 : }
81 :
82 0 : return IsValidHost(host);
83 : }
84 :
85 : bool
86 1 : AddonManagerWebAPI::IsAPIEnabled(JSContext* cx, JSObject* obj)
87 : {
88 1 : nsGlobalWindow* global = xpc::WindowGlobalOrNull(obj);
89 1 : if (!global) {
90 0 : return false;
91 : }
92 :
93 2 : nsCOMPtr<nsPIDOMWindowInner> win = global->AsInner();
94 1 : if (!win) {
95 0 : return false;
96 : }
97 :
98 : // Check that the current window and all parent frames are allowed access to
99 : // the API.
100 1 : while (win) {
101 1 : nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(win);
102 1 : if (!sop) {
103 0 : return false;
104 : }
105 :
106 1 : nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
107 1 : if (!principal) {
108 0 : return false;
109 : }
110 :
111 : // Reaching a window with a system principal means we have reached
112 : // privileged UI of some kind so stop at this point and allow access.
113 1 : if (principal->GetIsSystemPrincipal()) {
114 1 : return true;
115 : }
116 :
117 0 : nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
118 0 : if (!docShell) {
119 : // This window has been torn down so don't allow access to the API.
120 0 : return false;
121 : }
122 :
123 0 : if (!IsValidSite(win->GetDocumentURI())) {
124 0 : return false;
125 : }
126 :
127 : // Checks whether there is a parent frame of the same type. This won't cross
128 : // mozbrowser or chrome boundaries.
129 0 : nsCOMPtr<nsIDocShellTreeItem> parent;
130 0 : nsresult rv = docShell->GetSameTypeParent(getter_AddRefs(parent));
131 0 : if (NS_FAILED(rv)) {
132 0 : return false;
133 : }
134 :
135 0 : if (!parent) {
136 : // No parent means we've hit a mozbrowser or chrome boundary so allow
137 : // access to the API.
138 0 : return true;
139 : }
140 :
141 0 : nsIDocument* doc = win->GetDoc();
142 0 : if (!doc) {
143 0 : return false;
144 : }
145 :
146 0 : doc = doc->GetParentDocument();
147 0 : if (!doc) {
148 : // Getting here means something has been torn down so fail safe.
149 0 : return false;
150 : }
151 :
152 :
153 0 : win = doc->GetInnerWindow();
154 : }
155 :
156 : // Found a document with no inner window, don't grant access to the API.
157 0 : return false;
158 : }
159 :
160 : namespace dom {
161 :
162 : bool
163 0 : AddonManagerPermissions::IsHostPermitted(const GlobalObject& /*unused*/, const nsAString& host)
164 : {
165 0 : return IsValidHost(NS_ConvertUTF16toUTF8(host));
166 : }
167 :
168 : } // namespace mozilla::dom
169 :
170 :
171 : } // namespace mozilla
|