aboutsummaryrefslogtreecommitdiff
path: root/src/alert.cpp
diff options
context:
space:
mode:
authorRoss Nicoll <[email protected]>2018-04-22 17:19:03 +0100
committerRoss Nicoll <[email protected]>2018-09-19 22:11:47 +0100
commit41c868f47e671dc5009cd47496c39c13ae36306b (patch)
treee48b4f07bce4ff5aac8369551032dc46c46a8bf1 /src/alert.cpp
parentUpdate or eliminate remaining tests (#1483) (diff)
downloaddiscoin-41c868f47e671dc5009cd47496c39c13ae36306b.tar.xz
discoin-41c868f47e671dc5009cd47496c39c13ae36306b.zip
Re-introduce alert functionality (#1470)
Re-introduce alert functionality removed from Bitcoin upstream
Diffstat (limited to 'src/alert.cpp')
-rw-r--r--src/alert.cpp246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/alert.cpp b/src/alert.cpp
new file mode 100644
index 000000000..21e4887cf
--- /dev/null
+++ b/src/alert.cpp
@@ -0,0 +1,246 @@
+// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "alert.h"
+
+#include "clientversion.h"
+#include "net.h"
+#include "netmessagemaker.h"
+#include "pubkey.h"
+#include "timedata.h"
+#include "ui_interface.h"
+#include "util.h"
+#include "utilstrencodings.h"
+
+#include <stdint.h>
+#include <algorithm>
+#include <map>
+
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
+
+using namespace std;
+
+map<uint256, CAlert> mapAlerts;
+CCriticalSection cs_mapAlerts;
+
+void CUnsignedAlert::SetNull()
+{
+ nVersion = 1;
+ nRelayUntil = 0;
+ nExpiration = 0;
+ nID = 0;
+ nCancel = 0;
+ setCancel.clear();
+ nMinVer = 0;
+ nMaxVer = 0;
+ setSubVer.clear();
+ nPriority = 0;
+
+ strComment.clear();
+ strStatusBar.clear();
+ strReserved.clear();
+}
+
+std::string CUnsignedAlert::ToString() const
+{
+ std::string strSetCancel;
+ BOOST_FOREACH(int n, setCancel)
+ strSetCancel += strprintf("%d ", n);
+ std::string strSetSubVer;
+ BOOST_FOREACH(const std::string& str, setSubVer)
+ strSetSubVer += "\"" + str + "\" ";
+ return strprintf(
+ "CAlert(\n"
+ " nVersion = %d\n"
+ " nRelayUntil = %d\n"
+ " nExpiration = %d\n"
+ " nID = %d\n"
+ " nCancel = %d\n"
+ " setCancel = %s\n"
+ " nMinVer = %d\n"
+ " nMaxVer = %d\n"
+ " setSubVer = %s\n"
+ " nPriority = %d\n"
+ " strComment = \"%s\"\n"
+ " strStatusBar = \"%s\"\n"
+ ")\n",
+ nVersion,
+ nRelayUntil,
+ nExpiration,
+ nID,
+ nCancel,
+ strSetCancel,
+ nMinVer,
+ nMaxVer,
+ strSetSubVer,
+ nPriority,
+ strComment,
+ strStatusBar);
+}
+
+void CAlert::SetNull()
+{
+ CUnsignedAlert::SetNull();
+ vchMsg.clear();
+ vchSig.clear();
+}
+
+bool CAlert::IsNull() const
+{
+ return (nExpiration == 0);
+}
+
+uint256 CAlert::GetHash() const
+{
+ return Hash(this->vchMsg.begin(), this->vchMsg.end());
+}
+
+bool CAlert::IsInEffect() const
+{
+ return (GetAdjustedTime() < nExpiration);
+}
+
+bool CAlert::Cancels(const CAlert& alert) const
+{
+ if (!IsInEffect())
+ return false; // this was a no-op before 31403
+ return (alert.nID <= nCancel || setCancel.count(alert.nID));
+}
+
+bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
+{
+ // TODO: rework for client-version-embedded-in-strSubVer ?
+ return (IsInEffect() &&
+ nMinVer <= nVersion && nVersion <= nMaxVer &&
+ (setSubVer.empty() || setSubVer.count(strSubVerIn)));
+}
+
+bool CAlert::AppliesToMe() const
+{
+ return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
+}
+
+bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
+{
+ CPubKey key(alertKey);
+ if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
+ return error("CAlert::CheckSignature(): verify signature failed");
+
+ // Now unserialize the data
+ CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
+ sMsg >> *(CUnsignedAlert*)this;
+ return true;
+}
+
+CAlert CAlert::getAlertByHash(const uint256 &hash)
+{
+ CAlert retval;
+ {
+ LOCK(cs_mapAlerts);
+ map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
+ if(mi != mapAlerts.end())
+ retval = mi->second;
+ }
+ return retval;
+}
+
+bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
+{
+ if (!CheckSignature(alertKey))
+ return false;
+ if (!IsInEffect())
+ return false;
+
+ // alert.nID=max is reserved for if the alert key is
+ // compromised. It must have a pre-defined message,
+ // must never expire, must apply to all versions,
+ // and must cancel all previous
+ // alerts or it will be ignored (so an attacker can't
+ // send an "everything is OK, don't panic" version that
+ // cannot be overridden):
+ int maxInt = std::numeric_limits<int>::max();
+ if (nID == maxInt)
+ {
+ if (!(
+ nExpiration == maxInt &&
+ nCancel == (maxInt-1) &&
+ nMinVer == 0 &&
+ nMaxVer == maxInt &&
+ setSubVer.empty() &&
+ nPriority == maxInt &&
+ strStatusBar == "URGENT: Alert key compromised, upgrade required"
+ ))
+ return false;
+ }
+
+ {
+ LOCK(cs_mapAlerts);
+ // Cancel previous alerts
+ for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
+ {
+ const CAlert& alert = (*mi).second;
+ if (Cancels(alert))
+ {
+ LogPrint("alert", "cancelling alert %d\n", alert.nID);
+ uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
+ mapAlerts.erase(mi++);
+ }
+ else if (!alert.IsInEffect())
+ {
+ LogPrint("alert", "expiring alert %d\n", alert.nID);
+ uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
+ mapAlerts.erase(mi++);
+ }
+ else
+ mi++;
+ }
+
+ // Check if this alert has been cancelled
+ BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
+ {
+ const CAlert& alert = item.second;
+ if (alert.Cancels(*this))
+ {
+ LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
+ return false;
+ }
+ }
+
+ // Add to mapAlerts
+ mapAlerts.insert(make_pair(GetHash(), *this));
+ // Notify UI and -alertnotify if it applies to me
+ if(AppliesToMe())
+ {
+ uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
+ Notify(strStatusBar, fThread);
+ }
+ }
+
+ LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
+ return true;
+}
+
+void
+CAlert::Notify(const std::string& strMessage, bool fThread)
+{
+ std::string strCmd = GetArg("-alertnotify", "");
+ if (strCmd.empty()) return;
+
+ // Alert text should be plain ascii coming from a trusted source, but to
+ // be safe we first strip anything not in safeChars, then add single quotes around
+ // the whole string before passing it to the shell:
+ std::string singleQuote("'");
+ std::string safeStatus = SanitizeString(strMessage);
+ safeStatus = singleQuote+safeStatus+singleQuote;
+ boost::replace_all(strCmd, "%s", safeStatus);
+
+ if (fThread)
+ boost::thread t(runCommand, strCmd); // thread runs free
+ else
+ runCommand(strCmd);
+}