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 static const char* pszMainKey
= "04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284";
23 static const char* pszTestKey
= "04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a";
25 void CUnsignedAlert::SetNull()
43 std::string
CUnsignedAlert::ToString() const
45 std::string strSetCancel
;
46 BOOST_FOREACH(int n
, setCancel
)
47 strSetCancel
+= strprintf("%d ", n
);
48 std::string strSetSubVer
;
49 BOOST_FOREACH(std::string str
, setSubVer
)
50 strSetSubVer
+= "\"" + str
+ "\" ";
54 " nRelayUntil = %"PRI64d
"\n"
55 " nExpiration = %"PRI64d
"\n"
63 " strComment = \"%s\"\n"
64 " strStatusBar = \"%s\"\n"
77 strStatusBar
.c_str());
80 void CUnsignedAlert::print() const
82 printf("%s", ToString().c_str());
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
, 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 // returns true if wasn't already contained in the set
132 if (pnode
->setKnown
.insert(GetHash()).second
)
134 if (AppliesTo(pnode
->nVersion
, pnode
->strSubVer
) ||
136 GetAdjustedTime() < nRelayUntil
)
138 pnode
->PushMessage("alert", *this);
145 bool CAlert::CheckSignature() const
148 if (!key
.SetPubKey(ParseHex(fTestNet
? pszTestKey
: pszMainKey
)))
149 return error("CAlert::CheckSignature() : SetPubKey failed");
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(bool fThread
)
173 if (!CheckSignature())
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 printf("cancelling alert %d\n", alert
.nID
);
209 uiInterface
.NotifyAlertChanged((*mi
).first
, CT_DELETED
);
210 mapAlerts
.erase(mi
++);
212 else if (!alert
.IsInEffect())
214 printf("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 printf("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 std::string strCmd
= GetArg("-alertnotify", "");
242 // Alert text should be plain ascii coming from a trusted source, but to
243 // be safe we first strip anything not in safeChars, then add single quotes around
244 // the whole string before passing it to the shell:
245 std::string
singleQuote("'");
246 // safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything
247 // even possibly remotely dangerous like & or >
248 std::string
safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@");
249 std::string safeStatus
;
250 for (std::string::size_type i
= 0; i
< strStatusBar
.size(); i
++)
252 if (safeChars
.find(strStatusBar
[i
]) != std::string::npos
)
253 safeStatus
.push_back(strStatusBar
[i
]);
255 safeStatus
= singleQuote
+safeStatus
+singleQuote
;
256 boost::replace_all(strCmd
, "%s", safeStatus
);
259 boost::thread
t(runCommand
, strCmd
); // thread runs free
266 printf("accepted alert %d, AppliesToMe()=%d\n", nID
, AppliesToMe());