diff --git a/examples/user-authentication/create_user.sql b/examples/user-authentication/create_user.sql new file mode 100644 index 00000000..3f197609 --- /dev/null +++ b/examples/user-authentication/create_user.sql @@ -0,0 +1,11 @@ +WITH inserted_user AS ( + INSERT INTO user_info (username, password_hash) + VALUES (:username, crypt(:password, gen_salt('bf', 10))) + ON CONFLICT (username) DO NOTHING + RETURNING username +) +SELECT 'text' AS component, + COALESCE( + 'Welcome, ' || (SELECT username FROM inserted_user) || '! Your user account was successfully created. You can now [log in](sign%20in.sql).', + 'Sorry, this user name is already taken.' + ) AS contents_md; \ No newline at end of file diff --git a/examples/user-authentication/docker-compose.yml b/examples/user-authentication/docker-compose.yml new file mode 100644 index 00000000..c4478dc9 --- /dev/null +++ b/examples/user-authentication/docker-compose.yml @@ -0,0 +1,20 @@ +services: + web: + image: lovasoa/sqlpage + ports: + - "8080:8080" + volumes: + - .:/var/www + depends_on: + - db + environment: + DATABASE_URL: postgres://root:secret@db/sqlpage + db: # The DB environment variable can be set to "mariadb" or "postgres" to test the code with different databases + ports: + - "5432:5432" + - "3306:3306" + image: postgres + environment: + POSTGRES_USER: root + POSTGRES_DB: sqlpage + POSTGRES_PASSWORD: secret diff --git a/examples/user-authentication/index.sql b/examples/user-authentication/index.sql new file mode 100644 index 00000000..f406f570 --- /dev/null +++ b/examples/user-authentication/index.sql @@ -0,0 +1,13 @@ +SELECT 'shell' AS component, + 'User Management App' AS title, + 'user' AS icon, + '/' AS link, + 'sign in' AS menu_item, + 'sign up' AS menu_item; + +SELECT 'hero' AS component, + 'SQLPage Authentication Demo' AS title, + 'This application requires signing up to view the protected page.' AS description_md, + 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/Community_wp20.png/974px-Community_wp20.png' AS image, + 'protected_page.sql' AS link, + 'Access protected page' AS link_text; \ No newline at end of file diff --git a/examples/user-authentication/login.sql b/examples/user-authentication/login.sql new file mode 100644 index 00000000..3f163d9c --- /dev/null +++ b/examples/user-authentication/login.sql @@ -0,0 +1,11 @@ +INSERT INTO login_session (username) +SELECT username +FROM user_info +WHERE username = :username + AND password_hash = crypt(:password, password_hash) +RETURNING 'cookie' AS component, + 'session' AS name, + id AS value; + +SELECT 'http_header' AS component, + 'protected_page.sql' AS location; \ No newline at end of file diff --git a/examples/user-authentication/protected_page.sql b/examples/user-authentication/protected_page.sql new file mode 100644 index 00000000..19354272 --- /dev/null +++ b/examples/user-authentication/protected_page.sql @@ -0,0 +1,8 @@ + +SELECT 'text' AS component, + 'This content is [top secret](https://youtu.be/dQw4w9WgXcQ). You cannot view it if you are not connected.' AS contents_md; + +SELECT EXISTS(SELECT 1 FROM login_session WHERE id=sqlpage.cookie('session')) AS contents; +SELECT 'debug' AS component; +SELECT * FROM login_session; +SELECT sqlpage.cookie('session'); \ No newline at end of file diff --git a/examples/user-authentication/sign in.sql b/examples/user-authentication/sign in.sql new file mode 100644 index 00000000..3e090249 --- /dev/null +++ b/examples/user-authentication/sign in.sql @@ -0,0 +1,7 @@ +SELECT 'form' AS component, + 'Sign in' AS title, + 'Sign in' AS validate, + 'login.sql' AS action; + +SELECT 'username' AS name; +SELECT 'password' AS name, 'password' AS type; \ No newline at end of file diff --git a/examples/user-authentication/sign up.sql b/examples/user-authentication/sign up.sql new file mode 100644 index 00000000..479c036f --- /dev/null +++ b/examples/user-authentication/sign up.sql @@ -0,0 +1,8 @@ +SELECT 'form' AS component, + 'Create a new user account' AS title, + 'Sign up' AS validate, + 'create_user.sql' AS action; + +SELECT 'username' AS name; +SELECT 'password' AS name, 'password' AS type; +SELECT 'terms' AS name, 'I accept the terms and conditions' AS label, TRUE AS required, FALSE AS value, 'checkbox' AS type; \ No newline at end of file diff --git a/examples/user-authentication/sqlpage/migrations/0000_init.sql b/examples/user-authentication/sqlpage/migrations/0000_init.sql new file mode 100644 index 00000000..a96e8489 --- /dev/null +++ b/examples/user-authentication/sqlpage/migrations/0000_init.sql @@ -0,0 +1,13 @@ +CREATE TABLE user_info ( + username TEXT PRIMARY KEY, + password_hash TEXT NOT NULL +); + +-- Activate the pgcrypto extension to be able to hash passwords, and generate session IDs. +CREATE EXTENSION IF NOT EXISTS pgcrypto; + +CREATE TABLE login_session ( + id TEXT PRIMARY KEY DEFAULT encode(gen_random_bytes(128), 'hex'), + username TEXT NOT NULL REFERENCES user_info(username), + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file