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"
14 #include "utilstrencodings.h"
20 #include <boost/algorithm/string/classification.hpp>
21 #include <boost/algorithm/string/replace.hpp>
22 #include <boost/foreach.hpp>
23 #include <boost/thread.hpp>
27 map
<uint256
, CAlert
> mapAlerts
;
28 CCriticalSection cs_mapAlerts
;
30 void CUnsignedAlert::SetNull()
48 std::string
CUnsignedAlert::ToString() const
50 std::string strSetCancel
;
51 BOOST_FOREACH(int n
, setCancel
)
52 strSetCancel
+= strprintf("%d ", n
);
53 std::string strSetSubVer
;
54 BOOST_FOREACH(const std::string
& str
, setSubVer
)
55 strSetSubVer
+= "\"" + str
+ "\" ";
68 " strComment = \"%s\"\n"
69 " strStatusBar = \"%s\"\n"
85 void CAlert::SetNull()
87 CUnsignedAlert::SetNull();
92 bool CAlert::IsNull() const
94 return (nExpiration
== 0);
97 uint256
CAlert::GetHash() const
99 return Hash(this->vchMsg
.begin(), this->vchMsg
.end());
102 bool CAlert::IsInEffect() const
104 return (GetAdjustedTime() < nExpiration
);
107 bool CAlert::Cancels(const CAlert
& alert
) const
110 return false; // this was a no-op before 31403
111 return (alert
.nID
<= nCancel
|| setCancel
.count(alert
.nID
));
114 bool CAlert::AppliesTo(int nVersion
, const std::string
& strSubVerIn
) const
116 // TODO: rework for client-version-embedded-in-strSubVer ?
117 return (IsInEffect() &&
118 nMinVer
<= nVersion
&& nVersion
<= nMaxVer
&&
119 (setSubVer
.empty() || setSubVer
.count(strSubVerIn
)));
122 bool CAlert::AppliesToMe() const
124 return AppliesTo(PROTOCOL_VERSION
, FormatSubVersion(CLIENT_NAME
, CLIENT_VERSION
, std::vector
<std::string
>()));
127 bool CAlert::RelayTo(CNode
* pnode
) const
131 // don't relay to nodes which haven't sent their version message
132 if (pnode
->nVersion
== 0)
134 // returns true if wasn't already contained in the set
135 if (pnode
->setKnown
.insert(GetHash()).second
)
137 if (AppliesTo(pnode
->nVersion
, pnode
->strSubVer
) ||
139 GetAdjustedTime() < nRelayUntil
)
141 pnode
->PushMessage("alert", *this);
148 bool CAlert::CheckSignature(const std::vector
<unsigned char>& alertKey
) const
150 CPubKey
key(alertKey
);
151 if (!key
.Verify(Hash(vchMsg
.begin(), vchMsg
.end()), vchSig
))
152 return error("CAlert::CheckSignature(): verify signature failed");
154 // Now unserialize the data
155 CDataStream
sMsg(vchMsg
, SER_NETWORK
, PROTOCOL_VERSION
);
156 sMsg
>> *(CUnsignedAlert
*)this;
160 CAlert
CAlert::getAlertByHash(const uint256
&hash
)
165 map
<uint256
, CAlert
>::iterator mi
= mapAlerts
.find(hash
);
166 if(mi
!= mapAlerts
.end())
172 bool CAlert::ProcessAlert(const std::vector
<unsigned char>& alertKey
, bool fThread
)
174 if (!CheckSignature(alertKey
))
179 // alert.nID=max is reserved for if the alert key is
180 // compromised. It must have a pre-defined message,
181 // must never expire, must apply to all versions,
182 // and must cancel all previous
183 // alerts or it will be ignored (so an attacker can't
184 // send an "everything is OK, don't panic" version that
185 // cannot be overridden):
186 int maxInt
= std::numeric_limits
<int>::max();
190 nExpiration
== maxInt
&&
191 nCancel
== (maxInt
-1) &&
195 nPriority
== maxInt
&&
196 strStatusBar
== "URGENT: Alert key compromised, upgrade required"
203 // Cancel previous alerts
204 for (map
<uint256
, CAlert
>::iterator mi
= mapAlerts
.begin(); mi
!= mapAlerts
.end();)
206 const CAlert
& alert
= (*mi
).second
;
209 LogPrint("alert", "cancelling alert %d\n", alert
.nID
);
210 uiInterface
.NotifyAlertChanged((*mi
).first
, CT_DELETED
);
211 mapAlerts
.erase(mi
++);
213 else if (!alert
.IsInEffect())
215 LogPrint("alert", "expiring alert %d\n", alert
.nID
);
216 uiInterface
.NotifyAlertChanged((*mi
).first
, CT_DELETED
);
217 mapAlerts
.erase(mi
++);
223 // Check if this alert has been cancelled
224 BOOST_FOREACH(PAIRTYPE(const uint256
, CAlert
)& item
, mapAlerts
)
226 const CAlert
& alert
= item
.second
;
227 if (alert
.Cancels(*this))
229 LogPrint("alert", "alert already cancelled by %d\n", alert
.nID
);
235 mapAlerts
.insert(make_pair(GetHash(), *this));
236 // Notify UI and -alertnotify if it applies to me
239 uiInterface
.NotifyAlertChanged(GetHash(), CT_NEW
);
240 Notify(strStatusBar
, fThread
);
244 LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID
, AppliesToMe());
249 CAlert::Notify(const std::string
& strMessage
, bool fThread
)
251 std::string strCmd
= GetArg("-alertnotify", "");
252 if (strCmd
.empty()) return;
254 // Alert text should be plain ascii coming from a trusted source, but to
255 // be safe we first strip anything not in safeChars, then add single quotes around
256 // the whole string before passing it to the shell:
257 std::string
singleQuote("'");
258 std::string safeStatus
= SanitizeString(strMessage
);
259 safeStatus
= singleQuote
+safeStatus
+singleQuote
;
260 boost::replace_all(strCmd
, "%s", safeStatus
);
263 boost::thread
t(runCommand
, strCmd
); // thread runs free