otsdaq  v2_01_00
WizardSupervisor.cc
1 #include "otsdaq-core/WizardSupervisor/WizardSupervisor.h"
2 
3 #include "otsdaq-core/GatewaySupervisor/GatewaySupervisor.h"
4 
5 #include "otsdaq-core/MessageFacility/MessageFacility.h"
6 #include "otsdaq-core/Macros/CoutMacros.h"
7 
8 #include <xdaq/NamespaceURI.h>
9 #include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h"
10 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
11 #include "otsdaq-core/WebUsersUtilities/WebUsers.h"
12 #include "otsdaq-core/SOAPUtilities/SOAPUtilities.h"
13 #include "otsdaq-core/SOAPUtilities/SOAPCommand.h"
14 
15 #include <iostream>
16 #include <fstream>
17 #include <string>
18 #include <thread> // std::this_thread::sleep_for
19 #include <chrono> // std::chrono::seconds
20 #include <sys/stat.h> // mkdir
21 #include <dirent.h> //for DIR
22 
23 
24 
25 using namespace ots;
26 
27 
28 #define SECURITY_FILE_NAME std::string(getenv("SERVICE_DATA_PATH")) + "/OtsWizardData/security.dat"
29 #define SEQUENCE_FILE_NAME std::string(getenv("SERVICE_DATA_PATH")) + "/OtsWizardData/sequence.dat"
30 #define SEQUENCE_OUT_FILE_NAME std::string(getenv("SERVICE_DATA_PATH")) + "/OtsWizardData/sequence.out"
31 #define USER_DATA_PATH std::string(getenv("SERVICE_DATA_PATH")) + std::string("/")
32 //#define LOGBOOK_PREVIEWS_PATH "uploads/"
33 
34 #define XML_STATUS "editUserData_status"
35 
36 #define XML_ADMIN_STATUS "logbook_admin_status"
37 #define XML_MOST_RECENT_DAY "most_recent_day"
38 #define XML_EXPERIMENTS_ROOT "experiments"
39 #define XML_EXPERIMENT "experiment"
40 #define XML_ACTIVE_EXPERIMENT "active_experiment"
41 #define XML_EXPERIMENT_CREATE "create_time"
42 #define XML_EXPERIMENT_CREATOR "creator"
43 
44 #define XML_LOGBOOK_ENTRY "logbook_entry"
45 #define XML_LOGBOOK_ENTRY_SUBJECT "logbook_entry_subject"
46 #define XML_LOGBOOK_ENTRY_TEXT "logbook_entry_text"
47 #define XML_LOGBOOK_ENTRY_FILE "logbook_entry_file"
48 #define XML_LOGBOOK_ENTRY_TIME "logbook_entry_time"
49 #define XML_LOGBOOK_ENTRY_CREATOR "logbook_entry_creator"
50 #define XML_LOGBOOK_ENTRY_HIDDEN "logbook_entry_hidden"
51 #define XML_LOGBOOK_ENTRY_HIDER "logbook_entry_hider"
52 #define XML_LOGBOOK_ENTRY_HIDDEN_TIME "logbook_entry_hidden_time"
53 
54 #define XML_PREVIEW_INDEX "preview_index"
55 #define LOGBOOK_PREVIEW_FILE "preview.xml"
56 
57 
58 
59 XDAQ_INSTANTIATOR_IMPL(WizardSupervisor)
60 
61 
62 
63 #undef __MF_SUBJECT__
64 #define __MF_SUBJECT__ "Wizard"
65 
66 
67 //========================================================================================================================
68 WizardSupervisor::WizardSupervisor(xdaq::ApplicationStub * s) throw (xdaq::exception::Exception)
69 : xdaq::Application (s )
70 , SOAPMessenger (this)
71 , supervisorClass_ (getApplicationDescriptor()->getClassName())
72 , supervisorClassNoNamespace_ (supervisorClass_.substr(supervisorClass_.find_last_of(":")+1, supervisorClass_.length()-supervisorClass_.find_last_of(":")))
73 {
74  __SUP_COUT__ << "Constructor started." << __E__;
75 
76  INIT_MF("OtsConfigurationWizard");
77 
78 
79  //attempt to make directory structure (just in case)
80  mkdir((std::string(getenv("SERVICE_DATA_PATH"))).c_str(), 0755);
81  mkdir((std::string(getenv("SERVICE_DATA_PATH")) + "/OtsWizardData").c_str(), 0755);
82 
83  generateURL();
84  xgi::bind (this, &WizardSupervisor::Default, "Default" );
85  xgi::bind (this, &WizardSupervisor::verification, "Verify" );
86  xgi::bind (this, &WizardSupervisor::requestIcons, "requestIcons" );
87  xgi::bind (this, &WizardSupervisor::editSecurity, "editSecurity" );
88  xgi::bind (this, &WizardSupervisor::UserSettings, "UserSettings" );
89  xgi::bind (this, &WizardSupervisor::tooltipRequest, "TooltipRequest" );
90  xgi::bind (this, &WizardSupervisor::toggleSecurityCodeGeneration, "ToggleSecurityCodeGeneration" );
91  xoap::bind(this, &WizardSupervisor::supervisorSequenceCheck, "SupervisorSequenceCheck", XDAQ_NS_URI);
92  xoap::bind(this, &WizardSupervisor::supervisorLastConfigGroupRequest, "SupervisorLastConfigGroupRequest", XDAQ_NS_URI);
93  init();
94 
95  __SUP_COUT__ << "Constructor complete." << __E__;
96 }
97 
98 //========================================================================================================================
99 WizardSupervisor::~WizardSupervisor(void)
100 {
101  destroy();
102 }
103 
104 //========================================================================================================================
105 void WizardSupervisor::init(void)
106 {
107  //getApplicationContext();
108 
109  //init allowed file upload types
110  allowedFileUploadTypes_.push_back("image/png"); matchingFileUploadTypes_.push_back("png");
111  allowedFileUploadTypes_.push_back("image/jpeg"); matchingFileUploadTypes_.push_back("jpeg");
112  allowedFileUploadTypes_.push_back("image/gif"); matchingFileUploadTypes_.push_back("gif");
113  allowedFileUploadTypes_.push_back("image/bmp"); matchingFileUploadTypes_.push_back("bmp");
114  allowedFileUploadTypes_.push_back("application/pdf"); matchingFileUploadTypes_.push_back("pdf");
115  allowedFileUploadTypes_.push_back("application/zip"); matchingFileUploadTypes_.push_back("zip");
116  allowedFileUploadTypes_.push_back("text/plain"); matchingFileUploadTypes_.push_back("txt");
117 
118 
119 }
120 
121 //========================================================================================================================
122 void WizardSupervisor::generateURL()
123 {
124 
125  defaultSequence_ = true;
126 
127  int length = 4;
128  FILE *fp = fopen((SEQUENCE_FILE_NAME).c_str(),"r");
129  if(fp)
130  {
131  __COUT_INFO__ << "Sequence length file found: " << SEQUENCE_FILE_NAME << std::endl;
132  char line[100];
133  fgets(line,100,fp);
134  sscanf(line,"%d",&length);
135  fclose(fp);
136  if(length < 4)
137  length = 4; //don't allow shorter than 4
138  else
139  defaultSequence_ = false;
140  srand(time(0)); //randomize differently each "time"
141  }
142  else
143  {
144  __COUT_INFO__ << "(Reverting to default wiz security) Sequence length file NOT found: " << SEQUENCE_FILE_NAME << std::endl;
145  srand(0); //use same seed for convenience if file not found
146  }
147 
148  __COUT__ << "Sequence length = " << length << std::endl;
149 
150  securityCode_ = "";
151 
152  static const char alphanum[] =
153  "0123456789"
154  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
155  "abcdefghijklmnopqrstuvwxyz";
156 
157 
158  for (int i = 0; i < length; ++i) {
159  securityCode_ += alphanum[rand() % (sizeof(alphanum) - 1)];
160  }
161 
162  std::cout << __COUT_HDR_FL__ <<
163  getenv("OTS_CONFIGURATION_WIZARD_SUPERVISOR_SERVER") << ":" << getenv("PORT") <<
164  "/urn:xdaq-application:lid="
165  << this->getApplicationDescriptor()->getLocalId() << "/Verify?code=" << securityCode_ << std::endl;
166 
167  //Note: print out handled by StartOTS.sh now
168  //std::thread([&](WizardSupervisor *ptr, std::string securityCode)
169  // {printURL(ptr,securityCode);},this,securityCode_).detach();
170 
171  fp = fopen((SEQUENCE_OUT_FILE_NAME).c_str(),"w");
172  if(fp)
173  {
174  fprintf(fp,"%s",securityCode_.c_str());
175  fclose(fp);
176  }
177  else
178  __COUT_ERR__ << "Sequence output file NOT found: " << SEQUENCE_OUT_FILE_NAME << std::endl;
179 
180 
181  return;
182 }
183 
184 void WizardSupervisor::printURL(WizardSupervisor *ptr,
185  std::string securityCode)
186 {
187  INIT_MF("ConfigurationWizard");
188  // child process
189  int i = 0;
190  for (; i < 5; ++i)
191  {
192  std::this_thread::sleep_for (std::chrono::seconds(2));
193  std::cout << __COUT_HDR_FL__ <<
194  getenv("OTS_CONFIGURATION_WIZARD_SUPERVISOR_SERVER") << ":" << getenv("PORT") <<
195  "/urn:xdaq-application:lid="
196  << ptr->getApplicationDescriptor()->getLocalId() << "/Verify?code=" << securityCode << std::endl;
197  }
198 }
199 
200 //========================================================================================================================
201 void WizardSupervisor::destroy(void)
202 {
203  //called by destructor
204 
205 }
206 
207 
208 //========================================================================================================================
209 void WizardSupervisor::tooltipRequest(xgi::Input * in, xgi::Output * out)
210 throw (xgi::exception::Exception)
211 {
212  cgicc::Cgicc cgi(in);
213 
214  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
215  __COUT__ << "Command = " << Command << std::endl;
216 
217  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
218 
219  //SECURITY CHECK START ****
220  if(securityCode_.compare(submittedSequence) != 0)
221  {
222  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
223  return;
224  }
225  else
226  {
227  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
228  }
229  //SECURITY CHECK END ****
230 
231  HttpXmlDocument xmldoc;
232 
233  if(Command == "check")
234  {
235  WebUsers::tooltipCheckForUsername(
236  WebUsers::DEFAULT_ADMIN_USERNAME,
237  &xmldoc,
238  CgiDataUtilities::getData(cgi, "srcFile"),
239  CgiDataUtilities::getData(cgi, "srcFunc"),
240  CgiDataUtilities::getData(cgi, "srcId"));
241  }
242  else if(Command == "setNeverShow")
243  {
244  WebUsers::tooltipSetNeverShowForUsername(
245  WebUsers::DEFAULT_ADMIN_USERNAME,
246  &xmldoc,
247  CgiDataUtilities::getData(cgi, "srcFile"),
248  CgiDataUtilities::getData(cgi, "srcFunc"),
249  CgiDataUtilities::getData(cgi, "srcId"),
250  CgiDataUtilities::getData(cgi, "doNeverShow") == "1"?true:false,
251  CgiDataUtilities::getData(cgi, "temporarySilence") == "1"?true:false);
252 
253  }
254  else
255  __COUT__ << "Command Request, " << Command << ", not recognized." << std::endl;
256 
257  xmldoc.outputXmlDocument((std::ostringstream*) out, false, true);
258 }
259 
260 //========================================================================================================================
261 void WizardSupervisor::toggleSecurityCodeGeneration(xgi::Input * in, xgi::Output * out)
262 throw (xgi::exception::Exception)
263 {
264  cgicc::Cgicc cgi(in);
265 
266  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
267  __COUT__ << "Got to Command = " << Command << std::endl;
268 
269  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
270 
271  //SECURITY CHECK START ****
272  if(securityCode_.compare(submittedSequence) != 0)
273  {
274  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
275  return;
276  }
277  else
278  {
279  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
280  }
281  //SECURITY CHECK END ****
282 
283  HttpXmlDocument xmldoc;
284 
285  if(Command == "TurnGenerationOn")
286  {
287  __COUT__ << "Turning automatic URL Generation on with a sequence depth of 16!" << std::endl;
288  std::ofstream outfile ((SEQUENCE_FILE_NAME).c_str());
289  outfile << "16" << std::endl;
290  outfile.close();
291  generateURL();
292 
293  //std::stringstream url;
294  // url << getenv("OTS_CONFIGURATION_WIZARD_SUPERVISOR_SERVER") << ":" << getenv("PORT")
295  // << "/urn:xdaq-application:lid=" << this->getApplicationDescriptor()->getLocalId()
296  // << "/Verify?code=" << securityCode_;
297  // printURL(this, securityCode_);
298  std::thread([&](WizardSupervisor *ptr, std::string securityCode)
299  {printURL(ptr,securityCode);},this,securityCode_).detach();
300 
301  xmldoc.addTextElementToData("Status", "Generation_Success");
302  }
303  else
304  __COUT__ << "Command Request, " << Command << ", not recognized." << std::endl;
305 
306  xmldoc.outputXmlDocument((std::ostringstream*) out, false, true);
307 }
308 
309 //========================================================================================================================
310 //xoap::supervisorSequenceCheck
311 // verify cookie
312 xoap::MessageReference WizardSupervisor::supervisorSequenceCheck(xoap::MessageReference message)
313 throw (xoap::exception::Exception)
314 {
315  //receive request parameters
316  SOAPParameters parameters;
317  parameters.addParameter("sequence");
318  receive(message, parameters);
319 
320  std::string submittedSequence = parameters.getValue("sequence");
321 
322  //If submittedSequence matches securityCode_ then return full permissions (255)
323  // else, return permissions 0
324  std::map<std::string /*groupName*/,WebUsers::permissionLevel_t> permissionMap;
325 
326  if(securityCode_ == submittedSequence)
327  permissionMap.emplace(
328  std::pair<std::string /*groupName*/,WebUsers::permissionLevel_t>(
329  WebUsers::DEFAULT_USER_GROUP,
330  WebUsers::PERMISSION_LEVEL_ADMIN));
331  else
332  {
333  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
334 
335  permissionMap.emplace(
336  std::pair<std::string /*groupName*/,WebUsers::permissionLevel_t>(
337  WebUsers::DEFAULT_USER_GROUP,
338  WebUsers::PERMISSION_LEVEL_INACTIVE));
339  }
340 
341  //fill return parameters
342  SOAPParameters retParameters;
343  retParameters.addParameter("Permissions", StringMacros::mapToString(permissionMap));
344 
345 
346  return SOAPUtilities::makeSOAPMessageReference("SequenceResponse",
347  retParameters);
348 }
349 
350 //===================================================================================================================
351 //xoap::supervisorLastConfigGroupRequest
352 // return the group name and key for the last state machine activity
353 //
354 // Note: same as Supervisor::supervisorLastConfigGroupRequest
355 xoap::MessageReference WizardSupervisor::supervisorLastConfigGroupRequest(
356  xoap::MessageReference message)
357 throw (xoap::exception::Exception)
358 {
359  SOAPParameters parameters;
360  parameters.addParameter("ActionOfLastGroup");
361  receive(message, parameters);
362 
363  return GatewaySupervisor::lastConfigGroupRequestHandler(parameters);
364 }
365 
366 //========================================================================================================================
367 void WizardSupervisor::Default(xgi::Input * in, xgi::Output * out )
368 throw (xgi::exception::Exception)
369 {
370  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
371  *out << "Unauthorized Request.";
372 }
373 
374 //========================================================================================================================
375 void WizardSupervisor::verification(xgi::Input * in, xgi::Output * out )
376 throw (xgi::exception::Exception)
377 {
378  cgicc::Cgicc cgi(in);
379  std::string submittedSequence = CgiDataUtilities::getData(cgi, "code");
380  __COUT__ << "submittedSequence=" << submittedSequence <<
381  " " << time(0) << std::endl;
382 
383  std::string securityWarning = "";
384 
385  if(securityCode_.compare(submittedSequence) != 0)
386  {
387  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
388  *out << "Invalid code.";
389  return;
390  }
391  else
392  {
393  //defaultSequence_ = false;
394  __COUT__ << "*** Successfully authenticated security sequence " <<
395  "@ " << time(0) << std::endl;
396 
397  if (defaultSequence_)
398  {
399  //__COUT__ << " UNSECURE!!!" << std::endl;
400  securityWarning = "&secure=False";
401  }
402  }
403 
404  *out << "<!DOCTYPE HTML><html lang='en'><head><title>ots wiz</title>" <<
405  //show ots icon
406  // from http://www.favicon-generator.org/
407  "<link rel='apple-touch-icon' sizes='57x57' href='/WebPath/images/otsdaqIcons/apple-icon-57x57.png'>\
408  <link rel='apple-touch-icon' sizes='60x60' href='/WebPath/images/otsdaqIcons/apple-icon-60x60.png'>\
409  <link rel='apple-touch-icon' sizes='72x72' href='/WebPath/images/otsdaqIcons/apple-icon-72x72.png'>\
410  <link rel='apple-touch-icon' sizes='76x76' href='/WebPath/images/otsdaqIcons/apple-icon-76x76.png'>\
411  <link rel='apple-touch-icon' sizes='114x114' href='/WebPath/images/otsdaqIcons/apple-icon-114x114.png'>\
412  <link rel='apple-touch-icon' sizes='120x120' href='/WebPath/images/otsdaqIcons/apple-icon-120x120.png'>\
413  <link rel='apple-touch-icon' sizes='144x144' href='/WebPath/images/otsdaqIcons/apple-icon-144x144.png'>\
414  <link rel='apple-touch-icon' sizes='152x152' href='/WebPath/images/otsdaqIcons/apple-icon-152x152.png'>\
415  <link rel='apple-touch-icon' sizes='180x180' href='/WebPath/images/otsdaqIcons/apple-icon-180x180.png'>\
416  <link rel='icon' type='image/png' sizes='192x192' href='/WebPath/images/otsdaqIcons/android-icon-192x192.png'>\
417  <link rel='icon' type='image/png' sizes='32x32' href='/WebPath/images/otsdaqIcons/favicon-32x32.png'>\
418  <link rel='icon' type='image/png' sizes='96x96' href='/WebPath/images/otsdaqIcons/favicon-96x96.png'>\
419  <link rel='icon' type='image/png' sizes='16x16' href='/WebPath/images/otsdaqIcons/favicon-16x16.png'>\
420  <link rel='manifest' href='/WebPath/images/otsdaqIcons/manifest.json'>\
421  <meta name='msapplication-TileColor' content='#ffffff'>\
422  <meta name='msapplication-TileImage' content='/ms-icon-144x144.png'>\
423  <meta name='theme-color' content='#ffffff'>" <<
424  //end show ots icon
425  "</head>" <<
426  "<frameset col='100%' row='100%'><frame src='/WebPath/html/Wizard.html?urn=" <<
427  this->getApplicationDescriptor()->getLocalId() << securityWarning <<"'></frameset></html>";
428 
429 }
430 
431 //========================================================================================================================
432 void WizardSupervisor::requestIcons(xgi::Input * in, xgi::Output * out )
433 throw (xgi::exception::Exception)
434 {
435  cgicc::Cgicc cgi(in);
436 
437  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
438 
439  //SECURITY CHECK START ****
440  if(securityCode_.compare(submittedSequence) != 0)
441  {
442  __COUT__ << "Unauthorized Request made, security sequence doesn't match! " <<
443  time(0) << std::endl;
444  return;
445  }
446  else
447  {
448  __COUT__ << "***Successfully authenticated security sequence. " <<
449  time(0) << std::endl;
450  }
451  //SECURITY CHECK END ****
452 
453 
454  //an icon is 7 fields.. give comma-separated
455  //0 - subtext = text below icon
456  //1 - altText = text for icon if image set to 0
457  //2 - uniqueWin = if true, only one window is allowed, else multiple instances of window
458  //3 - permissions = security level needed to see icon
459  //4 - picfn = icon image filename, 0 for no image
460  //5 - linkurl = url of the window to open
461  //6 - folderPath = folder and subfolder location
462 
463  *out << "Security Settings,SEC,1,1,icon-SecuritySettings.png,/WebPath/html/SecuritySettings.html,/" <<
464  ",Edit User Data,USER,1,1,icon-EditUserData.png,/WebPath/html/EditUserData.html,/" <<
465  ",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,/" <<
466  ",Table Editor,TBL,0,1,icon-IconEditor.png,/urn:xdaq-application:lid=280/?configWindowName=tableEditor,/" <<
467  //",Iterate,IT,0,1,icon-Iterate.png,/urn:xdaq-application:lid=280/?configWindowName=iterate,/" <<
468  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,myFolder" <<
469  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,/myFolder/mySub.folder" <<
470  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,myFolder/" <<
471  ",Front-end Wizard,CFG,0,1,icon-Configure.png,/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&subsetBasePath=FEInterfaceConfiguration&recordAlias=Front%2Dend,Config Wizards" <<
472  ",Producer Wizard,CFG,0,1,icon-Configure.png,/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&subsetBasePath=FEInterfaceConfiguration&recordAlias=Producer,Config Wizards" <<
473  ",Consumer Wizard,CFG,0,1,icon-Configure.png,/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&subsetBasePath=FEInterfaceConfiguration&recordAlias=Consumer,Config Wizards" <<
474  ",Console,C,1,1,icon-Console.png,/urn:xdaq-application:lid=260/,/" <<
475  //",DB Utilities,DB,1,1,0,http://127.0.0.1:8080/db/client.html" <<
476  "";
477  return;
478 }
479 
480 //========================================================================================================================
481 void WizardSupervisor::editSecurity(xgi::Input * in, xgi::Output * out )
482 throw (xgi::exception::Exception)
483 {
484 
485  //if sequence doesn't match up -> return
486  cgicc::Cgicc cgi(in);
487  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
488  std::string submittedSecurity = CgiDataUtilities::postData(cgi, "selection");
489  std::string securityFileName = SECURITY_FILE_NAME;
490 
491 
492  //SECURITY CHECK START ****
493  if(securityCode_.compare(submittedSequence) != 0)
494  {
495  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
496  return;
497  }
498  else
499  {
500  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
501  }
502  //SECURITY CHECK END ****
503 
504 
505 
506  if(submittedSecurity != "")
507  {
508  __COUT__ << "Selection exists!" << std::endl;
509  __COUT__ << submittedSecurity << std::endl;
510 
511  if(submittedSecurity == "ResetAllUserData")
512  {
513  WebUsers::deleteUserData();
514  __COUT__ << "Turning URL Generation back to default!" << std::endl;
515  //std::remove((SEQUENCE_FILE_NAME).c_str());
516  //std::remove((SEQUENCE_OUT_FILE_NAME).c_str());
517  std::ofstream newFile ((SEQUENCE_FILE_NAME).c_str());
518  newFile << "4" << std::endl;
519  newFile.close();
520 
521  generateURL();
522  std::thread([&](WizardSupervisor *ptr, std::string securityCode)
523  {printURL(ptr,securityCode);},this,securityCode_).detach();
524  *out << "Default_URL_Generation";
525  }
526  else if(submittedSecurity == "ResetAllUserTooltips")
527  {
528  WebUsers::resetAllUserTooltips();
529  *out << submittedSecurity;
530  return;
531  }
532  else if(submittedSecurity == "DigestAccessAuthentication" ||
533  submittedSecurity == "NoSecurity")
534  {
535  std::ofstream writeSecurityFile;
536 
537  writeSecurityFile.open(securityFileName.c_str());
538  if(writeSecurityFile.is_open())
539  writeSecurityFile << submittedSecurity;
540  else
541  __COUT__ << "Error writing file!" << std::endl;
542 
543  writeSecurityFile.close();
544  }
545  else
546  {
547  __COUT_ERR__ << "Invalid submittedSecurity string: " <<
548  submittedSecurity << std::endl;
549  *out << "Error";
550  return;
551  }
552  }
553 
554 
555  //Always return the file
556  std::ifstream securityFile;
557  std::string line;
558  std::string security = "";
559  int lineNumber = 0;
560 
561  securityFile.open(securityFileName.c_str());
562 
563  if(!securityFile)
564  {
565  //__SS__ << "Error opening file: "<< securityFileName << std::endl;
566  //__COUT_ERR__ << "\n" << ss.str();
567 
568  //throw std::runtime_error(ss.str());
569  //return;
570  security = "DigestAccessAuthentication"; //default security when no file exists
571  }
572  if(securityFile.is_open())
573  {
574  //__COUT__ << "Opened File: " << securityFileName << std::endl;
575  while(std::getline(securityFile, line))
576  {
577  security += line;
578  lineNumber++;
579  }
580  //__COUT__ << std::to_string(lineNumber) << ":" << iconList << std::endl;
581 
582  //Close file
583  securityFile.close();
584  }
585 
586  *out << security;
587 }
588 //========================================================================================================================
589 void WizardSupervisor::UserSettings(xgi::Input * in, xgi::Output * out )
590 throw (xgi::exception::Exception)
591 {
592 
593  //if sequence doesn't match up -> return
594  cgicc::Cgicc cgi(in);
595  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
596  std::string securityFileName = SECURITY_FILE_NAME;
597  std::string Command;
598  if((Command = CgiDataUtilities::postData(cgi,"RequestType")) == "")
599  Command = cgi("RequestType"); //get command from form, if PreviewEntry
600 
601  __COUT__ << Command << std::endl;
602  __COUT__ << "We are vewing Users' Settings!" << std::endl;
603 
604  //SECURITY CHECK START ****
605  if(securityCode_.compare(submittedSequence) != 0)
606  {
607  __COUT__ << "Unauthorized Request made, security sequence doesn't match!" << std::endl;
608  __COUT__ << submittedSequence << std::endl;
609  //return;
610  }
611  else
612  {
613  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
614  }
615  //SECURITY CHECK END ****
616 
617 
618  HttpXmlDocument xmldoc;
619  uint64_t activeSessionIndex;
620  std::string user;
621  uint8_t userPermissions;
622 
623  if(Command != "")
624  {
625  __COUT__ << "Action exists!" << std::endl;
626  __COUT__ << Command << std::endl;
627 
628  if(Command == "Import")
629  {
630  //cleanup temporary folder
631  //NOTE: all input parameters for User Data will be attached to form
632  // so use cgi(xxx) to get values.
633  //increment number for each temporary preview, previewPostTempIndex_
634  //save entry and uploads to previewPath / previewPostTempIndex_ /.
635 
636  //cleanUpPreviews();
637 // std::string EntryText = cgi("EntryText");
638 // __COUT__ << "EntryText " << EntryText << std::endl << std::endl;
639 // std::string EntrySubject = cgi("EntrySubject");
640 // __COUT__ << "EntrySubject " << EntrySubject << std::endl << std::endl;
641 
642  //get creator name
643  //std::string creator = user;
644  //CgiDataUtilities::postData(cgi, "file"); CgiDataUtilities::postData(cgi, "file");//
645  __COUT__ << cgi("Entry") << std::endl;
646  __COUT__ << cgi("Filename") << std::endl;
647  __COUT__ << cgi("Imported_File") << std::endl;
648 
649 
650  const std::vector<cgicc::FormFile> files = cgi.getFiles();
651  __COUT__ << "FormFiles: " << sizeof(files) << std::endl;
652  __COUT__ << "Number of files: " << files.size() << std::endl;
653 
654  for(unsigned int i = 0; i < files.size(); ++i)
655  {
656  std::string filename = USER_DATA_PATH + files[i].getFilename();
657  __COUT__ << filename << std::endl;
658  std::ofstream myFile;
659  myFile.open(filename.c_str());
660  files[0].writeToStream(myFile);
661  }
662 
663 
664  __COUT__ << files[0].getFilename() << std::endl;
665  __COUT__ << "********************Files Begin********************" << std::endl;
666  for (unsigned int i=0; i<files.size(); ++i)
667  {
668 
669  __COUT__ << files[i].getDataType() << std::endl;
670 
671  }
672  __COUT__ << "*********************Files End*********************" << std::endl;
673 
674 
675 // savePostPreview(EntrySubject, EntryText, cgi.getFiles(), creator, &xmldoc);
676  //else xmldoc.addTextElementToData(XML_STATUS,"Failed - could not get username info.");
677  }
678  else if(Command == "Export")
679  {
680  __SS__ << "This doesn't compile Dan." << __E__;
681  __SS_THROW__;
682 //
683 // __COUT__ << "We are exporting Users' Settings!!!" << std::endl;
684 // //system('pwd');
685 //
686 // //Check for a TMP directory; if it doesn't exist, make it
687 // std::string command = "cd " + USER_DATA_PATH;
688 // std::string pathToTmp = USER_DATA_PATH + "/tmp/";
689 // std::filesystem::path tmp = pathToTmp;
690 //
691 // exec(command.c_str());
692 // __COUT__ << exec("pwd") << std::endl;
693 //
694 //
695 // if(std::filesystem::status_known(tmpDir) ? std::filesystem::exists(tmpDir) : std::filesystem::exists(tmpDir))
696 // __COUT__ << pathToTmp << " exists!" << std::endl;
697 // else
698 // __COUT__ << pathToTmp << "does not exist! Creating it now. " << std::endl;
699 //
700 // //Zip current files into TMP directory
701 // command = std::string("tar -cvf user_settings.tar") +
702 // std::string("ActiveConfigurationGroups.cfg ") +
703 // std::string("ConsolePreferences ") +
704 // std::string("CoreTableInfoNames.dat ") +
705 // std::string("LoginData ") +
706 // std::string("OtsWizardData ") +
707 // std::string("ProgressBarData ");
708 //
709 //
710 // //return zip
711 // if(exec("pwd").find(USER_DATA_PATH) != std::string::npos)
712 // {
713 // __COUT__ << "Found USER_DATA directory " << std::endl;
714 // system(command.c_str());
715 // __COUT__ << system("ls") << std::endl;
716 // }
717  }
718  else
719  {
720  __COUT__ << "Command request not recognized: " << Command << std::endl;
721  *out << "Error";
722  return;
723  }
724  }
725 
726 
727 
728 
729  *out << "test";
730  return;
731 }
732 //========================================================================================================================
733 // validateUploadFileType
734 // returns "" if file type is invalid, else returns file extension to use
735 std::string WizardSupervisor::validateUploadFileType(const std::string fileType)
736 {
737  for (unsigned int i=0; i<allowedFileUploadTypes_.size(); ++i)
738  if (allowedFileUploadTypes_[i] == fileType)
739  return matchingFileUploadTypes_[i]; //found and done
740 
741  return ""; //not valid, return ""
742 }
743 //========================================================================================================================
744 // cleanUpPreviews
745 // cleanup logbook preview directory
746 // all names have time_t creation time + "_" + incremented index
747 void WizardSupervisor::cleanUpPreviews()
748 {
749  std::string userData = (std::string)USER_DATA_PATH;
750 
751  DIR *dir = opendir(userData.c_str());
752  if(!dir)
753  {
754  __COUT__ << "Error - User Data directory missing: " << userData << std::endl;
755  return;
756  }
757 
758  struct dirent *entry;
759  time_t dirCreateTime;
760  unsigned int i;
761 
762  while((entry = readdir(dir))) //loop through all entries in directory and remove anything expired
763  {
764  if( strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0
765  && strcmp(entry->d_name, ".svn") != 0 )
766  {
767  //replace _ with space so sscanf works
768  for(i=0;i<strlen(entry->d_name);++i)
769  if(entry->d_name[i] == '_')
770  { entry->d_name[i] = ' '; break; }
771  sscanf(entry->d_name,"%li",&dirCreateTime);
772 
773  if((time(0) - dirCreateTime) > USER_DATA_EXPIRATION_TIME)
774  {
775  __COUT__ << "Expired" << std::endl;
776 
777  entry->d_name[i] = '_'; //put _ back
778 
779  __COUT__ << "rm -rf " << USER_DATA_PATH + (std::string)entry->d_name << std::endl << std::endl;
780  system(((std::string)("rm -rf " + userData + (std::string)entry->d_name)).c_str());
781  }
782  }
783  }
784 
785  closedir(dir);
786 }
787 
788 //========================================================================================================================
789 // savePostPreview
790 // save post to preview directory named with time and incremented index
791 void WizardSupervisor::savePostPreview(std::string &subject, std::string &text, const std::vector<cgicc::FormFile> &files, std::string creator,
792  HttpXmlDocument *xmldoc)
793 {
794  /*if(activeExperiment_ == "") //no active experiment!
795  {
796  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"Failed - no active experiment currently!");
797  return;
798  }
799 */
800  char fileIndex[40];
801  sprintf(fileIndex,"%lu_%lu",time(0),clock()); //create unique time label for entry time(0)_clock()
802  std::string userDataPath = (std::string)USER_DATA_PATH + (std::string)fileIndex;
803 
804  __COUT__ << "userDataPath " << userDataPath << std::endl;
805  if(-1 == mkdir(userDataPath.c_str(),0755))
806  {
807  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"Failed - directory could not be generated.");
808  return;
809  }
810 /*
811  //new directory created successfully, save text and files
812  //entry structure:
813  // <XML_LOGBOOK_ENTRY>
814  // <XML_LOGBOOK_ENTRY_TIME>
815  // <XML_LOGBOOK_ENTRY_CREATOR>
816  // <XML_LOGBOOK_ENTRY_SUBJECT>
817  // <XML_LOGBOOK_ENTRY_TEXT>
818  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
819  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
820  // </XML_LOGBOOK_ENTRY>
821 
822  escapeLogbookEntry(text);
823  escapeLogbookEntry(subject);
824  __COUT__ << "~~subject " << subject << std::endl << "~~text " << text << std::endl << std::endl;
825 
826  HttpXmlDocument previewXml;
827 
828  previewXml.addTextElementToData(XML_LOGBOOK_ENTRY);
829  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TIME, fileIndex, XML_LOGBOOK_ENTRY);
830  if(xmldoc) xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_TIME,fileIndex); //return time
831  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_CREATOR, creator, XML_LOGBOOK_ENTRY);
832  if(xmldoc) xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_CREATOR,creator); //return creator
833  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, text, XML_LOGBOOK_ENTRY);
834  if(xmldoc) xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_TEXT,text); //return text
835  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_SUBJECT, subject, XML_LOGBOOK_ENTRY);
836  if(xmldoc) xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_SUBJECT,subject); //return subject
837 
838  __COUT__ << "file size " << files.size() << std::endl;
839 
840  std::string filename;
841  std::ofstream myfile;
842  for (unsigned int i=0; i<files.size(); ++i)
843  {
844 
845  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_FILE, files[i].getDataType(), XML_LOGBOOK_ENTRY);
846  if(xmldoc) xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_FILE,files[i].getDataType()); //return file type
847 
848  if((filename = validateUploadFileType(files[i].getDataType())) == "") //invalid file type
849  {
850  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"Failed - invalid file type, " +
851  files[i].getDataType() + ".");
852  return;
853  }*/
854 
855  /*//file validated, so save upload to temp directory
856  sprintf(fileIndex,"%d",i);
857  filename = previewPath + "/" + (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE +
858  (std::string)fileIndex + "." + filename;
859 
860  __COUT__ << "file " << i << " - " << filename << std::endl;
861  myfile.open(filename.c_str());
862  if (myfile.is_open())
863  {
864  files[i].writeToStream(myfile);
865  myfile.close();
866  }
867  }*/
868 /*
869  //save xml doc for preview entry
870  previewXml.saveXmlDocument(USER_DATA_PATH + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
871 
872  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"1"); //1 indicates success!
873  if(xmldoc) xmldoc->addTextElementToData(XML_PREVIEW_INDEX,"1"); //1 indicates is a preview post*/
874 }
875 
876 //========================================================================================================================
877 std::string WizardSupervisor::exec(const char* cmd)
878 {
879  std::array<char, 128> buffer;
880  std::string result;
881  std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
882  if (!pipe) throw std::runtime_error("popen() failed!");
883  while (!feof(pipe.get())) {
884  if (fgets(buffer.data(), 128, pipe.get()) != nullptr)
885  result += buffer.data();
886  }
887  return result;
888 }
889