1 #include "../../include/freenet/introductionpuzzleinserter.h"
\r
2 #include "../../include/freenet/introductionpuzzlexml.h"
\r
3 #include "../../include/stringfunctions.h"
\r
4 #include "../../include/option.h"
\r
5 #include "../../include/freenet/captcha/simplecaptcha.h"
\r
6 #ifdef ALTERNATE_CAPTCHA
\r
7 #include "../../include/freenet/captcha/alternatecaptcha1.h"
\r
8 #include "../../include/freenet/captcha/alternatecaptcha2.h"
\r
10 #include "../../include/base64.h"
\r
12 #include <Poco/DateTimeFormatter.h>
\r
13 #include <Poco/UUIDGenerator.h>
\r
14 #include <Poco/UUID.h>
\r
20 IntroductionPuzzleInserter::IntroductionPuzzleInserter():IIndexInserter<long>()
\r
25 IntroductionPuzzleInserter::IntroductionPuzzleInserter(FCPv2 *fcp):IIndexInserter<long>(fcp)
\r
30 void IntroductionPuzzleInserter::CheckForNeededInsert()
\r
32 // only do 1 insert at a time
\r
33 if(m_inserting.size()==0)
\r
35 // select all local ids that aren't single use and that aren't currently inserting a puzzle and are publishing a trust list
\r
36 SQLite3DB::Recordset rs=m_db->Query("SELECT LocalIdentityID FROM tblLocalIdentity WHERE PublishTrustList='true' AND SingleUse='false' AND PrivateKey IS NOT NULL AND PrivateKey <> '' ORDER BY LastInsertedPuzzle;");
\r
40 int localidentityid=0;
\r
41 std::string localidentityidstr="";
\r
43 float minutesbetweeninserts=0;
\r
44 minutesbetweeninserts=1440.0/(float)m_maxpuzzleinserts;
\r
45 Poco::DateTime lastinsert=now;
\r
46 lastinsert-=Poco::Timespan(0,0,minutesbetweeninserts,0,0);
\r
50 localidentityidstr=rs.GetField(0);
\r
53 // if this identity has any non-solved puzzles for today, we don't need to insert a new puzzle
\r
54 SQLite3DB::Recordset rs2=m_db->Query("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE Day='"+Poco::DateTimeFormatter::format(now,"%Y-%m-%d")+"' AND FoundSolution='false' AND LocalIdentityID="+localidentityidstr+";");
\r
56 // identity doesn't have any non-solved puzzles for today - start a new insert
\r
57 if(rs2.Empty()==true)
\r
59 // make sure we are on the next day or the appropriate amount of time has elapsed since the last insert
\r
60 if(m_lastinserted.find(rs.GetInt(0))==m_lastinserted.end() || m_lastinserted[rs.GetInt(0)]<=lastinsert || m_lastinserted[rs.GetInt(0)].day()!=now.day())
\r
62 StartInsert(rs.GetInt(0));
\r
63 m_lastinserted[rs.GetInt(0)]=now;
\r
67 m_log->trace("IntroductionPuzzleInserter::CheckForNeededInsert waiting to insert puzzle for "+localidentityidstr);
\r
76 void IntroductionPuzzleInserter::GenerateCaptcha(std::string &encodeddata, std::string &solution)
\r
79 #ifdef ALTERNATE_CAPTCHA
\r
82 cap=new AlternateCaptcha1();
\r
86 cap=new AlternateCaptcha2();
\r
88 m_log->trace("IntroductionPuzzleInserter::GenerateCaptcha using alternate captcha generator");
\r
90 cap=new SimpleCaptcha();
\r
92 std::vector<unsigned char> puzzle;
\r
93 std::vector<unsigned char> puzzlesolution;
\r
96 cap->GetPuzzle(puzzle);
\r
97 cap->GetSolution(puzzlesolution);
\r
99 encodeddata.clear();
\r
102 Base64::Encode(puzzle,encodeddata);
\r
103 solution.insert(solution.begin(),puzzlesolution.begin(),puzzlesolution.end());
\r
109 const bool IntroductionPuzzleInserter::HandlePutFailed(FCPMessage &message)
\r
111 SQLite3DB::Statement st;
\r
112 std::vector<std::string> idparts;
\r
113 long localidentityid;
\r
115 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
116 StringFunctions::Convert(idparts[1],localidentityid);
\r
119 if(idparts[0]==m_fcpuniquename)
\r
121 // if fatal error or collision - mark index
\r
122 if(message["Fatal"]=="true" || message["Code"]=="9")
\r
124 m_db->Execute("UPDATE tblIntroductionPuzzleInserts SET Day='"+idparts[5]+"', InsertIndex="+idparts[2]+", FoundSolution='true' WHERE UUID='"+idparts[3]+"';");
\r
127 RemoveFromInsertList(localidentityid);
\r
129 m_log->debug("IntroductionPuzzleInserter::HandlePutFailed failed to insert puzzle "+idparts[3]);
\r
135 const bool IntroductionPuzzleInserter::HandlePutSuccessful(FCPMessage &message)
\r
137 Poco::DateTime now;
\r
138 SQLite3DB::Statement st;
\r
139 std::vector<std::string> idparts;
\r
140 long localidentityid;
\r
143 StringFunctions::Split(message["Identifier"],"|",idparts);
\r
146 if(idparts[0]==m_fcpuniquename)
\r
148 StringFunctions::Convert(idparts[1],localidentityid);
\r
149 StringFunctions::Convert(idparts[2],insertindex);
\r
151 st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET Day=?, InsertIndex=? WHERE UUID=?;");
\r
152 st.Bind(0,idparts[5]);
\r
153 st.Bind(1,insertindex);
\r
154 st.Bind(2,idparts[3]);
\r
158 st=m_db->Prepare("UPDATE tblLocalIdentity SET LastInsertedPuzzle=? WHERE LocalIdentityID=?;");
\r
159 st.Bind(0,Poco::DateTimeFormatter::format(now,"%Y-%m-%d %H:%M:%S"));
\r
160 st.Bind(1,localidentityid);
\r
164 RemoveFromInsertList(localidentityid);
\r
166 m_log->debug("IntroductionPuzzleInserter::HandlePutSuccessful inserted puzzle "+idparts[3]);
\r
172 void IntroductionPuzzleInserter::Initialize()
\r
174 m_fcpuniquename="IntroductionPuzzleInserter";
\r
175 m_maxpuzzleinserts=50;
\r
178 const bool IntroductionPuzzleInserter::StartInsert(const long &localidentityid)
\r
180 Poco::DateTime now;
\r
181 std::string idstring="";
\r
183 std::string indexstr="";
\r
184 Poco::UUIDGenerator uuidgen;
\r
186 std::string messagebase="";
\r
187 IntroductionPuzzleXML xml;
\r
188 std::string encodedpuzzle="";
\r
189 std::string solutionstring="";
\r
190 FCPMessage message;
\r
191 std::string xmldata="";
\r
192 std::string xmldatasizestr="";
\r
193 std::string privatekey="";
\r
194 std::string publickey="";
\r
195 std::string keypart="";
\r
197 StringFunctions::Convert(localidentityid,idstring);
\r
198 SQLite3DB::Recordset rs=m_db->Query("SELECT MAX(InsertIndex) FROM tblIntroductionPuzzleInserts WHERE Day='"+Poco::DateTimeFormatter::format(now,"%Y-%m-%d")+"' AND LocalIdentityID="+idstring+";");
\r
200 if(rs.Empty() || rs.GetField(0)==NULL)
\r
206 index=rs.GetInt(0)+1;
\r
208 StringFunctions::Convert(index,indexstr);
\r
210 if(index<m_maxpuzzleinserts)
\r
212 SQLite3DB::Recordset rs2=m_db->Query("SELECT PrivateKey,PublicKey FROM tblLocalIdentity WHERE LocalIdentityID="+idstring+";");
\r
213 if(rs2.Empty()==false && rs2.GetField(0)!=NULL)
\r
215 privatekey=rs2.GetField(0);
\r
216 if(rs2.GetField(1))
\r
218 publickey=rs2.GetField(1);
\r
220 if(publickey.size()>=50)
\r
223 keypart=StringFunctions::Replace(StringFunctions::Replace(publickey.substr(4,43),"-",""),"~","");
\r
227 Option::Instance()->Get("MessageBase",messagebase);
\r
229 GenerateCaptcha(encodedpuzzle,solutionstring);
\r
230 if(encodedpuzzle.size()==0)
\r
232 m_log->fatal("IntroductionPuzzleInserter::StartInsert could not create introduction puzzle");
\r
238 uuid=uuidgen.createRandom();
\r
242 m_log->fatal("IntroductionPuzzleInserter::StartInsert could not create UUID");
\r
245 xml.SetType("captcha");
\r
246 std::string uuidstr=uuid.toString();
\r
247 StringFunctions::UpperCase(uuidstr,uuidstr);
\r
248 xml.SetUUID(uuidstr+"@"+keypart);
\r
249 xml.SetPuzzleData(encodedpuzzle);
\r
250 xml.SetMimeType("image/bmp");
\r
252 xmldata=xml.GetXML();
\r
253 StringFunctions::Convert(xmldata.size(),xmldatasizestr);
\r
255 message.SetName("ClientPut");
\r
256 message["URI"]=privatekey+messagebase+"|"+Poco::DateTimeFormatter::format(now,"%Y-%m-%d")+"|IntroductionPuzzle|"+indexstr+".xml";
\r
257 message["Identifier"]=m_fcpuniquename+"|"+idstring+"|"+indexstr+"|"+xml.GetUUID()+"|"+message["URI"];
\r
258 message["UploadFrom"]="direct";
\r
259 message["DataLength"]=xmldatasizestr;
\r
260 m_fcp->SendMessage(message);
\r
261 m_fcp->SendRaw(xmldata.c_str(),xmldata.size());
\r
265 message.SetName("ClientPutComplexDir");
\r
266 message["URI"]="USK"+privatekey.substr(3)+messagebase+"|"+Poco::DateTimeFormatter::format(now,"%Y.%m.%d")+"|IntroductionPuzzle/0/";
\r
267 message["Identifier"]=m_fcpuniquename+"USK|"+message["URI"];
\r
268 message["DefaultName"]="IntroductionPuzzle.xml";
\r
269 message["Files.0.Name"]="IntroductionPuzzle.xml";
\r
270 message["Files.0.UplaodFrom"]="direct";
\r
271 message["Files.0.DataLength"]=xmldatasizestr;
\r
272 m_fcp->SendMessage(message);
\r
273 m_fcp->SendRaw(xmldata.c_str(),xmldata.size());
\r
275 m_db->Execute("INSERT INTO tblIntroductionPuzzleInserts(UUID,Type,MimeType,LocalIdentityID,PuzzleData,PuzzleSolution) VALUES('"+xml.GetUUID()+"','captcha','image/bmp',"+idstring+",'"+encodedpuzzle+"','"+solutionstring+"');");
\r
277 m_inserting.push_back(localidentityid);
\r
279 m_log->debug("IntroductionPuzzleInserter::StartInsert started insert for id "+idstring);
\r
283 m_log->warning("IntroductionPuzzleInserter::StartInsert already inserted max puzzles for "+idstring);
\r