| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <set> |
| #include <tuple> |
| |
| #include "base/json/json_reader.h" |
| #include "base/pickle.h" |
| #include "base/stl_util.h" |
| #include "base/values.h" |
| #include "extensions/common/api/sockets/sockets_manifest_permission.h" |
| #include "extensions/common/manifest_constants.h" |
| #include "ipc/ipc_message.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using content::SocketPermissionRequest; |
| |
| namespace extensions { |
| |
| namespace { |
| |
| const char kUdpBindPermission[] = |
| "{ \"udp\": { \"bind\": [\"127.0.0.1:3007\", \"a.com:80\"] } }"; |
| |
| const char kUdpSendPermission[] = |
| "{ \"udp\": { \"send\": [\"\", \"a.com:80\"] } }"; |
| |
| const char kTcpConnectPermission[] = |
| "{ \"tcp\": { \"connect\": [\"127.0.0.1:80\", \"a.com:80\"] } }"; |
| |
| const char kTcpServerListenPermission[] = |
| "{ \"tcpServer\": { \"listen\": [\"127.0.0.1:80\", \"a.com:80\"] } }"; |
| |
| static void AssertEmptyPermission(const SocketsManifestPermission* permission) { |
| EXPECT_TRUE(permission); |
| EXPECT_EQ(std::string(extensions::manifest_keys::kSockets), permission->id()); |
| EXPECT_EQ(permission->id(), permission->name()); |
| EXPECT_TRUE(permission->GetPermissions().empty()); |
| EXPECT_EQ(0u, permission->entries().size()); |
| } |
| |
| static std::unique_ptr<base::Value> ParsePermissionJSON( |
| const std::string& json) { |
| std::unique_ptr<base::Value> result(base::JSONReader::Read(json)); |
| EXPECT_TRUE(result) << "Invalid JSON string: " << json; |
| return result; |
| } |
| |
| static std::unique_ptr<SocketsManifestPermission> PermissionFromValue( |
| const base::Value& value) { |
| base::string16 error16; |
| std::unique_ptr<SocketsManifestPermission> permission( |
| SocketsManifestPermission::FromValue(value, &error16)); |
| EXPECT_TRUE(permission) << "Error parsing Value into permission: " << error16; |
| return permission; |
| } |
| |
| static std::unique_ptr<SocketsManifestPermission> PermissionFromJSON( |
| const std::string& json) { |
| std::unique_ptr<base::Value> value(ParsePermissionJSON(json)); |
| return PermissionFromValue(*value); |
| } |
| |
| struct CheckFormatEntry { |
| CheckFormatEntry(SocketPermissionRequest::OperationType operation_type, |
| std::string host_pattern) |
| : operation_type(operation_type), host_pattern(host_pattern) {} |
| |
| // operators <, == are needed by container std::set and algorithms |
| // std::set_includes and std::set_differences. |
| bool operator<(const CheckFormatEntry& rhs) const { |
| return std::tie(operation_type, host_pattern) < |
| std::tie(rhs.operation_type, rhs.host_pattern); |
| } |
| |
| bool operator==(const CheckFormatEntry& rhs) const { |
| return operation_type == rhs.operation_type && |
| host_pattern == rhs.host_pattern; |
| } |
| |
| SocketPermissionRequest::OperationType operation_type; |
| std::string host_pattern; |
| }; |
| |
| static testing::AssertionResult CheckFormat( |
| const std::multiset<CheckFormatEntry>& permissions, |
| const std::string& json) { |
| std::unique_ptr<SocketsManifestPermission> permission( |
| PermissionFromJSON(json)); |
| if (!permission) |
| return testing::AssertionFailure() << "Invalid permission " << json; |
| |
| if (permissions.size() != permission->entries().size()) { |
| return testing::AssertionFailure() |
| << "Incorrect # of entries in json: " << json; |
| } |
| |
| // Note: We use multiset because SocketsManifestPermission does not have to |
| // store entries in the order found in the json message. |
| std::multiset<CheckFormatEntry> parsed_permissions; |
| for (auto it = permission->entries().cbegin(); |
| it != permission->entries().cend(); ++it) { |
| parsed_permissions.insert( |
| CheckFormatEntry(it->pattern().type, it->GetHostPatternAsString())); |
| } |
| |
| if (!std::equal( |
| permissions.begin(), permissions.end(), parsed_permissions.begin())) { |
| return testing::AssertionFailure() << "Incorrect socket operations."; |
| } |
| return testing::AssertionSuccess(); |
| } |
| |
| static testing::AssertionResult CheckFormat(const std::string& json) { |
| return CheckFormat(std::multiset<CheckFormatEntry>(), json); |
| } |
| |
| static testing::AssertionResult CheckFormat(const std::string& json, |
| const CheckFormatEntry& op1) { |
| CheckFormatEntry entries[] = {op1}; |
| return CheckFormat( |
| std::multiset<CheckFormatEntry>(entries, entries + base::size(entries)), |
| json); |
| } |
| |
| static testing::AssertionResult CheckFormat(const std::string& json, |
| const CheckFormatEntry& op1, |
| const CheckFormatEntry& op2) { |
| CheckFormatEntry entries[] = {op1, op2}; |
| return CheckFormat( |
| std::multiset<CheckFormatEntry>(entries, entries + base::size(entries)), |
| json); |
| } |
| |
| static testing::AssertionResult CheckFormat(const std::string& json, |
| const CheckFormatEntry& op1, |
| const CheckFormatEntry& op2, |
| const CheckFormatEntry& op3, |
| const CheckFormatEntry& op4, |
| const CheckFormatEntry& op5, |
| const CheckFormatEntry& op6, |
| const CheckFormatEntry& op7, |
| const CheckFormatEntry& op8, |
| const CheckFormatEntry& op9) { |
| CheckFormatEntry entries[] = {op1, op2, op3, op4, op5, op6, op7, op8, op9}; |
| return CheckFormat( |
| std::multiset<CheckFormatEntry>(entries, entries + base::size(entries)), |
| json); |
| } |
| |
| } // namespace |
| |
| TEST(SocketsManifestPermissionTest, Empty) { |
| // Construction |
| std::unique_ptr<SocketsManifestPermission> permission( |
| new SocketsManifestPermission()); |
| AssertEmptyPermission(permission.get()); |
| |
| // Clone()/Equal() |
| std::unique_ptr<ManifestPermission> manifest_clone = permission->Clone(); |
| auto* clone = static_cast<SocketsManifestPermission*>(manifest_clone.get()); |
| AssertEmptyPermission(clone); |
| |
| EXPECT_TRUE(permission->Equal(clone)); |
| |
| // ToValue()/FromValue() |
| std::unique_ptr<const base::Value> value(permission->ToValue()); |
| EXPECT_TRUE(value.get()); |
| |
| std::unique_ptr<SocketsManifestPermission> permission2( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission2->FromValue(value.get())); |
| AssertEmptyPermission(permission2.get()); |
| |
| // Union/Diff/Intersection |
| std::unique_ptr<ManifestPermission> manifest_diff = permission->Diff(clone); |
| auto* diff = static_cast<SocketsManifestPermission*>(manifest_diff.get()); |
| AssertEmptyPermission(diff); |
| |
| std::unique_ptr<ManifestPermission> manifest_union = permission->Union(clone); |
| auto* union_perm = |
| static_cast<SocketsManifestPermission*>(manifest_union.get()); |
| AssertEmptyPermission(union_perm); |
| |
| std::unique_ptr<ManifestPermission> manifest_intersect = |
| permission->Intersect(clone); |
| auto* intersect = |
| static_cast<SocketsManifestPermission*>(manifest_intersect.get()); |
| AssertEmptyPermission(intersect); |
| |
| // IPC |
| std::unique_ptr<SocketsManifestPermission> ipc_perm( |
| new SocketsManifestPermission()); |
| std::unique_ptr<SocketsManifestPermission> ipc_perm2( |
| new SocketsManifestPermission()); |
| |
| IPC::Message m; |
| ipc_perm->Write(&m); |
| base::PickleIterator iter(m); |
| EXPECT_TRUE(ipc_perm2->Read(&m, &iter)); |
| AssertEmptyPermission(ipc_perm2.get()); |
| } |
| |
| TEST(SocketsManifestPermissionTest, JSONFormats) { |
| EXPECT_TRUE(CheckFormat( |
| "{\"udp\":{\"send\":\"\"}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "*:*"))); |
| EXPECT_TRUE(CheckFormat("{\"udp\":{\"send\":[]}}")); |
| EXPECT_TRUE(CheckFormat( |
| "{\"udp\":{\"send\":[\"\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "*:*"))); |
| EXPECT_TRUE(CheckFormat( |
| "{\"udp\":{\"send\":[\"a:80\", \"b:10\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "a:80"), |
| CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "b:10"))); |
| |
| EXPECT_TRUE( |
| CheckFormat("{\"udp\":{\"bind\":\"\"}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "*:*"))); |
| EXPECT_TRUE(CheckFormat("{\"udp\":{\"bind\":[]}}")); |
| EXPECT_TRUE( |
| CheckFormat("{\"udp\":{\"bind\":[\"\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "*:*"))); |
| EXPECT_TRUE( |
| CheckFormat("{\"udp\":{\"bind\":[\"a:80\", \"b:10\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "a:80"), |
| CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "b:10"))); |
| |
| EXPECT_TRUE(CheckFormat( |
| "{\"udp\":{\"multicastMembership\":\"\"}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, ""))); |
| EXPECT_TRUE(CheckFormat("{\"udp\":{\"multicastMembership\":[]}}")); |
| EXPECT_TRUE(CheckFormat( |
| "{\"udp\":{\"multicastMembership\":[\"\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, ""))); |
| EXPECT_TRUE(CheckFormat( |
| "{\"udp\":{\"multicastMembership\":[\"\", \"\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, ""))); |
| |
| EXPECT_TRUE(CheckFormat( |
| "{\"tcp\":{\"connect\":\"\"}}", |
| CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "*:*"))); |
| EXPECT_TRUE(CheckFormat("{\"tcp\":{\"connect\":[]}}")); |
| EXPECT_TRUE(CheckFormat( |
| "{\"tcp\":{\"connect\":[\"\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "*:*"))); |
| EXPECT_TRUE(CheckFormat( |
| "{\"tcp\":{\"connect\":[\"a:80\", \"b:10\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "a:80"), |
| CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "b:10"))); |
| |
| EXPECT_TRUE(CheckFormat( |
| "{\"tcpServer\":{\"listen\":\"\"}}", |
| CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "*:*"))); |
| EXPECT_TRUE(CheckFormat("{\"tcpServer\":{\"listen\":[]}}")); |
| EXPECT_TRUE(CheckFormat( |
| "{\"tcpServer\":{\"listen\":[\"\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "*:*"))); |
| EXPECT_TRUE(CheckFormat( |
| "{\"tcpServer\":{\"listen\":[\"a:80\", \"b:10\"]}}", |
| CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "a:80"), |
| CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "b:10"))); |
| |
| EXPECT_TRUE(CheckFormat( |
| "{" |
| "\"udp\":{" |
| "\"send\":[\"a:80\", \"b:10\"]," |
| "\"bind\":[\"a:80\", \"b:10\"]," |
| "\"multicastMembership\":\"\"" |
| "}," |
| "\"tcp\":{\"connect\":[\"a:80\", \"b:10\"]}," |
| "\"tcpServer\":{\"listen\":[\"a:80\", \"b:10\"]}" |
| "}", |
| CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "a:80"), |
| CheckFormatEntry(SocketPermissionRequest::UDP_SEND_TO, "b:10"), |
| CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "a:80"), |
| CheckFormatEntry(SocketPermissionRequest::UDP_BIND, "b:10"), |
| CheckFormatEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, ""), |
| CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "a:80"), |
| CheckFormatEntry(SocketPermissionRequest::TCP_CONNECT, "b:10"), |
| CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "a:80"), |
| CheckFormatEntry(SocketPermissionRequest::TCP_LISTEN, "b:10"))); |
| } |
| |
| TEST(SocketsManifestPermissionTest, FromToValue) { |
| std::unique_ptr<base::Value> udp_send( |
| ParsePermissionJSON(kUdpBindPermission)); |
| std::unique_ptr<base::Value> udp_bind( |
| ParsePermissionJSON(kUdpSendPermission)); |
| std::unique_ptr<base::Value> tcp_connect( |
| ParsePermissionJSON(kTcpConnectPermission)); |
| std::unique_ptr<base::Value> tcp_server_listen( |
| ParsePermissionJSON(kTcpServerListenPermission)); |
| |
| // FromValue() |
| std::unique_ptr<SocketsManifestPermission> permission1( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission1->FromValue(udp_send.get())); |
| EXPECT_EQ(2u, permission1->entries().size()); |
| |
| std::unique_ptr<SocketsManifestPermission> permission2( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission2->FromValue(udp_bind.get())); |
| EXPECT_EQ(2u, permission2->entries().size()); |
| |
| std::unique_ptr<SocketsManifestPermission> permission3( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission3->FromValue(tcp_connect.get())); |
| EXPECT_EQ(2u, permission3->entries().size()); |
| |
| std::unique_ptr<SocketsManifestPermission> permission4( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission4->FromValue(tcp_server_listen.get())); |
| EXPECT_EQ(2u, permission4->entries().size()); |
| |
| // ToValue() |
| std::unique_ptr<base::Value> value1 = permission1->ToValue(); |
| EXPECT_TRUE(value1); |
| std::unique_ptr<SocketsManifestPermission> permission1_1( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission1_1->FromValue(value1.get())); |
| EXPECT_TRUE(permission1->Equal(permission1_1.get())); |
| |
| std::unique_ptr<base::Value> value2 = permission2->ToValue(); |
| EXPECT_TRUE(value2); |
| std::unique_ptr<SocketsManifestPermission> permission2_1( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission2_1->FromValue(value2.get())); |
| EXPECT_TRUE(permission2->Equal(permission2_1.get())); |
| |
| std::unique_ptr<base::Value> value3 = permission3->ToValue(); |
| EXPECT_TRUE(value3); |
| std::unique_ptr<SocketsManifestPermission> permission3_1( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission3_1->FromValue(value3.get())); |
| EXPECT_TRUE(permission3->Equal(permission3_1.get())); |
| |
| std::unique_ptr<base::Value> value4 = permission4->ToValue(); |
| EXPECT_TRUE(value4); |
| std::unique_ptr<SocketsManifestPermission> permission4_1( |
| new SocketsManifestPermission()); |
| EXPECT_TRUE(permission4_1->FromValue(value4.get())); |
| EXPECT_TRUE(permission4->Equal(permission4_1.get())); |
| } |
| |
| TEST(SocketsManifestPermissionTest, SetOperations) { |
| std::unique_ptr<SocketsManifestPermission> permission1( |
| PermissionFromJSON(kUdpBindPermission)); |
| std::unique_ptr<SocketsManifestPermission> permission2( |
| PermissionFromJSON(kUdpSendPermission)); |
| std::unique_ptr<SocketsManifestPermission> permission3( |
| PermissionFromJSON(kTcpConnectPermission)); |
| std::unique_ptr<SocketsManifestPermission> permission4( |
| PermissionFromJSON(kTcpServerListenPermission)); |
| |
| // Union |
| std::unique_ptr<ManifestPermission> manifest_union = |
| permission1->Union(permission2.get()); |
| auto* union_perm = |
| static_cast<SocketsManifestPermission*>(manifest_union.get()); |
| |
| ASSERT_TRUE(union_perm); |
| EXPECT_EQ(4u, union_perm->entries().size()); |
| |
| EXPECT_TRUE(union_perm->Contains(permission1.get())); |
| EXPECT_TRUE(union_perm->Contains(permission2.get())); |
| EXPECT_FALSE(union_perm->Contains(permission3.get())); |
| EXPECT_FALSE(union_perm->Contains(permission4.get())); |
| |
| // Diff |
| std::unique_ptr<ManifestPermission> manifest_diff1 = |
| permission1->Diff(permission2.get()); |
| auto* diff1 = static_cast<SocketsManifestPermission*>(manifest_diff1.get()); |
| |
| ASSERT_TRUE(diff1); |
| EXPECT_EQ(2u, diff1->entries().size()); |
| |
| EXPECT_TRUE(permission1->Equal(diff1)); |
| EXPECT_TRUE(diff1->Equal(permission1.get())); |
| |
| std::unique_ptr<ManifestPermission> manifest_diff2 = |
| permission1->Diff(union_perm); |
| auto* diff2 = static_cast<SocketsManifestPermission*>(manifest_diff2.get()); |
| ASSERT_TRUE(diff2); |
| AssertEmptyPermission(diff2); |
| |
| // Intersection |
| std::unique_ptr<ManifestPermission> manifest_intersect1 = |
| union_perm->Intersect(permission1.get()); |
| auto* intersect1 = |
| static_cast<SocketsManifestPermission*>(manifest_intersect1.get()); |
| ASSERT_TRUE(intersect1); |
| EXPECT_EQ(2u, intersect1->entries().size()); |
| |
| EXPECT_TRUE(permission1->Equal(intersect1)); |
| EXPECT_TRUE(intersect1->Equal(permission1.get())); |
| } |
| |
| TEST(SocketsManifestPermissionTest, IPC) { |
| std::unique_ptr<SocketsManifestPermission> permission( |
| PermissionFromJSON(kUdpBindPermission)); |
| |
| std::unique_ptr<ManifestPermission> manifest_ipc_perm1 = permission->Clone(); |
| auto* ipc_perm1 = |
| static_cast<SocketsManifestPermission*>(manifest_ipc_perm1.get()); |
| |
| auto ipc_perm2 = std::make_unique<SocketsManifestPermission>(); |
| |
| IPC::Message m; |
| ipc_perm1->Write(&m); |
| base::PickleIterator iter(m); |
| EXPECT_TRUE(ipc_perm2->Read(&m, &iter)); |
| EXPECT_TRUE(permission->Equal(ipc_perm2.get())); |
| } |
| |
| } // namespace extensions |