Advertisement
Guest User

Untitled

a guest
Jul 14th, 2016
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.36 KB | None | 0 0
  1. /**
  2. * sendEmail
  3. * Function mapped to Laravel route. Defines variable arrays and calls Email Class executeEmail.
  4. *
  5. * @param Request $request Request object passed via AJAX from client.
  6. */
  7. public function sendEmail(Request $request) {
  8. $projectName = $request['projectName'];
  9. $projectId = intval($projectName,strpos($projectName,'_'));
  10. $projectName = substr($projectName,0,strpos($projectName,'_')-1);
  11. $period = 4;
  12.  
  13. try {
  14. $templateConfig = new TemplateConfiguration(
  15. array(
  16. 'templateName'=>$request['emailTemplate'],
  17. 'companyName'=>$request['companyName'],
  18. 'projectName'=>$projectName,
  19. 'projectId'=>$projectId
  20. )
  21. );
  22.  
  23. $emailConfig = new EmailConfiguration(
  24. array(
  25. 'host'=>$request['hostName'],
  26. 'port'=>$request['port'],
  27. 'authUsername'=>$request['username'],
  28. 'authPassword'=>$request['password'],
  29. 'fromEmail'=>$request['fromEmail'],
  30. 'subject'=>$request['subject']
  31. )
  32. );
  33.  
  34. Email::executeEmail($emailConfig,$templateConfig,$period);
  35. } catch(ConfigurationException $ce) {
  36.  
  37. } catch(EmailException $ee) {
  38.  
  39. }
  40. }
  41.  
  42. private $host;
  43. private $port;
  44. private $authUsername;
  45. private $authPassword;
  46. private $fromEmail;
  47. private $subject;
  48. private $usersIterator;
  49.  
  50. /**
  51. * EmailConfiguration constructor.
  52. * @param $emailSettings
  53. */
  54. public function __construct($emailSettings) {
  55. try {
  56. if($this->areSettingsValid($emailSettings)) {
  57. $this->host = $emailSettings['host'];
  58. $this->port = $emailSettings['port'];
  59. $this->authUsername = $emailSettings['authUsername'];
  60. $this->authPassword = $emailSettings['authPassword'];
  61. $this->fromEmail = $emailSettings['fromEmail'];
  62. $this->subject = $emailSettings['subject'];
  63.  
  64. try {
  65. $db = new DBManager();
  66. $sql = "SELECT * FROM gaig_users.users;";
  67. $users = $db->query($sql,array(),array('PDO::ATTR_CURSOR'),array('PDO::CURSOR_SCROLL'));
  68. $this->usersIterator = new PDOIterator($users);
  69. } catch(PDOException $pdoe) {
  70. DBManager::logConnectError(__CLASS__,__FUNCTION__,$pdoe->getMessage(),$pdoe->getTrace());
  71. throw new ConfigurationException('Failed to connect to database.',0,$pdoe);
  72. } catch(QueryException $qe) {
  73. DBManager::logQueryError(__CLASS__,__FUNCTION__,$qe);
  74. throw new ConfigurationException('Failed to query users from database.',0,$qe);
  75. }
  76. }
  77. } catch(OutOfBoundsException $oobe) {
  78. throw new ConfigurationException('Invalid email setting(s).',0,$oobe);
  79. } catch(InvalidArgumentException $iae) {
  80. throw new ConfigurationException('Invalid email setting(s).',0,$iae);
  81. }
  82.  
  83. }
  84.  
  85. /**
  86. * @param $emailSettings
  87. * @return bool
  88. */
  89. private function areSettingsValid($emailSettings) {
  90. $message = '';
  91. if(empty($emailSettings)) {
  92. throw new OutOfBoundsException('No settings specified.');
  93. }
  94. if(!is_array($emailSettings)) {
  95. throw new OutOfBoundsException('Expected array, received ' . get_class($emailSettings) . ' Object');
  96. }
  97. if(is_null($emailSettings['host'])) {
  98. $message .= 'Host value cannot be null.' . PHP_EOL;
  99. }
  100. if(is_null($emailSettings['port'])) {
  101. $message .= 'Port value cannot be null.' . PHP_EOL;
  102. }
  103. if(is_null($emailSettings['authUsername'])) {
  104. $message .= 'Authenticating username value cannot be null.' . PHP_EOL;
  105. }
  106. if(is_null($emailSettings['authPassword'])) {
  107. $message .= 'Authenticating password value cannot be null.' . PHP_EOL;
  108. }
  109. if(is_null($emailSettings['fromEmail'])) {
  110. $message .= 'From email address value cannot be null.' . PHP_EOL;
  111. }
  112. if(is_null($emailSettings['subject'])) {
  113. $message .= 'Subject value cannot be null.' . PHP_EOL;
  114. }
  115. if(!empty($message)) {
  116. throw new OutOfBoundsException($message);
  117. }
  118.  
  119. if($this->isValidDomainName($emailSettings['host'])) {
  120. if(!filter_var($emailSettings['port'],FILTER_VALIDATE_INT)) {
  121. $message .= 'Port is not a valid integer. Value provided: ' . var_export(['port'],true) . PHP_EOL;
  122. }
  123. if(!filter_var($emailSettings['fromEmail'],FILTER_VALIDATE_EMAIL)) {
  124. $message .= 'From Email is not a valid email address. Value provided: ' . var_export($emailSettings['fromEmail'],true) . PHP_EOL;
  125. }
  126. } else {
  127. if(filter_var($emailSettings['host'],FILTER_VALIDATE_IP)) {
  128. if(!filter_var($emailSettings['port'],FILTER_VALIDATE_INT)) {
  129. $message .= 'Port is not a valid integer. Value provided: ' . var_export(['port'],true) . PHP_EOL;
  130. }
  131. if(!filter_var($emailSettings['fromEmail'],FILTER_VALIDATE_EMAIL)) {
  132. $message .= 'From Email is not a valid email address. Value provided: ' . var_export($emailSettings['fromEmail'],true) . PHP_EOL;
  133. }
  134. } else {
  135. $message = 'Host is not a valid host name or IP address. Value provided: ' . var_export($emailSettings['host'],true) . PHP_EOL;
  136. }
  137. }
  138. if(!empty($message)) {
  139. throw new InvalidArgumentException($message);
  140. }
  141. return true;
  142. }
  143.  
  144. /**
  145. * @param $domainName
  146. * @return int
  147. */
  148. private function isValidDomainName($domainName) {
  149. $pattern = ';(?:https?://)?(?:[a-zA-z0-9]+?.(?:com|net|org|gov|edu|co.uk));';
  150. return (preg_match($pattern, $domainName));
  151. }
  152.  
  153. private $template;
  154. private $templatePrefix;
  155. private $companyName;
  156. private $projectName;
  157. private $projectId;
  158.  
  159. /**
  160. * TemplateConfiguration constructor.
  161. * @param $templateSettings
  162. */
  163. public function __construct($templateSettings) {
  164. try {
  165. if($this->areSettingsValid($templateSettings)) {
  166. $this->checkFileExist($templateSettings);
  167. }
  168. } catch(FileNotFoundException $fnfe) {
  169. throw new ConfigurationException('Invalid template name.',0,$fnfe);
  170. } catch(OutOfBoundsException $oobe) {
  171. throw new ConfigurationException('Invalid template setting(s).',0,$oobe);
  172. }
  173. }
  174.  
  175. /**
  176. * @param $templateSettings
  177. */
  178. private function checkFileExist($templateSettings) {
  179. $path = '../resources/views/emails';
  180. $templateName = $templateSettings['templateName'];
  181. if(file_exists("$path/phishing/$templateName")) {
  182. $this->templatePrefix = 'emails.phishing.';
  183. $this->setSettings($templateSettings);
  184. } else if(file_exists("$path/edu/$templateName")) {
  185. $this->templatePrefix = 'emails.edu.';
  186. $this->setSettings($templateSettings);
  187. } else {
  188. throw new FileNotFoundException("Failed to find template: $templateName");
  189. }
  190. }
  191.  
  192. /**
  193. * @param $templateSettings
  194. * @return bool
  195. */
  196. private function areSettingsValid($templateSettings) {
  197. $message = '';
  198. if(empty($templateSettings)) {
  199. throw new OutOfBoundsException('No settings specified.');
  200. }
  201. if(!is_array($templateSettings)) {
  202. throw new OutOfBoundsException('Expected array, received ' . get_class($templateSettings) . ' Object');
  203. }
  204. if(is_null($templateSettings['templateName'])) {
  205. $message .= 'Template Name value cannot be null.' . PHP_EOL;
  206. }
  207. if(is_null($templateSettings['companyName'])) {
  208. $message .= 'Company Name value cannot be null.' . PHP_EOL;
  209. }
  210. if(is_null($templateSettings['projectName'])) {
  211. $message .= 'Project Name value cannot be null.' . PHP_EOL;
  212. }
  213. if(is_null($templateSettings['projectId'])) {
  214. $message .= 'Project ID value cannot be null.' . PHP_EOL;
  215. }
  216. if(!empty($message)) {
  217. throw new OutOfBoundsException($message);
  218. }
  219. return true;
  220. }
  221.  
  222. /**
  223. * @param $templateSettings
  224. */
  225. private function setSettings($templateSettings) {
  226. $this->template = $templateSettings['templateName'];
  227. $this->companyName = $templateSettings['companyName'];
  228. $this->projectName = $templateSettings['projectName'];
  229. $this->projectId = $templateSettings['projectId'];
  230. }
  231.  
  232. /**
  233. * executeEmail
  234. * Public-facing method to send an email to a database of users if they are a valid recipient.
  235. *
  236. * @param array $emailSettings Host, port, username, and password variables for the mail server
  237. * @param array $template Email Template, Template Type, Template Target Type for user validation
  238. * string Email Template Path to the blade.php template file from the views directory
  239. * string Template Type Specifies whether the email is an Advanced (adv) or Basic (bsc) scam
  240. * string Template Target Type Specifies whether the email is a Targeted (T) or Generic (G) scam
  241. * @param array $params Period, Project Name, Project ID, From Email Address, Company Name, Subject
  242. * int Period Number of weeks to check back for recipient validation
  243. * string Project Name Name of this project
  244. * int Project Id ID of this project
  245. * string From Email Address Email to be sent from
  246. * string Company Name Name of company sponsoring this awareness test *optional*
  247. * string Subject Subject of email *optional*
  248. * @throws FailureException Thrown from sendEmail() if mail fails to be given to mail server
  249. */
  250.  
  251. /**
  252. * @param appEmailConfiguration $emailConfig
  253. * @param TemplateConfiguration $templateConfig
  254. * @param $period
  255. * @throws EmailException
  256. */
  257. public static function executeEmail(EmailConfiguration $emailConfig, TemplateConfiguration $templateConfig, $period) {
  258. try {
  259. foreach($emailConfig->getUsersIterator() as $user) {
  260. if(self::validateUser($templateConfig->getTemplateComplexityType(),
  261. $templateConfig->getTemplateTargetType(), $user, $period))
  262. {
  263. $urlId = self::getUrlId($user,$templateConfig->getProjectId());
  264.  
  265. $headers = array(
  266. 'companyName'=>$templateConfig->getCompanyName(),
  267. 'projectName'=>$templateConfig->getProjectName(),
  268. 'projectId'=>$templateConfig->getProjectId(),
  269. 'lastName'=>$user['USR_LastName'],
  270. 'username'=>$user['USR_Username'],
  271. 'urlId'=>$urlId
  272. );
  273. self::sendEmail($templateConfig->getTemplate(),$headers,$user['USR_Email'],
  274. $emailConfig->getFromEmail(),$emailConfig->getSubject());
  275.  
  276. $projects = array($templateConfig->getProjectName(),$user['USR_ProjectMostRecent'],$user['USR_ProjectPrevious']);
  277. self::updateUserProjects($projects,$user);
  278. }
  279. }
  280. } catch(PDOException $pdoe) {
  281. throw new EmailException('Failed to connect to database.',0,$pdoe);
  282. } catch(QueryException $qe) {
  283. throw new EmailException('Failed to query users from database.',0,$qe);
  284. } catch(FailureException $fe) {
  285. throw new EmailException('Failed to send email.',0,$fe);
  286. }
  287. }
  288.  
  289. /**
  290. * validateUser
  291. * Function checks if the specified user has not received a test within the specified duration,
  292. * if the template type is the same for the last two project participants, if the template target
  293. * is the same for last three project participants, or if the last project is identical to the new project.
  294. *
  295. * @param string $templateType Specifies whether the email is an Advanced (adv) or Basic (bsc) scam
  296. * @param string $templateTarget Specifies whether the email is a Targeted (T) or Generic (G) scam
  297. * @param array $user Associative Array containing the fields associated to the user
  298. * @param int $period Number of weeks to check back for recipient validation
  299. * @return bool
  300. */
  301. private function validateUser($templateType,$templateTarget,$user,$period) {
  302. $db = new DBManager();
  303. $date = date('Y-m-d',strtotime('-' . $period . 'weeks')) . '00:00:00';
  304. $sql = "SELECT max(SML_AccessTimestamp) as 'timestamp_check' from gaig_users.sent_email where SML_UserId = ? and SML_ProjectName = ?;";
  305. $bindings = array($user['USR_UserId'],$user['USR_ProjectMostRecent']);
  306. $timestampData = $db->query($sql,$bindings);
  307. $result = $timestampData->fetch(PDO::FETCH_ASSOC);
  308. if(!filter_var($user['USR_Email'],FILTER_VALIDATE_EMAIL)) {
  309. $this->badEmailAddressWarning(['USR_Username'] . ' has a bad email address. email=' . $user['USR_Email']);
  310. return false;
  311. }
  312. if($result['timestamp_check'] <= $date) {
  313. return true;
  314. } else if($templateType == substr($user['USR_ProjectMostRecent'],-5,3) &&
  315. $templateType == substr($user['USR_ProjectPrevious'],-5,3)) {
  316. return false;
  317. } else if($templateTarget == substr($user['USR_ProjectMostRecent'],-2,1) &&
  318. $templateTarget == substr($user['USR_ProjectPrevious'],-2,1) &&
  319. $templateTarget == substr($user['USR_ProjectLast'],-2,1)) {
  320. return false;
  321. } else if($templateType.$templateTarget ==
  322. substr($user['USR_ProjectMostRecent'],strpos($user['USR_ProjectMostRecent'],'-')+1,4)) {
  323. return false;
  324. }
  325. return true;
  326. }
  327.  
  328. /**
  329. * getUrlId
  330. * Generates or retrieves the UniqueURLId of the passed user.
  331. *
  332. * @param array $user User array extracted from PDOStatement
  333. * @return string
  334. */
  335. private function getUrlId($user,$projectId) {
  336. $db = new DBManager();
  337. if(!is_null($user['USR_UniqueURLId'])) {
  338. $urlId = $user['USR_UniqueURLId'];
  339. } else {
  340. $urlId = $this->random_str(15) . $projectId;
  341. $sql = "UPDATE gaig_users.users SET USR_UniqueURLId=? WHERE USR_UserId=?;";
  342. $bindings = array($urlId,$user['USR_UserId']);
  343. $db->query($sql,$bindings);
  344. }
  345. return $urlId;
  346. }
  347.  
  348. /**
  349. * updateUserProjects
  350. * Updates the user with the newest project and rotates the old projects down one.
  351. *
  352. * @param array $projects Most Recent Project, Previous Project, Oldest Project
  353. * @param array $user User array extracted from PDOStatement
  354. */
  355. private function updateUserProjects($projects,$user) {
  356. $db = new DBManager();
  357. $sql = "UPDATE gaig_users.users SET USR_ProjectMostRecent=?, USR_ProjectPrevious=?,
  358. USR_ProjectLast=? WHERE USR_Username=?;";
  359. $bindings = array($projects[0],$projects[1],$projects[2],$user['USR_Username']);
  360. $db->query($sql,$bindings);
  361. }
  362.  
  363. /**
  364. * sendEmail
  365. * Iterates through the PDO Result Set of users. Calls validRecipientAlgo to validate user. Sends email if
  366. * valid and updates user if valid.
  367. * @param array $params Required parameters to pass to the email template
  368. * @param string $from Email to be sent from
  369. * @param string $subject Subject of email
  370. * @throws FatalErrorException
  371. */
  372. private function sendEmail($template, $headers, $to, $from, $subject) {
  373. if(!Mail::send(['html' => $template],$headers, function($m) use ($from, $to, $subject) {
  374. $m->from($from);
  375. $m->to($to)->subject($subject);
  376. })) {
  377. throw new FailureException('Email failed to send to ' . $to . ' from ' . $from);
  378. }
  379. }
  380.  
  381. /**
  382. * random_str
  383. * Generates a random string.
  384. *
  385. * @param int $length Length of string to be returned
  386. * @param string $keyspace Allowed characters to be used in string
  387. * @return string
  388. */
  389. private function random_str($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
  390. {
  391. $str = '';
  392. $max = mb_strlen($keyspace, '8bit') - 1;
  393. for ($i = 0; $i < $length; ++$i) {
  394. $str .= $keyspace[random_int(0, $max)];
  395. }
  396. return $str;
  397. }
  398.  
  399. /**
  400. * badEmailAddressWarning
  401. * Logs error when a bad email address is found associated with a user
  402. *
  403. * @param string $message Error message to be logged
  404. */
  405. private function badEmailAddressWarning($message) {
  406. $path = '../storage/logs/badEmailAddress' . date('m-d-Y') . '.log';
  407. if(!file_exists($path)) {
  408. $file = fopen($path,'w');
  409. fclose($file);
  410. }
  411. error_log($message,3,$path);
  412. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement