Skip to main content
replaced http://dba.stackexchange.com/ with https://dba.stackexchange.com/
Source Link

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 databaseredesigning 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.

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

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 questionprevious 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.

Source Link
Trojan404
  • 838
  • 6
  • 25

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)
    }
}

Email

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;
}
}