OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "modules/permissions/Permissions.h" | 6 #include "modules/permissions/Permissions.h" |
7 | 7 |
8 #include "bindings/core/v8/Dictionary.h" | 8 #include "bindings/core/v8/Dictionary.h" |
| 9 #include "bindings/core/v8/Nullable.h" |
9 #include "bindings/core/v8/ScriptPromise.h" | 10 #include "bindings/core/v8/ScriptPromise.h" |
10 #include "bindings/core/v8/ScriptPromiseResolver.h" | 11 #include "bindings/core/v8/ScriptPromiseResolver.h" |
11 #include "bindings/modules/v8/V8MidiPermissionDescriptor.h" | 12 #include "bindings/modules/v8/V8MidiPermissionDescriptor.h" |
12 #include "bindings/modules/v8/V8PermissionDescriptor.h" | 13 #include "bindings/modules/v8/V8PermissionDescriptor.h" |
13 #include "bindings/modules/v8/V8PushPermissionDescriptor.h" | 14 #include "bindings/modules/v8/V8PushPermissionDescriptor.h" |
14 #include "core/dom/DOMException.h" | 15 #include "core/dom/DOMException.h" |
15 #include "core/dom/Document.h" | 16 #include "core/dom/Document.h" |
16 #include "core/dom/ExceptionCode.h" | 17 #include "core/dom/ExceptionCode.h" |
17 #include "modules/permissions/PermissionCallback.h" | 18 #include "modules/permissions/PermissionCallback.h" |
18 #include "modules/permissions/PermissionController.h" | 19 #include "modules/permissions/PermissionController.h" |
19 #include "modules/permissions/PermissionDescriptor.h" | 20 #include "modules/permissions/PermissionDescriptor.h" |
20 #include "modules/permissions/PermissionStatus.h" | 21 #include "modules/permissions/PermissionStatus.h" |
21 #include "modules/permissions/PermissionsCallback.h" | 22 #include "modules/permissions/PermissionsCallback.h" |
22 #include "platform/Logging.h" | 23 #include "platform/Logging.h" |
23 #include "public/platform/Platform.h" | 24 #include "public/platform/Platform.h" |
24 #include "public/platform/modules/permissions/WebPermissionClient.h" | 25 #include "public/platform/modules/permissions/WebPermissionClient.h" |
25 | 26 |
26 namespace blink { | 27 namespace blink { |
27 | 28 |
28 namespace { | 29 namespace { |
29 | 30 |
30 // Here we eagerly reject any permissions that we do not support. | 31 WebPermissionType getPermissionType(ScriptState* scriptState, const Dictionary&
rawPermission, const PermissionDescriptor& permission, ExceptionState& exception
State) |
31 // If the permission is handled here, it will not be propogated up to the conten
t layer. | |
32 // The return value indicates if the permissions has been handled by the funcito
n. | |
33 bool handleNotSupportedPermission( | |
34 ScriptState* scriptState, const Dictionary& rawPermission, ScriptPromiseReso
lver* resolver, WebPermissionType type, TrackExceptionState& exceptionState) | |
35 { | |
36 if (type == WebPermissionTypePushNotifications) { | |
37 PushPermissionDescriptor pushPermission = NativeValueTraits<PushPermissi
onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce
ptionState); | |
38 // Only "userVisibleOnly" push is supported for now. | |
39 if (!pushPermission.userVisibleOnly()) { | |
40 resolver->reject(DOMException::create(NotSupportedError, "Push Permi
ssion without userVisibleOnly:true isn't supported yet.")); | |
41 return true; | |
42 } | |
43 } | |
44 return false; | |
45 } | |
46 | |
47 WebPermissionType getPermissionType(ScriptState* scriptState, const Dictionary&
rawPermission, const PermissionDescriptor& permission, TrackExceptionState& exce
ptionState) | |
48 { | 32 { |
49 const String& name = permission.name(); | 33 const String& name = permission.name(); |
50 if (name == "geolocation") | 34 if (name == "geolocation") |
51 return WebPermissionTypeGeolocation; | 35 return WebPermissionTypeGeolocation; |
52 if (name == "notifications") | 36 if (name == "notifications") |
53 return WebPermissionTypeNotifications; | 37 return WebPermissionTypeNotifications; |
54 if (name == "push") | 38 if (name == "push") |
55 return WebPermissionTypePushNotifications; | 39 return WebPermissionTypePushNotifications; |
56 if (name == "midi") { | 40 if (name == "midi") { |
57 MidiPermissionDescriptor midiPermission = NativeValueTraits<MidiPermissi
onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce
ptionState); | 41 MidiPermissionDescriptor midiPermission = NativeValueTraits<MidiPermissi
onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce
ptionState); |
58 return midiPermission.sysex() ? WebPermissionTypeMidiSysEx : WebPermissi
onTypeMidi; | 42 return midiPermission.sysex() ? WebPermissionTypeMidiSysEx : WebPermissi
onTypeMidi; |
59 } | 43 } |
60 | 44 |
61 ASSERT_NOT_REACHED(); | 45 ASSERT_NOT_REACHED(); |
62 return WebPermissionTypeGeolocation; | 46 return WebPermissionTypeGeolocation; |
63 } | 47 } |
64 | 48 |
| 49 // Parses the raw permission dictionary and returns the PermissionType if |
| 50 // parsing was successful. If an exception occurs, it will be stored in |
| 51 // |exceptionState| and null will be returned. Therefore, the |exceptionState| |
| 52 // should be checked before attempting to use the returned permission as the |
| 53 // non-null assert will be fired otherwise. |
| 54 Nullable<WebPermissionType> parsePermission(ScriptState* scriptState, const Dict
ionary rawPermission, ExceptionState& exceptionState) |
| 55 { |
| 56 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor>::n
ativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState); |
| 57 |
| 58 if (exceptionState.hadException()) { |
| 59 exceptionState.throwTypeError(exceptionState.message()); |
| 60 return Nullable<WebPermissionType>(); |
| 61 } |
| 62 |
| 63 WebPermissionType type = getPermissionType(scriptState, rawPermission, permi
ssion, exceptionState); |
| 64 if (exceptionState.hadException()) { |
| 65 exceptionState.throwTypeError(exceptionState.message()); |
| 66 return Nullable<WebPermissionType>(); |
| 67 } |
| 68 |
| 69 // Here we reject any permissions which are not yet supported by Blink. |
| 70 if (type == WebPermissionTypePushNotifications) { |
| 71 PushPermissionDescriptor pushPermission = NativeValueTraits<PushPermissi
onDescriptor>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exce
ptionState); |
| 72 if (exceptionState.hadException()) { |
| 73 exceptionState.throwTypeError(exceptionState.message()); |
| 74 return Nullable<WebPermissionType>(); |
| 75 } |
| 76 |
| 77 // Only "userVisibleOnly" push is supported for now. |
| 78 if (!pushPermission.userVisibleOnly()) { |
| 79 exceptionState.throwDOMException(NotSupportedError, "Push Permission
without userVisibleOnly:true isn't supported yet."); |
| 80 return Nullable<WebPermissionType>(); |
| 81 } |
| 82 } |
| 83 |
| 84 return Nullable<WebPermissionType>(type); |
| 85 } |
| 86 |
65 } // anonymous namespace | 87 } // anonymous namespace |
66 | 88 |
67 // static | 89 // static |
68 WebPermissionClient* Permissions::getClient(ExecutionContext* executionContext) | 90 WebPermissionClient* Permissions::getClient(ExecutionContext* executionContext) |
69 { | 91 { |
70 if (executionContext->isDocument()) { | 92 if (executionContext->isDocument()) { |
71 Document* document = toDocument(executionContext); | 93 Document* document = toDocument(executionContext); |
72 if (!document->frame()) | 94 if (!document->frame()) |
73 return nullptr; | 95 return nullptr; |
74 PermissionController* controller = PermissionController::from(*document-
>frame()); | 96 PermissionController* controller = PermissionController::from(*document-
>frame()); |
75 return controller ? controller->client() : nullptr; | 97 return controller ? controller->client() : nullptr; |
76 } | 98 } |
77 return Platform::current()->permissionClient(); | 99 return Platform::current()->permissionClient(); |
78 } | 100 } |
79 | 101 |
80 ScriptPromise Permissions::query(ScriptState* scriptState, const Dictionary& raw
Permission) | 102 ScriptPromise Permissions::query(ScriptState* scriptState, const Dictionary& raw
Permission) |
81 { | 103 { |
82 WebPermissionClient* client = getClient(scriptState->executionContext()); | 104 WebPermissionClient* client = getClient(scriptState->executionContext()); |
83 if (!client) | 105 if (!client) |
84 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't query pe
rmissions.")); | 106 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't query pe
rmissions.")); |
85 | 107 |
86 TrackExceptionState exceptionState; | 108 ExceptionState exceptionState(ExceptionState::GetterContext, "query", "Perm
issions", scriptState->context()->Global(), scriptState->isolate()); |
87 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor>::n
ativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState); | 109 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio
n, exceptionState); |
88 | |
89 if (exceptionState.hadException()) | 110 if (exceptionState.hadException()) |
90 return ScriptPromise::reject(scriptState, v8::Exception::TypeError(v8Str
ing(scriptState->isolate(), exceptionState.message()))); | 111 return exceptionState.reject(scriptState); |
91 | 112 |
92 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 113 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
93 ScriptPromise promise = resolver->promise(); | 114 ScriptPromise promise = resolver->promise(); |
94 | 115 |
95 WebPermissionType type = getPermissionType(scriptState, rawPermission, permi
ssion, exceptionState); | |
96 if (handleNotSupportedPermission(scriptState, rawPermission, resolver, type,
exceptionState)) | |
97 return promise; | |
98 | |
99 // If the current origin is a file scheme, it will unlikely return a | 116 // If the current origin is a file scheme, it will unlikely return a |
100 // meaningful value because most APIs are broken on file scheme and no | 117 // meaningful value because most APIs are broken on file scheme and no |
101 // permission prompt will be shown even if the returned permission will most | 118 // permission prompt will be shown even if the returned permission will most |
102 // likely be "prompt". | 119 // likely be "prompt". |
103 client->queryPermission(type, KURL(KURL(), scriptState->executionContext()->
securityOrigin()->toString()), new PermissionCallback(resolver, type)); | 120 client->queryPermission(type.get(), KURL(KURL(), scriptState->executionConte
xt()->securityOrigin()->toString()), new PermissionCallback(resolver, type.get()
)); |
104 return promise; | 121 return promise; |
105 } | 122 } |
106 | 123 |
107 ScriptPromise Permissions::request(ScriptState* scriptState, const Dictionary& r
awPermission) | 124 ScriptPromise Permissions::request(ScriptState* scriptState, const Dictionary& r
awPermission) |
108 { | 125 { |
109 WebPermissionClient* client = getClient(scriptState->executionContext()); | 126 WebPermissionClient* client = getClient(scriptState->executionContext()); |
110 if (!client) | 127 if (!client) |
111 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't request
permissions.")); | 128 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't request
permissions.")); |
112 | 129 |
113 TrackExceptionState exceptionState; | 130 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe
rmissions", scriptState->context()->Global(), scriptState->isolate()); |
114 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor>::n
ativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState); | 131 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio
n, exceptionState); |
115 | |
116 if (exceptionState.hadException()) | 132 if (exceptionState.hadException()) |
117 return ScriptPromise::reject(scriptState, v8::Exception::TypeError(v8Str
ing(scriptState->isolate(), exceptionState.message()))); | 133 return exceptionState.reject(scriptState); |
118 | 134 |
119 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 135 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
120 ScriptPromise promise = resolver->promise(); | 136 ScriptPromise promise = resolver->promise(); |
121 | 137 |
122 WebPermissionType type = getPermissionType(scriptState, rawPermission, permi
ssion, exceptionState); | 138 client->requestPermission(type.get(), KURL(KURL(), scriptState->executionCon
text()->securityOrigin()->toString()), new PermissionCallback(resolver, type.get
())); |
123 if (handleNotSupportedPermission(scriptState, rawPermission, resolver, type,
exceptionState)) | |
124 return promise; | |
125 | |
126 client->requestPermission(type, KURL(KURL(), scriptState->executionContext()
->securityOrigin()->toString()), new PermissionCallback(resolver, type)); | |
127 return promise; | 139 return promise; |
128 } | 140 } |
129 | 141 |
130 ScriptPromise Permissions::request(ScriptState* scriptState, const Vector<Dictio
nary>& rawPermissions) | 142 ScriptPromise Permissions::request(ScriptState* scriptState, const Vector<Dictio
nary>& rawPermissions) |
131 { | 143 { |
132 WebPermissionClient* client = getClient(scriptState->executionContext()); | 144 WebPermissionClient* client = getClient(scriptState->executionContext()); |
133 if (!client) | 145 if (!client) |
134 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't request
permissions.")); | 146 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't request
permissions.")); |
135 | 147 |
136 TrackExceptionState exceptionState; | 148 ExceptionState exceptionState(ExceptionState::GetterContext, "request", "Pe
rmissions", scriptState->context()->Global(), scriptState->isolate()); |
137 OwnPtr<WebVector<WebPermissionType>> permissions = adoptPtr(new WebVector<We
bPermissionType>(rawPermissions.size())); | 149 OwnPtr<WebVector<WebPermissionType>> permissions = adoptPtr(new WebVector<We
bPermissionType>(rawPermissions.size())); |
138 | |
139 for (size_t i = 0; i < rawPermissions.size(); ++i) { | 150 for (size_t i = 0; i < rawPermissions.size(); ++i) { |
140 const Dictionary& rawPermission = rawPermissions[i]; | 151 const Dictionary& rawPermission = rawPermissions[i]; |
141 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor
>::nativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState); | |
142 | 152 |
| 153 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermi
ssion, exceptionState); |
143 if (exceptionState.hadException()) | 154 if (exceptionState.hadException()) |
144 return ScriptPromise::reject(scriptState, v8::Exception::TypeError(v
8String(scriptState->isolate(), exceptionState.message()))); | 155 return exceptionState.reject(scriptState); |
145 | 156 |
146 permissions->operator[](i) = getPermissionType(scriptState, rawPermissio
n, permission, exceptionState); | 157 permissions->operator[](i) = type.get(); |
147 } | 158 } |
148 | 159 |
149 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 160 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
150 ScriptPromise promise = resolver->promise(); | 161 ScriptPromise promise = resolver->promise(); |
151 | 162 |
152 // We need to do this is a separate loop because we can't create the Resolve
r and Promise untile we are clear of all parsing/type errors. | |
153 for (size_t i = 0; i < rawPermissions.size(); ++i) { | |
154 if (handleNotSupportedPermission(scriptState, rawPermissions[i], resolve
r, (*permissions)[i], exceptionState)) | |
155 return promise; | |
156 } | |
157 | |
158 client->requestPermissions(*permissions, KURL(KURL(), scriptState->execution
Context()->securityOrigin()->toString()), new PermissionsCallback(resolver, perm
issions.release())); | 163 client->requestPermissions(*permissions, KURL(KURL(), scriptState->execution
Context()->securityOrigin()->toString()), new PermissionsCallback(resolver, perm
issions.release())); |
159 return promise; | 164 return promise; |
160 } | 165 } |
161 | 166 |
162 ScriptPromise Permissions::revoke(ScriptState* scriptState, const Dictionary& ra
wPermission) | 167 ScriptPromise Permissions::revoke(ScriptState* scriptState, const Dictionary& ra
wPermission) |
163 { | 168 { |
164 WebPermissionClient* client = getClient(scriptState->executionContext()); | 169 WebPermissionClient* client = getClient(scriptState->executionContext()); |
165 if (!client) | 170 if (!client) |
166 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't revoke p
ermissions.")); | 171 return ScriptPromise::rejectWithDOMException(scriptState, DOMException::
create(InvalidStateError, "In its current state, the global scope can't revoke p
ermissions.")); |
167 | 172 |
168 TrackExceptionState exceptionState; | 173 ExceptionState exceptionState(ExceptionState::GetterContext, "revoke", "Per
missions", scriptState->context()->Global(), scriptState->isolate()); |
169 PermissionDescriptor permission = NativeValueTraits<PermissionDescriptor>::n
ativeValue(scriptState->isolate(), rawPermission.v8Value(), exceptionState); | 174 Nullable<WebPermissionType> type = parsePermission(scriptState, rawPermissio
n, exceptionState); |
170 | |
171 if (exceptionState.hadException()) | 175 if (exceptionState.hadException()) |
172 return ScriptPromise::reject(scriptState, v8::Exception::TypeError(v8Str
ing(scriptState->isolate(), exceptionState.message()))); | 176 return exceptionState.reject(scriptState); |
173 | 177 |
174 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; | 178 ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState)
; |
175 ScriptPromise promise = resolver->promise(); | 179 ScriptPromise promise = resolver->promise(); |
176 | 180 |
177 WebPermissionType type = getPermissionType(scriptState, rawPermission, permi
ssion, exceptionState); | 181 client->revokePermission(type.get(), KURL(KURL(), scriptState->executionCont
ext()->securityOrigin()->toString()), new PermissionCallback(resolver, type.get(
))); |
178 if (handleNotSupportedPermission(scriptState, rawPermission, resolver, type,
exceptionState)) | |
179 return promise; | |
180 | |
181 client->revokePermission(type, KURL(KURL(), scriptState->executionContext()-
>securityOrigin()->toString()), new PermissionCallback(resolver, type)); | |
182 return promise; | 182 return promise; |
183 } | 183 } |
184 | 184 |
185 } // namespace blink | 185 } // namespace blink |
OLD | NEW |