Add single user security mode (#3)
- Tweaks to SQL column definitions - Implement class autoloading - Split user config into its own file
This commit is contained in:
		
							parent
							
								
									8db4216ea2
								
							
						
					
					
						commit
						74bc83f266
					
				@ -14,6 +14,9 @@ class Data {
 | 
			
		||||
        return $db;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Make sure the expected tables exist
 | 
			
		||||
     */
 | 
			
		||||
    public static function ensureDb(): void {
 | 
			
		||||
        $db = self::getConnection();
 | 
			
		||||
        $tables = array();
 | 
			
		||||
@ -24,8 +27,7 @@ class Data {
 | 
			
		||||
                CREATE TABLE frc_user (
 | 
			
		||||
                    id       INTEGER NOT NULL PRIMARY KEY,
 | 
			
		||||
                    email    TEXT    NOT NULL,
 | 
			
		||||
                    password TEXT    NOT NULL,
 | 
			
		||||
                    salt     TEXT    NOT NULL)
 | 
			
		||||
                    password TEXT    NOT NULL)
 | 
			
		||||
                SQL;
 | 
			
		||||
            $db->exec($query);
 | 
			
		||||
            $db->exec('CREATE INDEX idx_user_email ON frc_user (email)');
 | 
			
		||||
@ -50,15 +52,46 @@ class Data {
 | 
			
		||||
                    published_on  TEXT    NOT NULL,
 | 
			
		||||
                    updated_on    TEXT,
 | 
			
		||||
                    content       TEXT    NOT NULL,
 | 
			
		||||
                    is_encoded    INTEGER NOT NULL,
 | 
			
		||||
                    is_read       INTEGER NOT NULL,
 | 
			
		||||
                    is_bookmarked INTEGER NOT NULL,
 | 
			
		||||
                    is_encoded    BOOLEAN NOT NULL,
 | 
			
		||||
                    is_read       BOOLEAN NOT NULL,
 | 
			
		||||
                    is_bookmarked BOOLEAN NOT NULL,
 | 
			
		||||
                    FOREIGN KEY (feed_id) REFERENCES feed (id))
 | 
			
		||||
                SQL;
 | 
			
		||||
            $db->exec($query);
 | 
			
		||||
        }
 | 
			
		||||
        $db->close();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Data::ensureDb();
 | 
			
		||||
    /**
 | 
			
		||||
     * Find a user by their ID
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $email The e-mail address of the user to retrieve
 | 
			
		||||
     * @return array|null The user information, or null if the user is not found
 | 
			
		||||
     */
 | 
			
		||||
    public static function findUserByEmail(string $email): ?array {
 | 
			
		||||
        $db = self::getConnection();
 | 
			
		||||
        $query = $db->prepare('SELECT * FROM frc_user WHERE email = :email');
 | 
			
		||||
        $query->bindValue(':email', $email);
 | 
			
		||||
        $result = $query->execute();
 | 
			
		||||
        if ($result) {
 | 
			
		||||
            $user = $result->fetchArray(SQLITE3_ASSOC);
 | 
			
		||||
            if ($user) return $user;
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add a user
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $email The e-mail address for the user
 | 
			
		||||
     * @param string $password The user's password
 | 
			
		||||
     */
 | 
			
		||||
    public static function addUser(string $email, string $password): void {
 | 
			
		||||
        $db = self::getConnection();
 | 
			
		||||
        $query = $db->prepare('INSERT INTO frc_user (email, password) VALUES (:email, :password)');
 | 
			
		||||
        $query->bindValue(':email', $email);
 | 
			
		||||
        $query->bindValue(':password', password_hash($password, PASSWORD_DEFAULT));
 | 
			
		||||
        $query->execute();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								src/lib/Security.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/lib/Security.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Security functions
 | 
			
		||||
 */
 | 
			
		||||
class Security {
 | 
			
		||||
 | 
			
		||||
    /** @var int Run as a single user requiring no password */
 | 
			
		||||
    public const int SINGLE_USER = 0;
 | 
			
		||||
 | 
			
		||||
    /** @var int Run as a single user requiring a password */
 | 
			
		||||
    public const int SINGLE_USER_WITH_PASSWORD = 1;
 | 
			
		||||
 | 
			
		||||
    /** @var int Require users to provide e-mail address and password */
 | 
			
		||||
    public const int MULTI_USER = 2;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Verify that user is logged on
 | 
			
		||||
     * @param bool $redirectIfAnonymous Whether to redirect the request if there is no user logged on
 | 
			
		||||
     */
 | 
			
		||||
    public static function verifyUser(bool $redirectIfAnonymous = true): void {
 | 
			
		||||
        switch (SECURITY_MODEL) {
 | 
			
		||||
            case self::SINGLE_USER:
 | 
			
		||||
                $user = self::retrieveSingleUser();
 | 
			
		||||
                break;
 | 
			
		||||
            case self::SINGLE_USER_WITH_PASSWORD:
 | 
			
		||||
                die('Single User w/ Password has not yet been implemented');
 | 
			
		||||
            case self::MULTI_USER:
 | 
			
		||||
                die('Multi-User Mode has not yet been implemented');
 | 
			
		||||
            default:
 | 
			
		||||
                die('Unrecognized security model (' . SECURITY_MODEL . ')');
 | 
			
		||||
        }
 | 
			
		||||
        if (!$user && $redirectIfAnonymous) {
 | 
			
		||||
            header('/logon?returnTo=' . $_SERVER["REQUEST_URI"], true, HTTP_REDIRECT_TEMP);
 | 
			
		||||
            die();
 | 
			
		||||
        }
 | 
			
		||||
        $_REQUEST['FRC_USER_ID']    = $user['id'];
 | 
			
		||||
        $_REQUEST['FRC_USER_EMAIL'] = $user['email'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve the single user
 | 
			
		||||
     * @return array The user information for the single user
 | 
			
		||||
     */
 | 
			
		||||
    private static function retrieveSingleUser(): array {
 | 
			
		||||
        $user = Data::findUserByEmail('solouser@example.com');
 | 
			
		||||
        if ($user) return $user;
 | 
			
		||||
        Data::addUser('solouser@example.com', 'no-password-required');
 | 
			
		||||
        return Data::findUserByEmail('solouser@example.com');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
include '../start.php';
 | 
			
		||||
 | 
			
		||||
Security::verifyUser();
 | 
			
		||||
 | 
			
		||||
page_head('Welcome');
 | 
			
		||||
?>
 | 
			
		||||
<p>Startup worked</p>
 | 
			
		||||
<p>User ID <?=$_REQUEST['FRC_USER_ID']?> - e-mail <?=$_REQUEST['FRC_USER_EMAIL']?></p>
 | 
			
		||||
<?php
 | 
			
		||||
page_foot();
 | 
			
		||||
 | 
			
		||||
@ -1,23 +1,16 @@
 | 
			
		||||
<?php
 | 
			
		||||
// USER CONFIGURATION ITEMS
 | 
			
		||||
spl_autoload_register(function ($class) {
 | 
			
		||||
    $file = implode(DIRECTORY_SEPARATOR, [ __DIR__, 'lib', "$class.php" ]);
 | 
			
		||||
    if (file_exists($file)) {
 | 
			
		||||
        require $file;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Which security model should the application use?
 | 
			
		||||
 * - 0 = single-user, no password
 | 
			
		||||
 * - 1 = single-user with password
 | 
			
		||||
 * - 2 = multi-user (all users require passwords)
 | 
			
		||||
 *
 | 
			
		||||
 * (NOTE THAT 1 AND 2 HAVE NOT YET BEEN IMPLEMENTED)
 | 
			
		||||
 */
 | 
			
		||||
const SECURITY_MODEL = 0;
 | 
			
		||||
require 'user-config.php';
 | 
			
		||||
 | 
			
		||||
/** The name of the database file where users and feeds should be kept */
 | 
			
		||||
const DATABASE_NAME = 'frc.db';
 | 
			
		||||
 | 
			
		||||
// END USER CONFIGURATION ITEMS
 | 
			
		||||
//   (editing below this line is not advised)
 | 
			
		||||
 | 
			
		||||
include 'lib/Data.php';
 | 
			
		||||
Data::ensureDb();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Render the page title
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								src/user-config.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/user-config.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * USER CONFIGURATION ITEMS
 | 
			
		||||
 *
 | 
			
		||||
 * Editing the values here customizes the behavior of Feed Reader Central
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Which security model should the application use? Options are:
 | 
			
		||||
 * - Security::SINGLE_USER (no e-mail required, does not require a password)
 | 
			
		||||
 * - Security::SINGLE_USER_WITH_PASSWORD (no e-mail required, does require a password)
 | 
			
		||||
 * - Security::MULTI_USER (e-mail and password required for all users)
 | 
			
		||||
 *
 | 
			
		||||
 * (NOTE THAT ONLY SINGLE_USER IS CURRENTLY IMPLEMENTED)
 | 
			
		||||
 */
 | 
			
		||||
const SECURITY_MODEL = Security::SINGLE_USER;
 | 
			
		||||
 | 
			
		||||
/** The name of the database file where users and feeds should be kept */
 | 
			
		||||
const DATABASE_NAME = 'frc.db';
 | 
			
		||||
 | 
			
		||||
// END USER CONFIGURATION ITEMS
 | 
			
		||||
//   (editing below this line is not advised)
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user