taeluf/user-gui

a user system for PHP, built on Liaison

v0.3.x-dev 2024-09-06 14:08 UTC

This package is auto-updated.

Last update: 2024-10-10 21:14:58 UTC


README

User Login

A User login system built with Liaison, which can be plugged into any existing website, whether you use Liaison or not.

UPGRADE NOTICE: v0.3 is abandoned. You should use v0.4

Warning: The documentation is ... incomplete & just kinda bad right now.
Legal: YOU ARE RESPONSIBLE FOR TERMS & CONDITIONS & legal stuff! If you use this software, you must read & understand them. If you do not agree with them or do not want to use them, then you must replace them. If what i've written is not legally sufficient, YOU ARE STILL LIABLE & I take no responsibility for any legal matters pertaining to your use of this software, user privacy, etc.

Status: Alpha, not feature complete (May 6, 2022)

This library has the essentials for user login: login, password reset, registration. It also has necessary features like terms & conditions & security stuff. It has CSRF, XSS prevention, honeypots, throttling, and security logs.

A big drawback currently is the lack of a GUI for user management, administration, and roles/permissions. This must be done in code, unfortunately. Though the back-end API is pretty easy to use so it's not that bad.

There are robust tests for most of the library. However, my CSRF is minimal & honeypot testing is non-existent (aside from trying it in the browser).

Setup is a bit cumbersome. Documentation is currently poor.

I plan to add some new cli commands & a convenience method for standard setups on your server.

Install

composer require taeluf/user-gui v0.3.x-dev   

or in your composer.json

{"require":{ "taeluf/user-gui": "v0.3.x-dev"}}  

Sever Setup

This is a simple setup for a Liaison server.

If you wish to use this on a non-liaison website, then instead of $liaison->deliver(), call $liaison->getResponse(), get the content & headers from the response & do with them as you need.

<?php  
  
// the root dir of your server  
$dir = dirname(__DIR__,2);  
  
require($dir.'/vendor/autoload.php');  
// optional if you have other setup to do  
require(__DIR__.'/bootstrap.php');  
  
// $user_lib_dir = $dir.'/vendor/taeluf/user-gui/code/';  
$user_lib_dir = $dir.'/code/';  
  
// initialize Liaison  
$lia = new \Lia();    
$main = \Lia\Package\Server::main($lia);    
  
  
  
// set the base url for the user pages  
$lia->set('user.base_url', '/user/');  
// init the user server  
$user_package = new \Lia\Package\Server($lia, 'user', $user_lib_dir);    
  
// load db settings from env file & make pdo  
$settings = json_decode(file_get_contents(dirname(__DIR__).'/db-env.json'),true);  
$pdo = new \PDO("mysql:dbname=".$settings['db'], $settings['user'], $settings['password']);  
  
// configure the user login library  
$lib = new \Tlf\User\Lib($pdo);  
$lib->config = [  
    'web_address'=>'https://example.com',  
    'email_from'=>'notauser@example.com',  
];  
  
// uncomment this line, run once, then re-comment this line  
// $lib->init_db();  
  
// log the user in  
$current_user = $lib->user_from_cookie();  
// if there was no cookie, we'll use an unregistered user  
if ($current_user===false)$current_user = new \Tlf\User($pdo);  
  
// passes the user & library to user pages (login, register, etc)  
$user_package->public_file_params = [  
    'user'=>$current_user,  
    'lib'=>$lib  
];  
  
   
  
$lia->deliver();  

Database setup

Uncomment the $lib->init_db() line in the deliver script above, then run the deliver script, then re-comment the init_db line

Permissions and Roles

Permissions can be added to users and to roles. Roles can then be added to users to grant a group of permissions. See permissions source code at code/class/Permissions.php.

Examples:

<?php  
$pdo = $this->pdo();  
$lib = new \Tlf\User\Lib($pdo);  
$user = $lib->user_from_email('reed@document.permissions');  
//user must already be registered!  
// allow a user to create blog posts  
$user->allow('blog:create');  
// allow user to edit a blog post with id = 37  
$user->allow('blog:edit-37');  
$this->is_true( // an assertion with my test lib  
    // check if user can create a blog post  
    $user->can('blog:create')  
);  
// remove permission  
$user->deny('blog:create');  
$this->is_false( // assertion to ensure the permission was removed  
    $user->can('blog:create')  
);  
/////  
// roles  
/////  
// add a role to the user  
$user->add_role('admin');  
// add a permission to the role  
$lib->role_allow('admin', 'blog:delete');  
$this->is_true(  
    $user->can('blog:delete')  
);  
// remove a specific permission from a role  
$lib->role_deny('admin', 'blog:delete');  
// delete a role alltogether  
$lib->role_delete('admin');  

Database Schema

This is the file: code/db/create.sql.

CREATE TABLE IF NOT EXISTS `user` (  
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
  `email` varchar(255) NOT NULL,  
  `password` varchar(255) NOT NULL,  
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,  
  `is_active` tinyint(1) DEFAULT 0,  
  PRIMARY KEY (`id`),  
    UNIQUE(`email`)  
) ;  
  
  
CREATE TABLE IF NOT EXISTS `code` (  
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
    `user_id` int(10) unsigned NOT NULL,  
    `type` varchar(30),  
    `code` varchar(255) NOT NULL,  
    `is_active` tinyint(1) NOT NULL DEFAULT '0',  
    `activated_at` datetime NULL DEFAULT NULL,  
    `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,  
    `expires_at` datetime NOT NULL,  
    PRIMARY KEY (`id`)  
) ;  
  
CREATE TABLE IF NOT EXISTS `permissions` (  
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
  `user_id` int(10) unsigned NOT NULL,  
  `action` varchar(255) NOT NULL,  
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  
  PRIMARY KEY (`id`),  
    INDEX(`action`)  
) ;  
  
  
CREATE TABLE IF NOT EXISTS `user_role` (  
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
  `user_id` int(10) unsigned NOT NULL,  
  `role` varchar(255) NOT NULL,  
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  
  PRIMARY KEY (`id`),  
    INDEX(`role`)  
) ;  
  
  
CREATE TABLE IF NOT EXISTS `role_permission` (  
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
  `role` varchar(255) NOT NULL,  
  `action` varchar(255) NOT NULL,  
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  
  PRIMARY KEY (`id`),  
    INDEX(`role`),  
    INDEX(`action`)  
) ;  
  
  
CREATE TABLE IF NOT EXISTS `throttle` (  
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
  `key` varchar(255) NOT NULL,  
  `actor` varchar(255) NOT NULL,  
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  
  `expires_at` timestamp(6) NOT NULL,  
  PRIMARY KEY (`id`)  
) ;  
  
CREATE TABLE IF NOT EXISTS `security_log` (  
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,  
  `email` varchar(255) NOT NULL,  
  `action` varchar(255) NOT NULL,  
  `ip` varchar(255) NOT NULL,  
  `user_agent` varchar(500) NOT NULL,  
  `created_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),  
  
    PRIMARY KEY(`id`)  
);