]> Git Repo - VerusCoin.git/blob - src/alert.cpp
Merge #5468 from
[VerusCoin.git] / src / alert.cpp
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.
5
6 #include "alert.h"
7
8 #include "chainparams.h"
9 #include "clientversion.h"
10 #include "net.h"
11 #include "pubkey.h"
12 #include "timedata.h"
13 #include "ui_interface.h"
14 #include "util.h"
15
16 #include <stdint.h>
17 #include <algorithm>
18 #include <map>
19
20 #include <boost/algorithm/string/classification.hpp>
21 #include <boost/algorithm/string/replace.hpp>
22 #include <boost/foreach.hpp>
23 #include <boost/thread.hpp>
24
25 using namespace std;
26
27 map<uint256, CAlert> mapAlerts;
28 CCriticalSection cs_mapAlerts;
29
30 void CUnsignedAlert::SetNull()
31 {
32     nVersion = 1;
33     nRelayUntil = 0;
34     nExpiration = 0;
35     nID = 0;
36     nCancel = 0;
37     setCancel.clear();
38     nMinVer = 0;
39     nMaxVer = 0;
40     setSubVer.clear();
41     nPriority = 0;
42
43     strComment.clear();
44     strStatusBar.clear();
45     strReserved.clear();
46 }
47
48 std::string CUnsignedAlert::ToString() const
49 {
50     std::string strSetCancel;
51     BOOST_FOREACH(int n, setCancel)
52         strSetCancel += strprintf("%d ", n);
53     std::string strSetSubVer;
54     BOOST_FOREACH(std::string str, setSubVer)
55         strSetSubVer += "\"" + str + "\" ";
56     return strprintf(
57         "CAlert(\n"
58         "    nVersion     = %d\n"
59         "    nRelayUntil  = %d\n"
60         "    nExpiration  = %d\n"
61         "    nID          = %d\n"
62         "    nCancel      = %d\n"
63         "    setCancel    = %s\n"
64         "    nMinVer      = %d\n"
65         "    nMaxVer      = %d\n"
66         "    setSubVer    = %s\n"
67         "    nPriority    = %d\n"
68         "    strComment   = \"%s\"\n"
69         "    strStatusBar = \"%s\"\n"
70         ")\n",
71         nVersion,
72         nRelayUntil,
73         nExpiration,
74         nID,
75         nCancel,
76         strSetCancel,
77         nMinVer,
78         nMaxVer,
79         strSetSubVer,
80         nPriority,
81         strComment,
82         strStatusBar);
83 }
84
85 void CAlert::SetNull()
86 {
87     CUnsignedAlert::SetNull();
88     vchMsg.clear();
89     vchSig.clear();
90 }
91
92 bool CAlert::IsNull() const
93 {
94     return (nExpiration == 0);
95 }
96
97 uint256 CAlert::GetHash() const
98 {
99     return Hash(this->vchMsg.begin(), this->vchMsg.end());
100 }
101
102 bool CAlert::IsInEffect() const
103 {
104     return (GetAdjustedTime() < nExpiration);
105 }
106
107 bool CAlert::Cancels(const CAlert& alert) const
108 {
109     if (!IsInEffect())
110         return false; // this was a no-op before 31403
111     return (alert.nID <= nCancel || setCancel.count(alert.nID));
112 }
113
114 bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
115 {
116     // TODO: rework for client-version-embedded-in-strSubVer ?
117     return (IsInEffect() &&
118             nMinVer <= nVersion && nVersion <= nMaxVer &&
119             (setSubVer.empty() || setSubVer.count(strSubVerIn)));
120 }
121
122 bool CAlert::AppliesToMe() const
123 {
124     return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
125 }
126
127 bool CAlert::RelayTo(CNode* pnode) const
128 {
129     if (!IsInEffect())
130         return false;
131     // don't relay to nodes which haven't sent their version message
132     if (pnode->nVersion == 0)
133         return false;
134     // returns true if wasn't already contained in the set
135     if (pnode->setKnown.insert(GetHash()).second)
136     {
137         if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
138             AppliesToMe() ||
139             GetAdjustedTime() < nRelayUntil)
140         {
141             pnode->PushMessage("alert", *this);
142             return true;
143         }
144     }
145     return false;
146 }
147
148 bool CAlert::CheckSignature() const
149 {
150     CPubKey key(Params().AlertKey());
151     if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
152         return error("CAlert::CheckSignature() : verify signature failed");
153
154     // Now unserialize the data
155     CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
156     sMsg >> *(CUnsignedAlert*)this;
157     return true;
158 }
159
160 CAlert CAlert::getAlertByHash(const uint256 &hash)
161 {
162     CAlert retval;
163     {
164         LOCK(cs_mapAlerts);
165         map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
166         if(mi != mapAlerts.end())
167             retval = mi->second;
168     }
169     return retval;
170 }
171
172 bool CAlert::ProcessAlert(bool fThread)
173 {
174     if (!CheckSignature())
175         return false;
176     if (!IsInEffect())
177         return false;
178
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();
187     if (nID == maxInt)
188     {
189         if (!(
190                 nExpiration == maxInt &&
191                 nCancel == (maxInt-1) &&
192                 nMinVer == 0 &&
193                 nMaxVer == maxInt &&
194                 setSubVer.empty() &&
195                 nPriority == maxInt &&
196                 strStatusBar == "URGENT: Alert key compromised, upgrade required"
197                 ))
198             return false;
199     }
200
201     {
202         LOCK(cs_mapAlerts);
203         // Cancel previous alerts
204         for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
205         {
206             const CAlert& alert = (*mi).second;
207             if (Cancels(alert))
208             {
209                 LogPrint("alert", "cancelling alert %d\n", alert.nID);
210                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
211                 mapAlerts.erase(mi++);
212             }
213             else if (!alert.IsInEffect())
214             {
215                 LogPrint("alert", "expiring alert %d\n", alert.nID);
216                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
217                 mapAlerts.erase(mi++);
218             }
219             else
220                 mi++;
221         }
222
223         // Check if this alert has been cancelled
224         BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
225         {
226             const CAlert& alert = item.second;
227             if (alert.Cancels(*this))
228             {
229                 LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
230                 return false;
231             }
232         }
233
234         // Add to mapAlerts
235         mapAlerts.insert(make_pair(GetHash(), *this));
236         // Notify UI and -alertnotify if it applies to me
237         if(AppliesToMe())
238         {
239             uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
240             Notify(strStatusBar, fThread);
241         }
242     }
243
244     LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
245     return true;
246 }
247
248 void
249 CAlert::Notify(const std::string& strMessage, bool fThread)
250 {
251     std::string strCmd = GetArg("-alertnotify", "");
252     if (strCmd.empty()) return;
253
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);
261
262     if (fThread)
263         boost::thread t(runCommand, strCmd); // thread runs free
264     else
265         runCommand(strCmd);
266 }
This page took 0.036502 seconds and 4 git commands to generate.