]> Git Repo - VerusCoin.git/blob - src/alert.cpp
Add support for spending keys to the encrypted wallet.
[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     strReserved.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(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         ")\n",
70         nVersion,
71         nRelayUntil,
72         nExpiration,
73         nID,
74         nCancel,
75         strSetCancel,
76         nMinVer,
77         nMaxVer,
78         strSetSubVer,
79         nPriority,
80         strComment,
81         strStatusBar);
82 }
83
84 void CAlert::SetNull()
85 {
86     CUnsignedAlert::SetNull();
87     vchMsg.clear();
88     vchSig.clear();
89 }
90
91 bool CAlert::IsNull() const
92 {
93     return (nExpiration == 0);
94 }
95
96 uint256 CAlert::GetHash() const
97 {
98     return Hash(this->vchMsg.begin(), this->vchMsg.end());
99 }
100
101 bool CAlert::IsInEffect() const
102 {
103     return (GetAdjustedTime() < nExpiration);
104 }
105
106 bool CAlert::Cancels(const CAlert& alert) const
107 {
108     if (!IsInEffect())
109         return false; // this was a no-op before 31403
110     return (alert.nID <= nCancel || setCancel.count(alert.nID));
111 }
112
113 bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
114 {
115     // TODO: rework for client-version-embedded-in-strSubVer ?
116     return (IsInEffect() &&
117             nMinVer <= nVersion && nVersion <= nMaxVer &&
118             (setSubVer.empty() || setSubVer.count(strSubVerIn)));
119 }
120
121 bool CAlert::AppliesToMe() const
122 {
123     return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
124 }
125
126 bool CAlert::RelayTo(CNode* pnode) const
127 {
128     if (!IsInEffect())
129         return false;
130     // don't relay to nodes which haven't sent their version message
131     if (pnode->nVersion == 0)
132         return false;
133     // returns true if wasn't already contained in the set
134     if (pnode->setKnown.insert(GetHash()).second)
135     {
136         if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
137             AppliesToMe() ||
138             GetAdjustedTime() < nRelayUntil)
139         {
140             pnode->PushMessage("alert", *this);
141             return true;
142         }
143     }
144     return false;
145 }
146
147 bool CAlert::CheckSignature(const std::vector<unsigned char>& alertKey) const
148 {
149     CPubKey key(alertKey);
150     if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
151         return error("CAlert::CheckSignature(): verify signature failed");
152
153     // Now unserialize the data
154     CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
155     sMsg >> *(CUnsignedAlert*)this;
156     return true;
157 }
158
159 CAlert CAlert::getAlertByHash(const uint256 &hash)
160 {
161     CAlert retval;
162     {
163         LOCK(cs_mapAlerts);
164         map<uint256, CAlert>::iterator mi = mapAlerts.find(hash);
165         if(mi != mapAlerts.end())
166             retval = mi->second;
167     }
168     return retval;
169 }
170
171 bool CAlert::ProcessAlert(const std::vector<unsigned char>& alertKey, bool fThread)
172 {
173     if (!CheckSignature(alertKey))
174         return false;
175     if (!IsInEffect())
176         return false;
177
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)
187     {
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"
196                 ))
197             return false;
198     }
199
200     {
201         LOCK(cs_mapAlerts);
202         // Cancel previous alerts
203         for (map<uint256, CAlert>::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();)
204         {
205             const CAlert& alert = (*mi).second;
206             if (Cancels(alert))
207             {
208                 LogPrint("alert", "cancelling alert %d\n", alert.nID);
209                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
210                 mapAlerts.erase(mi++);
211             }
212             else if (!alert.IsInEffect())
213             {
214                 LogPrint("alert", "expiring alert %d\n", alert.nID);
215                 uiInterface.NotifyAlertChanged((*mi).first, CT_DELETED);
216                 mapAlerts.erase(mi++);
217             }
218             else
219                 mi++;
220         }
221
222         // Check if this alert has been cancelled
223         BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
224         {
225             const CAlert& alert = item.second;
226             if (alert.Cancels(*this))
227             {
228                 LogPrint("alert", "alert already cancelled by %d\n", alert.nID);
229                 return false;
230             }
231         }
232
233         // Add to mapAlerts
234         mapAlerts.insert(make_pair(GetHash(), *this));
235         // Notify UI and -alertnotify if it applies to me
236         if(AppliesToMe())
237         {
238             uiInterface.NotifyAlertChanged(GetHash(), CT_NEW);
239             Notify(strStatusBar, fThread);
240         }
241     }
242
243     LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe());
244     return true;
245 }
246
247 void
248 CAlert::Notify(const std::string& strMessage, bool fThread)
249 {
250     std::string strCmd = GetArg("-alertnotify", "");
251     if (strCmd.empty()) return;
252
253     // Alert text should be plain ascii coming from a trusted source, but to
254     // be safe we first strip anything not in safeChars, then add single quotes around
255     // the whole string before passing it to the shell:
256     std::string singleQuote("'");
257     std::string safeStatus = SanitizeString(strMessage);
258     safeStatus = singleQuote+safeStatus+singleQuote;
259     boost::replace_all(strCmd, "%s", safeStatus);
260
261     if (fThread)
262         boost::thread t(runCommand, strCmd); // thread runs free
263     else
264         runCommand(strCmd);
265 }
This page took 0.038582 seconds and 4 git commands to generate.