Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / vpn_provider / vpn_provider_api.cc
blob3529f6379ba4d732f078792d4caeadd22016d802
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
3 // found in the LICENSE file.
5 #include "extensions/browser/api/vpn_provider/vpn_provider_api.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/values.h"
15 #include "extensions/browser/api/vpn_provider/vpn_service.h"
16 #include "extensions/browser/api/vpn_provider/vpn_service_factory.h"
17 #include "extensions/common/api/vpn_provider.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
20 namespace extensions {
22 namespace {
24 namespace api_vpn = extensions::api::vpn_provider;
26 const char kCIDRSeperator[] = "/";
28 bool CheckIPCIDRSanity(const std::string& value, bool cidr, bool ipv6) {
29 int dots = ipv6 ? 0 : 3;
30 int sep = cidr ? 1 : 0;
31 int colon = ipv6 ? 7 : 0;
32 bool hex_allowed = ipv6;
33 int counter = 0;
35 for (const auto& elem : value) {
36 if (base::IsAsciiDigit(elem)) {
37 counter++;
38 continue;
40 if (elem == '.') {
41 if (!dots)
42 return false;
43 dots--;
44 } else if (elem == kCIDRSeperator[0]) {
45 if (!sep || dots || colon == 7 || !counter)
46 return false;
47 // Separator observed, no more dots and colons, only digits are allowed
48 // after observing separator. So setting hex_allowed to false.
49 sep--;
50 counter = 0;
51 colon = 0;
52 hex_allowed = false;
53 } else if (elem == ':') {
54 if (!colon)
55 return false;
56 colon--;
57 } else if (!hex_allowed || !base::IsHexDigit(elem)) {
58 return false;
59 } else {
60 counter++;
63 return !sep && !dots && (colon < 7) && counter;
66 bool CheckIPCIDRSanityList(const std::vector<std::string>& list,
67 bool cidr,
68 bool ipv6) {
69 for (const auto& address : list) {
70 if (!CheckIPCIDRSanity(address, cidr, ipv6)) {
71 return false;
74 return true;
77 void ConvertParameters(const api_vpn::Parameters& parameters,
78 base::DictionaryValue* parameter_value,
79 std::string* error) {
80 if (!CheckIPCIDRSanity(parameters.address, true /* CIDR */,
81 false /*IPV4 */)) {
82 *error = "Address CIDR sanity check failed.";
83 return;
86 if (!CheckIPCIDRSanityList(parameters.exclusion_list, true /* CIDR */,
87 false /*IPV4 */)) {
88 *error = "Exclusion list CIDR sanity check failed.";
89 return;
92 if (!CheckIPCIDRSanityList(parameters.inclusion_list, true /* CIDR */,
93 false /*IPV4 */)) {
94 *error = "Inclusion list CIDR sanity check failed.";
95 return;
98 if (!CheckIPCIDRSanityList(parameters.dns_servers, false /* Not CIDR */,
99 false /*IPV4 */)) {
100 *error = "DNS server IP sanity check failed.";
101 return;
104 std::vector<std::string> cidr_parts = base::SplitString(
105 parameters.address, kCIDRSeperator, base::KEEP_WHITESPACE,
106 base::SPLIT_WANT_NONEMPTY);
107 CHECK_EQ(2u, cidr_parts.size());
109 parameter_value->SetStringWithoutPathExpansion(
110 shill::kAddressParameterThirdPartyVpn, cidr_parts[0]);
112 parameter_value->SetStringWithoutPathExpansion(
113 shill::kSubnetPrefixParameterThirdPartyVpn, cidr_parts[1]);
115 std::string ip_delimiter(1, shill::kIPDelimiter);
116 parameter_value->SetStringWithoutPathExpansion(
117 shill::kExclusionListParameterThirdPartyVpn,
118 base::JoinString(parameters.exclusion_list, ip_delimiter));
120 parameter_value->SetStringWithoutPathExpansion(
121 shill::kInclusionListParameterThirdPartyVpn,
122 base::JoinString(parameters.inclusion_list, ip_delimiter));
124 if (parameters.mtu) {
125 parameter_value->SetStringWithoutPathExpansion(
126 shill::kMtuParameterThirdPartyVpn, *parameters.mtu);
129 if (parameters.broadcast_address) {
130 parameter_value->SetStringWithoutPathExpansion(
131 shill::kBroadcastAddressParameterThirdPartyVpn,
132 *parameters.broadcast_address);
135 std::string non_ip_delimiter(1, shill::kNonIPDelimiter);
136 if (parameters.domain_search) {
137 parameter_value->SetStringWithoutPathExpansion(
138 shill::kDomainSearchParameterThirdPartyVpn,
139 base::JoinString(*parameters.domain_search, non_ip_delimiter));
142 parameter_value->SetStringWithoutPathExpansion(
143 shill::kDnsServersParameterThirdPartyVpn,
144 base::JoinString(parameters.dns_servers, ip_delimiter));
146 return;
149 } // namespace
151 VpnThreadExtensionFunction::~VpnThreadExtensionFunction() {
154 void VpnThreadExtensionFunction::SignalCallCompletionSuccess() {
155 Respond(NoArguments());
158 void VpnThreadExtensionFunction::SignalCallCompletionSuccessWithId(
159 const std::string& configuration_id) {
160 Respond(OneArgument(new base::StringValue(configuration_id)));
163 void VpnThreadExtensionFunction::SignalCallCompletionSuccessWithWarning(
164 const std::string& warning) {
165 if (!warning.empty()) {
166 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING, warning);
168 Respond(NoArguments());
171 void VpnThreadExtensionFunction::SignalCallCompletionFailure(
172 const std::string& error_name,
173 const std::string& error_message) {
174 if (!error_name.empty() && !error_message.empty()) {
175 Respond(Error(error_name + ": " + error_message));
176 } else if (!error_name.empty()) {
177 Respond(Error(error_name));
178 } else {
179 Respond(Error(error_message));
183 VpnProviderCreateConfigFunction::~VpnProviderCreateConfigFunction() {
186 ExtensionFunction::ResponseAction VpnProviderCreateConfigFunction::Run() {
187 scoped_ptr<api_vpn::CreateConfig::Params> params(
188 api_vpn::CreateConfig::Params::Create(*args_));
189 if (!params) {
190 return RespondNow(Error("Invalid arguments."));
193 chromeos::VpnService* service =
194 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
195 if (!service) {
196 return RespondNow(Error("Invalid profile."));
199 // Use the configuration name as ID. In the future, a different ID scheme may
200 // be used, requiring a mapping between the two.
201 service->CreateConfiguration(
202 extension_id(), extension()->name(), params->name,
203 base::Bind(
204 &VpnProviderCreateConfigFunction::SignalCallCompletionSuccessWithId,
205 this, params->name),
206 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
207 SignalCallCompletionFailure,
208 this));
210 return RespondLater();
213 VpnProviderDestroyConfigFunction::~VpnProviderDestroyConfigFunction() {
216 ExtensionFunction::ResponseAction VpnProviderDestroyConfigFunction::Run() {
217 scoped_ptr<api_vpn::DestroyConfig::Params> params(
218 api_vpn::DestroyConfig::Params::Create(*args_));
219 if (!params) {
220 return RespondNow(Error("Invalid arguments."));
223 chromeos::VpnService* service =
224 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
225 if (!service) {
226 return RespondNow(Error("Invalid profile."));
229 service->DestroyConfiguration(
230 extension_id(), params->id,
231 base::Bind(&VpnProviderDestroyConfigFunction::SignalCallCompletionSuccess,
232 this),
233 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
234 SignalCallCompletionFailure,
235 this));
237 return RespondLater();
240 VpnProviderSetParametersFunction::~VpnProviderSetParametersFunction() {
243 ExtensionFunction::ResponseAction VpnProviderSetParametersFunction::Run() {
244 scoped_ptr<api_vpn::SetParameters::Params> params(
245 api_vpn::SetParameters::Params::Create(*args_));
246 if (!params) {
247 return RespondNow(Error("Invalid arguments."));
250 chromeos::VpnService* service =
251 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
252 if (!service) {
253 return RespondNow(Error("Invalid profile."));
256 base::DictionaryValue parameter_value;
257 std::string error;
258 ConvertParameters(params->parameters, &parameter_value, &error);
259 if (!error.empty()) {
260 return RespondNow(Error(error));
263 service->SetParameters(
264 extension_id(), parameter_value,
265 base::Bind(&VpnProviderSetParametersFunction::
266 SignalCallCompletionSuccessWithWarning,
267 this),
268 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
269 SignalCallCompletionFailure,
270 this));
272 return RespondLater();
275 VpnProviderSendPacketFunction::~VpnProviderSendPacketFunction() {
278 ExtensionFunction::ResponseAction VpnProviderSendPacketFunction::Run() {
279 scoped_ptr<api_vpn::SendPacket::Params> params(
280 api_vpn::SendPacket::Params::Create(*args_));
281 if (!params) {
282 return RespondNow(Error("Invalid arguments."));
285 chromeos::VpnService* service =
286 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
287 if (!service) {
288 return RespondNow(Error("Invalid profile."));
291 service->SendPacket(
292 extension_id(), params->data,
293 base::Bind(&VpnProviderSendPacketFunction::SignalCallCompletionSuccess,
294 this),
295 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
296 SignalCallCompletionFailure,
297 this));
299 return RespondLater();
302 VpnProviderNotifyConnectionStateChangedFunction::
303 ~VpnProviderNotifyConnectionStateChangedFunction() {
306 ExtensionFunction::ResponseAction
307 VpnProviderNotifyConnectionStateChangedFunction::Run() {
308 scoped_ptr<api_vpn::NotifyConnectionStateChanged::Params> params(
309 api_vpn::NotifyConnectionStateChanged::Params::Create(*args_));
310 if (!params) {
311 return RespondNow(Error("Invalid arguments."));
314 chromeos::VpnService* service =
315 chromeos::VpnServiceFactory::GetForBrowserContext(browser_context());
316 if (!service) {
317 return RespondNow(Error("Invalid profile."));
320 service->NotifyConnectionStateChanged(
321 extension_id(), params->state,
322 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
323 SignalCallCompletionSuccess,
324 this),
325 base::Bind(&VpnProviderNotifyConnectionStateChangedFunction::
326 SignalCallCompletionFailure,
327 this));
329 return RespondLater();
332 } // namespace extensions