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