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