tdaq-develop-2025-02-12
WizardSupervisor.cc
1 #include "otsdaq/WizardSupervisor/WizardSupervisor.h"
2 
3 #include "otsdaq/CoreSupervisors/CorePropertySupervisorBase.h"
4 #include "otsdaq/GatewaySupervisor/GatewaySupervisor.h"
5 
6 #include "otsdaq/Macros/CoutMacros.h"
7 #include "otsdaq/MessageFacility/ITRACEController.h"
8 #include "otsdaq/MessageFacility/MessageFacility.h"
9 
10 #include <xdaq/NamespaceURI.h>
11 #include "otsdaq/CgiDataUtilities/CgiDataUtilities.h"
12 #include "otsdaq/SOAPUtilities/SOAPCommand.h"
13 #include "otsdaq/SOAPUtilities/SOAPUtilities.h"
14 #include "otsdaq/WebUsersUtilities/WebUsers.h"
15 #include "otsdaq/XmlUtilities/HttpXmlDocument.h"
16 
17 #include <dirent.h> //for DIR
18 #include <sys/stat.h> // mkdir
19 #include <boost/filesystem.hpp>
20 #include <chrono> // std::chrono::seconds
21 #include <cstdlib>
22 #include <fstream>
23 #include <iostream>
24 #include <string>
25 #include <thread> // std::this_thread::sleep_for
26 namespace filesystem = boost::filesystem;
27 using namespace ots;
28 
29 // clang-format off
30 
31 const std::string WizardSupervisor::WIZ_SUPERVISOR = __ENV__("OTS_CONFIGURATION_WIZARD_SUPERVISOR_SERVER");
32 const std::string WizardSupervisor::WIZ_PORT = __ENV__("PORT");
33 const std::string WizardSupervisor::SERVICE_DATA_PATH = __ENV__("SERVICE_DATA_PATH");
34 
35 #define SECURITY_FILE_NAME WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData/security.dat"
36 #define SEQUENCE_FILE_NAME WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData/sequence.dat"
37 #define SEQUENCE_OUT_FILE_NAME WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData/sequence.out"
38 #define USER_IMPORT_EXPORT_PATH WizardSupervisor::SERVICE_DATA_PATH + "/"
39 
40 #define XML_STATUS "editUserData_status"
41 
42 #define XML_ADMIN_STATUS "logbook_admin_status"
43 #define XML_MOST_RECENT_DAY "most_recent_day"
44 #define XML_EXPERIMENTS_ROOT "experiments"
45 #define XML_EXPERIMENT "experiment"
46 #define XML_ACTIVE_EXPERIMENT "active_experiment"
47 #define XML_EXPERIMENT_CREATE "create_time"
48 #define XML_EXPERIMENT_CREATOR "creator"
49 
50 #define XML_LOGBOOK_ENTRY "logbook_entry"
51 #define XML_LOGBOOK_ENTRY_SUBJECT "logbook_entry_subject"
52 #define XML_LOGBOOK_ENTRY_TEXT "logbook_entry_text"
53 #define XML_LOGBOOK_ENTRY_FILE "logbook_entry_file"
54 #define XML_LOGBOOK_ENTRY_TIME "logbook_entry_time"
55 #define XML_LOGBOOK_ENTRY_CREATOR "logbook_entry_creator"
56 #define XML_LOGBOOK_ENTRY_HIDDEN "logbook_entry_hidden"
57 #define XML_LOGBOOK_ENTRY_HIDER "logbook_entry_hider"
58 #define XML_LOGBOOK_ENTRY_HIDDEN_TIME "logbook_entry_hidden_time"
59 
60 #define XML_PREVIEW_INDEX "preview_index"
61 #define LOGBOOK_PREVIEW_FILE "preview.xml"
62 
63 XDAQ_INSTANTIATOR_IMPL(WizardSupervisor)
64 
65 #undef __MF_SUBJECT__
66 #define __MF_SUBJECT__ "Wizard"
67 
69 const std::vector<std::string> WizardSupervisor::allowedFileUploadTypes_ = {
70  "image/png",
71  "image/jpeg",
72  "image/gif",
73  "image/bmp",
74  "application/pdf",
75  "application/zip",
76  "text/plain"
77 };
78 const std::vector<std::string> WizardSupervisor::matchingFileUploadTypes_ = {
79  "png",
80  "jpeg",
81  "gif",
82  "ima/bmp",
83  "pdf",
84  "zip",
85  "txt"
86 };
87 
88 // clang-format on
89 
90 //==============================================================================
91 WizardSupervisor::WizardSupervisor(xdaq::ApplicationStub* s)
92  : xdaq::Application(s)
93  , SOAPMessenger(this)
94  , supervisorClass_(getApplicationDescriptor()->getClassName())
95  , supervisorClassNoNamespace_(supervisorClass_.substr(
96  supervisorClass_.find_last_of(":") + 1,
97  supervisorClass_.length() - supervisorClass_.find_last_of(":")))
98 {
99  __COUT__ << "Constructor." << __E__;
100 
101  INIT_MF("." /*directory used is USER_DATA/LOG/.*/);
102 
103  // get all supervisor info, and wiz mode, macroMaker mode, or not
104  allSupervisorInfo_.init(getApplicationContext());
105 
106  xgi::bind(this, &WizardSupervisor::Default, "Default");
107  xgi::bind(this, &WizardSupervisor::verification, "Verify");
108  xgi::bind(this, &WizardSupervisor::request, "Request");
109  xgi::bind(this, &WizardSupervisor::requestIcons, "requestIcons");
110  xgi::bind(this, &WizardSupervisor::editSecurity, "editSecurity");
111  xgi::bind(this, &WizardSupervisor::UserSettings, "UserSettings");
112  xgi::bind(this, &WizardSupervisor::tooltipRequest, "TooltipRequest");
113  xgi::bind(this,
114  &WizardSupervisor::toggleSecurityCodeGeneration,
115  "ToggleSecurityCodeGeneration");
116  xoap::bind(this,
117  &WizardSupervisor::supervisorSequenceCheck,
118  "SupervisorSequenceCheck",
119  XDAQ_NS_URI);
120  xoap::bind(this,
121  &WizardSupervisor::supervisorLastTableGroupRequest,
122  "SupervisorLastTableGroupRequest",
123  XDAQ_NS_URI);
124 
125  init();
126  generateURL();
127  GatewaySupervisor::indicateOtsAlive();
128 
129  __COUT__ << "Constructed." << __E__;
130 } // end constructor()
131 //==============================================================================
132 WizardSupervisor::~WizardSupervisor(void)
133 {
134  __COUT__ << "Destructor." << __E__;
135  destroy();
136  __COUT__ << "Destructed." << __E__;
137 }
138 
139 //==============================================================================
140 void WizardSupervisor::destroy(void)
141 {
142  // called by destructor
143 } // end destroy()
144 
145 //==============================================================================
146 void WizardSupervisor::init(void)
147 {
148  // attempt to make directory structure (just in case)
149  mkdir((WizardSupervisor::SERVICE_DATA_PATH).c_str(), 0755);
150  mkdir((WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData").c_str(), 0755);
151 
152 } // end init()
153 
154 //==============================================================================
155 void WizardSupervisor::requestIcons(xgi::Input* in, xgi::Output* out)
156 {
157  cgicc::Cgicc cgi(in);
158 
159  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
160 
161  // SECURITY CHECK START ****
162  if(securityCode_.compare(submittedSequence) != 0)
163  {
164  __COUT__ << "Unauthorized Request made, security sequence doesn't match! "
165  << time(0) << std::endl;
166  return;
167  }
168  else
169  {
170  __COUT__ << "*** Successfully authenticated security sequence @ " << time(0)
171  << std::endl;
172  }
173  // SECURITY CHECK END ****
174 
175  // an icon is 7 fields.. give comma-separated
176  // 0 - subtext = text below icon
177  // 1 - altText = text for icon if image set to 0
178  // 2 - uniqueWin = if true, only one window is allowed, else multiple instances of
179  // window 3 - permissions = security level needed to see icon 4 - picfn = icon image
180  // filename, 0 for no image 5 - linkurl = url of the window to open 6 - folderPath =
181  // folder and subfolder location
182 
183  // clang-format off
184  *out << "Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,/"
185 
186  << ",Table Editor,TBL,0,1,icon-ControlsDashboard.png,"
187  "/urn:xdaq-application:lid=280/?configWindowName=tableEditor,/"
188 
189  << ",Desktop Icon Editor,ICON,0,1,icon-IconEditor.png,"
190  "/WebPath/html/ConfigurationGUI_subset.html?urn=280&subsetBasePath=DesktopIconTable&"
191  "recordAlias=Icons&groupingFieldList=Status%2CFolderPath%2CRequiredPermissionLevel,/"
192 
193  //User Settings ------------------
194  << ",Edit User Accounts,USER,1,1,"
195  "/WebPath/images/dashboardImages/icon-Settings.png,/WebPath/html/UserSettings.html,/User Settings"
196 
197  << ",Security Settings,SEC,1,1,icon-SecuritySettings.png,"
198  "/WebPath/html/SecuritySettings.html,/User Settings"
199 
200  << ",Edit User Data,USER,1,1,icon-EditUserData.png,/WebPath/html/EditUserData.html,/User Settings"
201 
202  //end User Settings ------------------
203 
204  << ",Console,C,1,1,icon-Console.png,/urn:xdaq-application:lid=260/,/"
205 
206  //Configuration Wizards ------------------
207  << ",Front-end Wizard,CFG,0,1,icon-Configure.png,"
208  "/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&recordAlias=Front%2Dend,Config Wizards"
209 
210  << ",Processor Wizard,CFG,0,1,icon-Configure.png,"
211  "/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&recordAlias=Processor,Config Wizards"
212 
213  << ",artdaq Config Editor,CFG,0,1,icon-Configure.png,"
214  "/WebPath/html/ConfigurationGUI_artdaq.html?urn=280,Config Wizards"
215 
216  << ",Block Diagram,CFG,0,1,icon-Configure.png,"
217  "/WebPath/html/ConfigurationSubsetBlockDiagram.html?urn=280,Config Wizards"
218  //end Configuration Wizards ------------------
219 
220  << ",Code Editor,CODE,0,1,icon-CodeEditor.png,/urn:xdaq-application:lid=240/,/"
221 
222  //Documentation ------------------
223  << ",State Machine Screenshot,FSM-SS,1,1,icon-Physics.gif,"
224  "/WebPath/images/windowContentImages/state_machine_screenshot.png,/Documentation"
225 
226  //uniqueWin mode == 2 for new tab
227  << ",Redmine Project for otsdaq,RED,2,1,../otsdaqIcons/android-icon-36x36.png,"
228  "https://cdcvs.fnal.gov/redmine/projects/otsdaq,/Documentation"
229  //uniqueWin mode == 2 for new tab
230  << ",Homepage for otsdaq,OTS,2,1,../otsdaqIcons/android-icon-36x36.png,"
231  "https://otsdaq.fnal.gov,/Documentation"
232  //end Documentation ------------------
233 
234  //",Iterate,IT,0,1,icon-Iterate.png,/urn:xdaq-application:lid=280/?configWindowName=iterate,/"
235  //<<
236  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,myFolder"
237  //<<
238  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,/myFolder/mySub.folder"
239  //<<
240  //",Configure,CFG,0,1,icon-Configure.png,/urn:xdaq-application:lid=280/,myFolder/"
241  //<<
242 
243 
244  //",Consumer
245  // Wizard,CFG,0,1,icon-Configure.png,/WebPath/html/RecordWiz_ConfigurationGUI.html?urn=280&subsetBasePath=FEInterfaceConfiguration&recordAlias=Consumer,Config
246  // Wizards" <<
247 
248  //",DB Utilities,DB,1,1,0,http://127.0.0.1:8080/db/client.html" <<
249 
250 
251  << "";
252  // clang-format on
253  return;
254 } // end requestIcons()
255 
256 //==============================================================================
257 void WizardSupervisor::verification(xgi::Input* in, xgi::Output* out)
258 {
259  cgicc::Cgicc cgi(in);
260  std::string submittedSequence = CgiDataUtilities::getData(cgi, "code");
261  __COUT__ << "submittedSequence=" << submittedSequence << " " << time(0) << std::endl;
262 
263  std::string securityWarning = "";
264 
265  if(securityCode_.compare(submittedSequence) != 0)
266  {
267  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
268  << std::endl;
269  *out << "Invalid code.";
270  return;
271  }
272  else
273  {
274  // defaultSequence_ = false;
275  __COUT__ << "*** Successfully authenticated security sequence "
276  << "@ " << time(0) << std::endl;
277 
278  if(defaultSequence_)
279  {
280  //__COUT__ << " UNSECURE!!!" << std::endl;
281  securityWarning = "&secure=False";
282  }
283  }
284 
285  *out << "<!DOCTYPE HTML><html lang='en'><head><title>ots wiz</title>"
286  << GatewaySupervisor::getIconHeaderString() <<
287  // end show ots icon
288  "</head>"
289  << "<frameset col='100%' row='100%'><frame src='/WebPath/html/Wizard.html?urn="
290  << this->getApplicationDescriptor()->getLocalId() << securityWarning
291  << "'></frameset></html>";
292 } // end verification()
293 
294 //==============================================================================
295 void WizardSupervisor::generateURL()
296 {
297  defaultSequence_ = true;
298 
299  int length = 4;
300  FILE* fp = fopen((SEQUENCE_FILE_NAME).c_str(), "r");
301  if(fp)
302  {
303  __COUT_INFO__ << "Sequence length file found: " << SEQUENCE_FILE_NAME
304  << std::endl;
305  char line[100];
306  fgets(line, 100, fp);
307  sscanf(line, "%d", &length);
308  fclose(fp);
309  if(length < 4)
310  length = 4; // don't allow shorter than 4
311  else
312  defaultSequence_ = false;
313  srand(time(0)); // randomize differently each "time"
314  }
315  else
316  {
317  __COUT_INFO__
318  << "(Reverting to default wiz security) Sequence length file NOT found: "
319  << SEQUENCE_FILE_NAME << std::endl;
320  srand(0); // use same seed for convenience if file not found
321  }
322 
323  __COUT__ << "Sequence length = " << length << std::endl;
324 
325  securityCode_ = "";
326 
327  const char alphanum[] =
328  "0123456789"
329  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
330  "abcdefghijklmnopqrstuvwxyz";
331 
332  for(int i = 0; i < length; ++i)
333  {
334  securityCode_ += alphanum[rand() % (sizeof(alphanum) - 1)];
335  }
336 
337  __COUT__ << WizardSupervisor::WIZ_SUPERVISOR << ":" << WizardSupervisor::WIZ_PORT
338  << "/urn:xdaq-application:lid="
339  << this->getApplicationDescriptor()->getLocalId()
340  << "/Verify?code=" << securityCode_ << std::endl;
341 
342  // Note: print out handled by StartOTS.sh now
343  // std::thread([&](WizardSupervisor *ptr, std::string securityCode)
344  // {printURL(ptr,securityCode);},this,securityCode_).detach();
345 
346  fp = fopen((SEQUENCE_OUT_FILE_NAME).c_str(), "w");
347  if(fp)
348  {
349  fprintf(fp, "%s", securityCode_.c_str());
350  fclose(fp);
351  }
352  else
353  __COUT_ERR__ << "Sequence output file NOT found: " << SEQUENCE_OUT_FILE_NAME
354  << std::endl;
355 
356  return;
357 } // end generateURL()
358 
359 void WizardSupervisor::printURL(WizardSupervisor* ptr, std::string securityCode)
360 {
361  // child process
362  int i = 0;
363  for(; i < 5; ++i)
364  {
365  std::this_thread::sleep_for(std::chrono::seconds(2));
366  __COUT__ << WizardSupervisor::WIZ_SUPERVISOR << ":" << WizardSupervisor::WIZ_PORT
367  << "/urn:xdaq-application:lid="
368  << ptr->getApplicationDescriptor()->getLocalId()
369  << "/Verify?code=" << securityCode << std::endl;
370  }
371 } // end printURL()
372 
373 //==============================================================================
374 void WizardSupervisor::tooltipRequest(xgi::Input* in, xgi::Output* out)
375 {
376  cgicc::Cgicc cgi(in);
377 
378  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
379  //__COUT__ << "Command = " << Command << std::endl;
380 
381  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
382 
383  // SECURITY CHECK START ****
384  if(securityCode_.compare(submittedSequence) != 0)
385  {
386  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
387  << std::endl;
388  return;
389  }
390  // else
391  // {
392  // __COUT__ << "***Successfully authenticated security sequence." << std::endl;
393  // }
394  // SECURITY CHECK END ****
395 
396  HttpXmlDocument xmldoc;
397 
398  if(Command == "check")
399  {
400  WebUsers::tooltipCheckForUsername(WebUsers::DEFAULT_ADMIN_USERNAME,
401  &xmldoc,
402  CgiDataUtilities::getData(cgi, "srcFile"),
403  CgiDataUtilities::getData(cgi, "srcFunc"),
404  CgiDataUtilities::getData(cgi, "srcId"));
405  }
406  else if(Command == "setNeverShow")
407  {
409  WebUsers::DEFAULT_ADMIN_USERNAME,
410  &xmldoc,
411  CgiDataUtilities::getData(cgi, "srcFile"),
412  CgiDataUtilities::getData(cgi, "srcFunc"),
413  CgiDataUtilities::getData(cgi, "srcId"),
414  CgiDataUtilities::getData(cgi, "doNeverShow") == "1" ? true : false,
415  CgiDataUtilities::getData(cgi, "temporarySilence") == "1" ? true : false);
416  }
417  else
418  __COUT__ << "Command Request, " << Command << ", not recognized." << std::endl;
419 
420  xmldoc.outputXmlDocument((std::ostringstream*)out, false, true);
421 } // end tooltipRequest()
422 
423 //==============================================================================
424 void WizardSupervisor::toggleSecurityCodeGeneration(xgi::Input* in, xgi::Output* out)
425 {
426  cgicc::Cgicc cgi(in);
427 
428  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
429  __COUT__ << "Got to Command = " << Command << std::endl;
430 
431  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
432 
433  // SECURITY CHECK START ****
434  if(securityCode_.compare(submittedSequence) != 0)
435  {
436  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
437  << std::endl;
438  return;
439  }
440  else
441  {
442  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
443  }
444  // SECURITY CHECK END ****
445 
446  HttpXmlDocument xmldoc;
447 
448  if(Command == "TurnGenerationOn")
449  {
450  __COUT__ << "Turning automatic URL Generation on with a sequence depth of 16!"
451  << std::endl;
452  std::ofstream outfile((SEQUENCE_FILE_NAME).c_str());
453  outfile << "16" << std::endl;
454  outfile.close();
455  generateURL();
456 
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 } //end toggleSecurityCodeGeneration()
470 
471 //==============================================================================
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 } //end supervisorSequenceCheck()
508 
509 //===================================================================================================================
514 xoap::MessageReference WizardSupervisor::supervisorLastTableGroupRequest(
515  xoap::MessageReference message)
516 {
517  SOAPParameters parameters;
518  parameters.addParameter("ActionOfLastGroup");
519  SOAPUtilities::receive(message, parameters);
520 
521  return GatewaySupervisor::lastTableGroupRequestHandler(parameters);
522 } //end supervisorLastTableGroupRequest()
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 } //end Default()
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  *out << WebUsers::REQ_NO_PERMISSION_RESPONSE.c_str();
545  return;
546  }
547  else
548  {
549  __COUT__ << "***Successfully authenticated security sequence. " << time(0)
550  << std::endl;
551  }
552  // SECURITY CHECK END ****
553 
554  std::string requestType = CgiDataUtilities::getData(cgiIn, "RequestType");
555  __COUTV__(requestType);
556 
557  HttpXmlDocument xmlOut;
558 
559  try
560  {
561  // RequestType Commands:
562  // gatewayLaunchOTS
563  // gatewayLaunchWiz
564  // addDesktopIcon
565  // getSettings
566  // accountSettings
567 
568  if(requestType == "gatewayLaunchOTS" || requestType == "gatewayLaunchWiz")
569  {
570  // NOTE: similar to ConfigurationGUI version but DOES keep active login
571  // sessions
572 
573  __COUT_WARN__ << requestType << " requestType received! " << __E__;
574  __COUT_WARN__ << requestType << " requestType received! " << __E__;
575 
576  // now launch
577  ConfigurationManager cfgMgr;
578  if(requestType == "gatewayLaunchOTS")
579  GatewaySupervisor::launchStartOTSCommand("LAUNCH_OTS", &cfgMgr);
580  else if(requestType == "gatewayLaunchWiz")
581  GatewaySupervisor::launchStartOTSCommand("LAUNCH_WIZ", &cfgMgr);
582  }
583  else if(requestType == "addDesktopIcon")
584  {
585  GatewaySupervisor::handleAddDesktopIconRequest("admin", cgiIn, xmlOut);
586  }
587  else if(requestType == "getAppId")
588  {
589  GatewaySupervisor::handleGetApplicationIdRequest(
590  &allSupervisorInfo_, cgiIn, xmlOut);
591  }
592  else if(requestType == "getSettings")
593  {
594  std::string accounts = CgiDataUtilities::getData(cgiIn, "accounts");
595 
596  __COUT__ << "Get Settings Request" << __E__;
597  __COUT__ << "accounts = " << accounts << __E__;
598 
599  GatewaySupervisor::theWebUsers_.insertSettingsForUser(
600  0 /*admin UID*/, &xmlOut, accounts == "1");
601  }
602  else if(requestType == "accountSettings")
603  {
604  std::string type = CgiDataUtilities::postData(
605  cgiIn, "type"); // updateAccount, createAccount, deleteAccount
606  int type_int = -1;
607 
608  if(type == "updateAccount")
609  type_int = GatewaySupervisor::theWebUsers_.MOD_TYPE_UPDATE;
610  else if(type == "createAccount")
611  type_int = GatewaySupervisor::theWebUsers_.MOD_TYPE_ADD;
612  else if(type == "deleteAccount")
613  type_int = GatewaySupervisor::theWebUsers_.MOD_TYPE_DELETE;
614 
615  std::string username = CgiDataUtilities::postData(cgiIn, "username");
616  std::string displayname = CgiDataUtilities::postData(cgiIn, "displayname");
617  std::string email = CgiDataUtilities::postData(cgiIn, "useremail");
618  std::string permissions = CgiDataUtilities::postData(cgiIn, "permissions");
619  std::string accounts = CgiDataUtilities::getData(cgiIn, "accounts");
620 
621  __COUT__ << "accountSettings Request" << __E__;
622  __COUT__ << "type = " << type << " - " << type_int << __E__;
623  __COUT__ << "username = " << username << __E__;
624  __COUT__ << "useremail = " << email << __E__;
625  __COUT__ << "displayname = " << displayname << __E__;
626  __COUT__ << "permissions = " << permissions << __E__;
627 
628  GatewaySupervisor::theWebUsers_.modifyAccountSettings(
629  0 /*admin UID*/, type_int, username, displayname, email, permissions);
630 
631  __COUT__ << "accounts = " << accounts << __E__;
632 
633  GatewaySupervisor::theWebUsers_.insertSettingsForUser(
634  0 /*admin UID*/, &xmlOut, accounts == "1");
635  }
636  else
637  {
638  __SS__ << "requestType Request '" << requestType << "' not recognized."
639  << __E__;
640  __SS_THROW__;
641  }
642  }
643  catch(const std::runtime_error& e)
644  {
645  __SS__ << "An error was encountered handling requestType '" << requestType
646  << "':" << e.what() << __E__;
647  __COUT__ << "\n" << ss.str();
648  xmlOut.addTextElementToData("Error", ss.str());
649  }
650  catch(...)
651  {
652  __SS__ << "An unknown error was encountered handling requestType '" << requestType
653  << ".' "
654  << "Please check the printouts to debug." << __E__;
655  try
656  {
657  throw;
658  } //one more try to printout extra info
659  catch(const std::exception& e)
660  {
661  ss << "Exception message: " << e.what();
662  }
663  catch(...)
664  {
665  }
666  __COUT__ << "\n" << ss.str();
667  xmlOut.addTextElementToData("Error", ss.str());
668  }
669 
670  // report any errors encountered
671  {
672  unsigned int occurance = 0;
673  std::string err = xmlOut.getMatchingValue("Error", occurance++);
674  while(err != "")
675  {
676  __COUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err << __E__;
677  __COUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err << __E__;
678  err = xmlOut.getMatchingValue("Error", occurance++);
679  }
680  }
681 
682  // return xml doc holding server response
683  xmlOut.outputXmlDocument(
684  (std::ostringstream*)out,
685  false /*dispStdOut*/,
686  true /*allowWhiteSpace*/); // Note: allow white space need for error response
687 
688 } // end request()
689 
690 //==============================================================================
691 void WizardSupervisor::editSecurity(xgi::Input* in, xgi::Output* out)
692 {
693  // if sequence doesn't match up -> return
694  cgicc::Cgicc cgi(in);
695  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
696  std::string submittedSecurity = CgiDataUtilities::postData(cgi, "selection");
697 
698  // SECURITY CHECK START ****
699  if(securityCode_.compare(submittedSequence) != 0)
700  {
701  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
702  << std::endl;
703  return;
704  }
705  else
706  {
707  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
708  }
709  // SECURITY CHECK END ****
710 
711  if(submittedSecurity != "")
712  {
713  __COUT__ << "Selection exists!" << std::endl;
714  __COUT__ << submittedSecurity << std::endl;
715 
716  if(submittedSecurity == "ResetAllUserData")
717  {
718  WebUsers::deleteUserData();
719  __COUT__ << "Turning URL Generation back to default!" << std::endl;
720  // std::remove((SEQUENCE_FILE_NAME).c_str());
721  // std::remove((SEQUENCE_OUT_FILE_NAME).c_str());
722  std::ofstream newFile((SEQUENCE_FILE_NAME).c_str());
723  newFile << "4" << std::endl;
724  newFile.close();
725 
726  generateURL();
727  std::thread([&](WizardSupervisor* ptr,
728  std::string securityCode) { printURL(ptr, securityCode); },
729  this,
730  securityCode_)
731  .detach();
732  *out << "Default_URL_Generation";
733  }
734  else if(submittedSecurity == "ResetAllUserTooltips")
735  {
737  *out << submittedSecurity;
738  return;
739  }
740  else if(submittedSecurity == WebUsers::SECURITY_TYPE_DIGEST_ACCESS ||
741  submittedSecurity == WebUsers::SECURITY_TYPE_NONE)
742  {
743  // attempt to make directory structure (just in case)
744  mkdir((WizardSupervisor::SERVICE_DATA_PATH).c_str(), 0755);
745  mkdir((WizardSupervisor::SERVICE_DATA_PATH + "/OtsWizardData").c_str(), 0755);
746 
747  std::ofstream writeSecurityFile;
748 
749  writeSecurityFile.open((SECURITY_FILE_NAME).c_str());
750  if(writeSecurityFile.is_open())
751  writeSecurityFile << submittedSecurity;
752  else
753  {
754  __COUT_ERR__ << "Error writing file!" << std::endl;
755  *out << "Error";
756  return;
757  }
758 
759  writeSecurityFile.close();
760  }
761  else
762  {
763  __COUT_ERR__ << "Invalid submittedSecurity string: " << submittedSecurity
764  << std::endl;
765  *out << "Error";
766  return;
767  }
768  }
769 
770  {
771  // Always return the file
772  std::ifstream securityFile;
773  std::string security;
774 
775  securityFile.open((SECURITY_FILE_NAME).c_str());
776  if(securityFile.is_open())
777  {
778  std::getline(securityFile, security);
779  securityFile.close();
780  }
781  else
782  security =
783  WebUsers::SECURITY_TYPE_DEFAULT; // default security when no file exists
784 
785  *out << security;
786  }
787 
788 } // end editSecurity()
789 
790 //==============================================================================
791 void WizardSupervisor::UserSettings(xgi::Input* in, xgi::Output* out)
792 {
793  // if sequence doesn't match up -> return
794  cgicc::Cgicc cgi(in);
795  std::string submittedSequence = CgiDataUtilities::postData(cgi, "sequence");
796  std::string securityFileName = SECURITY_FILE_NAME;
797  std::string Command;
798  if((Command = CgiDataUtilities::postData(cgi, "RequestType")) == "")
799  Command = cgi("RequestType"); // get command from form, if PreviewEntry
800 
801  __COUT__ << Command << std::endl;
802  __COUT__ << "We are viewing Users' Settings!" << std::endl;
803 
804  // SECURITY CHECK START ****
805  if(securityCode_.compare(submittedSequence) != 0)
806  {
807  __COUT__ << "Unauthorized Request made, security sequence doesn't match!"
808  << std::endl;
809  __COUT__ << submittedSequence << std::endl;
810  // return;
811  }
812  else
813  {
814  __COUT__ << "***Successfully authenticated security sequence." << std::endl;
815  }
816  // SECURITY CHECK END ****
817 
818  HttpXmlDocument xmldoc;
819  // uint64_t activeSessionIndex;
820  std::string user;
821  // uint8_t userPermissions;
822 
823  if(Command != "")
824  {
825  __COUT__ << "Action exists!" << std::endl;
826  __COUT__ << Command << std::endl;
827 
828  if(Command == "Import")
829  {
830  // cleanup temporary folder
831  // NOTE: all input parameters for User Data will be attached to form
832  // so use cgi(xxx) to get values.
833  // increment number for each temporary preview, previewPostTempIndex_
834  // save entry and uploads to previewPath / previewPostTempIndex_ /.
835 
836  // cleanUpPreviews();
837  // std::string EntryText = cgi("EntryText");
838  // __COUT__ << "EntryText " << EntryText << std::endl << std::endl;
839  // std::string EntrySubject = cgi("EntrySubject");
840  // __COUT__ << "EntrySubject " << EntrySubject << std::endl <<
841  // std::endl;
842 
843  // get creator name
844  // std::string creator = user;
845  // CgiDataUtilities::postData(cgi, "file");//
846  // __COUT__ << cgi("Entry") << std::endl;
847  // __COUT__ << cgi("Filename") << std::endl;
848  // __COUT__ << cgi("Imported_File") << std::endl;
849 
850  std::string pathToTemporalFolder = USER_IMPORT_EXPORT_PATH + "tmp/";
851  filesystem::path temporaryPath = pathToTemporalFolder;
852 
853  if(filesystem::exists(temporaryPath))
854  __COUT__ << temporaryPath << " exists!" << std::endl;
855  else
856  {
857  __COUT__ << temporaryPath << " does not exist! Creating it now. "
858  << std::endl;
859  filesystem::create_directory(temporaryPath);
860  }
861 
862  // read the uploaded values
863  const std::vector<cgicc::FormFile> files = cgi.getFiles();
864  // __COUT__ << "FormFiles: " << sizeof(files) << std::endl;
865  // __COUT__ << "Number of files: " << files.size() << std::endl;
866  // sets uploaded values in a file with the same name within the structure
867  for(unsigned int i = 0; i < files.size(); ++i)
868  {
869  std::string filename = pathToTemporalFolder + files[i].getFilename();
870  // __SS__ << filename << __E__;
871  // __COUT_ERR__ << "\n" << ss.str();
872  std::size_t tarFoundFlag = filename.find(".tar");
873  std::size_t tarGzFoundFlag = filename.find("gz");
874  std::size_t tarBzFoundFlag = filename.find("bz2");
875 
876  if(tarFoundFlag != std::string::npos)
877  {
878  if(tarGzFoundFlag != std::string::npos ||
879  tarBzFoundFlag != std::string::npos)
880  {
881  __SS__
882  << "This is not a valid tar file, due to bad extension naming"
883  << __E__;
884  __COUT_ERR__ << "\n" << ss.str();
885  }
886  else
887  {
888  std::ofstream myFile;
889  myFile.open(filename.c_str());
890  files[0].writeToStream(myFile);
891  std::string commandToDecompressUserData =
892  std::string("tar -xvf ") + filename;
893  filesystem::current_path(USER_IMPORT_EXPORT_PATH);
894  system(commandToDecompressUserData.c_str());
895  // std::string resultString = StringMacros::exec(commandToDecompressUserData.c_str());
896  // __COUTV__(resultString);
897  }
898  }
899  else
900  {
901  __SS__ << "This is not a valid tar file for user preferences"
902  << __E__;
903  __COUT_ERR__ << "\n" << ss.str();
904  }
905  }
906 
907  // __COUT__ << files[0].getFilename() << std::endl;
908  // __COUT__ << "********************Files Begin********************" << std::endl;
909  // for(unsigned int i = 0; i < files.size(); ++i)
910  // {
911  // __COUT__ << files[i].getDataType() << std::endl;
912  // }
913  // __COUT__ << "*********************Files End*********************" << std::endl;
914 
915  // savePostPreview(EntrySubject, EntryText, cgi.getFiles(), creator,
916  //&xmldoc); else xmldoc.addTextElementToData(XML_STATUS,"Failed - could not
917  // get username info.");
918  }
919  else if(Command == "Export")
920  {
921  // __SS__ << "This has been commented out due to problems compiling. Contact "
922  // "system admins."
923  // << __E__;
924  //__COUT_ERR__ << "\n" << ss.str();
925 
926  // // Check for a TMP directory; if it doesn't exist, make it
927  std::string pathToTemporalFolder = USER_IMPORT_EXPORT_PATH + "tmp/";
928  filesystem::path temporaryPath = pathToTemporalFolder;
929 
930  if(filesystem::exists(temporaryPath))
931  __COUT__ << temporaryPath << " exists!" << std::endl;
932  else
933  {
934  __COUT__ << temporaryPath << " does not exist! Creating it now. "
935  << std::endl;
936  filesystem::create_directory(temporaryPath);
937  }
938  std::string commandToCompressUserData =
939  std::string("tar -cvf user_settings.tar ") +
940  std::string("ActiveTableGroups.cfg ") +
941  std::string("ConsolePreferences ") +
942  std::string("CoreTableInfoNames.dat ") + std::string("LoginData ") +
943  std::string("OtsWizardData ") + std::string("ProgressBarData ");
944 
945  filesystem::current_path(USER_IMPORT_EXPORT_PATH);
946  system(commandToCompressUserData.c_str());
947  filesystem::rename("user_settings.tar", "tmp/user_settings.tar");
948  filesystem::current_path(temporaryPath);
949  __COUT__ << system("echo You can find the output on the following path ")
950  << __E__;
951  __COUT__ << system("pwd") << std::endl;
952  }
953  else
954  {
955  __COUT__ << "Command request not recognized: " << Command << std::endl;
956  *out << "Error";
957  return;
958  }
959  }
960 
961  *out << "test";
962  return;
963 } //end UserSettings()
964 
965 //==============================================================================
968 std::string WizardSupervisor::validateUploadFileType(const std::string fileType)
969 {
970  for(unsigned int i = 0; i < allowedFileUploadTypes_.size(); ++i)
971  if(allowedFileUploadTypes_[i] == fileType)
972  return matchingFileUploadTypes_[i]; // found and done
973 
974  return ""; // not valid, return ""
975 } //end validateUploadFileType()
976 
977 //==============================================================================
981 void WizardSupervisor::cleanUpPreviews()
982 {
983  std::string userData = (std::string)USER_IMPORT_EXPORT_PATH;
984 
985  DIR* dir = opendir(userData.c_str());
986  if(!dir)
987  {
988  __COUT__ << "Error - User Data directory missing: " << userData << std::endl;
989  return;
990  }
991 
992  struct dirent* entry;
993  time_t dirCreateTime;
994  unsigned int i;
995 
996  while(
997  (entry = readdir(
998  dir))) // loop through all entries in directory and remove anything expired
999  {
1000  if(strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 &&
1001  strcmp(entry->d_name, ".svn") != 0)
1002  {
1003  // replace _ with space so sscanf works
1004  for(i = 0; i < strlen(entry->d_name); ++i)
1005  if(entry->d_name[i] == '_')
1006  {
1007  entry->d_name[i] = ' ';
1008  break;
1009  }
1010  sscanf(entry->d_name, "%li", &dirCreateTime);
1011 
1012  if((time(0) - dirCreateTime) > USER_DATA_EXPIRATION_TIME)
1013  {
1014  __COUT__ << "Expired" << std::endl;
1015 
1016  entry->d_name[i] = '_'; // put _ back
1017 
1018  __COUT__ << "rm -rf "
1019  << USER_IMPORT_EXPORT_PATH + (std::string)entry->d_name
1020  << std::endl
1021  << std::endl;
1022  system(((std::string)("rm -rf " + userData + (std::string)entry->d_name))
1023  .c_str());
1024  }
1025  }
1026  }
1027 
1028  closedir(dir);
1029 } //end cleanUpPreviews()
1030 
1031 //==============================================================================
1034 void WizardSupervisor::savePostPreview(std::string& /*subject*/,
1035  std::string& /*text*/,
1036  const std::vector<cgicc::FormFile>& /*files*/,
1037  std::string /*creator*/,
1038  HttpXmlDocument* xmldoc)
1039 {
1040  /*if(activeExperiment_ == "") //no active experiment!
1041  {
1042  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"Failed - no active experiment
1043  currently!"); return;
1044  }
1045 */
1046  char fileIndex[40];
1047  sprintf(fileIndex,
1048  "%lu_%lu",
1049  time(0),
1050  clock()); // create unique time label for entry time(0)_clock()
1051  std::string userDataPath =
1052  (std::string)USER_IMPORT_EXPORT_PATH + (std::string)fileIndex;
1053 
1054  __COUT__ << "userDataPath " << userDataPath << std::endl;
1055  if(-1 == mkdir(userDataPath.c_str(), 0755))
1056  {
1057  if(xmldoc)
1058  xmldoc->addTextElementToData(XML_STATUS,
1059  "Failed - directory could not be generated.");
1060  return;
1061  }
1062  /*
1063  //new directory created successfully, save text and files
1064  //entry structure:
1065  // <XML_LOGBOOK_ENTRY>
1066  // <XML_LOGBOOK_ENTRY_TIME>
1067  // <XML_LOGBOOK_ENTRY_CREATOR>
1068  // <XML_LOGBOOK_ENTRY_SUBJECT>
1069  // <XML_LOGBOOK_ENTRY_TEXT>
1070  // <XML_LOGBOOK_ENTRY_FILE value=fileType0>
1071  // <XML_LOGBOOK_ENTRY_FILE value=fileType1> ...
1072  // </XML_LOGBOOK_ENTRY>
1073 
1074  escapeLogbookEntry(text);
1075  escapeLogbookEntry(subject);
1076  __COUT__ << "~~subject " << subject << std::endl << "~~text " << text << std::endl <<
1077  std::endl;
1078 
1079  HttpXmlDocument previewXml;
1080 
1081  previewXml.addTextElementToData(XML_LOGBOOK_ENTRY);
1082  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TIME, fileIndex,
1083  XML_LOGBOOK_ENTRY); if(xmldoc)
1084  xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_TIME,fileIndex); //return time
1085  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_CREATOR, creator,
1086  XML_LOGBOOK_ENTRY); if(xmldoc)
1087  xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_CREATOR,creator); //return creator
1088  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_TEXT, text, XML_LOGBOOK_ENTRY);
1089  if(xmldoc) xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_TEXT,text); //return text
1090  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_SUBJECT, subject,
1091  XML_LOGBOOK_ENTRY); if(xmldoc)
1092  xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_SUBJECT,subject); //return subject
1093 
1094  __COUT__ << "file size " << files.size() << std::endl;
1095 
1096  std::string filename;
1097  std::ofstream myfile;
1098  for (unsigned int i=0; i<files.size(); ++i)
1099  {
1100 
1101  previewXml.addTextElementToParent(XML_LOGBOOK_ENTRY_FILE, files[i].getDataType(),
1102  XML_LOGBOOK_ENTRY); if(xmldoc)
1103  xmldoc->addTextElementToData(XML_LOGBOOK_ENTRY_FILE,files[i].getDataType()); //return
1104  file type
1105 
1106  if((filename = validateUploadFileType(files[i].getDataType())) == "") //invalid
1107  file type
1108  {
1109  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"Failed - invalid file
1110  type, " + files[i].getDataType() + "."); return;
1111  }*/
1112 
1113  /*//file validated, so save upload to temp directory
1114  sprintf(fileIndex,"%d",i);
1115  filename = previewPath + "/" + (std::string)LOGBOOK_PREVIEW_UPLOAD_PREFACE +
1116  (std::string)fileIndex + "." + filename;
1117 
1118  __COUT__ << "file " << i << " - " << filename << std::endl;
1119  myfile.open(filename.c_str());
1120  if (myfile.is_open())
1121  {
1122  files[i].writeToStream(myfile);
1123  myfile.close();
1124  }
1125  }*/
1126  /*
1127  //save xml doc for preview entry
1128  previewXml.saveXmlDocument(USER_IMPORT_EXPORT_PATH + "/" + (std::string)LOGBOOK_PREVIEW_FILE);
1129 
1130  if(xmldoc) xmldoc->addTextElementToData(XML_STATUS,"1"); //1 indicates success!
1131  if(xmldoc) xmldoc->addTextElementToData(XML_PREVIEW_INDEX,"1"); //1 indicates is a
1132  preview post*/
1133 } //end savePostPreview()
static std::string postData(cgicc::Cgicc &cgi, const std::string &needle)
static std::string getData(cgicc::Cgicc &cgi, const std::string &needle)
void outputXmlDocument(std::ostringstream *out, bool dispStdOut=false, bool allowWhiteSpace=false)
std::string getMatchingValue(const std::string &field, const unsigned int occurance=0)
static void resetAllUserTooltips(const std::string &userNeedle="*")
WebUsers::resetAllUserTooltips.
Definition: WebUsers.cc:2856
static void tooltipSetNeverShowForUsername(const std::string &username, HttpXmlDocument *xmldoc, const std::string &srcFile, const std::string &srcFunc, const std::string &srcId, bool doNeverShow, bool temporarySilence)
Definition: WebUsers.cc:2733
static void tooltipCheckForUsername(const std::string &username, HttpXmlDocument *xmldoc, const std::string &srcFile, const std::string &srcFunc, const std::string &srcId)
Definition: WebUsers.cc:2791
@ PERMISSION_LEVEL_ADMIN
max permission level!
Definition: WebUsers.h:64
xoap::MessageReference supervisorSequenceCheck(xoap::MessageReference message)
External Supervisor XOAP handlers.
void INIT_MF(const char *name)
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")