redaction_tool_unittest.cc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. // Copyright 2015 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.
  4. #include "components/feedback/redaction_tool.h"
  5. #include <gtest/gtest.h>
  6. #include <set>
  7. #include <utility>
  8. #include "base/strings/string_util.h"
  9. #include "build/chromeos_buildflags.h"
  10. #include "components/feedback/pii_types.h"
  11. namespace feedback {
  12. const char kFakeFirstPartyID[] = "nkoccljplnhpfnfiajclkommnmllphnl";
  13. const char* const kFakeFirstPartyExtensionIDs[] = {kFakeFirstPartyID, nullptr};
  14. struct StringWithRedaction {
  15. // The raw version of the string before redaction. May contain PII sensitive
  16. // data.
  17. std::string pre_redaction;
  18. // The string that's redacted of PII sensitive data.
  19. std::string post_redaction;
  20. // The PII type that string contains. PIIType::kNone if the string doesn't
  21. // contain any PII sensitive data.
  22. PIIType pii_type;
  23. };
  24. // For better readability, put all the pre/post redaction strings in an array of
  25. // StringWithRedaction struct, and then convert that to two strings which become
  26. // the input and output of the redactor.
  27. const StringWithRedaction kStringsWithRedactions[] = {
  28. {"aaaaaaaa [SSID=123aaaaaa]aaaaa", // SSID.
  29. "aaaaaaaa [SSID=<SSID: 1>]aaaaa", PIIType::kSSID},
  30. {"aaaaaaaahttp://tets.comaaaaaaa", // URL.
  31. "aaaaaaaa<URL: 1>", PIIType::kURL},
  32. {"u:object_r:system_data_file:s0:c512,c768", // No PII, it is an SELinux
  33. // context.
  34. "u:object_r:system_data_file:s0:c512,c768", PIIType::kNone},
  35. {"aaaaaemail@example.comaaa", // Email address.
  36. "<email: 1>", PIIType::kEmail},
  37. {"example@@1234", // No PII, it is not a valid email address.
  38. "example@@1234", PIIType::kNone},
  39. {"255.255.155.2", // IP address.
  40. "<IPv4: 1>", PIIType::kIPAddress},
  41. {"255.255.155.255", // IP address.
  42. "<IPv4: 2>", PIIType::kIPAddress},
  43. {"127.0.0.1", // IPv4 loopback.
  44. "<127.0.0.0/8: 3>", PIIType::kIPAddress},
  45. {"127.255.0.1", // IPv4 loopback.
  46. "<127.0.0.0/8: 4>", PIIType::kIPAddress},
  47. {"0.0.0.0", // Any IPv4.
  48. "<0.0.0.0/8: 5>", PIIType::kIPAddress},
  49. {"0.255.255.255", // Any IPv4.
  50. "<0.0.0.0/8: 6>", PIIType::kIPAddress},
  51. {"10.10.10.100", // IPv4 private class A.
  52. "<10.0.0.0/8: 7>", PIIType::kIPAddress},
  53. {"10.10.10.100", // Intentional duplicate.
  54. "<10.0.0.0/8: 7>", PIIType::kIPAddress},
  55. {"10.10.10.101", // IPv4 private class A.
  56. "<10.0.0.0/8: 8>", PIIType::kIPAddress},
  57. {"10.255.255.255", // IPv4 private class A.
  58. "<10.0.0.0/8: 9>", PIIType::kIPAddress},
  59. {"172.16.0.0", // IPv4 private class B.
  60. "<172.16.0.0/12: 10>", PIIType::kIPAddress},
  61. {"172.31.255.255", // IPv4 private class B.
  62. "<172.16.0.0/12: 11>", PIIType::kIPAddress},
  63. {"172.11.5.5", // IP address.
  64. "<IPv4: 12>", PIIType::kIPAddress},
  65. {"172.111.5.5", // IP address.
  66. "<IPv4: 13>", PIIType::kIPAddress},
  67. {"192.168.0.0", // IPv4 private class C.
  68. "<192.168.0.0/16: 14>", PIIType::kIPAddress},
  69. {"192.168.255.255", // IPv4 private class C.
  70. "<192.168.0.0/16: 15>", PIIType::kIPAddress},
  71. {"192.169.2.120", // IP address.
  72. "<IPv4: 16>", PIIType::kIPAddress},
  73. {"169.254.0.1", // Link local.
  74. "<169.254.0.0/16: 17>", PIIType::kIPAddress},
  75. {"169.200.0.1", // IP address.
  76. "<IPv4: 18>", PIIType::kIPAddress},
  77. {"fe80::", // Link local.
  78. "<fe80::/10: 1>", PIIType::kIPAddress},
  79. {"fe80::ffff", // Link local.
  80. "<fe80::/10: 2>", PIIType::kIPAddress},
  81. {"febf:ffff::ffff", // Link local.
  82. "<fe80::/10: 3>", PIIType::kIPAddress},
  83. {"fecc::1111", // IP address.
  84. "<IPv6: 4>", PIIType::kIPAddress},
  85. {"224.0.0.24", // Multicast.
  86. "<224.0.0.0/4: 19>", PIIType::kIPAddress},
  87. {"240.0.0.0", // IP address.
  88. "<IPv4: 20>", PIIType::kIPAddress},
  89. {"255.255.255.255", // Broadcast.
  90. "255.255.255.255", PIIType::kNone},
  91. {"100.115.92.92", // ChromeOS.
  92. "100.115.92.92", PIIType::kNone},
  93. {"100.115.91.92", // IP address.
  94. "<IPv4: 21>", PIIType::kIPAddress},
  95. {"1.1.1.1", // DNS
  96. "1.1.1.1", PIIType::kNone},
  97. {"8.8.8.8", // DNS
  98. "8.8.8.8", PIIType::kNone},
  99. {"8.8.4.4", // DNS
  100. "8.8.4.4", PIIType::kNone},
  101. {"8.8.8.4", // IP address.
  102. "<IPv4: 22>", PIIType::kIPAddress},
  103. {"255.255.259.255", // Not an IP address.
  104. "255.255.259.255", PIIType::kNone},
  105. {"255.300.255.255", // Not an IP address.
  106. "255.300.255.255", PIIType::kNone},
  107. {"3-1.2.3.4", // USB path, not an IP address.
  108. "3-1.2.3.4", PIIType::kNone},
  109. {"Revision: 81600.0000.00.29.19.16_DO", // Modem firmware
  110. "Revision: 81600.0000.00.29.19.16_DO", PIIType::kNone},
  111. {"aaaa123.123.45.4aaa", // IP address.
  112. "aaaa<IPv4: 23>aaa", PIIType::kIPAddress},
  113. {"11:11;11::11", // IP address.
  114. "11:11;<IPv6: 5>", PIIType::kIPAddress},
  115. {"11::11", // IP address.
  116. "<IPv6: 5>", PIIType::kIPAddress},
  117. {"11:11:abcdef:0:0:0:0:0", // No PII.
  118. "11:11:abcdef:0:0:0:0:0", PIIType::kNone},
  119. {"::", // Unspecified.
  120. "::", PIIType::kNone},
  121. {"::1", // Local host.
  122. "::1", PIIType::kNone},
  123. {"Instance::Set", // Ignore match, no PII.
  124. "Instance::Set", PIIType::kNone},
  125. {"Instant::ff", // Ignore match, no PII.
  126. "Instant::ff", PIIType::kNone},
  127. {"net::ERR_CONN_TIMEOUT", // Ignore match, no PII.
  128. "net::ERR_CONN_TIMEOUT", PIIType::kNone},
  129. {"ff01::1", // All nodes address (interface local).
  130. "ff01::1", PIIType::kNone},
  131. {"ff01::2", // All routers (interface local).
  132. "ff01::2", PIIType::kNone},
  133. {"ff01::3", // Multicast (interface local).
  134. "<ff01::/16: 6>", PIIType::kIPAddress},
  135. {"ff02::1", // All nodes address (link local).
  136. "ff02::1", PIIType::kNone},
  137. {"ff02::2", // All routers (link local).
  138. "ff02::2", PIIType::kNone},
  139. {"ff02::3", // Multicast (link local).
  140. "<ff02::/16: 7>", PIIType::kIPAddress},
  141. {"ff02::fb", // mDNSv6 (link local).
  142. "<ff02::/16: 8>", PIIType::kIPAddress},
  143. {"ff08::fb", // mDNSv6.
  144. "<IPv6: 9>", PIIType::kIPAddress},
  145. {"ff0f::101", // All NTP servers.
  146. "<IPv6: 10>", PIIType::kIPAddress},
  147. {"::ffff:cb0c:10ea", // IPv4-mapped IPV6 (IP address).
  148. "<IPv6: 11>", PIIType::kIPAddress},
  149. {"::ffff:a0a:a0a", // IPv4-mapped IPV6 (private class A).
  150. "<M 10.0.0.0/8: 12>", PIIType::kIPAddress},
  151. {"::ffff:a0a:a0a", // Intentional duplicate.
  152. "<M 10.0.0.0/8: 12>", PIIType::kIPAddress},
  153. {"::ffff:ac1e:1e1e", // IPv4-mapped IPV6 (private class B).
  154. "<M 172.16.0.0/12: 13>", PIIType::kIPAddress},
  155. {"::ffff:c0a8:640a", // IPv4-mapped IPV6 (private class C).
  156. "<M 192.168.0.0/16: 14>", PIIType::kIPAddress},
  157. {"::ffff:6473:5c01", // IPv4-mapped IPV6 (Chrome).
  158. "<M 100.115.92.1: 15>", PIIType::kIPAddress},
  159. {"64:ff9b::a0a:a0a", // IPv4-translated 6to4 IPV6 (private class A).
  160. "<T 10.0.0.0/8: 16>", PIIType::kIPAddress},
  161. {"64:ff9b::6473:5c01", // IPv4-translated 6to4 IPV6 (Chrome).
  162. "<T 100.115.92.1: 17>", PIIType::kIPAddress},
  163. {"::0101:ffff:c0a8:640a", // IP address.
  164. "<IPv6: 18>", PIIType::kIPAddress},
  165. {"aa:aa:aa:aa:aa:aa", // MAC address (BSSID).
  166. "[MAC OUI=aa:aa:aa IFACE=1]", PIIType::kMACAddress},
  167. {"chrome://resources/foo", // Secure chrome resource, exempt.
  168. "chrome://resources/foo", PIIType::kNone},
  169. {"chrome://settings/crisper.js", // Exempt settings URLs.
  170. "chrome://settings/crisper.js", PIIType::kNone},
  171. // Exempt first party extension.
  172. {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
  173. "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js",
  174. PIIType::kNone},
  175. {"chrome://resources/f?user=bar", // Potentially PII in parameter.
  176. "<URL: 2>", PIIType::kURL},
  177. {"chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/foobar.js?bar=x",
  178. "<URL: 3>", PIIType::kURL}, // Potentially PII in parameter.
  179. {"/root/27540283740a0897ab7c8de0f809add2bacde78f/foo",
  180. "/root/<HASH:2754 1>/foo", PIIType::kStableIdentifier}, // Hash string.
  181. {"B3mcFTkQAHofv94DDTUuVJGGEI/BbzsyDncplMCR2P4=", "<UID: 1>",
  182. PIIType::kStableIdentifier},
  183. #if BUILDFLAG(IS_CHROMEOS_ASH) // We only redact Android paths on Chrome OS.
  184. // Allowed android storage path.
  185. {"112K\t/home/root/deadbeef1234/android-data/data/system_de",
  186. "112K\t/home/root/deadbeef1234/android-data/data/system_de",
  187. PIIType::kNone},
  188. // Redacted app-specific storage path.
  189. {"8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/de",
  190. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/d_",
  191. PIIType::kAndroidAppStoragePath},
  192. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  193. };
  194. class RedactionToolTest : public testing::Test {
  195. protected:
  196. std::string RedactMACAddresses(const std::string& input) {
  197. return redactor_.RedactMACAddresses(input, nullptr);
  198. }
  199. std::string RedactHashes(const std::string& input) {
  200. return redactor_.RedactHashes(input, nullptr);
  201. }
  202. std::string RedactAndroidAppStoragePaths(const std::string& input) {
  203. return redactor_.RedactAndroidAppStoragePaths(input, nullptr);
  204. }
  205. std::string RedactCustomPatterns(const std::string& input) {
  206. return redactor_.RedactAndKeepSelectedCustomPatterns(
  207. input,
  208. /*pii_types_to_keep=*/{});
  209. }
  210. std::string RedactCustomPatternWithContext(
  211. const std::string& input,
  212. const CustomPatternWithAlias& pattern) {
  213. return redactor_.RedactCustomPatternWithContext(input, pattern, nullptr);
  214. }
  215. std::string RedactCustomPatternWithoutContext(
  216. const std::string& input,
  217. const CustomPatternWithAlias& pattern) {
  218. return redactor_.RedactCustomPatternWithoutContext(input, pattern, nullptr);
  219. }
  220. RedactionTool redactor_{kFakeFirstPartyExtensionIDs};
  221. };
  222. TEST_F(RedactionToolTest, Redact) {
  223. EXPECT_EQ("", redactor_.Redact(""));
  224. EXPECT_EQ("foo\nbar\n", redactor_.Redact("foo\nbar\n"));
  225. // Make sure MAC address redaction is invoked.
  226. EXPECT_EQ("[MAC OUI=02:46:8a IFACE=1]",
  227. redactor_.Redact("02:46:8a:ce:13:57"));
  228. // Make sure hash redaction is invoked.
  229. EXPECT_EQ("<HASH:1122 1>",
  230. redactor_.Redact("11223344556677889900AABBCCDDEEFF"));
  231. // Make sure custom pattern redaction is invoked.
  232. EXPECT_EQ("Cell ID: '<CellID: 1>'", RedactCustomPatterns("Cell ID: 'A1B2'"));
  233. // Make sure UUIDs are redacted.
  234. EXPECT_EQ(
  235. "REQUEST localhost - - \"POST /printers/<UUID: 1> HTTP/1.1\" 200 291 "
  236. "Create-Job successful-ok",
  237. redactor_.Redact(
  238. "REQUEST localhost - - \"POST /printers/"
  239. "cb738a9f-6433-4d95-a81e-94e4ae0ed30b HTTP/1.1\" 200 291 Create-Job "
  240. "successful-ok"));
  241. EXPECT_EQ(
  242. "REQUEST localhost - - \"POST /printers/<UUID: 2> HTTP/1.1\" 200 286 "
  243. "Create-Job successful-ok",
  244. redactor_.Redact(
  245. "REQUEST localhost - - \"POST /printers/"
  246. "d17188da-9cd3-44f4-b148-3e1d748a3b0f HTTP/1.1\" 200 286 Create-Job "
  247. "successful-ok"));
  248. }
  249. TEST_F(RedactionToolTest, RedactMACAddresses) {
  250. EXPECT_EQ("", RedactMACAddresses(""));
  251. EXPECT_EQ("foo\nbar\n", RedactMACAddresses("foo\nbar\n"));
  252. EXPECT_EQ("11:22:33:44:55", RedactMACAddresses("11:22:33:44:55"));
  253. EXPECT_EQ("[MAC OUI=aa:bb:cc IFACE=1]",
  254. RedactMACAddresses("aa:bb:cc:dd:ee:ff"));
  255. EXPECT_EQ("[MAC OUI=aa:bb:cc IFACE=1]",
  256. RedactMACAddresses("aa_bb_cc_dd_ee_ff"));
  257. EXPECT_EQ("[MAC OUI=aa:bb:cc IFACE=1]",
  258. RedactMACAddresses("aa-bb-cc-dd-ee-ff"));
  259. EXPECT_EQ("00:00:00:00:00:00", RedactMACAddresses("00:00:00:00:00:00"));
  260. EXPECT_EQ("ff:ff:ff:ff:ff:ff", RedactMACAddresses("ff:ff:ff:ff:ff:ff"));
  261. EXPECT_EQ(
  262. "BSSID: [MAC OUI=aa:bb:cc IFACE=1] in the middle\n"
  263. "[MAC OUI=bb:cc:dd IFACE=2] start of line\n"
  264. "end of line [MAC OUI=aa:bb:cc IFACE=1]\n"
  265. "no match across lines aa:bb:cc:\n"
  266. "dd:ee:ff two on the same line:\n"
  267. "x [MAC OUI=bb:cc:dd IFACE=2] [MAC OUI=cc:dd:ee IFACE=3] x\n",
  268. RedactMACAddresses("BSSID: aa:bb:cc:dd:ee:ff in the middle\n"
  269. "bb:cc:dd:ee:ff:00 start of line\n"
  270. "end of line aa:bb:cc:dd:ee:ff\n"
  271. "no match across lines aa:bb:cc:\n"
  272. "dd:ee:ff two on the same line:\n"
  273. "x bb:cc:dd:ee:ff:00 cc:dd:ee:ff:00:11 x\n"));
  274. EXPECT_EQ("Remember [MAC OUI=bb:cc:dd IFACE=2]?",
  275. RedactMACAddresses("Remember bB:Cc:DD:ee:ff:00?"));
  276. }
  277. TEST_F(RedactionToolTest, RedactHashes) {
  278. EXPECT_EQ("", RedactHashes(""));
  279. EXPECT_EQ("foo\nbar\n", RedactHashes("foo\nbar\n"));
  280. // Too short.
  281. EXPECT_EQ("11223344556677889900aabbccddee",
  282. RedactHashes("11223344556677889900aabbccddee"));
  283. // Not the right length.
  284. EXPECT_EQ("11223344556677889900aabbccddeeff1122",
  285. RedactHashes("11223344556677889900aabbccddeeff1122"));
  286. // Too long.
  287. EXPECT_EQ(
  288. "11223344556677889900aabbccddeeff11223344556677889900aabbccddeeff11",
  289. RedactHashes("11223344556677889900aabbccddeeff11223344556677889900aabb"
  290. "ccddeeff11"));
  291. // Test all 3 valid lengths.
  292. EXPECT_EQ("<HASH:aabb 1>", RedactHashes("aabbccddeeff00112233445566778899"));
  293. EXPECT_EQ("<HASH:aabb 2>",
  294. RedactHashes("aabbccddeeff00112233445566778899aabbccdd"));
  295. EXPECT_EQ(
  296. "<HASH:9988 3>",
  297. RedactHashes(
  298. "99887766554433221100ffeeddccbbaaaabbccddeeff00112233445566778899"));
  299. // Skip 32 byte hashes that have a at least 3 whitespace chars before it.
  300. EXPECT_EQ(" <HASH:aabb 1>",
  301. RedactHashes(" aabbccddeeff00112233445566778899"));
  302. EXPECT_EQ(" aabbccddeeff00112233445566778899",
  303. RedactHashes(" aabbccddeeff00112233445566778899"));
  304. // Multiline test.
  305. EXPECT_EQ(
  306. "Hash value=<HASH:aabb 1>, should be replaced as\n"
  307. "well as /<HASH:aabb 1>/ and mixed case of\n"
  308. "<HASH:aabb 1> but we don't go across lines\n"
  309. "aabbccddeeff\n00112233445566778899 but allow multiple on a line "
  310. "<HASH:aabb 4>-"
  311. "<HASH:0011 5>\n",
  312. RedactHashes(
  313. "Hash value=aabbccddeeff00112233445566778899, should be replaced as\n"
  314. "well as /aabbccddeeff00112233445566778899/ and mixed case of\n"
  315. "AaBbCCddEeFf00112233445566778899 but we don't go across lines\n"
  316. "aabbccddeeff\n00112233445566778899 but allow multiple on a line "
  317. "aabbccddeeffaabbccddeeffaabbccddeeffaabb-"
  318. "00112233445566778899aabbccddeeff\n"));
  319. }
  320. TEST_F(RedactionToolTest, RedactCustomPatterns) {
  321. EXPECT_EQ("", RedactCustomPatterns(""));
  322. EXPECT_EQ("Cell ID: '<CellID: 1>'", RedactCustomPatterns("Cell ID: 'A1B2'"));
  323. EXPECT_EQ("Cell ID: '<CellID: 2>'", RedactCustomPatterns("Cell ID: 'C1D2'"));
  324. EXPECT_EQ("foo Cell ID: '<CellID: 1>' bar",
  325. RedactCustomPatterns("foo Cell ID: 'A1B2' bar"));
  326. EXPECT_EQ("foo Location area code: '<LocAC: 1>' bar",
  327. RedactCustomPatterns("foo Location area code: 'A1B2' bar"));
  328. EXPECT_EQ("foo\na SSID='<SSID: 1>' b\n'",
  329. RedactCustomPatterns("foo\na SSID='Joe's' b\n'"));
  330. EXPECT_EQ("ssid '<SSID: 2>'", RedactCustomPatterns("ssid 'My AP'"));
  331. EXPECT_EQ("bssid 'aa:bb'", RedactCustomPatterns("bssid 'aa:bb'"));
  332. EXPECT_EQ("Scan SSID - hexdump(len=6): <SSIDHex: 1>\nfoo",
  333. RedactCustomPatterns(
  334. "Scan SSID - hexdump(len=6): 47 6f 6f 67 6c 65\nfoo"));
  335. EXPECT_EQ(
  336. "a\nb [SSID=<SSID: 3>] [SSID=<SSID: 1>] [SSID=foo\nbar] b",
  337. RedactCustomPatterns("a\nb [SSID=foo] [SSID=Joe's] [SSID=foo\nbar] b"));
  338. EXPECT_EQ("ssid=\"<SSID: 4>\"",
  339. RedactCustomPatterns("ssid=\"LittleTsunami\""));
  340. EXPECT_EQ("* SSID=<SSID: 5>", RedactCustomPatterns("* SSID=agnagna"));
  341. EXPECT_EQ("Specifier: <ArcNetworkFactory#1> SSID: <SSID: 6>",
  342. RedactCustomPatterns(
  343. "Specifier: <ArcNetworkFactory#1> SSID: \"GoogleGuest\""));
  344. EXPECT_EQ("Specifier: <ArcNetworkFactory#1> SSID: <SSID: 7>",
  345. RedactCustomPatterns(
  346. "Specifier: <ArcNetworkFactory#1> SSID: 'GoogleGuest'"));
  347. EXPECT_EQ("Specifier: <ArcNetworkFactory#1> SSID: <SSID: 8>",
  348. RedactCustomPatterns(
  349. "Specifier: <ArcNetworkFactory#1> SSID: GoogleGuest"));
  350. EXPECT_EQ("SerialNumber: <Serial: 1>",
  351. RedactCustomPatterns("SerialNumber: 1217D7EF"));
  352. EXPECT_EQ("serial number: <Serial: 2>",
  353. RedactCustomPatterns("serial number: 50C971FEE7F3x010900"));
  354. EXPECT_EQ("SerialNumber: <Serial: 3>",
  355. RedactCustomPatterns("SerialNumber: EVT23-17BA01-004"));
  356. EXPECT_EQ("serial=\"<Serial: 4>\"",
  357. RedactCustomPatterns("serial=\"1234AA5678\""));
  358. EXPECT_EQ("\"serial_number\"=\"<Serial: 1>\"",
  359. RedactCustomPatterns("\"serial_number\"=\"1217D7EF\""));
  360. EXPECT_EQ("SerialNumber: <Serial: 5>",
  361. RedactCustomPatterns("SerialNumber: 5:00:14.0"));
  362. EXPECT_EQ("Serial: <Serial: 6>",
  363. RedactCustomPatterns("Serial: ABCEFG\x01kjmn-as:342/234\\432"));
  364. // Don't overly redact serial numbers, we only do this for a specific
  365. // formatting case for edid-decode.
  366. EXPECT_EQ("Foo serial number 123",
  367. RedactCustomPatterns("Foo serial number 123"));
  368. EXPECT_EQ("Foo Serial Number <Serial: 7>",
  369. RedactCustomPatterns("Foo Serial Number 123"));
  370. // redact serial number separated by a | with the label "serial"
  371. EXPECT_EQ("serial | <Serial: 8>",
  372. RedactCustomPatterns("serial | 0x1cc04416"));
  373. EXPECT_EQ("serial |<Serial: 9>",
  374. RedactCustomPatterns("serial |0x1cc04417"));
  375. EXPECT_EQ("serial|<Serial: 10>", RedactCustomPatterns("serial|0x1cc04418"));
  376. EXPECT_EQ("serial|<Serial: 11>", RedactCustomPatterns("serial|agnagna"));
  377. // redact attested device id that is also a serial number
  378. EXPECT_EQ("\"attested_device_id\"=\"<Serial: 12>\"",
  379. RedactCustomPatterns("\"attested_device_id\"=\"5CD045B0DZ\""));
  380. EXPECT_EQ("\"attested_device_id\"=\"<Serial: 13>\"",
  381. RedactCustomPatterns("\"attested_device_id\"=\"5CD04-5B0DZ\""));
  382. // The dash cannot appear first or last.
  383. EXPECT_EQ("\"attested_device_id\"=\"-5CD045B0DZ\"",
  384. RedactCustomPatterns("\"attested_device_id\"=\"-5CD045B0DZ\""));
  385. EXPECT_EQ("\"attested_device_id\"=\"5CD045B0DZ-\"",
  386. RedactCustomPatterns("\"attested_device_id\"=\"5CD045B0DZ-\""));
  387. EXPECT_EQ("\"gaia_id\":\"<GAIA: 1>\"",
  388. RedactCustomPatterns("\"gaia_id\":\"1234567890\""));
  389. EXPECT_EQ("gaia_id='<GAIA: 2>'", RedactCustomPatterns("gaia_id='987654321'"));
  390. EXPECT_EQ("{id: <GAIA: 1>, email:",
  391. RedactCustomPatterns("{id: 1234567890, email:"));
  392. EXPECT_EQ("<email: 1>", RedactCustomPatterns("foo@bar.com"));
  393. EXPECT_EQ("Email: <email: 1>.", RedactCustomPatterns("Email: foo@bar.com."));
  394. EXPECT_EQ("Email:\n<email: 2>\n",
  395. RedactCustomPatterns("Email:\nfooooo@bar.com\n"));
  396. EXPECT_EQ("[<IPv6: 1>]",
  397. RedactCustomPatterns("[2001:0db8:0000:0000:0000:ff00:0042:8329]"));
  398. EXPECT_EQ("[<IPv6: 2>]",
  399. RedactCustomPatterns("[2001:db8:0:0:0:ff00:42:8329]"));
  400. EXPECT_EQ("[<IPv6: 3>]", RedactCustomPatterns("[2001:db8::ff00:42:8329]"));
  401. EXPECT_EQ("[<IPv6: 4>]", RedactCustomPatterns("[aa::bb]"));
  402. EXPECT_EQ("State::Abort", RedactCustomPatterns("State::Abort"));
  403. // Real IPv4 address
  404. EXPECT_EQ("<IPv4: 1>", RedactCustomPatterns("192.160.0.1"));
  405. // Non-PII IPv4 address (see MaybeScrubIPAddress)
  406. EXPECT_EQ("255.255.255.255", RedactCustomPatterns("255.255.255.255"));
  407. // Not an actual IPv4 address
  408. EXPECT_EQ("75.748.86.91", RedactCustomPatterns("75.748.86.91"));
  409. // USB Path - not an actual IPv4 Address
  410. EXPECT_EQ("4-3.3.3.3", RedactCustomPatterns("4-3.3.3.3"));
  411. // ModemManager modem firmware revisions - not actual IPv4 Addresses
  412. EXPECT_EQ("Revision: 81600.0000.00.29.19.16_DO",
  413. RedactCustomPatterns("Revision: 81600.0000.00.29.19.16_DO"));
  414. EXPECT_EQ("Revision: 11.608.09.01.21",
  415. RedactCustomPatterns("Revision: 11.608.09.01.21"));
  416. EXPECT_EQ("Revision: 11.208.09.01.21",
  417. RedactCustomPatterns("Revision: 11.208.09.01.21"));
  418. EXPECT_EQ("Revision: BD_3GHAP673A4V1.0.0B02",
  419. RedactCustomPatterns("Revision: BD_3GHAP673A4V1.0.0B02"));
  420. EXPECT_EQ("Revision: 2.5.21Hd (Date: Jun 17 2008, Time: 12:30:47)",
  421. RedactCustomPatterns(
  422. "Revision: 2.5.21Hd (Date: Jun 17 2008, Time: 12:30:47)"));
  423. EXPECT_EQ(
  424. "Revision: 9.5.05.01-02 [2006-10-20 17:19:09]",
  425. RedactCustomPatterns("Revision: 9.5.05.01-02 [2006-10-20 17:19:09]"));
  426. EXPECT_EQ("Revision: LQA0021.1.1_M573A",
  427. RedactCustomPatterns("Revision: LQA0021.1.1_M573A"));
  428. EXPECT_EQ("Revision: 10.10.10.10",
  429. RedactCustomPatterns("Revision: 10.10.10.10"));
  430. EXPECT_EQ("<URL: 1>", RedactCustomPatterns("http://example.com/foo?test=1"));
  431. EXPECT_EQ("Foo <URL: 2> Bar",
  432. RedactCustomPatterns("Foo http://192.168.0.1/foo?test=1#123 Bar"));
  433. const char* kURLs[] = {
  434. "http://example.com/foo?test=1",
  435. "http://userid:password@example.com:8080",
  436. "http://userid:password@example.com:8080/",
  437. "http://@example.com",
  438. "http://192.168.0.1",
  439. "http://192.168.0.1/",
  440. "http://اختبار.com",
  441. "http://test.com/foo(bar)baz.html",
  442. "http://test.com/foo%20bar",
  443. "ftp://test:tester@test.com",
  444. "chrome://extensions/",
  445. "chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/options.html",
  446. "http://example.com/foo?email=foo@bar.com",
  447. "rtsp://root@example.com/",
  448. "https://aaaaaaaaaaaaaaaa.com",
  449. "file:///var/log/messages",
  450. "file:///usr/local/home/iby/web%20page%20test.html",
  451. };
  452. for (size_t i = 0; i < std::size(kURLs); ++i) {
  453. SCOPED_TRACE(kURLs[i]);
  454. std::string got = RedactCustomPatterns(kURLs[i]);
  455. EXPECT_TRUE(
  456. base::StartsWith(got, "<URL: ", base::CompareCase::INSENSITIVE_ASCII));
  457. EXPECT_TRUE(base::EndsWith(got, ">", base::CompareCase::INSENSITIVE_ASCII));
  458. }
  459. // Test that "Android:" is not considered a schema with empty hier part.
  460. EXPECT_EQ("The following applies to Android:",
  461. RedactCustomPatterns("The following applies to Android:"));
  462. }
  463. TEST_F(RedactionToolTest, RedactCustomPatternWithContext) {
  464. // The PIIType for the CustomPatternWithAlias is not relevant, only for
  465. // testing.
  466. const CustomPatternWithAlias kPattern1 = {"ID", "(\\b(?i)id:? ')(\\d+)(')",
  467. PIIType::kStableIdentifier};
  468. const CustomPatternWithAlias kPattern2 = {"ID", "(\\b(?i)id=')(\\d+)(')",
  469. PIIType::kStableIdentifier};
  470. const CustomPatternWithAlias kPattern3 = {"IDG", "(\\b(?i)idg=')(\\d+)(')",
  471. PIIType::kLocationInfo};
  472. EXPECT_EQ("", RedactCustomPatternWithContext("", kPattern1));
  473. EXPECT_EQ("foo\nbar\n",
  474. RedactCustomPatternWithContext("foo\nbar\n", kPattern1));
  475. EXPECT_EQ("id '<ID: 1>'",
  476. RedactCustomPatternWithContext("id '2345'", kPattern1));
  477. EXPECT_EQ("id '<ID: 2>'",
  478. RedactCustomPatternWithContext("id '1234'", kPattern1));
  479. EXPECT_EQ("id: '<ID: 2>'",
  480. RedactCustomPatternWithContext("id: '1234'", kPattern1));
  481. EXPECT_EQ("ID: '<ID: 1>'",
  482. RedactCustomPatternWithContext("ID: '2345'", kPattern1));
  483. EXPECT_EQ("x1 id '<ID: 1>' 1x id '<ID: 2>'\nid '<ID: 1>'\n",
  484. RedactCustomPatternWithContext(
  485. "x1 id '2345' 1x id '1234'\nid '2345'\n", kPattern1));
  486. // Different pattern with same alias should reuse the replacements.
  487. EXPECT_EQ("id='<ID: 2>'",
  488. RedactCustomPatternWithContext("id='1234'", kPattern2));
  489. // Different alias should not reuse replacement from another pattern.
  490. EXPECT_EQ("idg='<IDG: 1>'",
  491. RedactCustomPatternWithContext("idg='1234'", kPattern3));
  492. EXPECT_EQ("x<FOO: 1>z",
  493. RedactCustomPatternWithContext("xyz", {"FOO", "()(y+)()"}));
  494. }
  495. TEST_F(RedactionToolTest, RedactCustomPatternWithoutContext) {
  496. // The PIIType for the CustomPatternWithAlias here is not relevant, only for
  497. // testing.
  498. CustomPatternWithAlias kPattern = {"pattern", "(o+)", PIIType::kEmail};
  499. EXPECT_EQ("", RedactCustomPatternWithoutContext("", kPattern));
  500. EXPECT_EQ("f<pattern: 1>\nf<pattern: 2>z\nf<pattern: 1>l\n",
  501. RedactCustomPatternWithoutContext("fo\nfooz\nfol\n", kPattern));
  502. }
  503. TEST_F(RedactionToolTest, RedactChunk) {
  504. std::string redaction_input;
  505. std::string redaction_output;
  506. for (const auto& s : kStringsWithRedactions) {
  507. redaction_input.append(s.pre_redaction).append("\n");
  508. redaction_output.append(s.post_redaction).append("\n");
  509. }
  510. EXPECT_EQ(redaction_output, redactor_.Redact(redaction_input));
  511. }
  512. TEST_F(RedactionToolTest, RedactAndKeepSelected) {
  513. std::string redaction_input;
  514. std::string redaction_output;
  515. for (const auto& s : kStringsWithRedactions) {
  516. redaction_input.append(s.pre_redaction).append("\n");
  517. redaction_output.append(s.post_redaction).append("\n");
  518. }
  519. // Test RedactAndKeepSelected() with no PII type to keep.
  520. EXPECT_EQ(redaction_output,
  521. redactor_.RedactAndKeepSelected(redaction_input, {}));
  522. // Test RedactAndKeepSelected() by only keeping IP addresses in the redacted
  523. // output.
  524. std::string redaction_output_ip;
  525. for (const auto& s : kStringsWithRedactions) {
  526. if (s.pii_type == PIIType::kIPAddress) {
  527. redaction_output_ip.append(s.pre_redaction).append("\n");
  528. } else {
  529. redaction_output_ip.append(s.post_redaction).append("\n");
  530. }
  531. }
  532. EXPECT_EQ(redaction_output_ip, redactor_.RedactAndKeepSelected(
  533. redaction_input, {PIIType::kIPAddress}));
  534. // Test RedactAndKeepSelected() by keeping MAC addresses and hashes in the
  535. // redacted output. The hashes that URLs and Android storage paths contain
  536. // will be redacted with the URL or Android storage path that they're part of.
  537. std::string redaction_output_mac_and_hashes;
  538. for (const auto& s : kStringsWithRedactions) {
  539. if (s.pii_type == PIIType::kMACAddress ||
  540. s.pii_type == PIIType::kStableIdentifier) {
  541. redaction_output_mac_and_hashes.append(s.pre_redaction).append("\n");
  542. } else {
  543. redaction_output_mac_and_hashes.append(s.post_redaction).append("\n");
  544. }
  545. }
  546. EXPECT_EQ(
  547. redaction_output_mac_and_hashes,
  548. redactor_.RedactAndKeepSelected(
  549. redaction_input, {PIIType::kMACAddress, PIIType::kStableIdentifier}));
  550. }
  551. TEST_F(RedactionToolTest, RedactUid) {
  552. EXPECT_EQ("<UID: 1>",
  553. redactor_.RedactAndKeepSelected(
  554. "B3mcFTkQAHofv94DDTUuVJGGEI/BbzsyDncplMCR2P4=", {}));
  555. }
  556. TEST_F(RedactionToolTest, RedactAndKeepSelectedHashes) {
  557. // Array of pairs containing pre/post redaction versions of the same string.
  558. // Will be appended to create input and expected output for the test. Keep
  559. // URLs and Android app storage paths but redact hashes. URLs and Android app
  560. // storage paths that contain hashes will be partially redacted.
  561. const std::pair<std::string, std::string> redaction_strings_with_hashes[] = {
  562. {"chrome://resources/"
  563. "f?user="
  564. "99887766554433221100ffeeddccbbaaaabbccddeeff00112233445566778899",
  565. "chrome://resources/f?user=<HASH:9988 1>"}, // URL that contains a hash.
  566. {"/root/27540283740a0897ab7c8de0f809add2bacde78f/foo",
  567. "/root/<HASH:2754 2>/foo"}, // String that contains a hash.
  568. {"this is the user hash that we need to redact "
  569. "aabbccddeeff00112233445566778899",
  570. "this is the user hash that we need to redact <HASH:aabb 3>"}, // String
  571. // that
  572. // contains
  573. // a hash.
  574. #if BUILDFLAG(IS_CHROMEOS_ASH)
  575. {"8.0K\t/home/root/aabbccddeeff00112233445566778899/"
  576. "android-data/data/data/pa.ckage2/de", // Android app storage
  577. // path that contains a
  578. // hash.
  579. "8.0K\t/home/root/<HASH:aabb 3>/android-data/data/data/pa.ckage2/de"}
  580. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  581. };
  582. std::string redaction_input;
  583. std::string redaction_output;
  584. for (const auto& s : redaction_strings_with_hashes) {
  585. redaction_input.append(s.first).append("\n");
  586. redaction_output.append(s.second).append("\n");
  587. }
  588. EXPECT_EQ(
  589. redaction_output,
  590. redactor_.RedactAndKeepSelected(
  591. redaction_input, {PIIType::kAndroidAppStoragePath, PIIType::kURL}));
  592. }
  593. TEST_F(RedactionToolTest, DetectPII) {
  594. std::string redaction_input;
  595. for (const auto& s : kStringsWithRedactions) {
  596. redaction_input.append(s.pre_redaction).append("\n");
  597. }
  598. std::map<PIIType, std::set<std::string>> pii_in_data {
  599. #if BUILDFLAG(IS_CHROMEOS_ASH) // We only detect Android paths on Chrome OS.
  600. {PIIType::kAndroidAppStoragePath, {"/de"}},
  601. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  602. {PIIType::kSSID, {"123aaaaaa"}},
  603. {PIIType::kURL,
  604. {"http://tets.comaaaaaaa", "chrome://resources/f?user=bar",
  605. "chrome-extension://nkoccljplnhpfnfiajclkommnmllphnl/"
  606. "foobar.js?bar=x"}},
  607. {PIIType::kEmail, {"aaaaaemail@example.comaaa"}},
  608. {PIIType::kIPAddress,
  609. {
  610. "255.255.155.2",
  611. "255.255.155.255",
  612. "127.0.0.1",
  613. "127.255.0.1",
  614. "0.0.0.0",
  615. "0.255.255.255",
  616. "10.10.10.100",
  617. "10.10.10.101",
  618. "10.255.255.255",
  619. "172.16.0.0",
  620. "172.31.255.255",
  621. "172.11.5.5",
  622. "172.111.5.5",
  623. "192.168.0.0",
  624. "192.168.255.255",
  625. "192.169.2.120",
  626. "169.254.0.1",
  627. "169.200.0.1",
  628. "224.0.0.24",
  629. "240.0.0.0",
  630. "100.115.91.92",
  631. "8.8.8.4",
  632. "123.123.45.4",
  633. "fe80::",
  634. "fe80::ffff",
  635. "febf:ffff::ffff",
  636. "fecc::1111",
  637. "11::11",
  638. "ff01::3",
  639. "ff02::3",
  640. "ff02::fb",
  641. "ff08::fb",
  642. "ff0f::101",
  643. "::ffff:cb0c:10ea",
  644. "::ffff:a0a:a0a",
  645. "::ffff:ac1e:1e1e",
  646. "::ffff:c0a8:640a",
  647. "::ffff:6473:5c01",
  648. "64:ff9b::a0a:a0a",
  649. "64:ff9b::6473:5c01",
  650. "::0101:ffff:c0a8:640a",
  651. }},
  652. {PIIType::kMACAddress, {"aa:aa:aa:aa:aa:aa"}}, {
  653. PIIType::kStableIdentifier, {
  654. "27540283740a0897ab7c8de0f809add2bacde78f",
  655. "B3mcFTkQAHofv94DDTUuVJGGEI/BbzsyDncplMCR2P4=",
  656. }
  657. }
  658. };
  659. EXPECT_EQ(pii_in_data, redactor_.Detect(redaction_input));
  660. }
  661. #if BUILDFLAG(IS_CHROMEOS_ASH) // We only redact Android paths on Chrome OS.
  662. TEST_F(RedactionToolTest, RedactAndroidAppStoragePaths) {
  663. EXPECT_EQ("", RedactAndroidAppStoragePaths(""));
  664. EXPECT_EQ("foo\nbar\n", RedactAndroidAppStoragePaths("foo\nbar\n"));
  665. constexpr char kDuOutput[] =
  666. "112K\t/home/root/deadbeef1234/android-data/data/system_de\n"
  667. // /data/data will be modified by the redactor.
  668. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pack.age1/a\n"
  669. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pack.age1/bc\n"
  670. "24K\t/home/root/deadbeef1234/android-data/data/data/pack.age1\n"
  671. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/de\n"
  672. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/de/"
  673. "\xe3\x81\x82\n"
  674. "8.1K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/de/"
  675. "\xe3\x81\x82\xe3\x81\x83\n"
  676. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/ef\n"
  677. "24K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2\n"
  678. "8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/a\n"
  679. "8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/bc\n"
  680. "24K\t/home/root/deadbeef1234/android-data/data/app/pack.age1\n"
  681. "8.0K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1/a\n"
  682. "8.0K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1/bc\n"
  683. "24K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1\n"
  684. "78M\t/home/root/deadbeef1234/android-data/data/data\n"
  685. "key=value path=/data/data/pack.age1/bc key=value\n"
  686. "key=value path=/data/user_de/0/pack.age1/bc key=value\n"
  687. "key=value exe=/data/app/pack.age1/bc key=value\n";
  688. constexpr char kDuOutputRedacted[] =
  689. "112K\t/home/root/deadbeef1234/android-data/data/system_de\n"
  690. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pack.age1/a\n"
  691. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pack.age1/b_\n"
  692. "24K\t/home/root/deadbeef1234/android-data/data/data/pack.age1\n"
  693. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/d_\n"
  694. // The non-ASCII directory names will become '*_'.
  695. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/d_/*_\n"
  696. "8.1K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/d_/*_\n"
  697. "8.0K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2/e_\n"
  698. "24K\t/home/root/deadbeef1234/android-data/data/data/pa.ckage2\n"
  699. "8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/a\n"
  700. "8.0K\t/home/root/deadbeef1234/android-data/data/app/pack.age1/b_\n"
  701. "24K\t/home/root/deadbeef1234/android-data/data/app/pack.age1\n"
  702. "8.0K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1/a\n"
  703. "8.0K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1/b_\n"
  704. "24K\t/home/root/deadbeef1234/android-data/data/user_de/0/pack.age1\n"
  705. "78M\t/home/root/deadbeef1234/android-data/data/data\n"
  706. "key=value path=/data/data/pack.age1/b_ key=value\n"
  707. "key=value path=/data/user_de/0/pack.age1/b_ key=value\n"
  708. "key=value exe=/data/app/pack.age1/b_ key=value\n";
  709. EXPECT_EQ(kDuOutputRedacted, RedactAndroidAppStoragePaths(kDuOutput));
  710. }
  711. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  712. TEST_F(RedactionToolTest, RedactBlockDevices) {
  713. // Test cases in the form {input, output}.
  714. std::pair<std::string, std::string> test_cases[] = {
  715. // UUIDs that come from the 'blkid' tool.
  716. {"PTUUID=\"985dff64-9c0f-3f49-945b-2d8c2e0238ec\"",
  717. "PTUUID=\"<UUID: 1>\""},
  718. {"UUID=\"E064-868C\"", "UUID=\"<UUID: 2>\""},
  719. {"PARTUUID=\"7D242B2B1C751832\"", "PARTUUID=\"<UUID: 3>\""},
  720. // Volume labels.
  721. {"LABEL=\"ntfs\"", "LABEL=\"<Volume Label: 1>\""},
  722. {"PARTLABEL=\"SD Card\"", "PARTLABEL=\"<Volume Label: 2>\""},
  723. // LVM UUIDd.
  724. {"{\"pv_fmt\":\"lvm2\", "
  725. "\"pv_uuid\":\"duD18x-P7QE-sTya-SaeO-aq07-YgEq-xj8UEz\", "
  726. "\"dev_size\":\"230.33g\"}",
  727. "{\"pv_fmt\":\"lvm2\", \"pv_uuid\":\"<UUID: 4>\", "
  728. "\"dev_size\":\"230.33g\"}"},
  729. {"{\"lv_uuid\":\"lKYORl-TWDP-OFLT-yDnB-jlQ7-aQrE-AwA8Oa\", "
  730. "\"lv_name\":\"[thinpool_tdata]\"",
  731. "{\"lv_uuid\":\"<UUID: 5>\", \"lv_name\":\"[thinpool_tdata]\""},
  732. // Removable media paths.
  733. {"/media/removable/SD Card/", "/media/removable/<Volume Label: 2>/"},
  734. {"'/media/removable/My Secret Volume Name' don't redact this",
  735. "'/media/removable/<Volume Label: 3>' don't redact this"},
  736. {"0 part /media/removable/My Secret Volume Name With Spaces ",
  737. "0 part /media/removable/<Volume Label: 4>"},
  738. };
  739. for (const auto& p : test_cases) {
  740. EXPECT_EQ(redactor_.Redact(p.first), p.second);
  741. }
  742. }
  743. } // namespace feedback