1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
8 #include "clientversion.h"
12 #include "ui_interface.h"
19 #include <boost/algorithm/string/classification.hpp>
20 #include <boost/algorithm/string/replace.hpp>
21 #include <boost/foreach.hpp>
22 #include <boost/thread.hpp>
26 map<uint256, CAlert> mapAlerts;
27 CCriticalSection cs_mapAlerts;
29 void CUnsignedAlert::SetNull()
47 std::string CUnsignedAlert::ToString() const
49 std::string strSetCancel;
50 BOOST_FOREACH(int n, setCancel)
51 strSetCancel += strprintf("%d ", n);
52 std::string strSetSubVer;
53 BOOST_FOREACH(std::string str, setSubVer)
54 strSetSubVer += "\"" + str + "\" ";
67 " strComment = \"%s\"\n"
68 " strStatusBar = \"%s\"\n"
84 void CAlert::SetNull()
86 CUnsignedAlert::SetNull();
91 bool CAlert::IsNull() const
93 return (nExpiration == 0);
96 uint256 CAlert::GetHash() const
98 return Hash(this->vchMsg.begin(), this->vchMsg.end());
101 bool CAlert::IsInEffect() const
103 return (GetAdjustedTime() < nExpiration);
106 bool CAlert::Cancels(const CAlert& alert) const
109 return false; // this was a no-op before 31403
110 return (alert.nID <= nCancel || setCancel.count(alert.nID));
113 bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
115 // TODO: rework for client-version-embedded-in-strSubVer ?
116 return (IsInEffect() &&
117 nMinVer <= nVersion && nVersion <= nMaxVer &&
118 (setSubVer.empty() || setSubVer.count(strSubVerIn)));
121 bool CAlert::AppliesToMe() const
123 return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
126 bool CAlert::RelayTo(CNode* pnode) const
130 // don't relay to nodes which haven't sent their version message
131 if (pnode->nVersion == 0)
133 // returns true if wasn't already contained in the set
134 if (pnode->setKnown.insert(GetHash()).second)
136 if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
138 GetAdjustedTime() < nRelayUntil)
140 pnode->PushMessage("alert", *this);
147 bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
149 CPubKey key(alertKey);
150 if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
151 return error("CAlert::CheckSignature(): verify signature failed");
153 // Now unserialize the data
154 CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
155 sMsg >> *(CUnsignedAlert*)this;
159 CAlert CAlert::getAlertByHash(const uint256 &hash)
164 map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
165 if(mi != mapAlerts.end())
171 bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
173 if (!CheckSignature(alertKey))
178 // alert.nID=max is reserved for if the alert key is
179 // compromised. It must have a pre-defined message,
180 // must never expire, must apply to all versions,
181 // and must cancel all previous
182 // alerts or it will be ignored (so an attacker can't
183 // send an "everything is OK, don't panic" version that
184 // cannot be overridden):
185 int maxInt = std::numeric_limits<int>::max();
189 nExpiration == maxInt &&
190 nCancel == (maxInt-1) &&
194 nPriority == maxInt &&
195 strStatusBar == "URGENT: Alert key compromised, upgrade required"
202 // Cancel previous alerts
203 for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
205 const CAlert& alert = (*mi).second;
208 LogPrint("alert", "cancelling alert %d\n", alert.nID);
209 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
210 mapAlerts.erase(mi++);
212 else if (!alert.IsInEffect())
214 LogPrint("alert", "expiring alert %d\n", alert.nID);
215 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
216 mapAlerts.erase(mi++);
222 // Check if this alert has been cancelled
223 BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
225 const CAlert& alert = item.second;
226 if (alert.Cancels(*this))
228 LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
234 mapAlerts.insert(make_pair(GetHash(), *this));
235 // Notify UI and -alertnotify if it applies to me
238 uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
239 Notify(strStatusBar, fThread);
243 LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
248 CAlert::Notify(const std::string& strMessage, bool fThread)
250 std::string strCmd = GetArg("-alertnotify", "");
251 if (strCmd.empty()) return;
253 // Alert text should be plain ascii coming from a trusted source, but to
254 // be safe we first strip anything not in safeChars, then add single quotes around
255 // the whole string before passing it to the shell:
256 std::string singleQuote("'");
257 std::string safeStatus = SanitizeString(strMessage);
258 safeStatus = singleQuote+safeStatus+singleQuote;
259 boost::replace_all(strCmd, "%s", safeStatus);
262 boost::thread t(runCommand, strCmd); // thread runs free