Skip to content

Commit

Permalink
Allow pinning of gateway-like urls
Browse files Browse the repository at this point in the history
  • Loading branch information
cypt4 committed Mar 10, 2023
1 parent 628dc45 commit fa52670
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 4 deletions.
40 changes: 37 additions & 3 deletions components/brave_wallet/browser/brave_wallet_pin_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,37 @@ absl::optional<mojom::WalletPinServiceErrorCode> StringToErrorCode(
return absl::nullopt;
}

absl::optional<std::string> ExtractCID(const std::string& ipfs_url) {
GURL gurl = GURL(ipfs_url);
absl::optional<std::string> ExtractIpfsUrl(const std::string& url) {
GURL gurl = GURL(url);

if (!gurl.is_valid()) {
return absl::nullopt;
}

if (gurl.SchemeIs(ipfs::kIPFSScheme)) {
return gurl.spec();
}

auto scope = ipfs::ExtractSourceFromGateway(gurl);
if (!scope || !scope->SchemeIs(ipfs::kIPFSScheme)) {
return absl::nullopt;
}

return scope.value().spec();
}

absl::optional<std::string> ExtractCID(const std::string& url) {
GURL gurl = GURL(ExtractIpfsUrl(url).value_or(""));

if (!gurl.is_valid()) {
return absl::nullopt;
}

if (!gurl.SchemeIs(ipfs::kIPFSScheme)) {
auto scope = ipfs::ExtractSourceFromGateway(gurl);
if (!scope || !scope->SchemeIs(ipfs::kIPFSScheme)) {
return absl::nullopt;
}
return absl::nullopt;
}

Expand Down Expand Up @@ -617,8 +640,19 @@ void BraveWalletPinService::OnTokenMetaDataReceived(
cids.push_back(metadata_cid.value());
cids.push_back(image_cid.value());

auto ipfs_image_url = ExtractIpfsUrl(*image_url);
if (!ipfs_image_url) {
auto pin_error = mojom::PinError::New(
mojom::WalletPinServiceErrorCode::ERR_NON_IPFS_TOKEN_URL,
"Can't find proper image field");
SetTokenStatus(service, token,
mojom::TokenPinStatusCode::STATUS_PINNING_FAILED, pin_error);
std::move(callback).Run(false, std::move(pin_error));
return;
}

content_type_checker_->CheckContentTypeSupported(
*image_url,
ipfs_image_url.value(),
base::BindOnce(&BraveWalletPinService::OnContentTypeChecked,
weak_ptr_factory_.GetWeakPtr(), std::move(service),
std::move(token), std::move(cids), std::move(callback)));
Expand Down
138 changes: 137 additions & 1 deletion components/brave_wallet/browser/brave_wallet_pin_service_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const char kMonkey3Path[] =
"nft.nftstorage.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x2";
const char kMonkey4Path[] =
"nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x3";
const char kMonkey5Path[] =
"nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x4";
const char kMonkey6Path[] =
"nft.local.60.0x1.0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d.0x5";

const char kMonkey1Url[] =
"ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/2413";
Expand All @@ -49,6 +53,10 @@ const char kMonkey3Url[] =
"ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/2777";
const char kMonkey4Url[] =
"ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/2888";
const char kMonkey5Url[] =
"https://ipfs.io/ipfs/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/2888";
const char kMonkey6Url[] =
"https://google.com/QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq/2888";

const char kMonkey1[] =
R"({"image":"ipfs://bafy1",
Expand Down Expand Up @@ -86,6 +94,24 @@ const char kMonkey4[] =
{"trait_type":"Eyes","value":"Closed"},
{"trait_type":"Clothes","value":"Toga"},
{"trait_type":"Hat","value":"Cowboy Hat"}]})";
const char kMonkey5[] =
R"({"image":"https://ipfs.io/ipfs/bafy3",
"attributes":[
{"trait_type":"Mouth","value":"Bored Cigarette"},
{"trait_type":"Fur","value":"Zombie"},
{"trait_type":"Background","value":"Purple"},
{"trait_type":"Eyes","value":"Closed"},
{"trait_type":"Clothes","value":"Toga"},
{"trait_type":"Hat","value":"Cowboy Hat"}]})";
const char kMonkey6[] =
R"({"image":"https://google.com/bafy3",
"attributes":[
{"trait_type":"Mouth","value":"Bored Cigarette"},
{"trait_type":"Fur","value":"Zombie"},
{"trait_type":"Background","value":"Purple"},
{"trait_type":"Eyes","value":"Closed"},
{"trait_type":"Clothes","value":"Toga"},
{"trait_type":"Hat","value":"Cowboy Hat"}]})";

base::Time g_overridden_now;
std::unique_ptr<ScopedTimeClockOverrides> OverrideWithTimeNow(
Expand Down Expand Up @@ -299,6 +325,116 @@ TEST_F(BraveWalletPinServiceTest, AddPin) {
}
}

TEST_F(BraveWalletPinServiceTest, AddPin_GatewayUrl) {
{
ON_CALL(*GetContentTypeChecker(), CheckContentTypeSupported(_, _))
.WillByDefault(::testing::Invoke(
[](const std::string& cid,
base::OnceCallback<void(absl::optional<bool>)> callback) {
std::move(callback).Run(true);
}));
}
// Right gateway
{
ON_CALL(*GetJsonRpcService(), GetERC721Metadata(_, _, _, _))
.WillByDefault(::testing::Invoke(
[](const std::string& contract_address, const std::string& token_id,
const std::string& chain_id,
MockJsonRpcService::GetERC721MetadataCallback callback) {
EXPECT_EQ("0x1", chain_id);
EXPECT_EQ("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
contract_address);
EXPECT_EQ("0x4", token_id);
std::move(callback).Run(kMonkey5Url, kMonkey5,
mojom::ProviderError::kSuccess, "");
}));
ON_CALL(*GetIpfsLocalPinService(), AddPins(_, _, _))
.WillByDefault(::testing::Invoke(
[](const std::string& prefix, const std::vector<std::string>& cids,
ipfs::AddPinCallback callback) {
EXPECT_EQ(kMonkey5Path, prefix);
EXPECT_EQ("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq",
cids.at(0));
EXPECT_EQ("bafy3", cids.at(1));
std::move(callback).Run(true);
}));

auto scoped_override = OverrideWithTimeNow(base::Time::FromTimeT(123u));

mojom::BlockchainTokenPtr token =
BraveWalletPinService::TokenFromPrefPath(kMonkey5Path);
token->is_erc721 = true;
absl::optional<bool> call_status;
service()->AddPin(
std::move(token), absl::nullopt,
base::BindLambdaForTesting(
[&call_status](bool result, mojom::PinErrorPtr error) {
call_status = result;
EXPECT_FALSE(error);
}));
EXPECT_TRUE(call_status.value());

const base::Value::Dict* token_record =
GetPrefs()
->GetDict(kPinnedNFTAssets)
.FindDictByDottedPath(kMonkey5Path);

base::Value::List expected_cids;
expected_cids.Append("QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariGR3jxcaWtq");
expected_cids.Append("bafy3");

EXPECT_EQ(BraveWalletPinService::StatusToString(
mojom::TokenPinStatusCode::STATUS_PINNED),
*(token_record->FindString("status")));
EXPECT_EQ(nullptr, token_record->FindDict("error"));
EXPECT_EQ(expected_cids, *(token_record->FindList("cids")));
EXPECT_EQ(base::Time::FromTimeT(123u),
base::ValueToTime(token_record->Find("validate_timestamp")));
}

// Wrong gateway
{
ON_CALL(*GetJsonRpcService(), GetERC721Metadata(_, _, _, _))
.WillByDefault(::testing::Invoke(
[](const std::string& contract_address, const std::string& token_id,
const std::string& chain_id,
MockJsonRpcService::GetERC721MetadataCallback callback) {
EXPECT_EQ("0x1", chain_id);
EXPECT_EQ("0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d",
contract_address);
EXPECT_EQ("0x5", token_id);
std::move(callback).Run(kMonkey6Url, kMonkey6,
mojom::ProviderError::kSuccess, "");
}));

mojom::BlockchainTokenPtr token =
BraveWalletPinService::TokenFromPrefPath(kMonkey6Path);
token->is_erc721 = true;
absl::optional<bool> call_status;
service()->AddPin(
std::move(token), absl::nullopt,
base::BindLambdaForTesting(
[&call_status](bool result, mojom::PinErrorPtr error) {
call_status = result;
EXPECT_TRUE(error);
}));

EXPECT_FALSE(call_status.value());

const base::Value::Dict* token_record =
GetPrefs()
->GetDict(kPinnedNFTAssets)
.FindDictByDottedPath(kMonkey6Path);

EXPECT_EQ(BraveWalletPinService::StatusToString(
mojom::TokenPinStatusCode::STATUS_PINNING_FAILED),
*(token_record->FindString("status")));
EXPECT_EQ(BraveWalletPinService::ErrorCodeToString(
mojom::WalletPinServiceErrorCode::ERR_NON_IPFS_TOKEN_URL),
token_record->FindByDottedPath("error.error_code")->GetString());
}
}

TEST_F(BraveWalletPinServiceTest, AddPin_ContentVerification) {
{
ON_CALL(*GetContentTypeChecker(), CheckContentTypeSupported(_, _))
Expand Down Expand Up @@ -471,7 +607,7 @@ TEST_F(BraveWalletPinServiceTest, AddPin_ContentVerification) {
}
}

TEST_F(BraveWalletPinServiceTest, AddPin_NonIpfsImage) {
TEST_F(BraveWalletPinServiceTest, _NonIpfsImage) {
{
ON_CALL(*GetJsonRpcService(), GetERC721Metadata(_, _, _, _))
.WillByDefault(::testing::Invoke(
Expand Down

0 comments on commit fa52670

Please sign in to comment.