Skip to content

Commit

Permalink
Merge pull request #8839 from brave/peers-edit
Browse files Browse the repository at this point in the history
Allow users to add IPFS peer servers
  • Loading branch information
spylogsster authored May 22, 2021
2 parents 92f97bf + 70d87d0 commit 17e0faa
Show file tree
Hide file tree
Showing 27 changed files with 1,222 additions and 64 deletions.
35 changes: 31 additions & 4 deletions app/brave_generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -781,13 +781,40 @@ By installing this extension, you are agreeing to the Google Widevine Terms of U
<message name="IDS_SETTINGS_IPNS_ADD_KEY_DIALOG_ERROR" desc="The error message for the add key dialog on IPFS Settings page if key name is invalid">
This name cannot be used
</message>
<message name="IDS_SETTINGS_IPNS_ADD_PEER_DIALOG_TITLE" desc="The title of the dialog to add new peer on IPFS Settings page">
Add new peer connection string
</message>
<message name="IDS_SETTINGS_IPFS_PEER_NODE_RESTART" desc="The message to restart node if peers were chagned on IPFS Settings page">
Restart node to apply changes
</message>
<message name="IDS_SETTINGS_IPFS_PEER_NODE_RESTART_BUTTON" desc="The button title to restart node if peers were chagned on IPFS Settings page">
Restart node
</message>
<message name="IDS_SETTINGS_ADD_PEER_DIALOG_PLACEHOLDER" desc="The placholder of the dialog to add new peer on IPFS Settings page">
/ip4/46.21.210.45/tcp/14406/quic/p2p/12D3KooWBdmLJjhpgJ9KZgLM3f894ff9xyBfPvPjFNn7MKJpyrC2
</message>
<message name="IDS_SETTINGS_IPNS_ADD_PEER_DIALOG_ERROR" desc="The error message for the add peer dialog on IPFS Settings page if the peer name is not valid">
This name is not valid
</message>
<message name="IDS_SETTINGS_IPFS_PEERS_LINK_TITLE" desc="The ipfs peers page link title on IPFS settings page">
Modify the peers list
</message>
<message name="IDS_SETTINGS_IPFS_PEERS_LINK_TITLE_DESC" desc="The ipfs peers page link description on IPFS settings page">
Set up ipfs peers description
</message>
<message name="IDS_SETTINGS_IPFS_PEERS_LIST_TITLE" desc="The title for peers list on IPFS settings page">
The peers list
</message>
<message name="IDS_SETTINGS_IPFS_DELETE_PEER_CONFIRMATION" desc="Confirmation text for deleting a peer from IPFS peers manager page">
Do you really want to delete <ph name="KEY_NAME">$1<ex>MyCustomPeerId</ex></ph>?
</message>
<message name="IDS_SETTINGS_IPNS_DELETE_KEY_CONFIRMATION" desc="Confirmation text for deleting a key from IPFS keys manager page">
Do you really want to delete <ph name="KEY_NAME">$1<ex>MyCustomKey</ex></ph>?
</message>
<message name="IDS_SETTINGS_IPNS_KEYS_NODE_NOT_LAUNCHED" desc="The message when node is not running on IPFS keys manager page">
<message name="IDS_SETTINGS_IPFS_NODE_NOT_LAUNCHED" desc="The message when node is not running on IPFS keys manager page">
Node is not launched
</message>
<message name="IDS_SETTINGS_IPNS_KEYS_START_NODE_ERROR" desc="The error message when node was unable to start on IPFS keys manager page">
<message name="IDS_SETTINGS_IPFS_START_NODE_ERROR" desc="The error message when node was unable to start on IPFS keys manager page">
IPFS service launch error, more information is available on the <ph name="BEGIN_LINK">&lt;a target="_blank" rel="noopener noreferrer" style="text-decoration: underline;" href="chrome://ipfs-internals/"&gt;</ph>diagnostic page<ph name="END_LINK">&lt;/a&gt;</ph>
</message>
<message name="IDS_SETTINGS_IPNS_KEYS_IMPORT_ERROR" desc="The error text if ipns keys import failed">
Expand All @@ -796,10 +823,10 @@ By installing this extension, you are agreeing to the Google Widevine Terms of U
<message name="IDS_SETTINGS_IPNS_KEYS_IMPORT_BUTTON_TITLE" desc="The title of the button to import ipns keys">
Import
</message>
<message name="IDS_SETTINGS_IPNS_KEYS_GENERATE_BUTTON_TITLE" desc="The title of the button to import ipns keys">
<message name="IDS_SETTINGS_IPNS_KEYS_GENERATE_BUTTON_TITLE" desc="The title of the button to generate ipns keys">
Generate
</message>
<message name="IDS_SETTINGS_IPNS_KEYS_START_NODE" desc="The button text to start node on IPFS keys manager page">
<message name="IDS_SETTINGS_IPFS_START_NODE" desc="The button text to start node on IPFS keys manager page">
Start node
</message>
<message name="IDS_SETTINGS_RESOLVE_IPFS_URLS_DESC" desc="The description for how to handle IPFS URIs">
Expand Down
146 changes: 146 additions & 0 deletions browser/extensions/api/ipfs_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,25 @@

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/files/file_util.h"
#include "base/json/json_writer.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/values.h"
#include "brave/browser/ipfs/ipfs_service_factory.h"
#include "brave/common/extensions/api/ipfs.h"
#include "brave/components/ipfs/ipfs_constants.h"
#include "brave/components/ipfs/ipfs_json_parser.h"
#include "brave/components/ipfs/ipfs_service.h"
#include "brave/components/ipfs/ipfs_utils.h"
#include "brave/components/ipfs/keys/ipns_keys_manager.h"
#include "brave/grit/brave_generated_resources.h"
#include "chrome/common/channel_info.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "ui/base/l10n/l10n_util.h"

using ipfs::IPFSResolveMethodTypes;
Expand Down Expand Up @@ -56,11 +64,149 @@ base::Value MakeResponseFromMap(const ipfs::IpnsKeysManager::KeysMap& keys) {
base::JSONWriter::Write(list, &json_string);
return base::Value(json_string);
}

base::Value MakePeersResponseFromVector(
const std::vector<std::string>& source) {
base::Value list(base::Value::Type::LIST);
for (const auto& item : source) {
std::string id;
std::string address;
if (!ipfs::ParsePeerConnectionString(item, &id, &address))
continue;
list.Append(MakeValue(id, address));
}
std::string json_string;
base::JSONWriter::Write(list, &json_string);
return base::Value(json_string);
}

bool WriteFileOnFileThread(const base::FilePath& path,
const std::string& value) {
return base::WriteFile(path, value.c_str(), value.size());
}

} // namespace

namespace extensions {
namespace api {

ExtensionFunction::ResponseAction IpfsRemoveIpfsPeerFunction::Run() {
if (!IsIpfsEnabled(browser_context()))
return RespondNow(Error("IPFS not enabled"));
::ipfs::IpfsService* ipfs_service = GetIpfsService(browser_context());
if (!ipfs_service) {
return RespondNow(Error("Could not obtain IPFS service"));
}
std::unique_ptr<ipfs::RemoveIpfsPeer::Params> params(
ipfs::RemoveIpfsPeer::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
ipfs_service->GetConfig(
base::BindOnce(&IpfsRemoveIpfsPeerFunction::OnConfigLoaded,
base::RetainedRef(this), params->id, params->address));
return RespondLater();
}

void IpfsRemoveIpfsPeerFunction::OnConfigLoaded(const std::string& peer_id,
const std::string& address,
bool success,
const std::string& config) {
if (!success) {
return Respond(Error("Unable to load config"));
}
std::string new_config =
IPFSJSONParser::RemovePeerFromConfigJSON(config, peer_id, address);
if (new_config.empty()) {
VLOG(1) << "New config is empty, probably passed incorrect values";
return Respond(OneArgument(base::Value(false)));
}
::ipfs::IpfsService* ipfs_service = GetIpfsService(browser_context());
if (!ipfs_service) {
return Respond(Error("Could not obtain IPFS service"));
}
auto config_path = ipfs_service->GetConfigFilePath();
auto write_callback =
base::BindOnce(&WriteFileOnFileThread, config_path, new_config);
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()}, std::move(write_callback),
base::BindOnce(&IpfsRemoveIpfsPeerFunction::OnConfigUpdated,
base::RetainedRef(this)));
}

void IpfsRemoveIpfsPeerFunction::OnConfigUpdated(bool success) {
Respond(OneArgument(base::Value(success)));
}

ExtensionFunction::ResponseAction IpfsAddIpfsPeerFunction::Run() {
if (!IsIpfsEnabled(browser_context()))
return RespondNow(Error("IPFS not enabled"));
::ipfs::IpfsService* ipfs_service = GetIpfsService(browser_context());
if (!ipfs_service) {
return RespondNow(Error("Could not obtain IPFS service"));
}
std::unique_ptr<ipfs::AddIpfsPeer::Params> params(
ipfs::AddIpfsPeer::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
ipfs_service->GetConfig(
base::BindOnce(&IpfsAddIpfsPeerFunction::OnConfigLoaded,
base::RetainedRef(this), params->value));
return RespondLater();
}

void IpfsAddIpfsPeerFunction::OnConfigLoaded(const std::string& peer,
bool success,
const std::string& config) {
if (!success) {
return Respond(Error("Unable to load config"));
}
std::string new_config = IPFSJSONParser::PutNewPeerToConfigJSON(config, peer);
if (new_config.empty()) {
VLOG(1) << "New config is empty, probably passed incorrect values";
return Respond(OneArgument(base::Value(false)));
}
::ipfs::IpfsService* ipfs_service = GetIpfsService(browser_context());
if (!ipfs_service) {
return Respond(Error("Could not obtain IPFS service"));
}
auto config_path = ipfs_service->GetConfigFilePath();
auto write_callback =
base::BindOnce(&WriteFileOnFileThread, config_path, new_config);
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()}, std::move(write_callback),
base::BindOnce(&IpfsAddIpfsPeerFunction::OnConfigUpdated,
base::RetainedRef(this)));
}

void IpfsAddIpfsPeerFunction::OnConfigUpdated(bool success) {
Respond(OneArgument(base::Value(success)));
}

ExtensionFunction::ResponseAction IpfsGetIpfsPeersListFunction::Run() {
if (!IsIpfsEnabled(browser_context()))
return RespondNow(Error("IPFS not enabled"));
::ipfs::IpfsService* ipfs_service = GetIpfsService(browser_context());
if (!ipfs_service) {
return RespondNow(Error("Could not obtain IPFS service"));
}
if (!ipfs_service->IsIPFSExecutableAvailable()) {
return RespondNow(Error("Could not obtain IPFS executable"));
}
ipfs_service->GetConfig(base::BindOnce(
&IpfsGetIpfsPeersListFunction::OnConfigLoaded, base::RetainedRef(this)));
return RespondLater();
}

void IpfsGetIpfsPeersListFunction::OnConfigLoaded(bool success,
const std::string& config) {
if (!success) {
return Respond(Error("Unable to load config"));
}
std::vector<std::string> peers;
if (!IPFSJSONParser::GetPeersFromConfigJSON(config, &peers)) {
VLOG(1) << "Unable to parse peers in config";
}
Respond(OneArgument(MakePeersResponseFromVector(peers)));
}

ExtensionFunction::ResponseAction IpfsRemoveIpnsKeyFunction::Run() {
if (!IsIpfsEnabled(browser_context()))
return RespondNow(Error("IPFS not enabled"));
Expand Down
41 changes: 41 additions & 0 deletions browser/extensions/api/ipfs_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,47 @@ class IpnsKeysManager;
namespace extensions {
namespace api {

class IpfsGetIpfsPeersListFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("ipfs.getIpfsPeersList", UNKNOWN)

protected:
void OnConfigLoaded(bool success, const std::string& config);
~IpfsGetIpfsPeersListFunction() override {}
ResponseAction Run() override;
};

class IpfsAddIpfsPeerFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("ipfs.addIpfsPeer", UNKNOWN)

protected:
void OnPeerAdded(bool result, const std::string& value);
void OnConfigLoaded(const std::string& peer,
bool success,
const std::string& config);
void OnConfigUpdated(bool success);

~IpfsAddIpfsPeerFunction() override {}
ResponseAction Run() override;
};

class IpfsRemoveIpfsPeerFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("ipfs.removeIpfsPeer", UNKNOWN)

protected:
void OnPeerAdded(bool result, const std::string& value);
void OnConfigLoaded(const std::string& peer_id,
const std::string& address,
bool success,
const std::string& config);
void OnConfigUpdated(bool success);

~IpfsRemoveIpfsPeerFunction() override {}
ResponseAction Run() override;
};

class IpfsRemoveIpnsKeyFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("ipfs.removeIpnsKey", UNKNOWN)
Expand Down
2 changes: 2 additions & 0 deletions browser/resources/settings/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ preprocess_if_expr("preprocess_generated") {
"brave_ipfs_page/change_ipfs_gateway_dialog.js",
"brave_ipfs_page/add_p2p_key_dialog.js",
"brave_ipfs_page/p2p_keys_subpage.m.js",
"brave_ipfs_page/ipfs_peers_subpage.m.js",
"brave_ipfs_page/add_ipfs_peer_dialog.js",
"brave_default_extensions_page/brave_default_extensions_browser_proxy.m.js",
"brave_default_extensions_page/brave_default_extensions_page.m.js",
"brave_help_tips_page/brave_help_tips_page.m.js",
Expand Down
9 changes: 9 additions & 0 deletions browser/resources/settings/brave_ipfs_page/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import("../settings.gni")
group("web_modules") {
public_deps = [
":brave_ipfs_page_module",
":ipfs_peers_subpage_module",
":modules",
":p2p_keys_subpage_module",
":templatize",
Expand All @@ -33,6 +34,13 @@ polymer_modulizer("p2p_keys_subpage") {
auto_imports = settings_auto_imports + [ "brave/browser/resources/settings/brave_ipfs_page/brave_ipfs_browser_proxy.html|BraveIPFSBrowserProxy, BraveIPFSBrowserProxyImpl" ]
namespace_rewrites = settings_namespace_rewrites
}
polymer_modulizer("ipfs_peers_subpage") {
js_file = "ipfs_peers_subpage.js"
html_file = "ipfs_peers_subpage.html"
html_type = "dom-module"
auto_imports = settings_auto_imports + [ "brave/browser/resources/settings/brave_ipfs_page/brave_ipfs_browser_proxy.html|BraveIPFSBrowserProxy, BraveIPFSBrowserProxyImpl" ]
namespace_rewrites = settings_namespace_rewrites
}
js_modulizer("modules") {
input_files = [ "brave_ipfs_browser_proxy.js" ]
namespace_rewrites = settings_namespace_rewrites
Expand All @@ -41,5 +49,6 @@ html_to_js("templatize") {
js_files = [
"change_ipfs_gateway_dialog.js",
"add_p2p_key_dialog.js",
"add_ipfs_peer_dialog.js",
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script type="module" src="brave_ipfs_browser_proxy.js"></script>
<script type="module" src="../settings_shared_css.js"></script>

<style include="settings-shared">
#submit {
margin-left : 10px;
}
</style>
<cr-dialog show-close-button show-on-attach>
<div slot="title">$i18n{ipfsAddPeerDialogTitle}</div>
<div slot="body">
<cr-input id="peer" label=""
type="text" placeholder="$i18n{ipfsAddPeerDialogPlacehodler}" invalid="[[!validValue_]]"
error-message="$i18n{ipfsAddPeerDialogError}" spellcheck="false"
on-input=nameChanged_
autofocus>
</cr-input>
</div>
<div slot="button-container">
<cr-button class="action-button" id="submit" on-click="handleSubmit_"
disabled="[[!isSubmitButtonEnabled_]]">
Submit
</cr-button>
</div>
</cr-dialog>
Loading

0 comments on commit 17e0faa

Please sign in to comment.