]> Git Repo - VerusCoin.git/blob - src/alert.cpp
Bump secp256k1 subtree
[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 "clientversion.h"
9 #include "net.h"
10 #include "pubkey.h"
11 #include "timedata.h"
12 #include "ui_interface.h"
13 #include "util.h"
14
15 #include <stdint.h>
16 #include <algorithm>
17 #include <map>
18
19 #include <boost/algorithm/string/classification.hpp>
20 #include <boost/algorithm/string/replace.hpp>
21 #include <boost/foreach.hpp>
22 #include <boost/thread.hpp>
23
24 using namespace std;
25
26 map<uint256, CAlert> mapAlerts;
27 CCriticalSection cs_mapAlerts;
28
29 void CUnsignedAlert::SetNull()
30 {
31     nVersion = 1;
32     nRelayUntil = 0;
33     nExpiration = 0;
34     nID = 0;
35     nCancel = 0;
36     setCancel.clear();
37     nMinVer = 0;
38     nMaxVer = 0;
39     setSubVer.clear();
40     nPriority = 0;
41
42     strComment.clear();
43     strStatusBar.clear();
44     strRPCError.clear();
45 }
46
47 std::string CUnsignedAlert::ToString() const
48 {
49     std::string strSetCancel;
50     BOOST_FOREACH(int n, setCancel)
51         strSetCancel += strprintf("%d ", n);
52     std::string strSetSubVer;
53     BOOST_FOREACH(const std::string& str, setSubVer)
54         strSetSubVer += "\"" + str + "\" ";
55     return strprintf(
56         "CAlert(\n"
57         "    nVersion     = %d\n"
58         "    nRelayUntil  = %d\n"
59         "    nExpiration  = %d\n"
60         "    nID          = %d\n"
61         "    nCancel      = %d\n"
62         "    setCancel    = %s\n"
63         "    nMinVer      = %d\n"
64         "    nMaxVer      = %d\n"
65         "    setSubVer    = %s\n"
66         "    nPriority    = %d\n"
67         "    strComment   = \"%s\"\n"
68         "    strStatusBar = \"%s\"\n"
69         "    strRPCError  = \"%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         strRPCError);
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, const 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     // don't relay to nodes which haven't sent their version message
133     if (pnode->nVersion == 0)
134         return false;
135     // returns true if wasn't already contained in the set
136     if (pnode->setKnown.insert(GetHash()).second)
137     {
138         if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
139             AppliesToMe() ||
140             GetAdjustedTime() < nRelayUntil)
141         {
142             pnode->PushMessage("alert", *this);
143             return true;
144         }
145     }
146     return false;
147 }
148
149 bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
150 {
151     CPubKey key(alertKey);
152     if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
153         return error("CAlert::CheckSignature(): verify signature failed");
154
155     // Now unserialize the data
156     CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
157     sMsg >> *(CUnsignedAlert*)this;
158     return true;
159 }
160
161 CAlert CAlert::getAlertByHash(const uint256 &hash)
162 {
163     CAlert retval;
164     {
165         LOCK(cs_mapAlerts);
166         map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
167         if(mi != mapAlerts.end())
168             retval = mi->second;
169     }
170     return retval;
171 }
172
173 bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
174 {
175     if (!CheckSignature(alertKey))
176         return false;
177     if (!IsInEffect())
178         return false;
179
180     // alert.nID=max is reserved for if the alert key is
181     // compromised. It must have a pre-defined message,
182     // must never expire, must apply to all versions,
183     // and must cancel all previous
184     // alerts or it will be ignored (so an attacker can't
185     // send an "everything is OK, don't panic" version that
186     // cannot be overridden):
187     int maxInt = std::numeric_limits<int>::max();
188     if (nID == maxInt)
189     {
190         if (!(
191                 nExpiration == maxInt &&
192                 nCancel == (maxInt-1) &&
193                 nMinVer == 0 &&
194                 nMaxVer == maxInt &&
195                 setSubVer.empty() &&
196                 nPriority == maxInt &&
197                 strStatusBar == "URGENT: Alert key compromised, upgrade required"
198                 ))
199             return false;
200     }
201
202     {
203         LOCK(cs_mapAlerts);
204         // Cancel previous alerts
205         for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
206         {
207             const CAlert& alert = (*mi).second;
208             if (Cancels(alert))
209             {
210                 LogPrint("alert", "cancelling alert %d\n", alert.nID);
211                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
212                 mapAlerts.erase(mi++);
213             }
214             else if (!alert.IsInEffect())
215             {
216                 LogPrint("alert", "expiring alert %d\n", alert.nID);
217                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
218                 mapAlerts.erase(mi++);
219             }
220             else
221                 mi++;
222         }
223
224         // Check if this alert has been cancelled
225         BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
226         {
227             const CAlert& alert = item.second;
228             if (alert.Cancels(*this))
229             {
230                 LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
231                 return false;
232             }
233         }
234
235         // Add to mapAlerts
236         mapAlerts.insert(make_pair(GetHash(), *this));
237         // Notify UI and -alertnotify if it applies to me
238         if(AppliesToMe())
239         {
240             uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
241             Notify(strStatusBar, fThread);
242         }
243     }
244
245     LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
246     return true;
247 }
248
249 void
250 CAlert::Notify(const std::string& strMessage, bool fThread)
251 {
252     std::string strCmd = GetArg("-alertnotify", "");
253     if (strCmd.empty()) return;
254
255     // Alert text should be plain ascii coming from a trusted source, but to
256     // be safe we first strip anything not in safeChars, then add single quotes around
257     // the whole string before passing it to the shell:
258     std::string singleQuote("'");
259     std::string safeStatus = SanitizeString(strMessage);
260     safeStatus = singleQuote+safeStatus+singleQuote;
261     boost::replace_all(strCmd, "%s", safeStatus);
262
263     if (fThread)
264         boost::thread t(runCommand, strCmd); // thread runs free
265     else
266         runCommand(strCmd);
267 }
This page took 0.038794 seconds and 4 git commands to generate.