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