Any suggestions as to the changes of my code as this project has progressed is appreciated. It is worth noting that I am working on redesigning my database redesigning my database. Therefore, the code may drastically change on the next iteration based on the new design.
Any suggestions as to the changes of my code as this project has progressed is appreciated. It is worth noting that I am working on redesigning my database. Therefore, the code may drastically change on the next iteration based on the new design.
Any suggestions as to the changes of my code as this project has progressed is appreciated. It is worth noting that I am working on redesigning my database. Therefore, the code may drastically change on the next iteration based on the new design.
Continuing on my quest to make sure that my application is developed strong, securely, and efficiently, I've updated my code as suggested in the previous question previous question.
Continuing on my quest to make sure that my application is developed strong, securely, and efficiently, I've updated my code as suggested in the previous question.
Continuing on my quest to make sure that my application is developed strong, securely, and efficiently, I've updated my code as suggested in the previous question.
Phishing Project Refactoring to Use a User Object
Continuing on my quest to make sure that my application is developed strong, securely, and efficiently, I've updated my code as suggested in the previous question.
To start, I've implemented a User_test
class (to be renamed once it is full implemented and designed). I have not yet added value verification to the constructor.
Any suggestions as to the changes of my code as this project has progressed is appreciated. It is worth noting that I am working on redesigning my database. Therefore, the code may drastically change on the next iteration based on the new design.
User_test
private $id;
private $username;
private $email;
private $firstName;
private $lastName;
private $uniqueURLId;
private $password;
private $mostRecentProject;
private $previousProject;
private $lastProject;
private $date;
/**
* User_test constructor.
* @param $user
*/
public function __construct($user)
{
$this->id = $user['USR_UserId']; //required
$this->username = $user['USR_Username']; //required
$this->email = $user['USR_Email']; //required
$this->firstName = $user['USR_FirstName']; //required
$this->lastName = $user['USR_LastName']; //required
$this->uniqueURLId = $user['USR_UniqueURLId'];
$this->password = $user['USR_Password']; //required
$this->mostRecentProject = $user['USR_ProjectMostRecent'];
$this->previousProject = $user['USR_ProjectPrevious'];
$this->lastProject = $user['USR_ProjectLast'];
}
/**
* checkURLId
* Checks if UniqueURLId is null and sets it if it is.
*
* @param int $projectId Integer ID referencing specific project to be concatenated onto the URLId
*/
private function checkURLId($projectId) {
if(is_null($this->uniqueURLId)) {
$db = new DBManager();
$this->uniqueURLId = RandomObjectGeneration::random_str(15) . $projectId;
$sql = "UPDATE gaig_users.users SET USR_UniqueURLId=? WHERE USR_UserId=?;";
$bindings = array($this->uniqueURLId,$this->id);
$db->query($sql,$bindings);
}
}
/**
* pushUser
* Pushes $this onto the provided array if it is valid.
*
* @param array $validUsers Array of User_test objects
* @param int $periodInWeeks Period to check in validation of user
* @param TemplateConfiguration $templateConfig Template Configuration for validation
*/
public function pushUser($validUsers, $periodInWeeks, TemplateConfiguration $templateConfig) {
try {
$this->checkURLId($templateConfig->getProjectId());
if($this->isValid($periodInWeeks,$templateConfig)) {
$validUsers[] = $this;
}
} catch(Exception $e) {
}
}
/**
* isValid
* Verifies the user is valid according to the verification algorithm defined in the check... functions.
*
* @param int $periodInWeeks Period to check in validation of user
* @param TemplateConfiguration $templateConfig Template Configuration for validation
* @return bool
*/
private function isValid($periodInWeeks, TemplateConfiguration $templateConfig) {
try {
$db = new DBManager();
$sql = "
SELECT MAX(SML_SentTimestamp) AS 'timestamp_check'
FROM gaig_users.sent_email
WHERE SML_UserId = ? AND SML_ProjectName = ?;";
$bindings = array($this->id,$this->mostRecentProject);
$data = $db->query($sql,$bindings);
if($data->rowCount() > 0) {
$result = $data->fetch();
$this->date = date('Y-m-d',strtotime('-' . $periodInWeeks . ' weeks')) . ' 00:00:00';
if($this->checkPeriod($this->date,$result['timestamp_check'])) {
return true;
}
$sql = "SELECT * FROM gaig_users.projects WHERE PRJ_ProjectId = ?;";
$data = $db->query($sql,array($this->mostRecentProject));
$mostRecentProj = new Project($data->fetch());
$newComplexity = $templateConfig->getTemplateComplexityType();
$newTarget = $templateConfig->getTemplateTargetType();
if($this->checkMRP($mostRecentProj,$newComplexity,$newTarget)) {
return false;
}
$data = $db->query($sql,array($this->previousProject));
$previousProj = new Project($data->fetch());
if($this->checkPP($mostRecentProj,$previousProj,$newComplexity)) {
return false;
}
$data = $db->query($sql,array($this->lastProject));
$lastProj = new Project($data->fetch());
if($this->checkLP($mostRecentProj,$previousProj,$lastProj,$newTarget)) {
return false;
}
}
return true;
} catch(Exception $e) {
//unsure how to manage any exceptions thrown yet, if at all. further design to come
}
}
/**
* checkPeriod - Verification Algorithm
* Verifies if the period is outside of periodInWeeks zone.
*
* @param string $date Date in format 'Y-m-d h:i:s'
* @param string $timestamp Date retrieved from PDOStatement
* @return bool
*/
private function checkPeriod($date,$timestamp) {
return $timestamp <= $date;
}
/**
* checkMRP - Verification Algorithm
* Checks the Most Recent Project to see if identical.
*
* @param Project $mrp Project object representing the Most Recent Project
* @param string $complexity Complexity type of requested template
* @param string $target Target type of requested template
* @return bool
*/
private function checkMRP(Project $mrp, $complexity, $target) {
return $complexity == $mrp->getTemplateComplexityType() &&
$target == $mrp->getTemplateTargetType();
}
/**
* checkPP - Verification Algorithm
* Checks the Previous Project and Most Recent Project for identical complexity type.
*
* @param Project $mrp Project object representing the Most Recent Project
* @param Project $pp Project object representing the Previous Project
* @param string $complexity Complexity type of requested template
* @return bool
*/
private function checkPP(Project $mrp, Project $pp, $complexity) {
return !is_null($pp) &&
$complexity == $mrp->getTemplateComplexityType() &&
$complexity == $pp->getTemplateComplexityType();
}
/**
* checkLP - Verification Algorithm
* Checks the Last Project, Previous Project, and Most Recent Project for identical target type.
*
* @param Project $mrp Project object representing the Most Recent Project
* @param Project $pp Project object representing the Previous Project
* @param Project $lp Project object representing the Last Project
* @param string $target Target type of requested template
* @return bool
*/
private function checkLP(Project $mrp, Project $pp, Project $lp, $target) {
return !is_null($lp) &&
!is_null($pp) &&
$target == $mrp->getTemplateTargetType() &&
$target == $pp->getTemplateTargetType() &&
$target == $lp->getTemplateTargetType();
}
public function getLastName() {
return $this->lastName;
}
public function getUsername() {
return $this->username;
}
public function getUniqueURLId() {
return $this->uniqueURLId;
}
public function getEmail() {
return $this->email;
}
I have not yet designed a UserCollection class. So right now I simply pass an array of User_test objects to the Email
class inside of the EmailConfiguration
object. This array is already verified as I use the TemplateConfiguration
object to verify all users when the EmailConfiguration
object is instantiated in PhishingController
.
TemplateConfiguration Validation Function
/**
* getValidUsers
* Retrieves all users from the database and validates them through the User_test object.
*
* @param array $returnUsers Array of User_test objects
* @param int $periodInWeeks Period to check for instant sending of email
* @return array
*/
public function getValidUsers($returnUsers, $periodInWeeks) {
$db = new DBManager();
$sql = "SELECT * FROM gaig_users.users;";
$users = $db->query($sql,array(),array('\PDO::ATTR_CURSOR'),array('\PDO::CURSOR_SCROLL'));
$usersIterator = new PDOIterator($users);
foreach($usersIterator as $user) {
$tempUser = new User_Test($user);
$tempUser->pushUser($returnUsers,$periodInWeeks,$this);
}
return $returnUsers;
}
PhishingController Instantiation and Email Execution
/**
* sendEmail
* Function mapped to Laravel route. Defines variable arrays and calls Email Class executeEmail.
*
* @param Request $request Request object passed via AJAX from client.
*/
public function sendEmail(Request $request) {
try {
$templateConfig = new TemplateConfiguration(
array(
'templateName'=>$request->input('emailTemplate'),
'companyName'=>$request->input('companyName'),
'projectName'=>$request->input('projectData')['projectName'],
'projectId'=>intval($request->input('projectData')['projectId'])
)
);
$periodInWeeks = 4;
$users = array();
$emailConfig = new EmailConfiguration(
array(
'host'=>$request->input('hostName'),
'port'=>$request->input('port'),
'authUsername'=>$request->input('username'),
'authPassword'=>$request->input('password'),
'fromEmail'=>$request->input('fromEmail'),
'subject'=>$request->input('subject'),
'users'=>$templateConfig->getValidUsers($users,$periodInWeeks)
)
);
Email::executeEmail($emailConfig,$templateConfig);
} catch(ConfigurationException $ce) {
//will be doing something here - what still has yet to be defined (likely just log the exception)
} catch(EmailException $ee) {
//will be doing something here - what still has yet to be defined (likely just log the exception)
}
}
private static $templateConfig;
private static $emailConfig;
/**
* executeEmail
* Public-facing method to send an email to a database of users if they are a valid recipient.
*
* @param EmailConfiguration $emailConfig Email Configuration object containing required information to send an email
* @param TemplateConfiguration $templateConfig Template Configuration object containing required information to build a template
* @throws EmailException Custom Exception to embody any exceptions thrown in this class
*/
public static function executeEmail(
EmailConfiguration $emailConfig,
TemplateConfiguration $templateConfig)
{
self::setTemplateConfig($templateConfig);
self::setEmailConfig($emailConfig);
try {
foreach($emailConfig->getUsers() as $user) {
self::sendEmail($user);
self::updateUserProjects($user);
}
} catch(Exception $e) {
throw new EmailException(__CLASS__ . ' Exception',0,$e);
}
}
/**
* updateUserProjects
* Updates the user with the newest project and rotates the old projects down one.
*
* @param array $user User array extracted from PDOStatement
*/
private function updateUserProjects($user) {
$db = new DBManager();
$sql = "UPDATE gaig_users.users SET USR_ProjectMostRecent=?, USR_ProjectPrevious=?,
USR_ProjectLast=? WHERE USR_Username=?;";
$bindings = array(self::$templateConfig->getProjectName(),
$user['USR_ProjectMostRecent'],
$user['USR_ProjectPrevious'],
$user['USR_Username']
);
$db->query($sql,$bindings);
}
/**
* sendEmail
* Sends them an email to the specified user.
*
* @param User_test $user User object
* @throws FailureException
*/
private static function sendEmail($user) {
$templateData = array(
'companyName'=>self::$templateConfig->getCompanyName(),
'projectName'=>self::$templateConfig->getProjectName(),
'projectId'=>self::$templateConfig->getProjectId(),
'lastName'=>$user->getLastName(),
'username'=>$user->getUsername(),
'urlId'=>$user->getUniqueURLId()
);
$subject = self::$emailConfig->getSubject();
$from = self::$emailConfig->getFromEmail();
$to = $user->getEmail();
$mailResult = Mail::send(
['html' => self::$templateConfig->getTemplate()],
$templateData,
function($m) use ($from, $to, $subject) {
$m->from($from);
$m->to($to)
->subject($subject);
}
);
if(!$mailResult) {
throw new FailureException('Email failed to send to ' . $to . ', from ' . $from);
}
}
private static function setTemplateConfig(TemplateConfiguration $templateConfig) {
self::$templateConfig = $templateConfig;
}
private static function setEmailConfig(EmailConfiguration $emailConfig) {
self::$emailConfig = $emailConfig;
}
I have also extrapolated the random_str
function to a library class.
Libraries
class RandomObjectGeneration
{
/**
* random_str
* Generates a random string.
*
* @param int $length Length of string to be returned
* @param string $keyspace Allowed characters to be used in string
* @return string
*/
public static function random_str($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
if(is_null($length) || !is_numeric($length)) {
throw new Exception();
}
$str = '';
$max = mb_strlen($keyspace) - 1;
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[random_int(0, $max)];
}
return $str;
}
}