From d47c70579f413a5aea1bdf4717fdce46739e8bc3 Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Thu, 15 Dec 2022 02:52:44 +0000 Subject: [PATCH] [BREAKING] Disable the 'sync' command This will require support from TaskChampion. --- src/commands/CmdSync.cpp | 336 +-------------------------------------- 1 file changed, 3 insertions(+), 333 deletions(-) diff --git a/src/commands/CmdSync.cpp b/src/commands/CmdSync.cpp index 4aa33c4bd..c430e3f74 100644 --- a/src/commands/CmdSync.cpp +++ b/src/commands/CmdSync.cpp @@ -53,340 +53,10 @@ CmdSync::CmdSync () } //////////////////////////////////////////////////////////////////////////////// -int CmdSync::execute (std::string& output) +int CmdSync::execute (std::string&) { - int status = 0; -#ifdef HAVE_LIBGNUTLS - std::stringstream out; - - Filter filter; - if (filter.hasFilter ()) - throw std::string ("Command line filters are not supported by this command."); - - // Loog for the 'init' keyword to indicate one-time pending.data upload. - bool first_time_init = false; - std::vector words = Context::getContext ().cli2.getWords (); - for (auto& word : words) - { - if (closeEnough ("initialize", word, 4)) - { - if (!Context::getContext ().config.getBoolean ("confirmation") || - confirm ("Please confirm that you wish to upload all your tasks to the Taskserver")) - first_time_init = true; - else - throw std::string ("Taskwarrior will not proceed with first-time sync initialization."); - } - } - - // If no server is set up, quit. - std::string connection = Context::getContext ().config.get ("taskd.server"); - if (connection == "" || - connection.rfind (':') == std::string::npos) - throw std::string ("Taskserver is not configured."); - - // Obtain credentials. - std::string credentials_string = Context::getContext ().config.get ("taskd.credentials"); - if (credentials_string == "") - throw std::string ("Taskserver credentials malformed."); - - auto credentials = split (credentials_string, '/'); - if (credentials.size () != 3) - throw std::string ("Taskserver credentials malformed."); - - // This was a Boolean value in 2.3.0, and is a tri-state since 2.4.0. - std::string trust_value = Context::getContext ().config.get ("taskd.trust"); - if (trust_value != "strict" && - trust_value != "ignore hostname" && - trust_value != "allow all") - throw std::string ("The 'taskd.trust' settings may now only contain a value of 'strict', 'ignore hostname' or 'allow all'."); - - enum TLSClient::trust_level trust = TLSClient::strict; - if (trust_value == "allow all") - trust = TLSClient::allow_all; - else if (trust_value == "ignore hostname") - trust = TLSClient::ignore_hostname; - - // CA must exist, if provided. - File ca (Context::getContext ().config.get ("taskd.ca")); - if (ca._data != "" && ! ca.exists ()) - throw std::string ("CA certificate not found."); - - if (trust == TLSClient::allow_all && ca._data != "") - throw std::string ("You should either provide a CA certificate or override verification, but not both."); - - File certificate (Context::getContext ().config.get ("taskd.certificate")); - if (! certificate.exists ()) - throw std::string ("Taskserver certificate missing."); - - File key (Context::getContext ().config.get ("taskd.key")); - if (! key.exists ()) - throw std::string ("Taskserver key missing."); - - // If this is a first-time initialization, send pending.data and - // completed.data, but not backlog.data. - std::string payload = ""; - int upload_count = 0; - if (first_time_init) - { - // Delete backlog.data. Because if we're uploading everything, the list of - // deltas is meaningless. - Context::getContext ().tdb2.backlog._file.truncate (); - - auto all_tasks = Context::getContext ().tdb2.all_tasks (); - for (auto& i : all_tasks) - { - payload += i.composeJSON () + '\n'; - ++upload_count; - } - } - else - { - std::vector lines = Context::getContext ().tdb2.backlog.get_lines (); - for (auto& i : lines) - { - if (i[0] == '{') - ++upload_count; - - payload += i + '\n'; - } - } - - // Send 'sync' + payload. - Msg request; - request.set ("client", PACKAGE_STRING); - request.set ("protocol", "v1"); - request.set ("type", "sync"); - request.set ("org", credentials[0]); - request.set ("user", credentials[1]); - request.set ("key", credentials[2]); - - // Tell the server that this is a full upload, allowing it to perhaps compact - // its data. - if (first_time_init) - request.set ("subtype", "init"); - - request.setPayload (payload); - - if (Context::getContext ().verbose ("sync")) - out << format ("Syncing with {1}", connection) - << '\n'; - - // Ignore harmful signals. - signal (SIGHUP, SIG_IGN); - signal (SIGINT, SIG_IGN); - signal (SIGPIPE, SIG_IGN); - signal (SIGTERM, SIG_IGN); - signal (SIGUSR1, SIG_IGN); - signal (SIGUSR2, SIG_IGN); - - Msg response; - if (send (connection, ca._data, certificate._data, key._data, trust, request, response)) - { - std::string code = response.get ("code"); - if (code == "200") - { - Color colorAdded; - Color colorChanged; - if (Context::getContext ().color ()) - { - colorAdded = Color (Context::getContext ().config.get ("color.sync.added")); - colorChanged = Color (Context::getContext ().config.get ("color.sync.changed")); - } - - int download_count = 0; - payload = response.getPayload (); - auto lines = split (payload, '\n'); - - // Load all tasks, but only if necessary. There is always a sync key in - // the payload, so if there are two or more lines, then we have merging - // to perform, otherwise it's just a backlog.data update. - if (lines.size () > 1) - Context::getContext ().tdb2.all_tasks (); - - std::string sync_key = ""; - for (auto& line : lines) - { - if (line[0] == '{') - { - ++download_count; - - Task from_server (line); - std::string uuid = from_server.get ("uuid"); - - // Is it a new task from the server, or an update to an existing one? - Task dummy; - if (Context::getContext ().tdb2.get (uuid, dummy)) - { - if (Context::getContext ().verbose ("sync")) - out << " " - << colorChanged.colorize ( - format ("modify {1} '{2}'", - uuid, - from_server.get ("description"))) - << '\n'; - Context::getContext ().tdb2.modify (from_server, false); - } - else - { - if (Context::getContext ().verbose ("sync")) - out << " " - << colorAdded.colorize ( - format (" add {1} '{2}'", - uuid, - from_server.get ("description"))) - << '\n'; - Context::getContext ().tdb2.add (from_server, false); - } - } - else if (line != "") - { - sync_key = line; - Context::getContext ().debug ("Sync key " + sync_key); - } - - // Otherwise line is blank, so ignore it. - } - - // Only update everything if there is a new sync_key. No sync_key means - // something horrible happened on the other end of the wire. - if (sync_key != "") - { - // Truncate backlog.data, save new sync_key. - Context::getContext ().tdb2.backlog._file.truncate (); - Context::getContext ().tdb2.backlog.clear_tasks (); - Context::getContext ().tdb2.backlog.clear_lines (); - Context::getContext ().tdb2.backlog.add_line (sync_key + '\n'); - - // Present a clear status message. - if (upload_count == 0 && download_count == 0) - // Note: should not happen - expect code 201 instead. - Context::getContext ().footnote ("Sync successful."); - else if (upload_count == 0 && download_count > 0) - Context::getContext ().footnote (format ("Sync successful. {1} changes downloaded.", download_count)); - else if (upload_count > 0 && download_count == 0) - Context::getContext ().footnote (format ("Sync successful. {1} changes uploaded.", upload_count)); - else if (upload_count > 0 && download_count > 0) - Context::getContext ().footnote (format ("Sync successful. {1} changes uploaded, {2} changes downloaded.", upload_count, download_count)); - } - - status = 0; - } - else if (code == "201") - { - Context::getContext ().footnote ("Sync successful. No changes."); - status = 0; - } - else if (code == "301") - { - std::string new_server = response.get ("info"); - Context::getContext ().config.set ("taskd.server", new_server); - Context::getContext ().error ("The server account has been relocated. Please update your configuration using:"); - Context::getContext ().error (" " + format ("task config taskd.server {1}", new_server)); - status = 2; - } - else if (code == "430") - { - Context::getContext ().error ("Sync failed. Either your credentials are incorrect, or your account doesn't exist on the Taskserver."); - status = 2; - } - else - { - Context::getContext ().error (format ("Sync failed. The Taskserver returned error: {1} {2}", - code, - response.get ("status"))); - status = 2; - } - - // Display all errors returned. This is recommended by the server protocol. - std::string to_be_displayed = response.get ("messages"); - if (to_be_displayed != "") - { - if (Context::getContext ().verbose ("footnote")) - Context::getContext ().footnote (to_be_displayed); - else - Context::getContext ().debug (to_be_displayed); - } - } - - // Some kind of low-level error: - // - Server down - // - Wrong address - // - Wrong port - // - Firewall - // - Network error - // - No signal/cable - else - { - Context::getContext ().error ("Sync failed. Could not connect to the Taskserver."); - status = 1; - } - - if (Context::getContext ().verbose ("sync")) - out << '\n'; - output = out.str (); - - // Restore signal handling. - signal (SIGHUP, SIG_DFL); - signal (SIGINT, SIG_DFL); - signal (SIGPIPE, SIG_DFL); - signal (SIGTERM, SIG_DFL); - signal (SIGUSR1, SIG_DFL); - signal (SIGUSR2, SIG_DFL); - -#else - // Without GnuTLS found at compile time, there is no working sync command. - throw std::string ("Taskwarrior was built without GnuTLS support. Sync is not available."); -#endif - return status; + throw std::string ("Sync support is disabled during transition to TaskChampion."); + return 0; } -#ifdef HAVE_LIBGNUTLS -//////////////////////////////////////////////////////////////////////////////// -bool CmdSync::send ( - const std::string& to, - const std::string& ca, - const std::string& certificate, - const std::string& key, - const enum TLSClient::trust_level trust, - const Msg& request, - Msg& response) -{ - // It is important that the ':' be the *last* colon, in order to support - // IPv6 addresses. - auto colon = to.rfind (':'); - if (colon == std::string::npos) - throw format ("Sync failed. Malformed configuration setting '{1}'", to); - - std::string server = to.substr (0, colon); - std::string port = to.substr (colon + 1); - - try - { - TLSClient client; - client.debug (Context::getContext ().config.getInteger ("debug.tls")); - - client.trust (trust); - client.ciphers (Context::getContext ().config.get ("taskd.ciphers")); - client.init (ca, certificate, key); - client.connect (server, port); - client.send (request.serialize () + '\n'); - - std::string incoming; - client.recv (incoming); - client.bye (); - - response.parse (incoming); - return true; - } - - catch (std::string& error) - { - Context::getContext ().error (error); - } - - // Indicate message failed. - return false; -} -#endif - ////////////////////////////////////////////////////////////////////////////////