1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
10 #include "ui_interface.h"
17 #include <boost/algorithm/string/classification.hpp>
18 #include <boost/algorithm/string/replace.hpp>
19 #include <boost/foreach.hpp>
23 map<uint256, CAlert> mapAlerts;
24 CCriticalSection cs_mapAlerts;
26 void CUnsignedAlert::SetNull()
44 std::string CUnsignedAlert::ToString() const
46 std::string strSetCancel;
47 BOOST_FOREACH(int n, setCancel)
48 strSetCancel += strprintf("%d ", n);
49 std::string strSetSubVer;
50 BOOST_FOREACH(std::string str, setSubVer)
51 strSetSubVer += "\"" + str + "\" ";
55 " nRelayUntil = %"PRId64"\n"
56 " nExpiration = %"PRId64"\n"
64 " strComment = \"%s\"\n"
65 " strStatusBar = \"%s\"\n"
81 void CUnsignedAlert::print() const
83 LogPrintf("%s", ToString());
86 void CAlert::SetNull()
88 CUnsignedAlert::SetNull();
93 bool CAlert::IsNull() const
95 return (nExpiration == 0);
98 uint256 CAlert::GetHash() const
100 return Hash(this->vchMsg.begin(), this->vchMsg.end());
103 bool CAlert::IsInEffect() const
105 return (GetAdjustedTime() < nExpiration);
108 bool CAlert::Cancels(const CAlert& alert) const
111 return false; // this was a no-op before 31403
112 return (alert.nID <= nCancel || setCancel.count(alert.nID));
115 bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
117 // TODO: rework for client-version-embedded-in-strSubVer ?
118 return (IsInEffect() &&
119 nMinVer <= nVersion && nVersion <= nMaxVer &&
120 (setSubVer.empty() || setSubVer.count(strSubVerIn)));
123 bool CAlert::AppliesToMe() const
125 return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
128 bool CAlert::RelayTo(CNode* pnode) const
132 // returns true if wasn't already contained in the set
133 if (pnode->setKnown.insert(GetHash()).second)
135 if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
137 GetAdjustedTime() < nRelayUntil)
139 pnode->PushMessage("alert", *this);
146 bool CAlert::CheckSignature() const
148 CPubKey key(Params().AlertKey());
149 if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
150 return error("CAlert::CheckSignature() : verify signature failed");
152 // Now unserialize the data
153 CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
154 sMsg >> *(CUnsignedAlert*)this;
158 CAlert CAlert::getAlertByHash(const uint256 &hash)
163 map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
164 if(mi != mapAlerts.end())
170 bool CAlert::ProcessAlert(bool fThread)
172 if (!CheckSignature())
177 // alert.nID=max is reserved for if the alert key is
178 // compromised. It must have a pre-defined message,
179 // must never expire, must apply to all versions,
180 // and must cancel all previous
181 // alerts or it will be ignored (so an attacker can't
182 // send an "everything is OK, don't panic" version that
183 // cannot be overridden):
184 int maxInt = std::numeric_limits<int>::max();
188 nExpiration == maxInt &&
189 nCancel == (maxInt-1) &&
193 nPriority == maxInt &&
194 strStatusBar == "URGENT: Alert key compromised, upgrade required"
201 // Cancel previous alerts
202 for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
204 const CAlert& alert = (*mi).second;
207 LogPrint("alert", "cancelling alert %d\n", alert.nID);
208 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
209 mapAlerts.erase(mi++);
211 else if (!alert.IsInEffect())
213 LogPrint("alert", "expiring alert %d\n", alert.nID);
214 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
215 mapAlerts.erase(mi++);
221 // Check if this alert has been cancelled
222 BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
224 const CAlert& alert = item.second;
225 if (alert.Cancels(*this))
227 LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
233 mapAlerts.insert(make_pair(GetHash(), *this));
234 // Notify UI and -alertnotify if it applies to me
237 uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
238 std::string strCmd = GetArg("-alertnotify", "");
241 // Alert text should be plain ascii coming from a trusted source, but to
242 // be safe we first strip anything not in safeChars, then add single quotes around
243 // the whole string before passing it to the shell:
244 std::string singleQuote("'");
245 std::string safeStatus = SanitizeString(strStatusBar);
246 safeStatus = singleQuote+safeStatus+singleQuote;
247 boost::replace_all(strCmd, "%s", safeStatus);
250 boost::thread t(runCommand, strCmd); // thread runs free
257 LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());