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