Update osx build instructions to ensure users link to the correct version of OpenSSL
[bitcoinplatinum.git] / src / alert.cpp
blob4b029840dd65c76c830b963c57ad021d17726191
1 //
2 // Alert system
3 //
5 #include <algorithm>
6 #include <boost/algorithm/string/classification.hpp>
7 #include <boost/algorithm/string/replace.hpp>
8 #include <boost/foreach.hpp>
9 #include <map>
11 #include "alert.h"
12 #include "key.h"
13 #include "net.h"
14 #include "sync.h"
15 #include "ui_interface.h"
17 using namespace std;
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()
27 nVersion = 1;
28 nRelayUntil = 0;
29 nExpiration = 0;
30 nID = 0;
31 nCancel = 0;
32 setCancel.clear();
33 nMinVer = 0;
34 nMaxVer = 0;
35 setSubVer.clear();
36 nPriority = 0;
38 strComment.clear();
39 strStatusBar.clear();
40 strReserved.clear();
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 + "\" ";
51 return strprintf(
52 "CAlert(\n"
53 " nVersion = %d\n"
54 " nRelayUntil = %"PRI64d"\n"
55 " nExpiration = %"PRI64d"\n"
56 " nID = %d\n"
57 " nCancel = %d\n"
58 " setCancel = %s\n"
59 " nMinVer = %d\n"
60 " nMaxVer = %d\n"
61 " setSubVer = %s\n"
62 " nPriority = %d\n"
63 " strComment = \"%s\"\n"
64 " strStatusBar = \"%s\"\n"
65 ")\n",
66 nVersion,
67 nRelayUntil,
68 nExpiration,
69 nID,
70 nCancel,
71 strSetCancel.c_str(),
72 nMinVer,
73 nMaxVer,
74 strSetSubVer.c_str(),
75 nPriority,
76 strComment.c_str(),
77 strStatusBar.c_str());
80 void CUnsignedAlert::print() const
82 printf("%s", ToString().c_str());
85 void CAlert::SetNull()
87 CUnsignedAlert::SetNull();
88 vchMsg.clear();
89 vchSig.clear();
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
109 if (!IsInEffect())
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
129 if (!IsInEffect())
130 return false;
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) ||
135 AppliesToMe() ||
136 GetAdjustedTime() < nRelayUntil)
138 pnode->PushMessage("alert", *this);
139 return true;
142 return false;
145 bool CAlert::CheckSignature() const
147 CKey key;
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;
156 return true;
159 CAlert CAlert::getAlertByHash(const uint256 &hash)
161 CAlert retval;
163 LOCK(cs_mapAlerts);
164 map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
165 if(mi != mapAlerts.end())
166 retval = mi->second;
168 return retval;
171 bool CAlert::ProcessAlert(bool fThread)
173 if (!CheckSignature())
174 return false;
175 if (!IsInEffect())
176 return false;
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();
186 if (nID == maxInt)
188 if (!(
189 nExpiration == maxInt &&
190 nCancel == (maxInt-1) &&
191 nMinVer == 0 &&
192 nMaxVer == maxInt &&
193 setSubVer.empty() &&
194 nPriority == maxInt &&
195 strStatusBar == "URGENT: Alert key compromised, upgrade required"
197 return false;
201 LOCK(cs_mapAlerts);
202 // Cancel previous alerts
203 for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
205 const CAlert& alert = (*mi).second;
206 if (Cancels(alert))
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++);
218 else
219 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);
229 return false;
233 // Add to mapAlerts
234 mapAlerts.insert(make_pair(GetHash(), *this));
235 // Notify UI and -alertnotify if it applies to me
236 if(AppliesToMe())
238 uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
239 std::string strCmd = GetArg("-alertnotify", "");
240 if (!strCmd.empty())
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);
258 if (fThread)
259 boost::thread t(runCommand, strCmd); // thread runs free
260 else
261 runCommand(strCmd);
266 printf("accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
267 return true;