6 #include <boost/algorithm/string/classification.hpp>
7 #include <boost/algorithm/string/replace.hpp>
8 #include <boost/foreach.hpp>
15 #include "ui_interface.h"
19 map<uint256, CAlert> mapAlerts;
20 CCriticalSection cs_mapAlerts;
22 void CUnsignedAlert::SetNull()
40 std::string CUnsignedAlert::ToString() const
42 std::string strSetCancel;
43 BOOST_FOREACH(int n, setCancel)
44 strSetCancel += strprintf("%d ", n);
45 std::string strSetSubVer;
46 BOOST_FOREACH(std::string str, setSubVer)
47 strSetSubVer += "\"" + str + "\" ";
51 " nRelayUntil = %"PRI64d"\n"
52 " nExpiration = %"PRI64d"\n"
60 " strComment = \"%s\"\n"
61 " strStatusBar = \"%s\"\n"
74 strStatusBar.c_str());
77 void CUnsignedAlert::print() const
79 printf("%s", ToString().c_str());
82 void CAlert::SetNull()
84 CUnsignedAlert::SetNull();
89 bool CAlert::IsNull() const
91 return (nExpiration == 0);
94 uint256 CAlert::GetHash() const
96 return Hash(this->vchMsg.begin(), this->vchMsg.end());
99 bool CAlert::IsInEffect() const
101 return (GetAdjustedTime() < nExpiration);
104 bool CAlert::Cancels(const CAlert& alert) const
107 return false; // this was a no-op before 31403
108 return (alert.nID <= nCancel || setCancel.count(alert.nID));
111 bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
113 // TODO: rework for client-version-embedded-in-strSubVer ?
114 return (IsInEffect() &&
115 nMinVer <= nVersion && nVersion <= nMaxVer &&
116 (setSubVer.empty() || setSubVer.count(strSubVerIn)));
119 bool CAlert::AppliesToMe() const
121 return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
124 bool CAlert::RelayTo(CNode* pnode) const
128 // returns true if wasn't already contained in the set
129 if (pnode->setKnown.insert(GetHash()).second)
131 if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
133 GetAdjustedTime() < nRelayUntil)
135 pnode->PushMessage("alert", *this);
142 bool CAlert::CheckSignature() const
144 CPubKey key(Params().AlertKey());
145 if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
146 return error("CAlert::CheckSignature() : verify signature failed");
148 // Now unserialize the data
149 CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
150 sMsg >> *(CUnsignedAlert*)this;
154 CAlert CAlert::getAlertByHash(const uint256 &hash)
159 map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
160 if(mi != mapAlerts.end())
166 bool CAlert::ProcessAlert(bool fThread)
168 if (!CheckSignature())
173 // alert.nID=max is reserved for if the alert key is
174 // compromised. It must have a pre-defined message,
175 // must never expire, must apply to all versions,
176 // and must cancel all previous
177 // alerts or it will be ignored (so an attacker can't
178 // send an "everything is OK, don't panic" version that
179 // cannot be overridden):
180 int maxInt = std::numeric_limits<int>::max();
184 nExpiration == maxInt &&
185 nCancel == (maxInt-1) &&
189 nPriority == maxInt &&
190 strStatusBar == "URGENT: Alert key compromised, upgrade required"
197 // Cancel previous alerts
198 for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
200 const CAlert& alert = (*mi).second;
203 printf("cancelling alert %d\n", alert.nID);
204 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
205 mapAlerts.erase(mi++);
207 else if (!alert.IsInEffect())
209 printf("expiring alert %d\n", alert.nID);
210 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
211 mapAlerts.erase(mi++);
217 // Check if this alert has been cancelled
218 BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
220 const CAlert& alert = item.second;
221 if (alert.Cancels(*this))
223 printf("alert already cancelled by %d\n", alert.nID);
229 mapAlerts.insert(make_pair(GetHash(), *this));
230 // Notify UI and -alertnotify if it applies to me
233 uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
234 std::string strCmd = GetArg("-alertnotify", "");
237 // Alert text should be plain ascii coming from a trusted source, but to
238 // be safe we first strip anything not in safeChars, then add single quotes around
239 // the whole string before passing it to the shell:
240 std::string singleQuote("'");
241 // safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything
242 // even possibly remotely dangerous like & or >
243 std::string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@");
244 std::string safeStatus;
245 for (std::string::size_type i = 0; i < strStatusBar.size(); i++)
247 if (safeChars.find(strStatusBar[i]) != std::string::npos)
248 safeStatus.push_back(strStatusBar[i]);
250 safeStatus = singleQuote+safeStatus+singleQuote;
251 boost::replace_all(strCmd, "%s", safeStatus);
254 boost::thread t(runCommand, strCmd); // thread runs free
261 printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());