Impleted SAML SSO #54
@ -17,7 +17,8 @@
 | 
				
			|||||||
      "ext-dom": "*",
 | 
					      "ext-dom": "*",
 | 
				
			||||||
    "ext-libxml": "*",
 | 
					    "ext-libxml": "*",
 | 
				
			||||||
    "donatello-za/rake-php-plus": "^1.0",
 | 
					    "donatello-za/rake-php-plus": "^1.0",
 | 
				
			||||||
    "phpmailer/phpmailer": "^6.9"
 | 
					    "phpmailer/phpmailer": "^6.9",
 | 
				
			||||||
 | 
					    "onelogin/php-saml": "^4.1"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "repositories": [
 | 
					  "repositories": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										100
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										100
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							@ -4,7 +4,7 @@
 | 
				
			|||||||
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
 | 
					        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
 | 
				
			||||||
        "This file is @generated automatically"
 | 
					        "This file is @generated automatically"
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
  "content-hash": "f156a57e5e895727417d4274c8ad414c",
 | 
					  "content-hash": "a0850a84ff9d5a207b7b0724563015c7",
 | 
				
			||||||
    "packages": [
 | 
					    "packages": [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "name": "donatello-za/rake-php-plus",
 | 
					          "name": "donatello-za/rake-php-plus",
 | 
				
			||||||
@ -873,6 +873,62 @@
 | 
				
			|||||||
            ],
 | 
					            ],
 | 
				
			||||||
          "time": "2023-11-08T09:30:43+00:00"
 | 
					          "time": "2023-11-08T09:30:43+00:00"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "onelogin/php-saml",
 | 
				
			||||||
 | 
					          "version": "4.1.0",
 | 
				
			||||||
 | 
					          "source": {
 | 
				
			||||||
 | 
					            "type": "git",
 | 
				
			||||||
 | 
					            "url": "https://github.com/onelogin/php-saml.git",
 | 
				
			||||||
 | 
					            "reference": "b22a57ebd13e838b90df5d3346090bc37056409d"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "dist": {
 | 
				
			||||||
 | 
					            "type": "zip",
 | 
				
			||||||
 | 
					            "url": "https://api.github.com/repos/onelogin/php-saml/zipball/b22a57ebd13e838b90df5d3346090bc37056409d",
 | 
				
			||||||
 | 
					            "reference": "b22a57ebd13e838b90df5d3346090bc37056409d",
 | 
				
			||||||
 | 
					            "shasum": ""
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "require": {
 | 
				
			||||||
 | 
					            "php": ">=7.3",
 | 
				
			||||||
 | 
					            "robrichards/xmlseclibs": ">=3.1.1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "require-dev": {
 | 
				
			||||||
 | 
					            "pdepend/pdepend": "^2.8.0",
 | 
				
			||||||
 | 
					            "php-coveralls/php-coveralls": "^2.0",
 | 
				
			||||||
 | 
					            "phploc/phploc": "^4.0 || ^5.0 || ^6.0 || ^7.0",
 | 
				
			||||||
 | 
					            "phpunit/phpunit": "^9.5",
 | 
				
			||||||
 | 
					            "sebastian/phpcpd": "^4.0 || ^5.0 || ^6.0 ",
 | 
				
			||||||
 | 
					            "squizlabs/php_codesniffer": "^3.5.8"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "suggest": {
 | 
				
			||||||
 | 
					            "ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs",
 | 
				
			||||||
 | 
					            "ext-dom": "Install xml lib",
 | 
				
			||||||
 | 
					            "ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)",
 | 
				
			||||||
 | 
					            "ext-zlib": "Install zlib"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "type": "library",
 | 
				
			||||||
 | 
					          "autoload": {
 | 
				
			||||||
 | 
					            "psr-4": {
 | 
				
			||||||
 | 
					              "OneLogin\\": "src/"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "notification-url": "https://packagist.org/downloads/",
 | 
				
			||||||
 | 
					          "license": [
 | 
				
			||||||
 | 
					            "MIT"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "description": "OneLogin PHP SAML Toolkit",
 | 
				
			||||||
 | 
					          "homepage": "https://developers.onelogin.com/saml/php",
 | 
				
			||||||
 | 
					          "keywords": [
 | 
				
			||||||
 | 
					            "SAML2",
 | 
				
			||||||
 | 
					            "onelogin",
 | 
				
			||||||
 | 
					            "saml"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "support": {
 | 
				
			||||||
 | 
					            "email": "sixto.garcia@onelogin.com",
 | 
				
			||||||
 | 
					            "issues": "https://github.com/onelogin/php-saml/issues",
 | 
				
			||||||
 | 
					            "source": "https://github.com/onelogin/php-saml/"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "time": "2022-07-15T20:44:36+00:00"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
            "name": "php-di/invoker",
 | 
					            "name": "php-di/invoker",
 | 
				
			||||||
        "version": "2.3.4",
 | 
					        "version": "2.3.4",
 | 
				
			||||||
@ -1614,6 +1670,48 @@
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
            "time": "2021-07-12T10:12:22+00:00"
 | 
					            "time": "2021-07-12T10:12:22+00:00"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "name": "robrichards/xmlseclibs",
 | 
				
			||||||
 | 
					          "version": "3.1.1",
 | 
				
			||||||
 | 
					          "source": {
 | 
				
			||||||
 | 
					            "type": "git",
 | 
				
			||||||
 | 
					            "url": "https://github.com/robrichards/xmlseclibs.git",
 | 
				
			||||||
 | 
					            "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "dist": {
 | 
				
			||||||
 | 
					            "type": "zip",
 | 
				
			||||||
 | 
					            "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/f8f19e58f26cdb42c54b214ff8a820760292f8df",
 | 
				
			||||||
 | 
					            "reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df",
 | 
				
			||||||
 | 
					            "shasum": ""
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "require": {
 | 
				
			||||||
 | 
					            "ext-openssl": "*",
 | 
				
			||||||
 | 
					            "php": ">= 5.4"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "type": "library",
 | 
				
			||||||
 | 
					          "autoload": {
 | 
				
			||||||
 | 
					            "psr-4": {
 | 
				
			||||||
 | 
					              "RobRichards\\XMLSecLibs\\": "src"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "notification-url": "https://packagist.org/downloads/",
 | 
				
			||||||
 | 
					          "license": [
 | 
				
			||||||
 | 
					            "BSD-3-Clause"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "description": "A PHP library for XML Security",
 | 
				
			||||||
 | 
					          "homepage": "https://github.com/robrichards/xmlseclibs",
 | 
				
			||||||
 | 
					          "keywords": [
 | 
				
			||||||
 | 
					            "security",
 | 
				
			||||||
 | 
					            "signature",
 | 
				
			||||||
 | 
					            "xml",
 | 
				
			||||||
 | 
					            "xmldsig"
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          "support": {
 | 
				
			||||||
 | 
					            "issues": "https://github.com/robrichards/xmlseclibs/issues",
 | 
				
			||||||
 | 
					            "source": "https://github.com/robrichards/xmlseclibs/tree/3.1.1"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "time": "2020-09-05T13:00:25+00:00"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
            "name": "selective/samesite-cookie",
 | 
					            "name": "selective/samesite-cookie",
 | 
				
			||||||
            "version": "0.3.0",
 | 
					            "version": "0.3.0",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										34
									
								
								dist/api/user/userData.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								dist/api/user/userData.php
									
									
									
									
										vendored
									
									
								
							@ -5,6 +5,7 @@ namespace api\user;
 | 
				
			|||||||
use Firebase\JWT\JWT;
 | 
					use Firebase\JWT\JWT;
 | 
				
			||||||
use PDO;
 | 
					use PDO;
 | 
				
			||||||
use function api\utils\dbConn;
 | 
					use function api\utils\dbConn;
 | 
				
			||||||
 | 
					use function api\utils\getSAMLSettings;
 | 
				
			||||||
use function api\utils\getSecretKey;
 | 
					use function api\utils\getSecretKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require_once __DIR__ . "/../utils/config.php";
 | 
					require_once __DIR__ . "/../utils/config.php";
 | 
				
			||||||
@ -138,5 +139,38 @@ class userData
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the SAML settings
 | 
				
			||||||
 | 
					     * @return array - SAML settings
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getSamlConf(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return getSAMLSettings();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if the SAML user exists
 | 
				
			||||||
 | 
					     * @param string $username - Username
 | 
				
			||||||
 | 
					     * @param string $email - Email
 | 
				
			||||||
 | 
					     * @return bool - True if the user exists, false if not
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function checkSAMLUser(string $username, string $email): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $conn = dbConn();
 | 
				
			||||||
 | 
					        $stmt = $conn->prepare("SELECT * FROM users WHERE username = :username AND email = :email");
 | 
				
			||||||
 | 
					        $stmt->bindParam(":username", $username);
 | 
				
			||||||
 | 
					        $stmt->bindParam(":email", $email);
 | 
				
			||||||
 | 
					        $stmt->execute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // set the resulting array to associative
 | 
				
			||||||
 | 
					        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($result)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										97
									
								
								dist/api/user/userRoutes.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										97
									
								
								dist/api/user/userRoutes.php
									
									
									
									
										vendored
									
									
								
							@ -5,6 +5,8 @@ require_once __DIR__ . "/../utils/routesInterface.php";
 | 
				
			|||||||
require_once "userData.php";
 | 
					require_once "userData.php";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use api\utils\routesInterface;
 | 
					use api\utils\routesInterface;
 | 
				
			||||||
 | 
					use OneLogin\Saml2\Auth;
 | 
				
			||||||
 | 
					use OneLogin\Saml2\Error;
 | 
				
			||||||
use Psr\Http\Message\ResponseInterface as Response;
 | 
					use Psr\Http\Message\ResponseInterface as Response;
 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface as Request;
 | 
					use Psr\Http\Message\ServerRequestInterface as Request;
 | 
				
			||||||
use Slim\App;
 | 
					use Slim\App;
 | 
				
			||||||
@ -12,14 +14,17 @@ use Slim\App;
 | 
				
			|||||||
class userRoutes implements routesInterface
 | 
					class userRoutes implements routesInterface
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    private userData $user;
 | 
					    private userData $user;
 | 
				
			||||||
 | 
					    private Auth $samlAuth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * constructor used to instantiate a base user routes, to be used in the index.php file.
 | 
					     * constructor used to instantiate a base user routes, to be used in the index.php file.
 | 
				
			||||||
     * @param App $app - the slim app used to create the routes
 | 
					     * @param App $app - the slim app used to create the routes
 | 
				
			||||||
 | 
					     * @throws Error
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(App $app)
 | 
					    public function __construct(App $app)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->user = new userData();
 | 
					        $this->user = new userData();
 | 
				
			||||||
 | 
					        $this->samlAuth = new Auth($this->user->getSamlConf());
 | 
				
			||||||
        $this->createRoutes($app);
 | 
					        $this->createRoutes($app);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,31 +35,9 @@ class userRoutes implements routesInterface
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function createRoutes(App $app): void
 | 
					    public function createRoutes(App $app): void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $app->post("/user/login", function (Request $request, Response $response)
 | 
					        $app->get("/user/login", function (Request $request, Response $response)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // get request data
 | 
					            $this->samlAuth->login();
 | 
				
			||||||
            $data = $request->getParsedBody();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (empty($data["username"]) || empty($data["password"]))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // uh oh user sent empty data
 | 
					 | 
				
			||||||
                return $response->withStatus(400);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->user->checkUser($data["username"], $data["password"]))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // yay, user is logged in
 | 
					 | 
				
			||||||
                $_SESSION["token"] = $this->user->createToken($data["username"]);
 | 
					 | 
				
			||||||
                $_SESSION["username"] = $data["username"];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                $inactive = 60 * 60 * 48; // 2 days
 | 
					 | 
				
			||||||
                $_SESSION["timeout"] = time() + $inactive;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                $response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
 | 
					 | 
				
			||||||
                return $response;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            $response->getBody()->write(json_encode(array("error" => "Unauthorised")));
 | 
					 | 
				
			||||||
            return $response->withStatus(401);
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $app->get("/user/logout", function (Request $request, Response $response)
 | 
					        $app->get("/user/logout", function (Request $request, Response $response)
 | 
				
			||||||
@ -92,6 +75,20 @@ class userRoutes implements routesInterface
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $app->get("/user/metadata", function (Request $request, Response $response)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            $settings = $this->samlAuth->getSettings();
 | 
				
			||||||
 | 
					            $metadata = $settings->getSPMetadata();
 | 
				
			||||||
 | 
					            $errors = $settings->validateMetadata($metadata);
 | 
				
			||||||
 | 
					            if (empty($errors))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                $response->getBody()->write($metadata);
 | 
				
			||||||
 | 
					                return $response->withHeader("Content-Type", "text/xml");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $response->getBody()->write(json_encode(array("error" => $errors)));
 | 
				
			||||||
 | 
					            return $response->withStatus(500);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
 | 
					        $app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (empty($args["email"]))
 | 
					            if (empty($args["email"]))
 | 
				
			||||||
@ -139,6 +136,58 @@ class userRoutes implements routesInterface
 | 
				
			|||||||
            return $response->withStatus(401);
 | 
					            return $response->withStatus(401);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $app->post("/user/login", function (Request $request, Response $response)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // get request data
 | 
				
			||||||
 | 
					            $data = $request->getParsedBody();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (empty($data["username"]) || empty($data["password"]))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // uh oh user sent empty data
 | 
				
			||||||
 | 
					                return $response->withStatus(400);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($this->user->checkUser($data["username"], $data["password"]))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // yay, user is logged in
 | 
				
			||||||
 | 
					                $_SESSION["token"] = $this->user->createToken($data["username"]);
 | 
				
			||||||
 | 
					                $_SESSION["username"] = $data["username"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $inactive = 60 * 60 * 48; // 2 days
 | 
				
			||||||
 | 
					                $_SESSION["timeout"] = time() + $inactive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
 | 
				
			||||||
 | 
					                return $response;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $response->getBody()->write(json_encode(array("error" => "Unauthorised")));
 | 
				
			||||||
 | 
					            return $response->withStatus(401);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $app->post("/user/acs", function (Request $request, Response $response)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            $this->samlAuth->processResponse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $attributes = $this->samlAuth->getAttributes();
 | 
				
			||||||
 | 
					            $username = $attributes["username"][0];
 | 
				
			||||||
 | 
					            $email = $attributes["email"][0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($this->user->checkSAMLUser($username, $email))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // yay, user is logged in
 | 
				
			||||||
 | 
					                $_SESSION["token"] = $this->user->createToken($username);
 | 
				
			||||||
 | 
					                $_SESSION["username"] = $username;
 | 
				
			||||||
 | 
					                $_SESSION["email"] = $email;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $inactive = 60 * 60 * 48; // 2 days
 | 
				
			||||||
 | 
					                $_SESSION["timeout"] = time() + $inactive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return $response->withHeader("Location", "https://rohitpai.co.uk/editor/editor.html")->withStatus(302);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $response->getBody()->write(json_encode(array("error" => "Unauthorised")));
 | 
				
			||||||
 | 
					            return $response->withStatus(401);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $app->post("/user/changePassword", function (Request $request, Response $response)
 | 
					        $app->post("/user/changePassword", function (Request $request, Response $response)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
 | 
					            if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								dist/blog/css/main.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/blog/css/main.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/css/main.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/css/main.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/editor/css/main.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/editor/css/main.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/editor/index.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/editor/index.html
									
									
									
									
										vendored
									
									
								
							@ -1 +1 @@
 | 
				
			|||||||
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><main class="login"><div id="login" class="container shown"><h1>Login To Editor</h1><form action="" method="POST"><div class="formControl"><label for="username">Username</label> <input type="text" id="username" name="username" required></div><div class="formControl passwordControl"><label for="password">Password</label> <input type="password" id="password" name="password" required> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="loginError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" id="resetPwd">Reset Password</a></div></form></div><div id="resetPassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="#" method="POST"><div class="formControl"><label for="email">Email</label> <input type="email" id="email" name="email"></div><div class="error hidden" id="resetError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login</a></div></form></div><div id="checkResetCode" class="container" style="display: none; transform: translateX(150vw)"><h1>Check Reset Code</h1><form action="#" method="POST"><div class="formControl"><label for="code">Code</label> <input type="text" id="code" name="code"></div><div class="error hidden" id="resetCodeError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend Email</a></div></form></div><div id="changePassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="" method="POST"><div class="formControl"><label for="pass">Password</label> <input type="password" name="pass" id="pass"> <i class="fa-solid fa-eye"></i></div><div class="formControl"><label for="rePass">Password</label> <input type="password" name="rePass" id="rePass"> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="changeError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</a></div></form></div></main><script src="js/index.js"></script></body></html>
 | 
					<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><main class="login"><div id="login" class="container shown"><h1>Login To Editor</h1><form action="" method="POST"><div class="formControl"><label for="username">Username</label> <input type="text" id="username" name="username" required></div><div class="formControl passwordControl"><label for="password">Password</label> <input type="password" id="password" name="password" required> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="loginError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="/api/user/login" class="btn btnPrimary boxShadowIn boxShadowOut">Login with Jump Cloud</a> <button type="button" id="resetPwd" class="btn btnPrimary boxShadowIn boxShadowOut">Reset Password</button></div></form></div><div id="resetPassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="#" method="POST"><div class="formControl"><label for="email">Email</label> <input type="email" id="email" name="email"></div><div class="error hidden" id="resetError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login</button></div></form></div><div id="checkResetCode" class="container" style="display: none; transform: translateX(150vw)"><h1>Check Reset Code</h1><form action="#" method="POST"><div class="formControl"><label for="code">Code</label> <input type="text" id="code" name="code"></div><div class="error hidden" id="resetCodeError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend Email</button></div></form></div><div id="changePassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="" method="POST"><div class="formControl"><label for="pass">Password</label> <input type="password" name="pass" id="pass"> <i class="fa-solid fa-eye"></i></div><div class="formControl"><label for="rePass">Password</label> <input type="password" name="rePass" id="rePass"> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="changeError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</button></div></form></div></main><script src="js/index.js"></script></body></html>
 | 
				
			||||||
@ -5,6 +5,7 @@ namespace api\user;
 | 
				
			|||||||
use Firebase\JWT\JWT;
 | 
					use Firebase\JWT\JWT;
 | 
				
			||||||
use PDO;
 | 
					use PDO;
 | 
				
			||||||
use function api\utils\dbConn;
 | 
					use function api\utils\dbConn;
 | 
				
			||||||
 | 
					use function api\utils\getSAMLSettings;
 | 
				
			||||||
use function api\utils\getSecretKey;
 | 
					use function api\utils\getSecretKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require_once __DIR__ . "/../utils/config.php";
 | 
					require_once __DIR__ . "/../utils/config.php";
 | 
				
			||||||
@ -138,5 +139,38 @@ class userData
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the SAML settings
 | 
				
			||||||
 | 
					     * @return array - SAML settings
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getSamlConf(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return getSAMLSettings();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if the SAML user exists
 | 
				
			||||||
 | 
					     * @param string $username - Username
 | 
				
			||||||
 | 
					     * @param string $email - Email
 | 
				
			||||||
 | 
					     * @return bool - True if the user exists, false if not
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function checkSAMLUser(string $username, string $email): bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $conn = dbConn();
 | 
				
			||||||
 | 
					        $stmt = $conn->prepare("SELECT * FROM users WHERE username = :username AND email = :email");
 | 
				
			||||||
 | 
					        $stmt->bindParam(":username", $username);
 | 
				
			||||||
 | 
					        $stmt->bindParam(":email", $email);
 | 
				
			||||||
 | 
					        $stmt->execute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // set the resulting array to associative
 | 
				
			||||||
 | 
					        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($result)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -5,6 +5,8 @@ require_once __DIR__ . "/../utils/routesInterface.php";
 | 
				
			|||||||
require_once "userData.php";
 | 
					require_once "userData.php";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use api\utils\routesInterface;
 | 
					use api\utils\routesInterface;
 | 
				
			||||||
 | 
					use OneLogin\Saml2\Auth;
 | 
				
			||||||
 | 
					use OneLogin\Saml2\Error;
 | 
				
			||||||
use Psr\Http\Message\ResponseInterface as Response;
 | 
					use Psr\Http\Message\ResponseInterface as Response;
 | 
				
			||||||
use Psr\Http\Message\ServerRequestInterface as Request;
 | 
					use Psr\Http\Message\ServerRequestInterface as Request;
 | 
				
			||||||
use Slim\App;
 | 
					use Slim\App;
 | 
				
			||||||
@ -12,14 +14,17 @@ use Slim\App;
 | 
				
			|||||||
class userRoutes implements routesInterface
 | 
					class userRoutes implements routesInterface
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    private userData $user;
 | 
					    private userData $user;
 | 
				
			||||||
 | 
					    private Auth $samlAuth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * constructor used to instantiate a base user routes, to be used in the index.php file.
 | 
					     * constructor used to instantiate a base user routes, to be used in the index.php file.
 | 
				
			||||||
     * @param App $app - the slim app used to create the routes
 | 
					     * @param App $app - the slim app used to create the routes
 | 
				
			||||||
 | 
					     * @throws Error
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(App $app)
 | 
					    public function __construct(App $app)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->user = new userData();
 | 
					        $this->user = new userData();
 | 
				
			||||||
 | 
					        $this->samlAuth = new Auth($this->user->getSamlConf());
 | 
				
			||||||
        $this->createRoutes($app);
 | 
					        $this->createRoutes($app);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,31 +35,9 @@ class userRoutes implements routesInterface
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function createRoutes(App $app): void
 | 
					    public function createRoutes(App $app): void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $app->post("/user/login", function (Request $request, Response $response)
 | 
					        $app->get("/user/login", function (Request $request, Response $response)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // get request data
 | 
					            $this->samlAuth->login();
 | 
				
			||||||
            $data = $request->getParsedBody();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (empty($data["username"]) || empty($data["password"]))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // uh oh user sent empty data
 | 
					 | 
				
			||||||
                return $response->withStatus(400);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->user->checkUser($data["username"], $data["password"]))
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                // yay, user is logged in
 | 
					 | 
				
			||||||
                $_SESSION["token"] = $this->user->createToken($data["username"]);
 | 
					 | 
				
			||||||
                $_SESSION["username"] = $data["username"];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                $inactive = 60 * 60 * 48; // 2 days
 | 
					 | 
				
			||||||
                $_SESSION["timeout"] = time() + $inactive;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                $response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
 | 
					 | 
				
			||||||
                return $response;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            $response->getBody()->write(json_encode(array("error" => "Unauthorised")));
 | 
					 | 
				
			||||||
            return $response->withStatus(401);
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $app->get("/user/logout", function (Request $request, Response $response)
 | 
					        $app->get("/user/logout", function (Request $request, Response $response)
 | 
				
			||||||
@ -92,6 +75,20 @@ class userRoutes implements routesInterface
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $app->get("/user/metadata", function (Request $request, Response $response)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            $settings = $this->samlAuth->getSettings();
 | 
				
			||||||
 | 
					            $metadata = $settings->getSPMetadata();
 | 
				
			||||||
 | 
					            $errors = $settings->validateMetadata($metadata);
 | 
				
			||||||
 | 
					            if (empty($errors))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                $response->getBody()->write($metadata);
 | 
				
			||||||
 | 
					                return $response->withHeader("Content-Type", "text/xml");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $response->getBody()->write(json_encode(array("error" => $errors)));
 | 
				
			||||||
 | 
					            return $response->withStatus(500);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
 | 
					        $app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (empty($args["email"]))
 | 
					            if (empty($args["email"]))
 | 
				
			||||||
@ -139,6 +136,61 @@ class userRoutes implements routesInterface
 | 
				
			|||||||
            return $response->withStatus(401);
 | 
					            return $response->withStatus(401);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $app->post("/user/login", function (Request $request, Response $response)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            // get request data
 | 
				
			||||||
 | 
					            $data = $request->getParsedBody();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (empty($data["username"]) || empty($data["password"]))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // uh oh user sent empty data
 | 
				
			||||||
 | 
					                return $response->withStatus(400);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($this->user->checkUser($data["username"], $data["password"]))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                // yay, user is logged in
 | 
				
			||||||
 | 
					                $_SESSION["token"] = $this->user->createToken($data["username"]);
 | 
				
			||||||
 | 
					                $_SESSION["username"] = $data["username"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $inactive = 60 * 60 * 48; // 2 days
 | 
				
			||||||
 | 
					                $_SESSION["timeout"] = time() + $inactive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                $response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
 | 
				
			||||||
 | 
					                return $response;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $response->getBody()->write(json_encode(array("error" => "Unauthorised")));
 | 
				
			||||||
 | 
					            return $response->withStatus(401);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $app->post("/user/acs", function (Request $request, Response $response)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            $this->samlAuth->processResponse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $attributes = $this->samlAuth->getAttributes();
 | 
				
			||||||
 | 
					//            $username = $attributes["username"][0];
 | 
				
			||||||
 | 
					//            $email = $attributes["email"][0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $response->getBody()->write(json_encode($attributes));
 | 
				
			||||||
 | 
					            return $response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//            if ($this->user->checkSAMLUser($username, $email))
 | 
				
			||||||
 | 
					//            {
 | 
				
			||||||
 | 
					//                // yay, user is logged in
 | 
				
			||||||
 | 
					//                $_SESSION["token"] = $this->user->createToken($username);
 | 
				
			||||||
 | 
					//                $_SESSION["username"] = $username;
 | 
				
			||||||
 | 
					//                $_SESSION["email"] = $email;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//                $inactive = 60 * 60 * 48; // 2 days
 | 
				
			||||||
 | 
					//                $_SESSION["timeout"] = time() + $inactive;
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//                return $response->withHeader("Location", "https://rohitpai.co.uk/editor/editor.html")->withStatus(302);
 | 
				
			||||||
 | 
					//            }
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//            $response->getBody()->write(json_encode(array("error" => "Unauthorised")));
 | 
				
			||||||
 | 
					//            return $response->withStatus(401);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $app->post("/user/changePassword", function (Request $request, Response $response)
 | 
					        $app->post("/user/changePassword", function (Request $request, Response $response)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
 | 
					            if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
 | 
				
			||||||
 | 
				
			|||||||
@ -190,6 +190,10 @@ div.categories {
 | 
				
			|||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					div.form input[type="submit"] {
 | 
				
			||||||
 | 
					    align-self: flex-start;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.image img, .image_resized img {
 | 
					.image img, .image_resized img {
 | 
				
			||||||
    max-width: 100%;
 | 
					    max-width: 100%;
 | 
				
			||||||
    -webkit-border-radius: 10px;
 | 
					    -webkit-border-radius: 10px;
 | 
				
			||||||
 | 
				
			|||||||
@ -162,11 +162,6 @@ div.form .formControl.passwordControl {
 | 
				
			|||||||
    display: block;
 | 
					    display: block;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
form input[type="submit"],
 | 
					 | 
				
			||||||
div.form input[type="submit"] {
 | 
					 | 
				
			||||||
    align-self: flex-start;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
form .formControl input:not([type="submit"]), form .formControl textarea,
 | 
					form .formControl input:not([type="submit"]), form .formControl textarea,
 | 
				
			||||||
form .formControl .ck.ck-editor__top .ck-sticky-panel .ck-toolbar,
 | 
					form .formControl .ck.ck-editor__top .ck-sticky-panel .ck-toolbar,
 | 
				
			||||||
form .formControl .ck.ck-editor__main .ck-content, div.menu input:not([type="submit"]),
 | 
					form .formControl .ck.ck-editor__main .ck-content, div.menu input:not([type="submit"]),
 | 
				
			||||||
 | 
				
			|||||||
@ -66,14 +66,22 @@ div#login input[type=submit]{
 | 
				
			|||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
div.btnContainer {
 | 
					div.btnContainer {
 | 
				
			||||||
    width: 100%;
 | 
					    width: 60%;
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    flex-direction: row;
 | 
					    flex-direction: column;
 | 
				
			||||||
    justify-content: space-between;
 | 
					    justify-content: center;
 | 
				
			||||||
    align-items: center;
 | 
					    align-items: stretch;
 | 
				
			||||||
 | 
					    gap: 1em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					div.btnContainer a {
 | 
				
			||||||
 | 
					    justify-content: center;
 | 
				
			||||||
 | 
					    text-transform: unset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					form div.btnContainer input[type="submit"] {
 | 
				
			||||||
 | 
					    align-self: stretch;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
div.btnContainer a:not(.btn) {
 | 
					div.btnContainer a:not(.btn) {
 | 
				
			||||||
 | 
				
			|||||||
@ -32,8 +32,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            <div class="btnContainer">
 | 
					            <div class="btnContainer">
 | 
				
			||||||
                <input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
 | 
					                <input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
 | 
				
			||||||
 | 
					                <a href="/api/user/login" class="btn btnPrimary boxShadowIn boxShadowOut">Login with Jump Cloud</a>
 | 
				
			||||||
                <a href="#" id="resetPwd">Reset Password</a>
 | 
					                <button type="button" id="resetPwd" class="btn btnPrimary boxShadowIn boxShadowOut">Reset Password
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@ -54,7 +55,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            <div class="btnContainer">
 | 
					            <div class="btnContainer">
 | 
				
			||||||
                <input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
 | 
					                <input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
 | 
				
			||||||
                <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login</a>
 | 
					                <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@ -75,7 +77,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            <div class="btnContainer">
 | 
					            <div class="btnContainer">
 | 
				
			||||||
                <input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
 | 
					                <input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
 | 
				
			||||||
                <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend Email</a>
 | 
					                <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend
 | 
				
			||||||
 | 
					                    Email
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@ -102,7 +106,7 @@
 | 
				
			|||||||
            
 | 
					            
 | 
				
			||||||
            <div class="btnContainer">
 | 
					            <div class="btnContainer">
 | 
				
			||||||
                <input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
 | 
					                <input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
 | 
				
			||||||
                <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</a>
 | 
					                <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</button>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </form>
 | 
					        </form>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user