]> Git Repo - VerusCoin.git/blob - src/alert.cpp
Merge pull request #3649
[VerusCoin.git] / src / alert.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 The Bitcoin developers
3 // Distributed under the MIT/X11 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 "key.h"
9 #include "net.h"
10 #include "ui_interface.h"
11 #include "util.h"
12
13 #include <algorithm>
14 #include <inttypes.h>
15 #include <map>
16
17 #include <boost/algorithm/string/classification.hpp>
18 #include <boost/algorithm/string/replace.hpp>
19 #include <boost/foreach.hpp>
20
21 using namespace std;
22
23 map<uint256, CAlert> mapAlerts;
24 CCriticalSection cs_mapAlerts;
25
26 void CUnsignedAlert::SetNull()
27 {
28     nVersion = 1;
29     nRelayUntil = 0;
30     nExpiration = 0;
31     nID = 0;
32     nCancel = 0;
33     setCancel.clear();
34     nMinVer = 0;
35     nMaxVer = 0;
36     setSubVer.clear();
37     nPriority = 0;
38
39     strComment.clear();
40     strStatusBar.clear();
41     strReserved.clear();
42 }
43
44 std::string CUnsignedAlert::ToString() const
45 {
46     std::string strSetCancel;
47     BOOST_FOREACH(int n, setCancel)
48         strSetCancel += strprintf("%d ", n);
49     std::string strSetSubVer;
50     BOOST_FOREACH(std::string str, setSubVer)
51         strSetSubVer += "\"" + str + "\" ";
52     return strprintf(
53         "CAlert(\n"
54         "    nVersion     = %d\n"
55         "    nRelayUntil  = %"PRId64"\n"
56         "    nExpiration  = %"PRId64"\n"
57         "    nID          = %d\n"
58         "    nCancel      = %d\n"
59         "    setCancel    = %s\n"
60         "    nMinVer      = %d\n"
61         "    nMaxVer      = %d\n"
62         "    setSubVer    = %s\n"
63         "    nPriority    = %d\n"
64         "    strComment   = \"%s\"\n"
65         "    strStatusBar = \"%s\"\n"
66         ")\n",
67         nVersion,
68         nRelayUntil,
69         nExpiration,
70         nID,
71         nCancel,
72         strSetCancel,
73         nMinVer,
74         nMaxVer,
75         strSetSubVer,
76         nPriority,
77         strComment,
78         strStatusBar);
79 }
80
81 void CUnsignedAlert::print() const
82 {
83     LogPrintf("%s", ToString());
84 }
85
86 void CAlert::SetNull()
87 {
88     CUnsignedAlert::SetNull();
89     vchMsg.clear();
90     vchSig.clear();
91 }
92
93 bool CAlert::IsNull() const
94 {
95     return (nExpiration == 0);
96 }
97
98 uint256 CAlert::GetHash() const
99 {
100     return Hash(this->vchMsg.begin(), this->vchMsg.end());
101 }
102
103 bool CAlert::IsInEffect() const
104 {
105     return (GetAdjustedTime() < nExpiration);
106 }
107
108 bool CAlert::Cancels(const CAlert& alert) const
109 {
110     if (!IsInEffect())
111         return false; // this was a no-op before 31403
112     return (alert.nID <= nCancel || setCancel.count(alert.nID));
113 }
114
115 bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
116 {
117     // TODO: rework for client-version-embedded-in-strSubVer ?
118     return (IsInEffect() &&
119             nMinVer <= nVersion && nVersion <= nMaxVer &&
120             (setSubVer.empty() || setSubVer.count(strSubVerIn)));
121 }
122
123 bool CAlert::AppliesToMe() const
124 {
125     return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
126 }
127
128 bool CAlert::RelayTo(CNode* pnode) const
129 {
130     if (!IsInEffect())
131         return false;
132     // returns true if wasn't already contained in the set
133     if (pnode->setKnown.insert(GetHash()).second)
134     {
135         if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
136             AppliesToMe() ||
137             GetAdjustedTime() < nRelayUntil)
138         {
139             pnode->PushMessage("alert", *this);
140             return true;
141         }
142     }
143     return false;
144 }
145
146 bool CAlert::CheckSignature() const
147 {
148     CPubKey key(Params().AlertKey());
149     if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
150         return error("CAlert::CheckSignature() : verify signature failed");
151
152     // Now unserialize the data
153     CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
154     sMsg >> *(CUnsignedAlert*)this;
155     return true;
156 }
157
158 CAlert CAlert::getAlertByHash(const uint256 &hash)
159 {
160     CAlert retval;
161     {
162         LOCK(cs_mapAlerts);
163         map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
164         if(mi != mapAlerts.end())
165             retval = mi->second;
166     }
167     return retval;
168 }
169
170 bool CAlert::ProcessAlert(bool fThread)
171 {
172     if (!CheckSignature())
173         return false;
174     if (!IsInEffect())
175         return false;
176
177     // alert.nID=max is reserved for if the alert key is
178     // compromised. It must have a pre-defined message,
179     // must never expire, must apply to all versions,
180     // and must cancel all previous
181     // alerts or it will be ignored (so an attacker can't
182     // send an "everything is OK, don't panic" version that
183     // cannot be overridden):
184     int maxInt = std::numeric_limits<int>::max();
185     if (nID == maxInt)
186     {
187         if (!(
188                 nExpiration == maxInt &&
189                 nCancel == (maxInt-1) &&
190                 nMinVer == 0 &&
191                 nMaxVer == maxInt &&
192                 setSubVer.empty() &&
193                 nPriority == maxInt &&
194                 strStatusBar == "URGENT: Alert key compromised, upgrade required"
195                 ))
196             return false;
197     }
198
199     {
200         LOCK(cs_mapAlerts);
201         // Cancel previous alerts
202         for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
203         {
204             const CAlert& alert = (*mi).second;
205             if (Cancels(alert))
206             {
207                 LogPrint("alert", "cancelling alert %d\n", alert.nID);
208                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
209                 mapAlerts.erase(mi++);
210             }
211             else if (!alert.IsInEffect())
212             {
213                 LogPrint("alert", "expiring alert %d\n", alert.nID);
214                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
215                 mapAlerts.erase(mi++);
216             }
217             else
218                 mi++;
219         }
220
221         // Check if this alert has been cancelled
222         BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
223         {
224             const CAlert& alert = item.second;
225             if (alert.Cancels(*this))
226             {
227                 LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
228                 return false;
229             }
230         }
231
232         // Add to mapAlerts
233         mapAlerts.insert(make_pair(GetHash(), *this));
234         // Notify UI and -alertnotify if it applies to me
235         if(AppliesToMe())
236         {
237             uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
238             std::string strCmd = GetArg("-alertnotify", "");
239             if (!strCmd.empty())
240             {
241                 // Alert text should be plain ascii coming from a trusted source, but to
242                 // be safe we first strip anything not in safeChars, then add single quotes around
243                 // the whole string before passing it to the shell:
244                 std::string singleQuote("'");
245                 std::string safeStatus = SanitizeString(strStatusBar);
246                 safeStatus = singleQuote+safeStatus+singleQuote;
247                 boost::replace_all(strCmd, "%s", safeStatus);
248
249                 if (fThread)
250                     boost::thread t(runCommand, strCmd); // thread runs free
251                 else
252                     runCommand(strCmd);
253             }
254         }
255     }
256
257     LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
258     return true;
259 }
This page took 0.035825 seconds and 4 git commands to generate.