version 0.2.17
[fms.git] / src / freenet / introductionpuzzleinserter.cpp
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 #include "../../include/uuidgenerator.h"\r
7 #include "../../include/base64.h"\r
8 \r
9 #ifdef XMEM\r
10         #include <xmem.h>\r
11 #endif\r
12 \r
13 IntroductionPuzzleInserter::IntroductionPuzzleInserter():IIndexInserter<long>()\r
14 {\r
15         Initialize();\r
16 }\r
17 \r
18 IntroductionPuzzleInserter::IntroductionPuzzleInserter(FCPv2 *fcp):IIndexInserter<long>(fcp)\r
19 {\r
20         Initialize();\r
21 }\r
22 \r
23 void IntroductionPuzzleInserter::CheckForNeededInsert()\r
24 {\r
25         // only do 1 insert at a time\r
26         if(m_inserting.size()==0)\r
27         {\r
28                 // select all local ids that aren't single use and that aren't currently inserting a puzzle and are publishing a trust list\r
29                 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
30                 \r
31                 while(!rs.AtEnd())\r
32                 {\r
33                         std::string localidentityidstr;\r
34                         DateTime now;\r
35                         now.SetToGMTime();\r
36 \r
37                         if(rs.GetField(0))\r
38                         {\r
39                                 localidentityidstr=rs.GetField(0);\r
40                         }\r
41 \r
42                         // if this identity has any non-solved puzzles for today, we don't need to insert a new puzzle\r
43                         SQLite3DB::Recordset rs2=m_db->Query("SELECT UUID FROM tblIntroductionPuzzleInserts WHERE Day='"+now.Format("%Y-%m-%d")+"' AND FoundSolution='false' AND LocalIdentityID="+localidentityidstr+";");\r
44 \r
45                         // identity doesn't have any non-solved puzzles for today - start a new insert\r
46                         if(rs2.Empty()==true)\r
47                         {\r
48                                 StartInsert(rs.GetInt(0));\r
49                         }\r
50 \r
51                         rs.Next();\r
52                 }\r
53         }\r
54 }\r
55 \r
56 void IntroductionPuzzleInserter::GenerateCaptcha(std::string &encodeddata, std::string &solution)\r
57 {\r
58         SimpleCaptcha captcha;\r
59         std::vector<unsigned char> puzzle;\r
60         std::vector<unsigned char> puzzlesolution;\r
61 \r
62         captcha.Generate();\r
63         captcha.GetPuzzle(puzzle);\r
64         captcha.GetSolution(puzzlesolution);\r
65 \r
66         encodeddata.clear();\r
67         solution.clear();\r
68 \r
69         Base64::Encode(puzzle,encodeddata);\r
70         solution.insert(solution.begin(),puzzlesolution.begin(),puzzlesolution.end());\r
71 \r
72 }\r
73 \r
74 const bool IntroductionPuzzleInserter::HandlePutFailed(FCPMessage &message)\r
75 {\r
76         SQLite3DB::Statement st;\r
77         std::vector<std::string> idparts;\r
78         long localidentityid;\r
79 \r
80         StringFunctions::Split(message["Identifier"],"|",idparts);\r
81         StringFunctions::Convert(idparts[1],localidentityid);\r
82 \r
83         // non USK\r
84         if(idparts[0]==m_fcpuniquename)\r
85         {\r
86                 // if fatal error or collision - mark index\r
87                 if(message["Fatal"]=="true" || message["Code"]=="9")\r
88                 {\r
89                         m_db->Execute("UPDATE tblIntroductionPuzzleInserts SET Day='"+idparts[5]+"', InsertIndex="+idparts[2]+", FoundSolution='true' WHERE UUID='"+idparts[3]+"';");\r
90                 }\r
91 \r
92                 RemoveFromInsertList(localidentityid);\r
93 \r
94                 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IntroductionPuzzleInserter::HandlePutFailed failed to insert puzzle "+idparts[3]);\r
95         }\r
96 \r
97         return true;\r
98 }\r
99 \r
100 const bool IntroductionPuzzleInserter::HandlePutSuccessful(FCPMessage &message)\r
101 {\r
102         DateTime now;\r
103         SQLite3DB::Statement st;\r
104         std::vector<std::string> idparts;\r
105         long localidentityid;\r
106         long insertindex;\r
107 \r
108         now.SetToGMTime();\r
109         StringFunctions::Split(message["Identifier"],"|",idparts);\r
110 \r
111         // non USK\r
112         if(idparts[0]==m_fcpuniquename)\r
113         {\r
114                 StringFunctions::Convert(idparts[1],localidentityid);\r
115                 StringFunctions::Convert(idparts[2],insertindex);\r
116 \r
117                 st=m_db->Prepare("UPDATE tblIntroductionPuzzleInserts SET Day=?, InsertIndex=? WHERE UUID=?;");\r
118                 st.Bind(0,idparts[5]);\r
119                 st.Bind(1,insertindex);\r
120                 st.Bind(2,idparts[3]);\r
121                 st.Step();\r
122                 st.Finalize();\r
123 \r
124                 st=m_db->Prepare("UPDATE tblLocalIdentity SET LastInsertedPuzzle=? WHERE LocalIdentityID=?;");\r
125                 st.Bind(0,now.Format("%Y-%m-%d %H:%M:%S"));\r
126                 st.Bind(1,localidentityid);\r
127                 st.Step();\r
128                 st.Finalize();\r
129 \r
130                 RemoveFromInsertList(localidentityid);\r
131 \r
132                 m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IntroductionPuzzleInserter::HandlePutSuccessful inserted puzzle "+idparts[3]);\r
133         }\r
134 \r
135         return true;\r
136 }\r
137 \r
138 void IntroductionPuzzleInserter::Initialize()\r
139 {\r
140         m_fcpuniquename="IntroductionPuzzleInserter";\r
141 }\r
142 \r
143 const bool IntroductionPuzzleInserter::StartInsert(const long &localidentityid)\r
144 {\r
145         DateTime now;\r
146         std::string idstring;\r
147         long index=0;\r
148         std::string indexstr;\r
149         UUIDGenerator uuid;\r
150         std::string messagebase;\r
151         IntroductionPuzzleXML xml;\r
152         std::string encodedpuzzle;\r
153         std::string solutionstring;\r
154         FCPMessage message;\r
155         std::string xmldata;\r
156         std::string xmldatasizestr;\r
157         std::string privatekey="";\r
158         std::string publickey="";\r
159         std::string keypart="";\r
160 \r
161         StringFunctions::Convert(localidentityid,idstring);\r
162         now.SetToGMTime();\r
163         SQLite3DB::Recordset rs=m_db->Query("SELECT MAX(InsertIndex) FROM tblIntroductionPuzzleInserts WHERE Day='"+now.Format("%Y-%m-%d")+"' AND LocalIdentityID="+idstring+";");\r
164 \r
165         if(rs.Empty() || rs.GetField(0)==NULL)\r
166         {\r
167                 index=0;\r
168         }\r
169         else\r
170         {\r
171                 index=rs.GetInt(0)+1;\r
172         }\r
173         StringFunctions::Convert(index,indexstr);\r
174 \r
175         SQLite3DB::Recordset rs2=m_db->Query("SELECT PrivateKey,PublicKey FROM tblLocalIdentity WHERE LocalIdentityID="+idstring+";");\r
176         if(rs2.Empty()==false && rs2.GetField(0)!=NULL)\r
177         {\r
178                 privatekey=rs2.GetField(0);\r
179                 if(rs2.GetField(1))\r
180                 {\r
181                         publickey=rs2.GetField(1);\r
182                 }\r
183                 if(publickey.size()>=50)\r
184                 {\r
185                         // remove - and ~\r
186                         keypart=StringFunctions::Replace(StringFunctions::Replace(publickey.substr(4,43),"-",""),"~","");\r
187                 }\r
188         }\r
189 \r
190         Option::Instance()->Get("MessageBase",messagebase);\r
191 \r
192         GenerateCaptcha(encodedpuzzle,solutionstring);\r
193 \r
194         xml.SetType("captcha");\r
195         xml.SetUUID(uuid.Generate()+"@"+keypart);\r
196         xml.SetPuzzleData(encodedpuzzle);\r
197         xml.SetMimeType("image/bmp");\r
198 \r
199         xmldata=xml.GetXML();\r
200         StringFunctions::Convert(xmldata.size(),xmldatasizestr);\r
201 \r
202         message.SetName("ClientPut");\r
203         message["URI"]=privatekey+messagebase+"|"+now.Format("%Y-%m-%d")+"|IntroductionPuzzle|"+indexstr+".xml";\r
204         message["Identifier"]=m_fcpuniquename+"|"+idstring+"|"+indexstr+"|"+xml.GetUUID()+"|"+message["URI"];\r
205         message["UploadFrom"]="direct";\r
206         message["DataLength"]=xmldatasizestr;\r
207         m_fcp->SendMessage(message);\r
208         m_fcp->SendRaw(xmldata.c_str(),xmldata.size());\r
209 \r
210         // insert to USK\r
211         message.Reset();\r
212         message.SetName("ClientPutComplexDir");\r
213         message["URI"]="USK"+privatekey.substr(3)+messagebase+"|"+now.Format("%Y.%m.%d")+"|IntroductionPuzzle/0/";\r
214         message["Identifier"]=m_fcpuniquename+"USK|"+message["URI"];\r
215         message["DefaultName"]="IntroductionPuzzle.xml";\r
216         message["Files.0.Name"]="IntroductionPuzzle.xml";\r
217         message["Files.0.UplaodFrom"]="direct";\r
218         message["Files.0.DataLength"]=xmldatasizestr;\r
219         m_fcp->SendMessage(message);\r
220         m_fcp->SendRaw(xmldata.c_str(),xmldata.size());\r
221 \r
222         m_db->Execute("INSERT INTO tblIntroductionPuzzleInserts(UUID,Type,MimeType,LocalIdentityID,PuzzleData,PuzzleSolution) VALUES('"+xml.GetUUID()+"','captcha','image/bmp',"+idstring+",'"+encodedpuzzle+"','"+solutionstring+"');");\r
223 \r
224         m_inserting.push_back(localidentityid);\r
225 \r
226         m_log->WriteLog(LogFile::LOGLEVEL_DEBUG,"IntroductionPuzzleInserter::StartInsert started insert for id "+idstring);\r
227 \r
228         return true;\r
229 \r
230 }\r