summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchocobo@chromium.org <chocobo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-15 01:08:42 +0000
committerchocobo@chromium.org <chocobo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-15 01:08:42 +0000
commitb053e3e31795c5a944b074516786eca4e30893d5 (patch)
treec880107f9d6f13deb26b904b08ebcbe4678fe7ad
parent1bedb77908a1543e79a63283f0d54ffdd458a3bf (diff)
downloadchromium_src-b053e3e31795c5a944b074516786eca4e30893d5.zip
chromium_src-b053e3e31795c5a944b074516786eca4e30893d5.tar.gz
chromium_src-b053e3e31795c5a944b074516786eca4e30893d5.tar.bz2
Show parse errors in the UI when loading ONC files.
Resubmitting reverted CL with fix BUG=chromium-os:23757 TEST=manual Review URL: http://codereview.chromium.org/8883046 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@114558 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/cros/mock_network_library.h4
-rw-r--r--chrome/browser/chromeos/cros/network_library.cc29
-rw-r--r--chrome/browser/chromeos/cros/network_library.h5
-rw-r--r--chrome/browser/chromeos/cros/onc_network_parser.cc68
-rw-r--r--chrome/browser/chromeos/cros/onc_network_parser_unittest.cc3
-rw-r--r--chrome/browser/policy/network_configuration_updater.cc7
-rw-r--r--chrome/browser/policy/network_configuration_updater_unittest.cc9
-rw-r--r--chrome/browser/resources/net_internals/browser_bridge.js6
-rw-r--r--chrome/browser/resources/net_internals/chromeos_view.js8
-rw-r--r--chrome/browser/ui/webui/net_internals_ui.cc7
10 files changed, 109 insertions, 37 deletions
diff --git a/chrome/browser/chromeos/cros/mock_network_library.h b/chrome/browser/chromeos/cros/mock_network_library.h
index aa0b469..293149b 100644
--- a/chrome/browser/chromeos/cros/mock_network_library.h
+++ b/chrome/browser/chromeos/cros/mock_network_library.h
@@ -155,7 +155,9 @@ class MockNetworkLibrary : public NetworkLibrary {
HardwareAddressFormat));
MOCK_METHOD1(SetIPConfig, void(const NetworkIPConfig&));
MOCK_METHOD0(SwitchToPreferredNetwork, void(void));
- MOCK_METHOD2(LoadOncNetworks, bool(const std::string&, const std::string&));
+ MOCK_METHOD3(LoadOncNetworks, bool(const std::string&,
+ const std::string&,
+ std::string*));
MOCK_METHOD2(SetActiveNetwork, bool(ConnectionType, const std::string&));
};
diff --git a/chrome/browser/chromeos/cros/network_library.cc b/chrome/browser/chromeos/cros/network_library.cc
index 43acb7c..d1625d1 100644
--- a/chrome/browser/chromeos/cros/network_library.cc
+++ b/chrome/browser/chromeos/cros/network_library.cc
@@ -1745,7 +1745,8 @@ class NetworkLibraryImplBase : public NetworkLibrary {
// virtual SetIPConfig implemented in derived classes.
virtual void SwitchToPreferredNetwork() OVERRIDE;
virtual bool LoadOncNetworks(const std::string& onc_blob,
- const std::string& passcode) OVERRIDE;
+ const std::string& passcode,
+ std::string* error) OVERRIDE;
virtual bool SetActiveNetwork(ConnectionType type,
const std::string& service_path) OVERRIDE;
@@ -2834,14 +2835,23 @@ void NetworkLibraryImplBase::SwitchToPreferredNetwork() {
}
bool NetworkLibraryImplBase::LoadOncNetworks(const std::string& onc_blob,
- const std::string& passcode) {
+ const std::string& passcode,
+ std::string* error) {
// TODO(gspencer): Add support for decrypting onc files. crbug.com/19397
OncNetworkParser parser(onc_blob);
+ if (!parser.parse_error().empty()) {
+ if (error)
+ *error = parser.parse_error();
+ return false;
+ }
+
for (int i = 0; i < parser.GetCertificatesSize(); i++) {
// Insert each of the available certs into the certificate DB.
if (parser.ParseCertificate(i).get() == NULL) {
DLOG(WARNING) << "Cannot parse certificate in ONC file";
+ if (error)
+ *error = parser.parse_error();
return false;
}
}
@@ -2851,6 +2861,8 @@ bool NetworkLibraryImplBase::LoadOncNetworks(const std::string& onc_blob,
scoped_ptr<Network> network(parser.ParseNetwork(i));
if (!network.get()) {
DLOG(WARNING) << "Cannot parse network in ONC file";
+ if (error)
+ *error = parser.parse_error();
return false;
}
@@ -2868,8 +2880,15 @@ bool NetworkLibraryImplBase::LoadOncNetworks(const std::string& onc_blob,
CallConfigureService(network->unique_id(), &dict);
}
- return (parser.GetNetworkConfigsSize() != 0 ||
- parser.GetCertificatesSize() != 0);
+
+ if (parser.GetNetworkConfigsSize() != 0 ||
+ parser.GetCertificatesSize() != 0) {
+ if (error)
+ *error = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_NETWORK_IMPORT);
+ return false;
+ }
+ return true;
}
////////////////////////////////////////////////////////////////////////////
@@ -5102,7 +5121,7 @@ void NetworkLibraryImplStub::Init() {
" ],"
" \"Certificates\": []"
"}");
- LoadOncNetworks(test_blob, "");
+ LoadOncNetworks(test_blob, "", NULL);
}
////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/chromeos/cros/network_library.h b/chrome/browser/chromeos/cros/network_library.h
index b27f4db..5fe3a90 100644
--- a/chrome/browser/chromeos/cros/network_library.h
+++ b/chrome/browser/chromeos/cros/network_library.h
@@ -1789,8 +1789,11 @@ class NetworkLibrary {
virtual void SwitchToPreferredNetwork() = 0;
// Load networks from an Open Network Configuration blob.
+ // If there was an error, this will return false and |error| will be set to
+ // the error message.
virtual bool LoadOncNetworks(const std::string& onc_blob,
- const std::string& passcode) = 0;
+ const std::string& passcode,
+ std::string* error) = 0;
// This sets the active network for the network type. Note: priority order
// is unchanged (i.e. if a wifi network is set to active, but an ethernet
diff --git a/chrome/browser/chromeos/cros/onc_network_parser.cc b/chrome/browser/chromeos/cros/onc_network_parser.cc
index 670d08a..eedf109 100644
--- a/chrome/browser/chromeos/cros/onc_network_parser.cc
+++ b/chrome/browser/chromeos/cros/onc_network_parser.cc
@@ -16,11 +16,13 @@
#include "chrome/browser/chromeos/cros/native_network_parser.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/common/net/x509_certificate_model.h"
+#include "grit/generated_resources.h"
#include "net/base/cert_database.h"
#include "net/base/crypto_module.h"
#include "net/base/net_errors.h"
#include "net/base/x509_certificate.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
+#include "ui/base/l10n/l10n_util.h"
namespace chromeos {
@@ -235,10 +237,13 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseCertificate(
int cert_index) {
CHECK(certificates_);
CHECK(static_cast<size_t>(cert_index) < certificates_->GetSize());
- CHECK(cert_index >= 0);
+ CHECK_GE(cert_index, 0);
base::DictionaryValue* certificate = NULL;
- certificates_->GetDictionary(cert_index, &certificate);
- CHECK(certificate);
+ if (!certificates_->GetDictionary(cert_index, &certificate)) {
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_DATA_MALFORMED);
+ return NULL;
+ }
if (VLOG_IS_ON(2)) {
std::string certificate_json;
@@ -254,6 +259,8 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseCertificate(
if (!certificate->GetString("GUID", &guid) || guid.empty()) {
LOG(WARNING) << "ONC File: certificate missing identifier at index"
<< cert_index;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_GUID_MISSING);
return NULL;
}
@@ -262,9 +269,10 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseCertificate(
net::CertDatabase cert_database;
if (remove) {
- bool success = DeleteCertAndKeyByNickname(guid);
- DCHECK(success);
- // TODO(gspencer): return removed certificate?
+ if (!DeleteCertAndKeyByNickname(guid)) {
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_DELETE);
+ }
return NULL;
}
@@ -280,15 +288,22 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseCertificate(
LOG(WARNING) << "ONC File: certificate of unknown type: " << cert_type
<< " at index " << cert_index;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_TYPE_MISSING);
return NULL;
}
Network* OncNetworkParser::ParseNetwork(int n) {
- if (!network_configs_)
- return NULL;
+ CHECK(network_configs_);
+ CHECK(static_cast<size_t>(n) < network_configs_->GetSize());
+ CHECK_GE(n, 0);
DictionaryValue* info = NULL;
- if (!network_configs_->GetDictionary(n, &info))
+ if (!network_configs_->GetDictionary(n, &info)) {
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
return NULL;
+ }
+
if (VLOG_IS_ON(2)) {
std::string network_json;
base::JSONWriter::Write(static_cast<base::Value*>(info),
@@ -304,8 +319,11 @@ Network* OncNetworkParser::CreateNetworkFromInfo(
const std::string& service_path,
const DictionaryValue& info) {
ConnectionType type = ParseTypeFromDictionary(info);
- if (type == TYPE_UNKNOWN) // Return NULL if cannot parse network type.
+ if (type == TYPE_UNKNOWN) { // Return NULL if cannot parse network type.
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_NETWORK_TYPE_MISSING);
return NULL;
+ }
scoped_ptr<Network> network(CreateNewNetwork(type, service_path));
if (!ParseNestedObject(network.get(),
"NetworkConfiguration",
@@ -313,6 +331,9 @@ Network* OncNetworkParser::CreateNetworkFromInfo(
network_configuration_signature,
ParseNetworkConfigurationValue)) {
LOG(WARNING) << "Network " << network->name() << " failed to parse.";
+ if (parse_error_.empty())
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
return NULL;
}
if (VLOG_IS_ON(2)) {
@@ -373,6 +394,8 @@ OncNetworkParser::ParseServerOrCaCertificate(
if (!trust_list->GetString(i, &trust_type)) {
LOG(WARNING) << "ONC File: certificate trust is invalid at index "
<< cert_index;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_TRUST_INVALID);
return NULL;
}
if (trust_type == "Web") {
@@ -381,6 +404,8 @@ OncNetworkParser::ParseServerOrCaCertificate(
LOG(WARNING) << "ONC File: certificate contains unknown "
<< "trust type: " << trust_type
<< " at index " << cert_index;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_TRUST_UNKNOWN);
return NULL;
}
}
@@ -391,6 +416,8 @@ OncNetworkParser::ParseServerOrCaCertificate(
LOG(WARNING) << "ONC File: certificate missing appropriate "
<< "certificate data for type: " << cert_type
<< " at index " << cert_index;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_DATA_MISSING);
return NULL;
}
@@ -398,6 +425,8 @@ OncNetworkParser::ParseServerOrCaCertificate(
if (!base::Base64Decode(x509_data, &decoded_x509)) {
LOG(WARNING) << "Unable to base64 decode X509 data: \""
<< x509_data << "\".";
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_DATA_MALFORMED);
return NULL;
}
@@ -408,6 +437,8 @@ OncNetworkParser::ParseServerOrCaCertificate(
guid.c_str());
if (!x509_cert.get()) {
LOG(WARNING) << "Unable to create X509 certificate from bytes.";
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_DATA_MALFORMED);
return NULL;
}
@@ -417,7 +448,7 @@ OncNetworkParser::ParseServerOrCaCertificate(
bool success = false;
if (cert_type == "Server") {
success = cert_database.ImportServerCert(cert_list, &failures);
- } else { // Authority cert
+ } else { // Authority cert
net::CertDatabase::TrustBits trust = web_trust ?
net::CertDatabase::TRUSTED_SSL :
net::CertDatabase::UNTRUSTED;
@@ -428,11 +459,15 @@ OncNetworkParser::ParseServerOrCaCertificate(
<< net::ErrorToString(failures[0].net_error)
<< ") importing " << cert_type << " certificate at index "
<< cert_index;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_IMPORT);
return NULL;
}
if (!success) {
LOG(WARNING) << "ONC File: Unknown error importing " << cert_type
<< " certificate at index " << cert_index;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_UNKNOWN);
return NULL;
}
VLOG(2) << "Successfully imported server/ca certificate at index "
@@ -451,6 +486,8 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseClientCertificate(
pkcs12_data.empty()) {
LOG(WARNING) << "ONC File: PKCS12 data is missing for Client "
<< "certificate at index " << cert_index;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_DATA_MISSING);
return NULL;
}
@@ -458,6 +495,8 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseClientCertificate(
if (!base::Base64Decode(pkcs12_data, &decoded_pkcs12)) {
LOG(WARNING) << "Unable to base64 decode PKCS#12 data: \""
<< pkcs12_data << "\".";
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_DATA_MALFORMED);
return NULL;
}
@@ -471,6 +510,8 @@ scoped_refptr<net::X509Certificate> OncNetworkParser::ParseClientCertificate(
LOG(WARNING) << "ONC File: Unable to import Client certificate at index "
<< cert_index
<< " (error " << net::ErrorToString(result) << ").";
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_CERT_IMPORT);
return NULL;
}
@@ -515,6 +556,8 @@ bool OncNetworkParser::ParseNestedObject(Network* network,
bool any_errors = false;
if (!value.IsType(base::Value::TYPE_DICTIONARY)) {
VLOG(1) << network->name() << ": expected object of type " << onc_type;
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
return false;
}
VLOG(2) << "Parsing nested object of type " << onc_type;
@@ -560,6 +603,9 @@ bool OncNetworkParser::ParseNestedObject(Network* network,
<< "(" << index << ")] = " << value_json;
}
}
+ if (any_errors)
+ parse_error_ = l10n_util::GetStringUTF8(
+ IDS_NETWORK_CONFIG_ERROR_NETWORK_PROP_DICT_MALFORMED);
return !any_errors;
}
diff --git a/chrome/browser/chromeos/cros/onc_network_parser_unittest.cc b/chrome/browser/chromeos/cros/onc_network_parser_unittest.cc
index ec5907a..9b3ece0 100644
--- a/chrome/browser/chromeos/cros/onc_network_parser_unittest.cc
+++ b/chrome/browser/chromeos/cros/onc_network_parser_unittest.cc
@@ -263,7 +263,6 @@ TEST_F(OncNetworkParserTest, TestCreateNetworkWifi1) {
EXPECT_EQ(1, parser.GetNetworkConfigsSize());
EXPECT_EQ(0, parser.GetCertificatesSize());
- EXPECT_FALSE(parser.ParseNetwork(1));
scoped_ptr<Network> network(parser.ParseNetwork(0));
ASSERT_TRUE(network.get());
@@ -299,7 +298,6 @@ TEST_F(OncNetworkParserTest, TestCreateNetworkWifiEAP1) {
EXPECT_EQ(1, parser.GetNetworkConfigsSize());
EXPECT_EQ(0, parser.GetCertificatesSize());
- EXPECT_FALSE(parser.ParseNetwork(1));
scoped_ptr<Network> network(parser.ParseNetwork(0));
ASSERT_TRUE(network.get());
@@ -339,7 +337,6 @@ TEST_F(OncNetworkParserTest, TestCreateNetworkWifiEAP2) {
EXPECT_EQ(1, parser.GetNetworkConfigsSize());
EXPECT_EQ(0, parser.GetCertificatesSize());
- EXPECT_FALSE(parser.ParseNetwork(1));
scoped_ptr<Network> network(parser.ParseNetwork(0));
ASSERT_TRUE(network.get());
diff --git a/chrome/browser/policy/network_configuration_updater.cc b/chrome/browser/policy/network_configuration_updater.cc
index 788a010..a1597ca 100644
--- a/chrome/browser/policy/network_configuration_updater.cc
+++ b/chrome/browser/policy/network_configuration_updater.cc
@@ -56,8 +56,11 @@ void NetworkConfigurationUpdater::ApplyNetworkConfiguration(
if (*cached_value != new_network_config) {
*cached_value = new_network_config;
- if (!network_library_->LoadOncNetworks(new_network_config, ""))
- LOG(WARNING) << "Network library failed to load ONC configuration.";
+ std::string error;
+ if (!network_library_->LoadOncNetworks(new_network_config, "", &error)) {
+ LOG(WARNING) << "Network library failed to load ONC configuration:"
+ << error;
+ }
}
}
diff --git a/chrome/browser/policy/network_configuration_updater_unittest.cc b/chrome/browser/policy/network_configuration_updater_unittest.cc
index d1e71a2..82db2e9 100644
--- a/chrome/browser/policy/network_configuration_updater_unittest.cc
+++ b/chrome/browser/policy/network_configuration_updater_unittest.cc
@@ -11,6 +11,7 @@
using testing::Mock;
using testing::Return;
+using testing::_;
namespace policy {
@@ -26,7 +27,7 @@ class NetworkConfigurationUpdaterTest
TEST_P(NetworkConfigurationUpdaterTest, InitialUpdate) {
provider_.AddPolicy(GetParam(), Value::CreateStringValue(kFakeONC));
- EXPECT_CALL(network_library_, LoadOncNetworks(kFakeONC, ""))
+ EXPECT_CALL(network_library_, LoadOncNetworks(kFakeONC, "", _))
.WillRepeatedly(Return(true));
NetworkConfigurationUpdater updater(&provider_, &network_library_);
@@ -37,20 +38,20 @@ TEST_P(NetworkConfigurationUpdaterTest, PolicyChange) {
NetworkConfigurationUpdater updater(&provider_, &network_library_);
// We should update if policy changes.
- EXPECT_CALL(network_library_, LoadOncNetworks(kFakeONC, ""))
+ EXPECT_CALL(network_library_, LoadOncNetworks(kFakeONC, "", _))
.WillOnce(Return(true));
provider_.AddPolicy(GetParam(), Value::CreateStringValue(kFakeONC));
provider_.NotifyPolicyUpdated();
Mock::VerifyAndClearExpectations(&network_library_);
// No update if the set the same value again.
- EXPECT_CALL(network_library_, LoadOncNetworks(kFakeONC, ""))
+ EXPECT_CALL(network_library_, LoadOncNetworks(kFakeONC, "", _))
.Times(0);
provider_.NotifyPolicyUpdated();
Mock::VerifyAndClearExpectations(&network_library_);
// Another update is expected if the policy goes away.
- EXPECT_CALL(network_library_, LoadOncNetworks("", ""))
+ EXPECT_CALL(network_library_, LoadOncNetworks("", "", _))
.WillOnce(Return(true));
provider_.RemovePolicy(GetParam());
provider_.NotifyPolicyUpdated();
diff --git a/chrome/browser/resources/net_internals/browser_bridge.js b/chrome/browser/resources/net_internals/browser_bridge.js
index 6a2d308..032b2e1 100644
--- a/chrome/browser/resources/net_internals/browser_bridge.js
+++ b/chrome/browser/resources/net_internals/browser_bridge.js
@@ -316,9 +316,9 @@ var BrowserBridge = (function() {
this.hstsObservers_[i].onHSTSQueryResult(info);
},
- receivedONCFileParse: function(status) {
+ receivedONCFileParse: function(error) {
for (var i = 0; i < this.crosONCFileParseObservers_.length; i++)
- this.crosONCFileParseObservers_[i].onONCFileParse(status);
+ this.crosONCFileParseObservers_[i].onONCFileParse(error);
},
receivedHttpCacheInfo: function(info) {
@@ -498,7 +498,7 @@ var BrowserBridge = (function() {
* Adds a listener for ONC file parse status. The observer will be called
* back with:
*
- * observer.onONCFileParse(status);
+ * observer.onONCFileParse(error);
*/
addCrosONCFileParseObserver: function(observer) {
this.crosONCFileParseObservers_.push(observer);
diff --git a/chrome/browser/resources/net_internals/chromeos_view.js b/chrome/browser/resources/net_internals/chromeos_view.js
index b560d82..a3d2a35 100644
--- a/chrome/browser/resources/net_internals/chromeos_view.js
+++ b/chrome/browser/resources/net_internals/chromeos_view.js
@@ -20,7 +20,7 @@ var CrosView = (function() {
if (fileContent)
g_browser.importONCFile(fileContent, passcode);
else
- setParseStatus_(false);
+ setParseStatus_('ONC file parse failed: cannot read file');
}
/**
@@ -69,11 +69,11 @@ var CrosView = (function() {
*
* @private
*/
- function setParseStatus_(success) {
+ function setParseStatus_(error) {
var parseStatus = $(CrosView.PARSE_STATUS_ID);
parseStatus.hidden = false;
- parseStatus.textContent = success ?
- "ONC file successfully parsed" : "ONC file parse failed";
+ parseStatus.textContent = error ?
+ 'ONC file parse failed: ' + error : 'ONC file successfully parsed';
reset_();
}
diff --git a/chrome/browser/ui/webui/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals_ui.cc
index 8660432..09851c0 100644
--- a/chrome/browser/ui/webui/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals_ui.cc
@@ -1295,10 +1295,11 @@ void NetInternalsMessageHandler::OnImportONCFile(const ListValue* list) {
NOTREACHED();
}
- const bool success = chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
- LoadOncNetworks(onc_blob, passcode);
+ std::string error;
+ chromeos::CrosLibrary::Get()->GetNetworkLibrary()->
+ LoadOncNetworks(onc_blob, passcode, &error);
SendJavascriptCommand("receivedONCFileParse",
- Value::CreateBooleanValue(success));
+ Value::CreateStringValue(error));
}
#endif